Mangrove
The C++ Object Document Mapper for MongoDB
query_builder.hpp
1 // Copyright 2016 MongoDB Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <mangrove/config/prelude.hpp>
18 
19 #include <chrono>
20 #include <cstddef>
21 #include <stdexcept>
22 #include <tuple>
23 #include <type_traits>
24 
25 #include <bsoncxx/builder/core.hpp>
26 #include <bsoncxx/view_or_value.hpp>
27 
28 #include <mangrove/expression_syntax.hpp>
29 #include <mangrove/nvp.hpp>
30 #include <mangrove/util.hpp>
31 
32 namespace mangrove {
33 MANGROVE_INLINE_NAMESPACE_BEGIN
34 
39 template <typename T>
40 auto is_bson_appendable_impl(int)
41  -> decltype(std::declval<bsoncxx::builder::core>().append(std::declval<T>()), std::true_type{});
42 
43 template <typename T>
44 std::false_type is_bson_appendable_impl(...);
45 
46 template <typename T>
47 using is_bson_appendable = decltype(is_bson_appendable_impl<T>(0));
48 
49 template <typename T>
50 constexpr bool is_bson_appendable_v = is_bson_appendable<T>::value;
51 
59 // Specialization for appendable types.
60 template <typename T>
61 std::enable_if_t<is_bson_appendable_v<T>> append_value_to_bson(T value,
62  bsoncxx::builder::core &builder) {
63  builder.append(value);
64 }
65 
66 // Specialization for non-iterable, non-expression types that must be serialized.
67 template <typename T>
68 std::enable_if_t<!is_bson_appendable_v<T> && !is_iterable_not_string_v<T> &&
69  details::isnt_expression_v<T>>
70 append_value_to_bson(const T &value, bsoncxx::builder::core &builder) {
71  auto serialized_value = boson::to_document<T>(value);
72  builder.append(bsoncxx::types::b_document{serialized_value});
73 }
74 
75 // Specialization for iterable types that must be serialized.
76 template <typename Iterable>
77 std::enable_if_t<is_iterable_not_string_v<Iterable>> append_value_to_bson(
78  const Iterable &arr, bsoncxx::builder::core &builder) {
79  builder.open_array();
80  for (const auto &x : arr) {
81  append_value_to_bson(x, builder);
82  }
83  builder.close_array();
84 }
85 
86 // Specialization for expression types that must be serialized.
87 template <typename Expression>
88 std::enable_if_t<!details::isnt_expression_v<Expression>> append_value_to_bson(
89  const Expression &expr, bsoncxx::builder::core &builder) {
90  builder.open_document();
91  expr.append_to_bson(builder);
92  builder.close_document();
93 }
94 
95 // std::chrono::time_point must be explicitly serialized into b_date
96 template <typename Clock, typename Duration>
97 void append_value_to_bson(const std::chrono::time_point<Clock, Duration> &tp,
98  bsoncxx::builder::core &builder) {
99  builder.append(bsoncxx::types::b_date(tp));
100 }
101 
107 template <typename NvpT>
108 class sort_expr {
109  public:
110  using field_type = NvpT;
116  constexpr sort_expr(const NvpT &nvp, bool ascending) : _nvp(nvp), _ascending(ascending) {
117  }
118 
125  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
126  if (wrap) {
127  builder.open_document();
128  }
129 
130  std::string s;
131  builder.key_view(_nvp.append_name(s));
132  builder.append(_ascending ? 1 : -1);
133 
134  if (wrap) {
135  builder.close_document();
136  }
137  }
138 
143  operator bsoncxx::document::view_or_value() const {
144  auto builder = bsoncxx::builder::core(false);
145  append_to_bson(builder);
146  return builder.extract_document();
147  }
148 
149  private:
150  const NvpT _nvp;
151  const bool _ascending;
152 };
153 
165 template <typename NvpT, typename U>
166 class comparison_expr {
167  public:
168  using field_type = NvpT;
175  constexpr comparison_expr(const NvpT &nvp, const U &field, const char *op)
176  : _nvp(nvp), _field(field), _operator(op) {
177  }
178 
187  constexpr comparison_expr(const comparison_expr &expr, const char *op)
188  : _nvp(expr._nvp), _field(expr._field), _operator(op) {
189  }
190 
194  std::string &append_name(std::string &s) const {
195  return _nvp.append_name(s);
196  }
197 
206  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false,
207  bool omit_name = false) const {
208  if (wrap) {
209  builder.open_document();
210  }
211  if (!omit_name && !is_free_nvp_v<field_type>) {
212  std::string s;
213  builder.key_view(_nvp.append_name(s));
214  builder.open_document();
215  }
216 
217  builder.key_view(_operator);
218  append_value_to_bson(_field, builder);
219 
220  if (!omit_name && !is_free_nvp_v<field_type>) {
221  builder.close_document();
222  }
223  if (wrap) {
224  builder.close_document();
225  }
226  }
227 
232  operator bsoncxx::document::view_or_value() const {
233  auto builder = bsoncxx::builder::core(false);
234  append_to_bson(builder);
235  return builder.extract_document();
236  }
237 
238  private:
239  const NvpT _nvp;
240  const U &_field;
241  const char *_operator;
242 };
243 
249 template <typename NvpT, typename U>
250 class comparison_value_expr : public comparison_expr<NvpT, U> {
251  public:
252  constexpr comparison_value_expr(NvpT nvp, const U &value, const char *op)
253  : comparison_expr<NvpT, U>(nvp, _value, op), _value(value) {
254  }
255 
256  private:
257  const U _value;
258 };
259 
265 template <typename NvpT>
266 class mod_expr {
267  public:
268  using field_type = NvpT;
275  constexpr mod_expr(NvpT nvp, const int &divisor, const int &remainder)
276  : _nvp(nvp), _divisor(divisor), _remainder(remainder) {
277  }
278 
282  std::string &append_name(std::string &s) const {
283  return _nvp.append_name(s);
284  }
285 
292  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false,
293  bool omit_name = false) const {
294  if (wrap) {
295  builder.open_document();
296  }
297  if (!omit_name && !is_free_nvp_v<field_type>) {
298  std::string s;
299  builder.key_view(_nvp.append_name(s));
300  builder.open_document();
301  }
302  builder.key_view("$mod");
303  builder.open_array();
304  builder.append(_divisor);
305  builder.append(_remainder);
306  builder.close_array();
307  if (!omit_name && !is_free_nvp_v<field_type>) {
308  builder.close_document();
309  }
310  if (wrap) {
311  builder.close_document();
312  }
313  }
314 
319  operator bsoncxx::document::view_or_value() const {
320  auto builder = bsoncxx::builder::core(false);
321  append_to_bson(builder);
322  return builder.extract_document();
323  }
324 
325  private:
326  const NvpT _nvp;
327  const int &_divisor;
328  const int &_remainder;
329 };
330 
336  public:
347  text_search_expr(const char *search,
348  bsoncxx::stdx::optional<const char *> language = bsoncxx::stdx::nullopt,
349  bsoncxx::stdx::optional<bool> case_sensitive = bsoncxx::stdx::nullopt,
350  bsoncxx::stdx::optional<bool> diacritic_sensitive = bsoncxx::stdx::nullopt)
351  : _search(search),
352  _language(language),
353  _case_sensitive(case_sensitive),
354  _diacritic_sensitive(diacritic_sensitive) {
355  }
356 
357  text_search_expr &language() {
358  _language = bsoncxx::stdx::nullopt;
359  return *this;
360  }
361 
362  text_search_expr &language(const char *lang) {
363  _language = lang;
364  return *this;
365  }
366 
367  text_search_expr &case_sensitive() {
368  _case_sensitive = bsoncxx::stdx::nullopt;
369  return *this;
370  }
371 
372  text_search_expr &case_sensitive(bool case_sensitive) {
373  _case_sensitive = case_sensitive;
374  return *this;
375  }
376 
377  text_search_expr &diacritic_sensitive() {
378  _diacritic_sensitive = bsoncxx::stdx::nullopt;
379  return *this;
380  }
381 
382  text_search_expr &diacritic_sensitive(bool diacritic_sensitive) {
383  _diacritic_sensitive = diacritic_sensitive;
384  return *this;
385  }
386 
393  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
394  if (wrap) {
395  builder.open_document();
396  }
397  builder.key_view("$text");
398  builder.open_document();
399  builder.key_view("$search");
400  builder.append(_search);
401  if (_language) {
402  builder.key_view("$language");
403  builder.append(_language.value());
404  }
405  // hese values are false by default, so one can save bandwidth space ommitting them unless
406  // they're set to true.
407  if (_case_sensitive) {
408  builder.key_view("$caseSensitive");
409  builder.append(_case_sensitive.value());
410  }
411  if (_diacritic_sensitive) {
412  builder.key_view("$diacriticSensitive");
413  builder.append(_diacritic_sensitive.value());
414  }
415  builder.close_document();
416  if (wrap) {
417  builder.close_document();
418  }
419  }
420 
425  operator bsoncxx::document::view_or_value() const {
426  auto builder = bsoncxx::builder::core(false);
427  append_to_bson(builder);
428  return builder.extract_document();
429  }
430 
431  private:
432  const char *_search;
433  mongocxx::stdx::optional<const char *> _language;
434  bsoncxx::stdx::optional<bool> _case_sensitive;
435  bsoncxx::stdx::optional<bool> _diacritic_sensitive;
436 };
437 
443 template <typename Expr>
444 class not_expr {
445  public:
446  using field_type = typename Expr::field_type;
447 
452  constexpr not_expr(const Expr &expr) : _expr(expr) {
453  }
454 
458  std::string &append_name(std::string &s) const {
459  return _expr.append_name(s);
460  }
461 
471  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false,
472  bool omit_name = false) const {
473  if (wrap) {
474  builder.open_document();
475  }
476  if (!omit_name && !is_free_nvp_v<field_type>) {
477  std::string s;
478  builder.key_view(_expr.append_name(s));
479  builder.open_document();
480  }
481 
482  builder.key_view("$not");
483  // Append contained expression in a document, without its name.
484  _expr.append_to_bson(builder, true, true);
485 
486  if (!omit_name && !is_free_nvp_v<field_type>) {
487  builder.close_document();
488  }
489  if (wrap) {
490  builder.close_document();
491  }
492  }
493 
498  operator bsoncxx::document::view_or_value() const {
499  auto builder = bsoncxx::builder::core(false);
500  append_to_bson(builder);
501  return builder.extract_document();
502  }
503 
504  private:
505  const Expr _expr;
506 };
507 
513 template <expression_category list_type, typename... Args>
514 class expression_list {
515  public:
520  expression_list(const Args &... args) : storage(std::make_tuple(args...)) {
521  }
522 
529  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
530  tuple_for_each(storage, [&](const auto &v) { v.append_to_bson(builder, wrap); });
531  }
532 
536  operator bsoncxx::document::view_or_value() const {
537  auto builder = bsoncxx::builder::core(false);
538  append_to_bson(builder);
539  return builder.extract_document();
540  }
541 
542  std::tuple<Args...> storage;
543 };
544 
549 template <typename Expr1, typename Expr2>
550 class boolean_expr {
551  public:
558  constexpr boolean_expr(const Expr1 &lhs, const Expr2 &rhs, const char *op)
559  : _lhs(lhs), _rhs(rhs), _op(op) {
560  }
561 
567  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
568  if (wrap) {
569  builder.open_document();
570  }
571 
572  builder.key_view(_op);
573  builder.open_array();
574 
575  // append left hand side
576  builder.open_document();
577  _lhs.append_to_bson(builder, wrap);
578  builder.close_document();
579 
580  // append right hand side
581  builder.open_document();
582  _rhs.append_to_bson(builder, wrap);
583  builder.close_document();
584 
585  builder.close_array();
586 
587  if (wrap) {
588  builder.close_document();
589  }
590  }
591 
596  operator bsoncxx::document::view_or_value() const {
597  auto builder = bsoncxx::builder::core(false);
598  append_to_bson(builder);
599  return builder.extract_document();
600  }
601 
602  const Expr1 _lhs;
603  const Expr2 _rhs;
604  const char *_op;
605 };
606 
612 template <typename List>
613 class boolean_list_expr {
614  public:
620  constexpr boolean_list_expr(const List args, const char *op) : _args(args), _op(op) {
621  }
622 
628  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
629  if (wrap) {
630  builder.open_document();
631  }
632  builder.key_view(_op);
633  builder.open_array();
634  _args.append_to_bson(builder, true);
635  builder.close_array();
636  if (wrap) {
637  builder.close_document();
638  }
639  }
640 
645  operator bsoncxx::document::view_or_value() const {
646  auto builder = bsoncxx::builder::core(false);
647  append_to_bson(builder);
648  return builder.extract_document();
649  }
650 
651  const List _args;
652  const char *_op;
653 };
654 
658 template <typename Expr>
660  public:
661  constexpr isolated_expr(const Expr &expr) : _expr(expr) {
662  }
663 
670  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
671  if (wrap) {
672  builder.open_document();
673  }
674 
675  _expr.append_to_bson(builder, false);
676  builder.key_view("$isolated");
677  builder.append(1);
678 
679  if (wrap) {
680  builder.close_document();
681  }
682  }
683 
687  operator bsoncxx::document::view_or_value() const {
688  auto builder = bsoncxx::builder::core(false);
689  append_to_bson(builder);
690  return {builder.extract_document()};
691  }
692 
693  private:
694  const Expr _expr;
695 };
696 
708 template <typename NvpT, typename U>
709 class update_expr {
710  public:
711  using field_type = NvpT;
712  constexpr update_expr(const NvpT &nvp, const U &val, const char *op)
713  : _nvp(nvp), _val(val), _op(op) {
714  }
715 
721  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
722  if (wrap) {
723  builder.open_document();
724  }
725  builder.key_view(_op);
726  builder.open_document();
727  std::string s;
728  builder.key_view(_nvp.append_name(s));
729  append_value_to_bson(_val, builder);
730  builder.close_document();
731  if (wrap) {
732  builder.close_document();
733  }
734  }
735 
739  operator bsoncxx::document::view_or_value() const {
740  auto builder = bsoncxx::builder::core(false);
741  append_to_bson(builder);
742  return {builder.extract_document()};
743  }
744 
745  private:
746  const NvpT _nvp;
747  const U &_val;
748  const char *_op;
749 };
750 
751 template <typename NvpT, typename U>
752 class update_value_expr : public update_expr<NvpT, U> {
753  public:
754  constexpr update_value_expr(NvpT nvp, U value, const char *op)
755  : update_expr<NvpT, U>(nvp, _val, op), _val(value) {
756  }
757 
758  private:
759  const U _val;
760 };
761 
765 template <typename NvpT>
766 class unset_expr {
767  public:
768  using field_type = NvpT;
769  constexpr unset_expr(const NvpT &nvp) : _nvp(nvp) {
770  }
771 
777  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
778  if (wrap) {
779  builder.open_document();
780  }
781  builder.key_view("$unset");
782  builder.open_document();
783  std::string s;
784  builder.key_view(_nvp.append_name(s));
785  builder.append("");
786  builder.close_document();
787  if (wrap) {
788  builder.close_document();
789  }
790  }
791 
792  operator bsoncxx::document::view_or_value() const {
793  auto builder = bsoncxx::builder::core(false);
794  append_to_bson(builder);
795  return {builder.extract_document()};
796  }
797 
798  private:
799  const NvpT _nvp;
800 };
801 
805 template <typename NvpT>
806 class current_date_expr {
807  public:
808  using field_type = NvpT;
814  constexpr current_date_expr(const NvpT &nvp, bool is_date) : _nvp(nvp), _is_date(is_date) {
815  }
816 
823  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
824  if (wrap) {
825  builder.open_document();
826  }
827  builder.key_view("$currentDate");
828  builder.open_document();
829  std::string s;
830  builder.key_view(_nvp.append_name(s));
831 
832  // type specification
833  builder.open_document();
834  builder.key_view("$type");
835  builder.append(_is_date ? "date" : "timestamp");
836  builder.close_document();
837 
838  builder.close_document();
839  if (wrap) {
840  builder.close_document();
841  }
842  }
843 
844  operator bsoncxx::document::view_or_value() const {
845  auto builder = bsoncxx::builder::core(false);
846  append_to_bson(builder);
847  return {builder.extract_document()};
848  }
849 
850  private:
851  const NvpT _nvp;
852  const bool _is_date;
853 };
854 
860 template <typename NvpT, typename U>
862  public:
863  using field_type = NvpT;
870  constexpr add_to_set_update_expr(const NvpT &nvp, const U &val, bool each)
871  : _nvp(nvp), _val(val), _each(each) {
872  }
873 
880  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
881  if (wrap) {
882  builder.open_document();
883  }
884  builder.key_view("$addToSet");
885  builder.open_document();
886  std::string s;
887  builder.key_view(_nvp.append_name(s));
888 
889  // wrap value in $each: {} if necessary.
890  if (_each) {
891  builder.open_document();
892  builder.key_view("$each");
893  }
894  append_value_to_bson(_val, builder);
895  if (_each) {
896  builder.close_document();
897  }
898 
899  builder.close_document();
900  if (wrap) {
901  builder.close_document();
902  }
903  }
904 
905  operator bsoncxx::document::view_or_value() const {
906  auto builder = bsoncxx::builder::core(false);
907  append_to_bson(builder);
908  return {builder.extract_document()};
909  }
910 
911  private:
912  const NvpT _nvp;
913  const U &_val;
914  bool _each;
915 };
916 
926 template <typename NvpT, typename U, typename Sort>
927 class push_update_expr {
928  public:
929  using field_type = NvpT;
943  constexpr push_update_expr(
944  const NvpT &nvp, const U &val, bool each,
945  bsoncxx::stdx::optional<std::int32_t> slice = bsoncxx::stdx::nullopt,
946  const bsoncxx::stdx::optional<Sort> &sort = bsoncxx::stdx::nullopt,
947  bsoncxx::stdx::optional<std::uint32_t> position = bsoncxx::stdx::nullopt)
948  : _nvp(nvp), _val(val), _each(each), _slice(slice), _sort(sort), _position(position) {
949  }
950 
951  /* Functions that set new values for modifers. These create new copies of the expression,
952  * primarily because $sort can take different types of parameters. */
953 
960  constexpr push_update_expr<NvpT, U, Sort> slice(std::int32_t slice) {
961  return {_nvp, _val, _each, slice, _sort, _position};
962  }
963 
970  return {_nvp, _val, _each, bsoncxx::stdx::nullopt, _sort, _position};
971  }
972 
980  template <typename OtherNvpT>
982  const sort_expr<OtherNvpT> &sort) {
983  return {_nvp, _val, _each, _slice, sort, _position};
984  }
985 
992  constexpr push_update_expr<NvpT, U, int> sort(int sort) {
993  return {_nvp, _val, _each, _slice, sort, _position};
994  }
995 
1002  return {_nvp, _val, _each, _slice, bsoncxx::stdx::nullopt, _position};
1003  }
1004 
1011  constexpr push_update_expr<NvpT, U, Sort> position(std::uint32_t position) {
1012  return {_nvp, _val, _each, _slice, _sort, position};
1013  }
1014 
1021  return {_nvp, _val, _each, _slice, _sort, bsoncxx::stdx::nullopt};
1022  }
1023 
1030  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
1031  if (wrap) {
1032  builder.open_document();
1033  }
1034  builder.key_view("$push");
1035  builder.open_document();
1036  std::string s;
1037  builder.key_view(_nvp.append_name(s));
1038 
1039  // wrap value in "$each: {}" if necessary.
1040  if (_each) {
1041  builder.open_document();
1042  builder.key_view("$each");
1043  }
1044  append_value_to_bson(_val, builder);
1045  if (_each) {
1046  if (_slice) {
1047  builder.key_view("$slice");
1048  builder.append(_slice.value());
1049  }
1050  if (_sort) {
1051  builder.key_view("$sort");
1052  append_value_to_bson(_sort.value(), builder);
1053  }
1054  if (_position) {
1055  builder.key_view("$position");
1056  builder.append(static_cast<std::int64_t>(_position.value()));
1057  }
1058  builder.close_document();
1059  }
1060 
1061  builder.close_document();
1062  if (wrap) {
1063  builder.close_document();
1064  }
1065  }
1066 
1067  operator bsoncxx::document::view_or_value() const {
1068  auto builder = bsoncxx::builder::core(false);
1069  append_to_bson(builder);
1070  return {builder.extract_document()};
1071  }
1072 
1073  private:
1074  const NvpT _nvp;
1075  const U &_val;
1076  const bool _each;
1077  const bsoncxx::stdx::optional<std::int32_t> _slice;
1078  const bsoncxx::stdx::optional<Sort> _sort;
1079  const bsoncxx::stdx::optional<std::uint32_t> _position;
1080 };
1081 
1088 template <typename NvpT, typename Integer>
1089 class bit_update_expr {
1090  public:
1091  using field_type = NvpT;
1092  constexpr bit_update_expr(const NvpT &nvp, Integer mask, const char *op)
1093  : _nvp(nvp), _mask(mask), _operation(op){};
1094 
1101  void append_to_bson(bsoncxx::builder::core &builder, bool wrap = false) const {
1102  if (wrap) {
1103  builder.open_document();
1104  }
1105  builder.key_view("$bit");
1106  builder.open_document();
1107  std::string s;
1108  builder.key_view(_nvp.append_name(s));
1109 
1110  // bit operation
1111  builder.open_document();
1112  builder.key_view(_operation);
1113  builder.append(_mask);
1114  builder.close_document();
1115 
1116  builder.close_document();
1117  if (wrap) {
1118  builder.close_document();
1119  }
1120  }
1121 
1122  operator bsoncxx::document::view_or_value() const {
1123  auto builder = bsoncxx::builder::core(false);
1124  append_to_bson(builder);
1125  return {builder.extract_document()};
1126  }
1127 
1128  private:
1129  const NvpT _nvp;
1130  const Integer _mask;
1131  const char *_operation;
1132 };
1133 
1134 /* Query comparison operators */
1135 
1136 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1138  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1139  return {lhs, rhs, "$eq"};
1140 }
1141 
1142 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1144  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1145  return eq(lhs, rhs);
1146 }
1147 
1148 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1150  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1151  return {lhs, rhs, "$gt"};
1152 }
1153 
1154 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1156  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1157  return gt(lhs, rhs);
1158 }
1159 
1160 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1162  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1163  return {lhs, rhs, "$gte"};
1164 }
1165 
1166 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1168  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1169  return gte(lhs, rhs);
1170 }
1171 
1172 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1174  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1175  return {lhs, rhs, "$lt"};
1176 }
1177 
1178 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1180  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1181  return lt(lhs, rhs);
1182 }
1183 
1184 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1186  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1187  return {lhs, rhs, "$lte"};
1188 }
1189 
1190 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1192  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1193  return lte(lhs, rhs);
1194 }
1195 
1196 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1198  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1199  return {lhs, rhs, "$ne"};
1200 }
1201 
1202 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1204  const NvpT &lhs, const typename NvpT::no_opt_type &rhs) {
1205  return ne(lhs, rhs);
1206 }
1207 
1211 // TODO replace is_query_expression with is_unary_expression or something.
1212 template <typename Expr, typename = std::enable_if_t<details::is_query_expression_v<Expr>>>
1213 constexpr not_expr<Expr> operator!(const Expr &expr) {
1214  return {expr};
1215 }
1216 
1217 // Specialization of the ! operator for regexes, since the $regex operator cannot appear inside
1218 // a $not operator.
1219 // Instead, create an expression of the form {field: {$not: /regex/}}
1220 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>>
1223  return {regex_expr, "$not"};
1224 }
1225 
1226 template <typename Expr, expression_category list_type, typename... Args, size_t... idxs>
1227 constexpr expression_list<list_type, Expr, Args...> append_impl(
1228  expression_list<list_type, Args...> list, Expr expr, std::index_sequence<idxs...>) {
1229  return {expr, std::get<idxs>(list.storage)...};
1230 }
1231 
1236 template <typename Expr, expression_category list_type,
1237  typename = std::enable_if_t<details::is_expression_type<list_type, Expr>::value>,
1238  typename... Args>
1239 constexpr expression_list<list_type, Expr, Args...> operator,(
1240  expression_list<list_type, Args...> &&list, Expr &&expr) {
1241  return append_impl(list, expr, std::index_sequence_for<Args...>());
1242 }
1243 
1244 template <typename Expr1, typename Expr2,
1245  typename = std::enable_if_t<!details::isnt_expression_v<Expr1> &&
1248 constexpr expression_list<details::expression_type<Expr1>::value, Expr1, Expr2> operator,(
1249  Expr1 &&expr1, Expr2 &&expr2) {
1250  return {expr1, expr2};
1251 }
1252 
1256 template <typename Expr1, typename Expr2,
1257  typename = std::enable_if_t<details::is_query_expression_v<Expr1> &&
1258  details::is_query_expression_v<Expr2>>>
1259 constexpr boolean_expr<Expr1, Expr2> operator&&(const Expr1 &lhs, const Expr2 &rhs) {
1260  return {lhs, rhs, "$and"};
1261 }
1262 
1263 template <typename Expr1, typename Expr2,
1264  typename = std::enable_if_t<details::is_query_expression_v<Expr1> &&
1265  details::is_query_expression_v<Expr2>>>
1266 constexpr boolean_expr<Expr1, Expr2> operator||(const Expr1 &lhs, const Expr2 &rhs) {
1267  return {lhs, rhs, "$or"};
1268 }
1269 
1270 // TODO I'd like list ops for "and" and "or" as well, but these are reserved keywords.
1271 // Perhaps use list_and, list_or, list_nor instead?
1272 // Currently chaining &&'s or ||'s provides the same results as a boolean operation on a list,
1273 // and
1274 // not much different in terms of performance.
1275 
1281 template <typename... Args>
1282 constexpr boolean_list_expr<expression_list<expression_category::query, Args...>> nor(
1284  return {list, "$nor"};
1285 }
1286 
1290 template <typename... QueryExpressions,
1291  typename = typename all_true<details::is_query_expression_v<QueryExpressions>...>::type>
1292 constexpr boolean_list_expr<expression_list<expression_category::query, QueryExpressions...>> nor(
1293  QueryExpressions... args) {
1294  return {{args...}, "$nor"};
1295 }
1296 
1310 inline text_search_expr text(
1311  const char *search, bsoncxx::stdx::optional<const char *> language = bsoncxx::stdx::nullopt,
1312  bsoncxx::stdx::optional<bool> case_sensitive = bsoncxx::stdx::nullopt,
1313  bsoncxx::stdx::optional<bool> diacritic_sensitive = bsoncxx::stdx::nullopt) {
1314  return {search, language, case_sensitive, diacritic_sensitive};
1315 }
1316 
1320 template <typename Expr, typename = std::enable_if_t<details::is_query_expression_v<Expr>>>
1321 constexpr isolated_expr<Expr> isolated(const Expr &expr) {
1322  return {expr};
1323 }
1324 
1325 /* Arithmetic update operators */
1326 
1327 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1328  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1330  const NvpT &nvp, const typename NvpT::no_opt_type &val) {
1331  return {nvp, val, "$inc"};
1332 }
1333 
1334 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1335  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1337  const NvpT &nvp, const typename NvpT::no_opt_type &val) {
1338  return {nvp, -val, "$inc"};
1339 }
1340 
1341 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1342  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1343 constexpr update_value_expr<NvpT, typename NvpT::no_opt_type> operator++(const NvpT &nvp) {
1344  return {nvp, 1, "$inc"};
1345 }
1346 
1347 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1348  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1349 constexpr update_value_expr<NvpT, typename NvpT::no_opt_type> operator++(const NvpT &nvp, int) {
1350  return {nvp, 1, "$inc"};
1351 }
1352 
1353 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1354  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1355 constexpr update_value_expr<NvpT, typename NvpT::no_opt_type> operator--(const NvpT &nvp) {
1356  return {nvp, -1, "$inc"};
1357 }
1358 
1359 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1360  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1361 constexpr update_value_expr<NvpT, typename NvpT::no_opt_type> operator--(const NvpT &nvp, int) {
1362  return {nvp, -1, "$inc"};
1363 }
1364 
1365 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1366  typename = std::enable_if_t<std::is_arithmetic<typename NvpT::no_opt_type>::value>>
1368  const NvpT &nvp, const typename NvpT::no_opt_type &val) {
1369  return {nvp, val, "$mul"};
1370 }
1371 
1372 /* Bitwise update operators */
1373 
1374 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1375  typename = std::enable_if_t<std::is_integral<typename NvpT::no_opt_type>::value>>
1377  const NvpT &nvp, const typename NvpT::no_opt_type &mask) {
1378  return {nvp, mask, "and"};
1379 }
1380 
1381 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1382  typename = std::enable_if_t<std::is_integral<typename NvpT::no_opt_type>::value>>
1384  const NvpT &nvp, const typename NvpT::no_opt_type &mask) {
1385  return {nvp, mask, "or"};
1386 }
1387 
1388 template <typename NvpT, typename = std::enable_if_t<is_nvp_v<NvpT>>,
1389  typename = std::enable_if_t<std::is_integral<typename NvpT::no_opt_type>::value>>
1391  const NvpT &nvp, const typename NvpT::no_opt_type &mask) {
1392  return {nvp, mask, "xor"};
1393 }
1394 
1395 MANGROVE_INLINE_NAMESPACE_END
1396 } // namespace mangrove
1397 
1398 #include <mangrove/config/postlude.hpp>
constexpr push_update_expr(const NvpT &nvp, const U &val, bool each, bsoncxx::stdx::optional< std::int32_t > slice=bsoncxx::stdx::nullopt, const bsoncxx::stdx::optional< Sort > &sort=bsoncxx::stdx::nullopt, bsoncxx::stdx::optional< std::uint32_t > position=bsoncxx::stdx::nullopt)
Constructs a $push expression, with the given optional modifiers.
Definition: query_builder.hpp:943
Represents an array update epression that uses the $push operator.
Definition: expression_syntax.hpp:89
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends each element to a BSON code builder.
Definition: query_builder.hpp:529
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this expression to a BSON core builder, as a key-value pair of the form "key: +/-1"...
Definition: query_builder.hpp:125
expression_list(const Args &...args)
Constructs an expression list of the given arguments.
Definition: query_builder.hpp:520
Creates an expression that uses the $currentDate operator.
Definition: expression_syntax.hpp:83
Represents a query that performs a text search with the $text operator.
Definition: query_builder.hpp:335
An object that represents a name-value pair of a member in an object.
Definition: nvp.hpp:47
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false, bool omit_name=false) const
Appends this expression to a BSON core builder, as a key-value pair of the form "key: {$cmp: val}"...
Definition: query_builder.hpp:206
This class represents a query expression using the $mod operator, that checks the modulus of a certai...
Definition: expression_syntax.hpp:60
constexpr sort_expr(const NvpT &nvp, bool ascending)
Creates a sort expression with the given name-value-pair and sort order.
Definition: query_builder.hpp:116
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as an expression &#39;.
Definition: query_builder.hpp:823
constexpr boolean_list_expr(const List args, const char *op)
Constructs a boolean expression from a list of sub-expressions, and a certain operator.
Definition: query_builder.hpp:620
constexpr push_update_expr< NvpT, U, Sort > slice()
Create a copy of this expression without a $slice modifier.
Definition: query_builder.hpp:969
constexpr mod_expr(NvpT nvp, const int &divisor, const int &remainder)
Constructs a mod_expr that represents a query with the $mod operator.
Definition: query_builder.hpp:275
constexpr push_update_expr< NvpT, U, Sort > position()
Create a copy of this expression without $position modifier.
Definition: query_builder.hpp:1020
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as a key-value pair "$op: [{lhs}, {rhs}]".
Definition: query_builder.hpp:567
constexpr push_update_expr< NvpT, U, sort_expr< OtherNvpT > > sort(const sort_expr< OtherNvpT > &sort)
Create a copy of this expression with a different $sort modifier value.
Definition: query_builder.hpp:981
An expression that uses the $addToSet operator to add unique elements to an array.
Definition: expression_syntax.hpp:86
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder, with $isolated set as an extra field.
Definition: query_builder.hpp:670
This represents a boolean expression with two arguments.
Definition: expression_syntax.hpp:68
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false, bool omit_name=false) const
Appends this expression to a BSON core builder, as a key-value pair of the form "key: {$not: {$cmp: v...
Definition: query_builder.hpp:471
constexpr comparison_expr(const comparison_expr &expr, const char *op)
Takes a comparison expression, and creates a new one with a different operator, but the same value an...
Definition: query_builder.hpp:187
An expression that wraps another expression and adds an $isolated operator.
Definition: query_builder.hpp:659
Represents an expresion that uses the $unset operator.
Definition: expression_syntax.hpp:80
constexpr push_update_expr< NvpT, U, Sort > sort()
Create a copy of this expression without a $sort modifier.
Definition: query_builder.hpp:1001
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as an expression &#39;.
Definition: query_builder.hpp:1030
std::string & append_name(std::string &s) const
Appends the name of the contained field to a string.
Definition: query_builder.hpp:194
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as an expression &#39;$bit: { <field>: { <and|or|xor>: <int> } ...
Definition: query_builder.hpp:1101
A type traits struct that determines whether a certain type stores a date.
Definition: util.hpp:153
Represents an update operator that modifies a certain elements.
Definition: expression_syntax.hpp:74
Expression that updates field using the $bit operator, which does bitwise operations using a mask...
Definition: expression_syntax.hpp:92
Definition: collection_wrapper.hpp:28
This represents an expression with the $not operator, which wraps a comparison expression and negates...
Definition: expression_syntax.hpp:63
constexpr current_date_expr(const NvpT &nvp, bool is_date)
Creates an expression that uses the $currentDate operator with a given field and type.
Definition: query_builder.hpp:814
constexpr push_update_expr< NvpT, U, Sort > position(std::uint32_t position)
Create a copy of this expression with a different $position modifier value.
Definition: query_builder.hpp:1011
constexpr push_update_expr< NvpT, U, Sort > slice(std::int32_t slice)
Create a copy of this expression with a different $slice modifier value.
Definition: query_builder.hpp:960
constexpr comparison_expr(const NvpT &nvp, const U &field, const char *op)
Constructs a query expression for the given key, value, and comparison type.
Definition: query_builder.hpp:175
Represents a comparison expression as above, but stores a value instead of a reference.
Definition: expression_syntax.hpp:57
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as a key-value pair "$op: {field: value}".
Definition: query_builder.hpp:721
A templated struct for determining whether a variadic list of boolean conditions is all true...
Definition: util.hpp:40
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this expression to a BSON core builder, as a key-value pair of the form " key: { $mod: [ divi...
Definition: query_builder.hpp:393
Definition: expression_syntax.hpp:109
This class represents a boolean expression over an array of arguments.
Definition: expression_syntax.hpp:71
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as a key-value pair "$unset: {field: &#39;&#39;}".
Definition: query_builder.hpp:777
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false, bool omit_name=false) const
Appends this expression to a BSON core builder, as a key-value pair of the form " key: { $mod: [ divi...
Definition: query_builder.hpp:292
std::string & append_name(std::string &s) const
Appends the name of the contained field to a string.
Definition: query_builder.hpp:458
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as an expression &#39;.
Definition: query_builder.hpp:880
constexpr add_to_set_update_expr(const NvpT &nvp, const U &val, bool each)
Constructs an add_to_set_update_expr with the given parameters.
Definition: query_builder.hpp:870
Definition: expression_syntax.hpp:77
constexpr not_expr(const Expr &expr)
Creates a $not expression that negates the given comparison expression.
Definition: query_builder.hpp:452
constexpr boolean_expr(const Expr1 &lhs, const Expr2 &rhs, const char *op)
Constructs a boolean expression from two other expressions, and a certain operator.
Definition: query_builder.hpp:558
text_search_expr(const char *search, bsoncxx::stdx::optional< const char * > language=bsoncxx::stdx::nullopt, bsoncxx::stdx::optional< bool > case_sensitive=bsoncxx::stdx::nullopt, bsoncxx::stdx::optional< bool > diacritic_sensitive=bsoncxx::stdx::nullopt)
Creates a text search expression.
Definition: query_builder.hpp:347
constexpr push_update_expr< NvpT, U, int > sort(int sort)
Create a copy of this expression with a different $slice modifier value.
Definition: query_builder.hpp:992
An expression that represents a sorting order.
Definition: expression_syntax.hpp:48
std::string & append_name(std::string &s) const
Appends the name of the contained field to a string.
Definition: query_builder.hpp:282
Represents a query expression with the syntax "key: {$op: value}".
Definition: expression_syntax.hpp:54
void append_to_bson(bsoncxx::builder::core &builder, bool wrap=false) const
Appends this query to a BSON core builder as a key-value pair "$op: [{lhs}, {rhs}]".
Definition: query_builder.hpp:628
This represents a list of expressions.
Definition: expression_syntax.hpp:51