blob: b90c7d0deed1ee92ef81e4905113101ed4b92def [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// Copyright (C) MongoDB, Inc. 2017-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
7package command
8
9import (
10 "context"
11
12 "github.com/mongodb/mongo-go-driver/bson"
13 "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
14 "github.com/mongodb/mongo-go-driver/x/bsonx"
15 "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
16 "github.com/mongodb/mongo-go-driver/x/network/description"
17 "github.com/mongodb/mongo-go-driver/x/network/result"
18 "github.com/mongodb/mongo-go-driver/x/network/wiremessage"
19)
20
21// FindOneAndUpdate represents the findOneAndUpdate operation.
22//
23// The findOneAndUpdate command modifies and returns a single document.
24type FindOneAndUpdate struct {
25 NS Namespace
26 Query bsonx.Doc
27 Update bsonx.Doc
28 Opts []bsonx.Elem
29 WriteConcern *writeconcern.WriteConcern
30 Clock *session.ClusterClock
31 Session *session.Client
32
33 result result.FindAndModify
34 err error
35}
36
37// Encode will encode this command into a wire message for the given server description.
38func (f *FindOneAndUpdate) Encode(desc description.SelectedServer) (wiremessage.WireMessage, error) {
39 cmd, err := f.encode(desc)
40 if err != nil {
41 return nil, err
42 }
43
44 return cmd.Encode(desc)
45}
46
47func (f *FindOneAndUpdate) encode(desc description.SelectedServer) (*Write, error) {
48 if err := f.NS.Validate(); err != nil {
49 return nil, err
50 }
51
52 command := bsonx.Doc{
53 {"findAndModify", bsonx.String(f.NS.Collection)},
54 {"query", bsonx.Document(f.Query)},
55 {"update", bsonx.Document(f.Update)},
56 }
57 command = append(command, f.Opts...)
58
59 write := &Write{
60 Clock: f.Clock,
61 DB: f.NS.DB,
62 Command: command,
63 Session: f.Session,
64 }
65 if desc.WireVersion != nil && desc.WireVersion.Max >= 4 {
66 write.WriteConcern = f.WriteConcern
67 }
68 return write, nil
69}
70
71// Decode will decode the wire message using the provided server description. Errors during decoding
72// are deferred until either the Result or Err methods are called.
73func (f *FindOneAndUpdate) Decode(desc description.SelectedServer, wm wiremessage.WireMessage) *FindOneAndUpdate {
74 rdr, err := (&Write{}).Decode(desc, wm).Result()
75 if err != nil {
76 f.err = err
77 return f
78 }
79
80 return f.decode(desc, rdr)
81}
82
83func (f *FindOneAndUpdate) decode(desc description.SelectedServer, rdr bson.Raw) *FindOneAndUpdate {
84 f.result, f.err = unmarshalFindAndModifyResult(rdr)
85 return f
86}
87
88// Result returns the result of a decoded wire message and server description.
89func (f *FindOneAndUpdate) Result() (result.FindAndModify, error) {
90 if f.err != nil {
91 return result.FindAndModify{}, f.err
92 }
93 return f.result, nil
94}
95
96// Err returns the error set on this command.
97func (f *FindOneAndUpdate) Err() error { return f.err }
98
99// RoundTrip handles the execution of this command using the provided wiremessage.ReadWriter.
100func (f *FindOneAndUpdate) RoundTrip(ctx context.Context, desc description.SelectedServer, rw wiremessage.ReadWriter) (result.FindAndModify, error) {
101 cmd, err := f.encode(desc)
102 if err != nil {
103 return result.FindAndModify{}, err
104 }
105
106 rdr, err := cmd.RoundTrip(ctx, desc, rw)
107 if err != nil {
108 return result.FindAndModify{}, err
109 }
110
111 return f.decode(desc, rdr).Result()
112}