@@ -76,32 +76,95 @@ using bsoncxx::document::view_or_value;
7676
7777namespace {
7878
79+ using bsoncxx::stdx::make_unique;
80+ using mongocxx::libbson::scoped_bson_t ;
81+
7982const char * get_collection_name (mongoc_collection_t * collection) {
8083 return mongocxx::libmongoc::collection_get_name (collection);
8184}
8285
86+ void destroy_fam_opts (mongoc_find_and_modify_opts_t * opts) {
87+ mongocxx::libmongoc::find_and_modify_opts_destroy (opts);
88+ }
89+
90+ template <typename T>
8391mongocxx::stdx::optional<bsoncxx::document::value> find_and_modify (
84- mongoc_collection_t * collection,
85- bsoncxx::document::view command,
86- bsoncxx::document::view opts,
87- const bsoncxx::stdx::optional<mongocxx::write_concern>& wc) {
88- bsoncxx::builder::basic::document opts_builder;
89- opts_builder.append (concatenate (opts));
92+ mongoc_collection_t * collection_t ,
93+ const mongoc_client_session_t * session_t ,
94+ view_or_value filter,
95+ view_or_value* update,
96+ mongoc_find_and_modify_flags_t flags,
97+ bool bypass,
98+ const T& options) {
99+ using unique_opts =
100+ std::unique_ptr<mongoc_find_and_modify_opts_t ,
101+ std::function<void MONGOCXX_CALL (mongoc_find_and_modify_opts_t *)>>;
90102
91- if (wc) {
92- if (!wc->is_acknowledged () && opts[" collation" ]) {
103+ auto opts = unique_opts (mongocxx::libmongoc::find_and_modify_opts_new (), destroy_fam_opts);
104+
105+ bsoncxx::builder::basic::document extra;
106+ ::bson_error_t error;
107+
108+ // Write concern, collation, and session are passed in "extra".
109+ if (options.write_concern ()) {
110+ if (!options.write_concern ()->is_acknowledged () && options.collation ()) {
93111 throw mongocxx::logic_error{mongocxx::error_code::k_invalid_parameter};
94112 }
95- opts_builder.append (concatenate (wc->to_document ()));
113+ extra.append (concatenate (options.write_concern ()->to_document ()));
114+ }
115+
116+ if (session_t ) {
117+ bson_t bson = BSON_INITIALIZER;
118+ if (!mongocxx::libmongoc::client_session_append (session_t , &bson, &error)) {
119+ bson_destroy (&bson);
120+ throw mongocxx::logic_error{mongocxx::error_code::k_invalid_session, error.message };
121+ }
122+
123+ // document::value takes ownership of the bson buffer.
124+ bsoncxx::document::value session_id{bsoncxx::helpers::value_from_bson_t (&bson)};
125+ extra.append (concatenate (session_id.view ()));
126+ }
127+
128+ if (options.collation ()) {
129+ extra.append (kvp (" collation" , *options.collation ()));
130+ }
131+
132+ scoped_bson_t extra_bson{extra.view ()};
133+ mongocxx::libmongoc::find_and_modify_opts_append (opts.get (), extra_bson.bson ());
134+
135+ if (update) {
136+ scoped_bson_t update_bson{update->view ()};
137+ mongocxx::libmongoc::find_and_modify_opts_set_update (opts.get (), update_bson.bson ());
96138 }
97139
98- mongocxx::libbson::scoped_bson_t command_bson{command};
99- mongocxx::libbson::scoped_bson_t opts_bson{opts_builder.extract ()};
140+ if (bypass) {
141+ mongocxx::libmongoc::find_and_modify_opts_set_bypass_document_validation (opts.get (), true );
142+ }
143+
144+ if (options.sort ()) {
145+ scoped_bson_t sort_bson{*options.sort ()};
146+ mongocxx::libmongoc::find_and_modify_opts_set_sort (opts.get (), sort_bson.bson ());
147+ }
148+
149+ if (options.projection ()) {
150+ scoped_bson_t projection_bson{*options.projection ()};
151+ mongocxx::libmongoc::find_and_modify_opts_set_fields (opts.get (), projection_bson.bson ());
152+ }
153+
154+ if (options.max_time ()) {
155+ mongocxx::libmongoc::find_and_modify_opts_set_max_time_ms (
156+ opts.get (), static_cast <uint32_t >(options.max_time ()->count ()));
157+ }
158+
159+ // Upsert, remove, and new are passed in flags.
160+ mongocxx::libmongoc::find_and_modify_opts_set_flags (opts.get (), flags);
161+
162+ // Call mongoc_collection_find_and_modify_with_opts.
163+ scoped_bson_t filter_bson{filter.view ()};
100164 mongocxx::libbson::scoped_bson_t reply;
101- ::bson_error_t error;
102165
103- bool result = mongocxx::libmongoc::collection_write_command_with_opts (
104- collection, command_bson .bson (), opts_bson. bson (), reply.bson_for_init (), &error);
166+ bool result = mongocxx::libmongoc::collection_find_and_modify_with_opts (
167+ collection_t , filter_bson .bson (), opts. get (), reply.bson_for_init (), &error);
105168
106169 if (!result) {
107170 if (!reply.view ().empty ()) {
@@ -801,50 +864,22 @@ stdx::optional<bsoncxx::document::value> collection::_find_one_and_replace(
801864 view_or_value filter,
802865 view_or_value replacement,
803866 const options::find_one_and_replace& options) {
804- bsoncxx::builder::basic::document command_doc;
805- bsoncxx::builder::basic::document options_doc;
806-
807- command_doc.append (
808- kvp (" findAndModify" , libmongoc::collection_get_name (_get_impl ().collection_t )));
809-
810- options_doc.append (kvp (" query" , filter));
811-
812- options_doc.append (kvp (" update" , replacement.view ()));
813-
814- if (options.sort ()) {
815- options_doc.append (kvp (" sort" , *options.sort ()));
816- }
817-
818- if (options.bypass_document_validation ()) {
819- options_doc.append (kvp (" bypassDocumentValidation" , *options.bypass_document_validation ()));
820- }
821-
822- if (options.collation ()) {
823- options_doc.append (kvp (" collation" , *options.collation ()));
824- }
825-
826- if (options.projection ()) {
827- options_doc.append (kvp (" fields" , *options.projection ()));
828- }
829-
867+ mongoc_find_and_modify_flags_t flags = MONGOC_FIND_AND_MODIFY_NONE;
830868 if (options.upsert ().value_or (false )) {
831- options_doc. append ( kvp ( " upsert " , *options. upsert ()) );
869+ flags = ( mongoc_find_and_modify_flags_t )(flags | MONGOC_FIND_AND_MODIFY_UPSERT );
832870 }
833871
834872 if (options.return_document () == options::return_document::k_after) {
835- options_doc. append ( kvp ( " new " , true ) );
873+ flags = ( mongoc_find_and_modify_flags_t )(flags | MONGOC_FIND_AND_MODIFY_RETURN_NEW );
836874 }
837875
838- if (options.max_time ()) {
839- options_doc.append (kvp (" maxTimeMS" , bsoncxx::types::b_int64{options.max_time ()->count ()}));
840- }
841-
842- if (session) {
843- options_doc.append (bsoncxx::builder::concatenate_doc{session->_get_impl ().to_document ()});
844- }
845-
846- return find_and_modify (
847- _get_impl ().collection_t , command_doc.view (), options_doc.view (), options.write_concern ());
876+ return find_and_modify (_get_impl ().collection_t ,
877+ session ? session->_get_impl ().get_session_t () : nullptr ,
878+ filter,
879+ &replacement,
880+ flags,
881+ options.bypass_document_validation ().value_or (false ),
882+ options);
848883}
849884
850885stdx::optional<bsoncxx::document::value> collection::find_one_and_replace (
@@ -865,50 +900,22 @@ stdx::optional<bsoncxx::document::value> collection::_find_one_and_update(
865900 view_or_value filter,
866901 view_or_value update,
867902 const options::find_one_and_update& options) {
868- bsoncxx::builder::basic::document command_doc;
869- bsoncxx::builder::basic::document options_doc;
870-
871- command_doc.append (
872- kvp (" findAndModify" , libmongoc::collection_get_name (_get_impl ().collection_t )));
873-
874- options_doc.append (kvp (" query" , filter));
875-
876- options_doc.append (kvp (" update" , update));
877-
878- if (options.sort ()) {
879- options_doc.append (kvp (" sort" , *options.sort ()));
880- }
881-
882- if (options.return_document () == options::return_document::k_after) {
883- options_doc.append (kvp (" new" , true ));
884- }
885-
886- if (options.bypass_document_validation ()) {
887- options_doc.append (kvp (" bypassDocumentValidation" , *options.bypass_document_validation ()));
888- }
889-
890- if (options.collation ()) {
891- options_doc.append (kvp (" collation" , *options.collation ()));
892- }
893-
894- if (options.projection ()) {
895- options_doc.append (kvp (" fields" , *options.projection ()));
896- }
897-
903+ mongoc_find_and_modify_flags_t flags = MONGOC_FIND_AND_MODIFY_NONE;
898904 if (options.upsert ().value_or (false )) {
899- options_doc.append (kvp (" upsert" , *options.upsert ()));
900- }
901-
902- if (options.max_time ()) {
903- options_doc.append (kvp (" maxTimeMS" , bsoncxx::types::b_int64{options.max_time ()->count ()}));
905+ flags = (mongoc_find_and_modify_flags_t )(flags | MONGOC_FIND_AND_MODIFY_UPSERT);
904906 }
905907
906- if (session ) {
907- options_doc. append (bsoncxx::builder::concatenate_doc{session-> _get_impl (). to_document ()} );
908+ if (options. return_document () == options::return_document::k_after ) {
909+ flags = ( mongoc_find_and_modify_flags_t )(flags | MONGOC_FIND_AND_MODIFY_RETURN_NEW );
908910 }
909911
910- return find_and_modify (
911- _get_impl ().collection_t , command_doc.view (), options_doc.view (), options.write_concern ());
912+ return find_and_modify (_get_impl ().collection_t ,
913+ session ? session->_get_impl ().get_session_t () : nullptr ,
914+ filter,
915+ &update,
916+ flags,
917+ options.bypass_document_validation ().value_or (false ),
918+ options);
912919}
913920
914921stdx::optional<bsoncxx::document::value> collection::find_one_and_update (
@@ -928,42 +935,13 @@ stdx::optional<bsoncxx::document::value> collection::_find_one_and_delete(
928935 const client_session* session,
929936 view_or_value filter,
930937 const options::find_one_and_delete& options) {
931- bsoncxx::builder::basic::document command_doc;
932- bsoncxx::builder::basic::document options_doc;
933-
934- command_doc.append (
935- kvp (" findAndModify" , libmongoc::collection_get_name (_get_impl ().collection_t )));
936-
937- options_doc.append (kvp (" query" , filter));
938-
939- options_doc.append (kvp (" remove" , true ));
940-
941- if (options.sort ()) {
942- options_doc.append (kvp (" sort" , *options.sort ()));
943- }
944-
945- if (options.collation ()) {
946- options_doc.append (kvp (" collation" , *options.collation ()));
947- }
948-
949- if (options.projection ()) {
950- options_doc.append (kvp (" fields" , *options.projection ()));
951- }
952-
953- if (options.max_time ()) {
954- options_doc.append (kvp (" maxTimeMS" , bsoncxx::types::b_int64{options.max_time ()->count ()}));
955- }
956-
957- if (options.write_concern ()) {
958- options_doc.append (kvp (" writeConcern" , options.write_concern ()->to_document ()));
959- }
960-
961- if (session) {
962- options_doc.append (bsoncxx::builder::concatenate_doc{session->_get_impl ().to_document ()});
963- }
964-
965- return find_and_modify (
966- _get_impl ().collection_t , command_doc.view (), options_doc.view (), options.write_concern ());
938+ return find_and_modify (_get_impl ().collection_t ,
939+ session ? session->_get_impl ().get_session_t () : nullptr ,
940+ filter,
941+ nullptr ,
942+ MONGOC_FIND_AND_MODIFY_REMOVE,
943+ false ,
944+ options);
967945}
968946
969947stdx::optional<bsoncxx::document::value> collection::find_one_and_delete (
0 commit comments