1
2
3
4
5
6
7 package operation
8
9 import (
10 "context"
11 "errors"
12 "fmt"
13 "time"
14
15 "go.mongodb.org/mongo-driver/bson"
16 "go.mongodb.org/mongo-driver/bson/bsontype"
17 "go.mongodb.org/mongo-driver/event"
18 "go.mongodb.org/mongo-driver/internal/driverutil"
19 "go.mongodb.org/mongo-driver/mongo/description"
20 "go.mongodb.org/mongo-driver/mongo/writeconcern"
21 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
22 "go.mongodb.org/mongo-driver/x/mongo/driver"
23 "go.mongodb.org/mongo-driver/x/mongo/driver/session"
24 )
25
26
27 type FindAndModify struct {
28 arrayFilters bsoncore.Array
29 bypassDocumentValidation *bool
30 collation bsoncore.Document
31 comment bsoncore.Value
32 fields bsoncore.Document
33 maxTime *time.Duration
34 newDocument *bool
35 query bsoncore.Document
36 remove *bool
37 sort bsoncore.Document
38 update bsoncore.Value
39 upsert *bool
40 session *session.Client
41 clock *session.ClusterClock
42 collection string
43 monitor *event.CommandMonitor
44 database string
45 deployment driver.Deployment
46 selector description.ServerSelector
47 writeConcern *writeconcern.WriteConcern
48 retry *driver.RetryMode
49 crypt driver.Crypt
50 hint bsoncore.Value
51 serverAPI *driver.ServerAPIOptions
52 let bsoncore.Document
53 timeout *time.Duration
54
55 result FindAndModifyResult
56 }
57
58
59 type LastErrorObject struct {
60
61 UpdatedExisting bool
62
63 Upserted interface{}
64 }
65
66
67 type FindAndModifyResult struct {
68
69 Value bsoncore.Document
70
71 LastErrorObject LastErrorObject
72 }
73
74 func buildFindAndModifyResult(response bsoncore.Document) (FindAndModifyResult, error) {
75 elements, err := response.Elements()
76 if err != nil {
77 return FindAndModifyResult{}, err
78 }
79 famr := FindAndModifyResult{}
80 for _, element := range elements {
81 switch element.Key() {
82 case "value":
83 var ok bool
84 famr.Value, ok = element.Value().DocumentOK()
85
86
87 if element.Value().Type != bsontype.Null && !ok {
88 return famr, fmt.Errorf("response field 'value' is type document or null, but received BSON type %s", element.Value().Type)
89 }
90 case "lastErrorObject":
91 valDoc, ok := element.Value().DocumentOK()
92 if !ok {
93 return famr, fmt.Errorf("response field 'lastErrorObject' is type document, but received BSON type %s", element.Value().Type)
94 }
95
96 var leo LastErrorObject
97 if err = bson.Unmarshal(valDoc, &leo); err != nil {
98 return famr, err
99 }
100 famr.LastErrorObject = leo
101 }
102 }
103 return famr, nil
104 }
105
106
107 func NewFindAndModify(query bsoncore.Document) *FindAndModify {
108 return &FindAndModify{
109 query: query,
110 }
111 }
112
113
114 func (fam *FindAndModify) Result() FindAndModifyResult { return fam.result }
115
116 func (fam *FindAndModify) processResponse(info driver.ResponseInfo) error {
117 var err error
118
119 fam.result, err = buildFindAndModifyResult(info.ServerResponse)
120 return err
121
122 }
123
124
125 func (fam *FindAndModify) Execute(ctx context.Context) error {
126 if fam.deployment == nil {
127 return errors.New("the FindAndModify operation must have a Deployment set before Execute can be called")
128 }
129
130 return driver.Operation{
131 CommandFn: fam.command,
132 ProcessResponseFn: fam.processResponse,
133
134 RetryMode: fam.retry,
135 Type: driver.Write,
136 Client: fam.session,
137 Clock: fam.clock,
138 CommandMonitor: fam.monitor,
139 Database: fam.database,
140 Deployment: fam.deployment,
141 MaxTime: fam.maxTime,
142 Selector: fam.selector,
143 WriteConcern: fam.writeConcern,
144 Crypt: fam.crypt,
145 ServerAPI: fam.serverAPI,
146 Timeout: fam.timeout,
147 Name: driverutil.FindAndModifyOp,
148 }.Execute(ctx)
149
150 }
151
152 func (fam *FindAndModify) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
153 dst = bsoncore.AppendStringElement(dst, "findAndModify", fam.collection)
154 if fam.arrayFilters != nil {
155
156 if desc.WireVersion == nil || !desc.WireVersion.Includes(6) {
157 return nil, errors.New("the 'arrayFilters' command parameter requires a minimum server wire version of 6")
158 }
159 dst = bsoncore.AppendArrayElement(dst, "arrayFilters", fam.arrayFilters)
160 }
161 if fam.bypassDocumentValidation != nil {
162
163 dst = bsoncore.AppendBooleanElement(dst, "bypassDocumentValidation", *fam.bypassDocumentValidation)
164 }
165 if fam.collation != nil {
166
167 if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
168 return nil, errors.New("the 'collation' command parameter requires a minimum server wire version of 5")
169 }
170 dst = bsoncore.AppendDocumentElement(dst, "collation", fam.collation)
171 }
172 if fam.comment.Type != bsontype.Type(0) {
173 dst = bsoncore.AppendValueElement(dst, "comment", fam.comment)
174 }
175 if fam.fields != nil {
176
177 dst = bsoncore.AppendDocumentElement(dst, "fields", fam.fields)
178 }
179 if fam.newDocument != nil {
180
181 dst = bsoncore.AppendBooleanElement(dst, "new", *fam.newDocument)
182 }
183 if fam.query != nil {
184
185 dst = bsoncore.AppendDocumentElement(dst, "query", fam.query)
186 }
187 if fam.remove != nil {
188
189 dst = bsoncore.AppendBooleanElement(dst, "remove", *fam.remove)
190 }
191 if fam.sort != nil {
192
193 dst = bsoncore.AppendDocumentElement(dst, "sort", fam.sort)
194 }
195 if fam.update.Data != nil {
196 dst = bsoncore.AppendValueElement(dst, "update", fam.update)
197 }
198 if fam.upsert != nil {
199
200 dst = bsoncore.AppendBooleanElement(dst, "upsert", *fam.upsert)
201 }
202 if fam.hint.Type != bsontype.Type(0) {
203
204 if desc.WireVersion == nil || !desc.WireVersion.Includes(8) {
205 return nil, errors.New("the 'hint' command parameter requires a minimum server wire version of 8")
206 }
207 if !fam.writeConcern.Acknowledged() {
208 return nil, errUnacknowledgedHint
209 }
210 dst = bsoncore.AppendValueElement(dst, "hint", fam.hint)
211 }
212 if fam.let != nil {
213 dst = bsoncore.AppendDocumentElement(dst, "let", fam.let)
214 }
215
216 return dst, nil
217 }
218
219
220 func (fam *FindAndModify) ArrayFilters(arrayFilters bsoncore.Array) *FindAndModify {
221 if fam == nil {
222 fam = new(FindAndModify)
223 }
224
225 fam.arrayFilters = arrayFilters
226 return fam
227 }
228
229
230 func (fam *FindAndModify) BypassDocumentValidation(bypassDocumentValidation bool) *FindAndModify {
231 if fam == nil {
232 fam = new(FindAndModify)
233 }
234
235 fam.bypassDocumentValidation = &bypassDocumentValidation
236 return fam
237 }
238
239
240 func (fam *FindAndModify) Collation(collation bsoncore.Document) *FindAndModify {
241 if fam == nil {
242 fam = new(FindAndModify)
243 }
244
245 fam.collation = collation
246 return fam
247 }
248
249
250 func (fam *FindAndModify) Comment(comment bsoncore.Value) *FindAndModify {
251 if fam == nil {
252 fam = new(FindAndModify)
253 }
254
255 fam.comment = comment
256 return fam
257 }
258
259
260 func (fam *FindAndModify) Fields(fields bsoncore.Document) *FindAndModify {
261 if fam == nil {
262 fam = new(FindAndModify)
263 }
264
265 fam.fields = fields
266 return fam
267 }
268
269
270 func (fam *FindAndModify) MaxTime(maxTime *time.Duration) *FindAndModify {
271 if fam == nil {
272 fam = new(FindAndModify)
273 }
274
275 fam.maxTime = maxTime
276 return fam
277 }
278
279
280 func (fam *FindAndModify) NewDocument(newDocument bool) *FindAndModify {
281 if fam == nil {
282 fam = new(FindAndModify)
283 }
284
285 fam.newDocument = &newDocument
286 return fam
287 }
288
289
290 func (fam *FindAndModify) Query(query bsoncore.Document) *FindAndModify {
291 if fam == nil {
292 fam = new(FindAndModify)
293 }
294
295 fam.query = query
296 return fam
297 }
298
299
300 func (fam *FindAndModify) Remove(remove bool) *FindAndModify {
301 if fam == nil {
302 fam = new(FindAndModify)
303 }
304
305 fam.remove = &remove
306 return fam
307 }
308
309
310 func (fam *FindAndModify) Sort(sort bsoncore.Document) *FindAndModify {
311 if fam == nil {
312 fam = new(FindAndModify)
313 }
314
315 fam.sort = sort
316 return fam
317 }
318
319
320 func (fam *FindAndModify) Update(update bsoncore.Value) *FindAndModify {
321 if fam == nil {
322 fam = new(FindAndModify)
323 }
324
325 fam.update = update
326 return fam
327 }
328
329
330 func (fam *FindAndModify) Upsert(upsert bool) *FindAndModify {
331 if fam == nil {
332 fam = new(FindAndModify)
333 }
334
335 fam.upsert = &upsert
336 return fam
337 }
338
339
340 func (fam *FindAndModify) Session(session *session.Client) *FindAndModify {
341 if fam == nil {
342 fam = new(FindAndModify)
343 }
344
345 fam.session = session
346 return fam
347 }
348
349
350 func (fam *FindAndModify) ClusterClock(clock *session.ClusterClock) *FindAndModify {
351 if fam == nil {
352 fam = new(FindAndModify)
353 }
354
355 fam.clock = clock
356 return fam
357 }
358
359
360 func (fam *FindAndModify) Collection(collection string) *FindAndModify {
361 if fam == nil {
362 fam = new(FindAndModify)
363 }
364
365 fam.collection = collection
366 return fam
367 }
368
369
370 func (fam *FindAndModify) CommandMonitor(monitor *event.CommandMonitor) *FindAndModify {
371 if fam == nil {
372 fam = new(FindAndModify)
373 }
374
375 fam.monitor = monitor
376 return fam
377 }
378
379
380 func (fam *FindAndModify) Database(database string) *FindAndModify {
381 if fam == nil {
382 fam = new(FindAndModify)
383 }
384
385 fam.database = database
386 return fam
387 }
388
389
390 func (fam *FindAndModify) Deployment(deployment driver.Deployment) *FindAndModify {
391 if fam == nil {
392 fam = new(FindAndModify)
393 }
394
395 fam.deployment = deployment
396 return fam
397 }
398
399
400 func (fam *FindAndModify) ServerSelector(selector description.ServerSelector) *FindAndModify {
401 if fam == nil {
402 fam = new(FindAndModify)
403 }
404
405 fam.selector = selector
406 return fam
407 }
408
409
410 func (fam *FindAndModify) WriteConcern(writeConcern *writeconcern.WriteConcern) *FindAndModify {
411 if fam == nil {
412 fam = new(FindAndModify)
413 }
414
415 fam.writeConcern = writeConcern
416 return fam
417 }
418
419
420
421
422 func (fam *FindAndModify) Retry(retry driver.RetryMode) *FindAndModify {
423 if fam == nil {
424 fam = new(FindAndModify)
425 }
426
427 fam.retry = &retry
428 return fam
429 }
430
431
432 func (fam *FindAndModify) Crypt(crypt driver.Crypt) *FindAndModify {
433 if fam == nil {
434 fam = new(FindAndModify)
435 }
436
437 fam.crypt = crypt
438 return fam
439 }
440
441
442 func (fam *FindAndModify) Hint(hint bsoncore.Value) *FindAndModify {
443 if fam == nil {
444 fam = new(FindAndModify)
445 }
446
447 fam.hint = hint
448 return fam
449 }
450
451
452 func (fam *FindAndModify) ServerAPI(serverAPI *driver.ServerAPIOptions) *FindAndModify {
453 if fam == nil {
454 fam = new(FindAndModify)
455 }
456
457 fam.serverAPI = serverAPI
458 return fam
459 }
460
461
462 func (fam *FindAndModify) Let(let bsoncore.Document) *FindAndModify {
463 if fam == nil {
464 fam = new(FindAndModify)
465 }
466
467 fam.let = let
468 return fam
469 }
470
471
472 func (fam *FindAndModify) Timeout(timeout *time.Duration) *FindAndModify {
473 if fam == nil {
474 fam = new(FindAndModify)
475 }
476
477 fam.timeout = timeout
478 return fam
479 }
480
View as plain text