github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/x/mongo/driver/operation/count.go (about) 1 // Copyright (C) MongoDB, Inc. 2019-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 package operation 8 9 import ( 10 "context" 11 "errors" 12 "fmt" 13 "time" 14 15 "go.mongodb.org/mongo-driver/bson/bsontype" 16 "go.mongodb.org/mongo-driver/event" 17 "go.mongodb.org/mongo-driver/mongo/description" 18 "go.mongodb.org/mongo-driver/mongo/readconcern" 19 "go.mongodb.org/mongo-driver/mongo/readpref" 20 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" 21 "go.mongodb.org/mongo-driver/x/mongo/driver" 22 "go.mongodb.org/mongo-driver/x/mongo/driver/session" 23 ) 24 25 // Count represents a count operation. 26 type Count struct { 27 maxTime *time.Duration 28 query bsoncore.Document 29 session *session.Client 30 clock *session.ClusterClock 31 collection string 32 comment bsoncore.Value 33 monitor *event.CommandMonitor 34 crypt driver.Crypt 35 database string 36 deployment driver.Deployment 37 readConcern *readconcern.ReadConcern 38 readPreference *readpref.ReadPref 39 selector description.ServerSelector 40 retry *driver.RetryMode 41 result CountResult 42 serverAPI *driver.ServerAPIOptions 43 timeout *time.Duration 44 } 45 46 // CountResult represents a count result returned by the server. 47 type CountResult struct { 48 // The number of documents found 49 N int64 50 } 51 52 func buildCountResult(response bsoncore.Document) (CountResult, error) { 53 elements, err := response.Elements() 54 if err != nil { 55 return CountResult{}, err 56 } 57 cr := CountResult{} 58 for _, element := range elements { 59 switch element.Key() { 60 case "n": // for count using original command 61 var ok bool 62 cr.N, ok = element.Value().AsInt64OK() 63 if !ok { 64 return cr, fmt.Errorf("response field 'n' is type int64, but received BSON type %s", 65 element.Value().Type) 66 } 67 case "cursor": // for count using aggregate with $collStats 68 firstBatch, err := element.Value().Document().LookupErr("firstBatch") 69 if err != nil { 70 return cr, err 71 } 72 73 // get count value from first batch 74 val := firstBatch.Array().Index(0) 75 count, err := val.Document().LookupErr("n") 76 if err != nil { 77 return cr, err 78 } 79 80 // use count as Int64 for result 81 var ok bool 82 cr.N, ok = count.AsInt64OK() 83 if !ok { 84 return cr, fmt.Errorf("response field 'n' is type int64, but received BSON type %s", 85 element.Value().Type) 86 } 87 } 88 } 89 return cr, nil 90 } 91 92 // NewCount constructs and returns a new Count. 93 func NewCount() *Count { 94 return &Count{} 95 } 96 97 // Result returns the result of executing this operation. 98 func (c *Count) Result() CountResult { return c.result } 99 100 func (c *Count) processResponse(info driver.ResponseInfo) error { 101 var err error 102 c.result, err = buildCountResult(info.ServerResponse) 103 return err 104 } 105 106 // Execute runs this operations and returns an error if the operation did not execute successfully. 107 func (c *Count) Execute(ctx context.Context) error { 108 if c.deployment == nil { 109 return errors.New("the Count operation must have a Deployment set before Execute can be called") 110 } 111 112 err := driver.Operation{ 113 CommandFn: c.command, 114 ProcessResponseFn: c.processResponse, 115 RetryMode: c.retry, 116 Type: driver.Read, 117 Client: c.session, 118 Clock: c.clock, 119 CommandMonitor: c.monitor, 120 Crypt: c.crypt, 121 Database: c.database, 122 Deployment: c.deployment, 123 MaxTime: c.maxTime, 124 ReadConcern: c.readConcern, 125 ReadPreference: c.readPreference, 126 Selector: c.selector, 127 ServerAPI: c.serverAPI, 128 Timeout: c.timeout, 129 }.Execute(ctx) 130 131 // Swallow error if NamespaceNotFound(26) is returned from aggregate on non-existent namespace 132 if err != nil { 133 dErr, ok := err.(driver.Error) 134 if ok && dErr.Code == 26 { 135 err = nil 136 } 137 } 138 return err 139 } 140 141 func (c *Count) command(dst []byte, _ description.SelectedServer) ([]byte, error) { 142 dst = bsoncore.AppendStringElement(dst, "count", c.collection) 143 if c.query != nil { 144 dst = bsoncore.AppendDocumentElement(dst, "query", c.query) 145 } 146 if c.comment.Type != bsontype.Type(0) { 147 dst = bsoncore.AppendValueElement(dst, "comment", c.comment) 148 } 149 return dst, nil 150 } 151 152 // MaxTime specifies the maximum amount of time to allow the query to run on the server. 153 func (c *Count) MaxTime(maxTime *time.Duration) *Count { 154 if c == nil { 155 c = new(Count) 156 } 157 158 c.maxTime = maxTime 159 return c 160 } 161 162 // Query determines what results are returned from find. 163 func (c *Count) Query(query bsoncore.Document) *Count { 164 if c == nil { 165 c = new(Count) 166 } 167 168 c.query = query 169 return c 170 } 171 172 // Session sets the session for this operation. 173 func (c *Count) Session(session *session.Client) *Count { 174 if c == nil { 175 c = new(Count) 176 } 177 178 c.session = session 179 return c 180 } 181 182 // ClusterClock sets the cluster clock for this operation. 183 func (c *Count) ClusterClock(clock *session.ClusterClock) *Count { 184 if c == nil { 185 c = new(Count) 186 } 187 188 c.clock = clock 189 return c 190 } 191 192 // Collection sets the collection that this command will run against. 193 func (c *Count) Collection(collection string) *Count { 194 if c == nil { 195 c = new(Count) 196 } 197 198 c.collection = collection 199 return c 200 } 201 202 // Comment sets a value to help trace an operation. 203 func (c *Count) Comment(comment bsoncore.Value) *Count { 204 if c == nil { 205 c = new(Count) 206 } 207 208 c.comment = comment 209 return c 210 } 211 212 // CommandMonitor sets the monitor to use for APM events. 213 func (c *Count) CommandMonitor(monitor *event.CommandMonitor) *Count { 214 if c == nil { 215 c = new(Count) 216 } 217 218 c.monitor = monitor 219 return c 220 } 221 222 // Crypt sets the Crypt object to use for automatic encryption and decryption. 223 func (c *Count) Crypt(crypt driver.Crypt) *Count { 224 if c == nil { 225 c = new(Count) 226 } 227 228 c.crypt = crypt 229 return c 230 } 231 232 // Database sets the database to run this operation against. 233 func (c *Count) Database(database string) *Count { 234 if c == nil { 235 c = new(Count) 236 } 237 238 c.database = database 239 return c 240 } 241 242 // Deployment sets the deployment to use for this operation. 243 func (c *Count) Deployment(deployment driver.Deployment) *Count { 244 if c == nil { 245 c = new(Count) 246 } 247 248 c.deployment = deployment 249 return c 250 } 251 252 // ReadConcern specifies the read concern for this operation. 253 func (c *Count) ReadConcern(readConcern *readconcern.ReadConcern) *Count { 254 if c == nil { 255 c = new(Count) 256 } 257 258 c.readConcern = readConcern 259 return c 260 } 261 262 // ReadPreference set the read preference used with this operation. 263 func (c *Count) ReadPreference(readPreference *readpref.ReadPref) *Count { 264 if c == nil { 265 c = new(Count) 266 } 267 268 c.readPreference = readPreference 269 return c 270 } 271 272 // ServerSelector sets the selector used to retrieve a server. 273 func (c *Count) ServerSelector(selector description.ServerSelector) *Count { 274 if c == nil { 275 c = new(Count) 276 } 277 278 c.selector = selector 279 return c 280 } 281 282 // Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based 283 // on how the operation is set. 284 func (c *Count) Retry(retry driver.RetryMode) *Count { 285 if c == nil { 286 c = new(Count) 287 } 288 289 c.retry = &retry 290 return c 291 } 292 293 // ServerAPI sets the server API version for this operation. 294 func (c *Count) ServerAPI(serverAPI *driver.ServerAPIOptions) *Count { 295 if c == nil { 296 c = new(Count) 297 } 298 299 c.serverAPI = serverAPI 300 return c 301 } 302 303 // Timeout sets the timeout for this operation. 304 func (c *Count) Timeout(timeout *time.Duration) *Count { 305 if c == nil { 306 c = new(Count) 307 } 308 309 c.timeout = timeout 310 return c 311 }