3737// corresponding page on mongodb.com/docs. See CXX-1249 and DRIVERS-356 for more info.
3838
3939template <typename T>
40- void check_field (const T& document, const char * field, bool should_have, int example_no) {
40+ void check_field (const T& document,
41+ const char * field,
42+ bool should_have,
43+ int example_no,
44+ const char * example_type = NULL ) {
45+ std::string example_type_formatted = example_type ? example_type + std::string (" " ) : " " ;
4146 if (should_have) {
4247 if (!document[field]) {
43- throw std::logic_error (std::string (" document in example " ) +
44- std::to_string (example_no) + " should have field " + field);
48+ throw std::logic_error (std::string (" document in " ) + example_type_formatted +
49+ std::string (" example " ) + std::to_string (example_no) +
50+ " should not have field " + field);
4551 }
4652 } else {
4753 if (document[field]) {
48- throw std::logic_error (std::string (" document in example " ) +
49- std::to_string (example_no) + " should not have field " + field);
54+ throw std::logic_error (std::string (" document in " ) + example_type_formatted +
55+ std::string (" example " ) + std::to_string (example_no) +
56+ " should not have field " + field);
5057 }
5158 }
5259}
@@ -61,6 +68,22 @@ void check_has_no_field(const T& document, const char* field, int example_no) {
6168 check_field (document, field, false , example_no);
6269}
6370
71+ template <typename T>
72+ void check_has_field (const T& document,
73+ const char * field,
74+ int example_no,
75+ const char * example_type) {
76+ check_field (document, field, true , example_no, example_type);
77+ }
78+
79+ template <typename T>
80+ void check_has_no_field (const T& document,
81+ const char * field,
82+ int example_no,
83+ const char * example_type) {
84+ check_field (document, field, false , example_no, example_type);
85+ }
86+
6487bool should_run_client_side_encryption_test (void ) {
6588 const char * const vars[] = {
6689 " MONGOCXX_TEST_AWS_SECRET_ACCESS_KEY" ,
@@ -187,6 +210,46 @@ static bool is_replica_set(const mongocxx::client& client) {
187210 return static_cast <bool >(reply.view ()[" setName" ]);
188211}
189212
213+ static bool version_at_least (mongocxx::database& db,
214+ int minimum_major,
215+ int minimum_minor,
216+ int minimum_patch) {
217+ using bsoncxx::builder::basic::kvp;
218+ using bsoncxx::builder::basic::make_document;
219+
220+ auto resp = db.run_command (make_document (kvp (" buildInfo" , 1 )));
221+ auto version = resp.find (" version" )->get_string ().value ;
222+ std::string major_string;
223+ std::string minor_string;
224+ std::string patch_string;
225+ int split = 0 ;
226+ for (auto i : version) {
227+ if (i == ' .' ) {
228+ split += 1 ;
229+ continue ;
230+ }
231+ if (split == 0 ) {
232+ major_string += i;
233+ } else if (split == 1 ) {
234+ minor_string += i;
235+ } else if (split == 2 ) {
236+ patch_string += i;
237+ }
238+ }
239+
240+ std::vector<int > server_semver{
241+ std::stoi (major_string), std::stoi (minor_string), std::stoi (minor_string)};
242+ std::vector<int > minimum_semver{minimum_major, minimum_minor, minimum_patch};
243+ for (size_t i = 0 ; i < server_semver.size (); i++) {
244+ if (server_semver[i] < minimum_semver[i]) {
245+ return false ;
246+ } else if (server_semver[i] > minimum_semver[i]) {
247+ return true ;
248+ }
249+ }
250+ return true ;
251+ }
252+
190253void insert_examples (mongocxx::database db) {
191254 db[" inventory" ].drop ();
192255
@@ -869,7 +932,7 @@ void query_null_missing_fields_examples(mongocxx::database db) {
869932 }
870933}
871934
872- void projection_examples (mongocxx::database db) {
935+ void projection_insertion_example (mongocxx::database db) {
873936 db[" inventory" ].drop ();
874937
875938 {
@@ -915,6 +978,10 @@ void projection_examples(mongocxx::database db) {
915978 throw std::logic_error (" wrong count in example 42" );
916979 }
917980 }
981+ }
982+
983+ void projection_examples (mongocxx::database db) {
984+ projection_insertion_example (db);
918985
919986 {
920987 // Start Example 43
@@ -1092,6 +1159,63 @@ void projection_examples(mongocxx::database db) {
10921159 }
10931160}
10941161
1162+ void projection_with_aggregation_example (mongocxx::database db) {
1163+ {
1164+ if (!version_at_least (db, 4 , 4 , 0 )) {
1165+ return ;
1166+ }
1167+
1168+ projection_insertion_example (db);
1169+
1170+ // Start Aggregation Projection Example 1
1171+ using bsoncxx::builder::basic::kvp;
1172+ using bsoncxx::builder::basic::make_array;
1173+ using bsoncxx::builder::basic::make_document;
1174+
1175+ auto cursor = db[" inventory" ].find (
1176+ make_document (),
1177+ mongocxx::options::find{}.projection (make_document (
1178+ kvp (" _id" , 0 ),
1179+ kvp (" item" , 1 ),
1180+ kvp (" status" ,
1181+ make_document (kvp (
1182+ " $switch" ,
1183+ make_document (
1184+ kvp (" branches" ,
1185+ make_array (
1186+ make_document (
1187+ kvp (" case" ,
1188+ make_document (kvp (" $eq" , make_array (" $status" , " A" )))),
1189+ kvp (" then" , " Available" )),
1190+ make_document (
1191+ kvp (" case" ,
1192+ make_document (kvp (" $eq" , make_array (" $status" , " D" )))),
1193+ kvp (" then" , " Discontinued" )))),
1194+ kvp (" default" , " No status found" ))))),
1195+ kvp (" area" ,
1196+ make_document (kvp (
1197+ " $concat" ,
1198+ make_array (
1199+ make_document (kvp (
1200+ " $toString" ,
1201+ make_document (kvp (" $multiply" , make_array (" $size.h" , " $size.w" ))))),
1202+ " " ,
1203+ " $size.uom" )))),
1204+ kvp (" reportNumber" , make_document (kvp (" $literal" , 1 ))))));
1205+ // End Aggregation Projection Example 1
1206+
1207+ for (auto && document : cursor) {
1208+ check_has_no_field (document, " _id" , 1 , " aggregation projection" );
1209+ check_has_field (document, " item" , 1 , " aggregation projection" );
1210+ check_has_field (document, " status" , 1 , " aggregation projection" );
1211+ check_has_no_field (document, " size" , 1 , " aggregation projection" );
1212+ check_has_no_field (document, " instock" , 1 , " aggregation projection" );
1213+ check_has_field (document, " area" , 1 , " aggregation projection" );
1214+ check_has_field (document, " reportNumber" , 1 , " aggregation projection" );
1215+ }
1216+ }
1217+ }
1218+
10951219void update_examples (mongocxx::database db) {
10961220 db[" inventory" ].drop ();
10971221
@@ -1467,24 +1591,6 @@ static void snapshot_example2(mongocxx::client& client) {
14671591 }
14681592}
14691593
1470- static bool version_at_least (mongocxx::database& db, int minimum_major) {
1471- using bsoncxx::builder::basic::kvp;
1472- using bsoncxx::builder::basic::make_document;
1473-
1474- auto resp = db.run_command (make_document (kvp (" buildInfo" , 1 )));
1475- auto version = resp.find (" version" )->get_string ().value ;
1476- std::string major_string;
1477- for (auto i : version) {
1478- if (i == ' .' ) {
1479- break ;
1480- }
1481- major_string += i;
1482- }
1483- int server_major = std::stoi (major_string);
1484-
1485- return server_major >= minimum_major;
1486- }
1487-
14881594// https://jira.mongodb.com/browse/CXX-2505
14891595static void queryable_encryption_api (mongocxx::client& client) {
14901596 // Start Queryable Encryption Example
@@ -1610,14 +1716,15 @@ int main() {
16101716 query_array_embedded_documents_examples (db);
16111717 query_null_missing_fields_examples (db);
16121718 projection_examples (db);
1719+ projection_with_aggregation_example (db);
16131720 update_examples (db);
16141721 delete_examples (db);
1615- if (is_replica_set (conn) && version_at_least (db, 5 )) {
1722+ if (is_replica_set (conn) && version_at_least (db, 5 , 0 , 0 )) {
16161723 snapshot_example1 (conn);
16171724 snapshot_example2 (conn);
16181725 }
16191726 if (should_run_client_side_encryption_test () && is_replica_set (conn) &&
1620- version_at_least (db, 7 )) {
1727+ version_at_least (db, 7 , 0 , 0 )) {
16211728 queryable_encryption_api (conn);
16221729 }
16231730 } catch (const std::logic_error& e) {
0 commit comments