/
UCS
/
sqlite_orm
Обзор
Документация
Войти
/
UCS
/
sqlite_orm
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
dev/conditions.h
1 265 строк
37 KB
klaus triendl
Renamed everything related to former 'storage impl' to 'db object'
05 июн 2022, 11:52
05 июн 2022, 11:52
9726e82
Код
Авторство
О чём код?
#pragma once #include <string> // std::string #include <type_traits> // std::enable_if, std::is_same #include <vector> // std::vector #include <tuple> // std::tuple, std::tuple_size #include <sstream> // std::stringstream #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" #include "type_traits.h" #include "collate_argument.h" #include "constraints.h" #include "optional_container.h" #include "serializer_context.h" #include "tags.h" #include "expression.h" #include "type_printer.h" #include "literal.h" namespace sqlite_orm { namespace internal { struct limit_string { operator std::string() const { return "LIMIT"; } }; /** * Stores LIMIT/OFFSET info */ template<class T, bool has_offset, bool offset_is_implicit, class O> struct limit_t : limit_string { T lim; optional_container<O> off; limit_t() = default; limit_t(decltype(lim) lim_) : lim(std::move(lim_)) {} limit_t(decltype(lim) lim_, decltype(off) off_) : lim(std::move(lim_)), off(std::move(off_)) {} }; template<class T> struct is_limit : std::false_type {}; template<class T, bool has_offset, bool offset_is_implicit, class O> struct is_limit<limit_t<T, has_offset, offset_is_implicit, O>> : std::true_type {}; /** * Stores OFFSET only info */ template<class T> struct offset_t { T off; }; template<class T> using is_offset = polyfill::is_specialization_of<T, offset_t>; /** * Collated something */ template<class T> struct collate_t : public condition_t { T expr; collate_argument argument; collate_t(T expr_, collate_argument argument_) : expr(std::move(expr_)), argument(argument_) {} operator std::string() const { return collate_constraint_t{this->argument}; } }; struct named_collate_base { std::string name; operator std::string() const { return "COLLATE " + this->name; } }; /** * Collated something with custom collate function */ template<class T> struct named_collate : named_collate_base { T expr; named_collate(T expr_, std::string name_) : named_collate_base{std::move(name_)}, expr(std::move(expr_)) {} }; struct negated_condition_string { operator std::string() const { return "NOT"; } }; /** * Result of not operator */ template<class C> struct negated_condition_t : condition_t, negated_condition_string { C c; negated_condition_t(C c_) : c(std::move(c_)) {} }; /** * Base class for binary conditions * L is left argument type * R is right argument type * S is 'string' class (a class which has cast to `std::string` operator) * Res is result type */ template<class L, class R, class S, class Res> struct binary_condition : condition_t, S { using left_type = L; using right_type = R; using result_type = Res; left_type l; right_type r; binary_condition() = default; binary_condition(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; struct and_condition_string { operator std::string() const { return "AND"; } }; /** * Result of and operator */ template<class L, class R> struct and_condition_t : binary_condition<L, R, and_condition_string, bool> { using super = binary_condition<L, R, and_condition_string, bool>; using super::super; }; template<class L, class R> and_condition_t<L, R> make_and_condition(L left, R right) { return {std::move(left), std::move(right)}; } struct or_condition_string { operator std::string() const { return "OR"; } }; /** * Result of or operator */ template<class L, class R> struct or_condition_t : binary_condition<L, R, or_condition_string, bool> { using super = binary_condition<L, R, or_condition_string, bool>; using super::super; }; template<class L, class R> or_condition_t<L, R> make_or_condition(L left, R right) { return {std::move(left), std::move(right)}; } struct is_equal_string { operator std::string() const { return "="; } }; /** * = and == operators object */ template<class L, class R> struct is_equal_t : binary_condition<L, R, is_equal_string, bool>, negatable_t { using self = is_equal_t<L, R>; using binary_condition<L, R, is_equal_string, bool>::binary_condition; collate_t<self> collate_binary() const { return {*this, collate_argument::binary}; } collate_t<self> collate_nocase() const { return {*this, collate_argument::nocase}; } collate_t<self> collate_rtrim() const { return {*this, collate_argument::rtrim}; } named_collate<self> collate(std::string name) const { return {*this, std::move(name)}; } template<class C> named_collate<self> collate() const { std::stringstream ss; ss << C::name() << std::flush; return {*this, ss.str()}; } }; struct is_not_equal_string { operator std::string() const { return "!="; } }; /** * != operator object */ template<class L, class R> struct is_not_equal_t : binary_condition<L, R, is_not_equal_string, bool>, negatable_t { using self = is_not_equal_t<L, R>; using binary_condition<L, R, is_not_equal_string, bool>::binary_condition; collate_t<self> collate_binary() const { return {*this, collate_argument::binary}; } collate_t<self> collate_nocase() const { return {*this, collate_argument::nocase}; } collate_t<self> collate_rtrim() const { return {*this, collate_argument::rtrim}; } }; struct greater_than_string { operator std::string() const { return ">"; } }; /** * > operator object. */ template<class L, class R> struct greater_than_t : binary_condition<L, R, greater_than_string, bool>, negatable_t { using self = greater_than_t<L, R>; using binary_condition<L, R, greater_than_string, bool>::binary_condition; collate_t<self> collate_binary() const { return {*this, collate_argument::binary}; } collate_t<self> collate_nocase() const { return {*this, collate_argument::nocase}; } collate_t<self> collate_rtrim() const { return {*this, collate_argument::rtrim}; } }; struct greater_or_equal_string { operator std::string() const { return ">="; } }; /** * >= operator object. */ template<class L, class R> struct greater_or_equal_t : binary_condition<L, R, greater_or_equal_string, bool>, negatable_t { using self = greater_or_equal_t<L, R>; using binary_condition<L, R, greater_or_equal_string, bool>::binary_condition; collate_t<self> collate_binary() const { return {*this, collate_argument::binary}; } collate_t<self> collate_nocase() const { return {*this, collate_argument::nocase}; } collate_t<self> collate_rtrim() const { return {*this, collate_argument::rtrim}; } }; struct lesser_than_string { operator std::string() const { return "<"; } }; /** * < operator object. */ template<class L, class R> struct lesser_than_t : binary_condition<L, R, lesser_than_string, bool>, negatable_t { using self = lesser_than_t<L, R>; using binary_condition<L, R, lesser_than_string, bool>::binary_condition; collate_t<self> collate_binary() const { return {*this, collate_argument::binary}; } collate_t<self> collate_nocase() const { return {*this, collate_argument::nocase}; } collate_t<self> collate_rtrim() const { return {*this, collate_argument::rtrim}; } }; struct lesser_or_equal_string { operator std::string() const { return "<="; } }; /** * <= operator object. */ template<class L, class R> struct lesser_or_equal_t : binary_condition<L, R, lesser_or_equal_string, bool>, negatable_t { using self = lesser_or_equal_t<L, R>; using binary_condition<L, R, lesser_or_equal_string, bool>::binary_condition; collate_t<self> collate_binary() const { return {*this, collate_argument::binary}; } collate_t<self> collate_nocase() const { return {*this, collate_argument::nocase}; } collate_t<self> collate_rtrim() const { return {*this, collate_argument::rtrim}; } }; struct in_base { bool negative = false; // used in not_in #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED in_base(bool negative) : negative{negative} {} #endif }; /** * IN operator object. */ template<class L, class A> struct dynamic_in_t : condition_t, in_base, negatable_t { using self = dynamic_in_t<L, A>; L left; // left expression A argument; // in arg dynamic_in_t(L left_, A argument_, bool negative_) : in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {} }; template<class L, class... Args> struct in_t : condition_t, in_base, negatable_t { L left; std::tuple<Args...> argument; in_t(L left_, decltype(argument) argument_, bool negative_) : in_base{negative_}, left(std::move(left_)), argument(std::move(argument_)) {} }; struct is_null_string { operator std::string() const { return "IS NULL"; } }; /** * IS NULL operator object. */ template<class T> struct is_null_t : is_null_string, negatable_t { using self = is_null_t<T>; T t; is_null_t(T t_) : t(std::move(t_)) {} }; struct is_not_null_string { operator std::string() const { return "IS NOT NULL"; } }; /** * IS NOT NULL operator object. */ template<class T> struct is_not_null_t : is_not_null_string, negatable_t { using self = is_not_null_t<T>; T t; is_not_null_t(T t_) : t(std::move(t_)) {} }; struct order_by_base { int asc_desc = 0; // 1: asc, -1: desc std::string _collate_argument; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED order_by_base() = default; order_by_base(decltype(asc_desc) asc_desc_, decltype(_collate_argument) _collate_argument_) : asc_desc(asc_desc_), _collate_argument(move(_collate_argument_)) {} #endif }; struct order_by_string { operator std::string() const { return "ORDER BY"; } }; /** * ORDER BY argument holder. */ template<class O> struct order_by_t : order_by_base, order_by_string { using expression_type = O; using self = order_by_t<expression_type>; expression_type expression; order_by_t(expression_type expression_) : order_by_base(), expression(std::move(expression_)) {} self asc() const { auto res = *this; res.asc_desc = 1; return res; } self desc() const { auto res = *this; res.asc_desc = -1; return res; } self collate_binary() const { auto res = *this; res._collate_argument = collate_constraint_t::string_from_collate_argument(collate_argument::binary); return res; } self collate_nocase() const { auto res = *this; res._collate_argument = collate_constraint_t::string_from_collate_argument(collate_argument::nocase); return res; } self collate_rtrim() const { auto res = *this; res._collate_argument = collate_constraint_t::string_from_collate_argument(collate_argument::rtrim); return res; } self collate(std::string name) const { auto res = *this; res._collate_argument = std::move(name); return res; } template<class C> self collate() const { std::stringstream ss; ss << C::name() << std::flush; return this->collate(ss.str()); } }; /** * ORDER BY pack holder. */ template<class... Args> struct multi_order_by_t : order_by_string { using args_type = std::tuple<Args...>; args_type args; multi_order_by_t(args_type args_) : args{std::move(args_)} {} }; struct dynamic_order_by_entry_t : order_by_base { std::string name; dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) : order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {} }; /** * C - serializer context class */ template<class C> struct dynamic_order_by_t : order_by_string { using context_t = C; using entry_t = dynamic_order_by_entry_t; using const_iterator = typename std::vector<entry_t>::const_iterator; dynamic_order_by_t(const context_t& context_) : context(context_) {} template<class O> void push_back(order_by_t<O> order_by) { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); } const_iterator begin() const { return this->entries.begin(); } const_iterator end() const { return this->entries.end(); } void clear() { this->entries.clear(); } protected: std::vector<entry_t> entries; context_t context; }; template<class T> SQLITE_ORM_INLINE_VAR constexpr bool is_order_by_v = polyfill::disjunction_v<polyfill::is_specialization_of<T, order_by_t>, polyfill::is_specialization_of<T, multi_order_by_t>, polyfill::is_specialization_of<T, dynamic_order_by_t>>; template<class T> using is_order_by = polyfill::bool_constant<is_order_by_v<T>>; struct between_string { operator std::string() const { return "BETWEEN"; } }; /** * BETWEEN operator object. */ template<class A, class T> struct between_t : condition_t, between_string { using expression_type = A; using lower_type = T; using upper_type = T; expression_type expr; lower_type b1; upper_type b2; between_t(expression_type expr_, lower_type b1_, upper_type b2_) : expr(std::move(expr_)), b1(std::move(b1_)), b2(std::move(b2_)) {} }; struct like_string { operator std::string() const { return "LIKE"; } }; /** * LIKE operator object. */ template<class A, class T, class E> struct like_t : condition_t, like_string, negatable_t { using self = like_t<A, T, E>; using arg_t = A; using pattern_t = T; using escape_t = E; arg_t arg; pattern_t pattern; optional_container<escape_t> arg3; // not escape cause escape exists as a function here like_t(arg_t arg_, pattern_t pattern_, optional_container<escape_t> escape_) : arg(std::move(arg_)), pattern(std::move(pattern_)), arg3(std::move(escape_)) {} template<class C> like_t<A, T, C> escape(C c) const { optional_container<C> newArg3{std::move(c)}; return {std::move(this->arg), std::move(this->pattern), std::move(newArg3)}; } }; struct glob_string { operator std::string() const { return "GLOB"; } }; template<class A, class T> struct glob_t : condition_t, glob_string, internal::negatable_t { using self = glob_t<A, T>; using arg_t = A; using pattern_t = T; arg_t arg; pattern_t pattern; glob_t(arg_t arg_, pattern_t pattern_) : arg(std::move(arg_)), pattern(std::move(pattern_)) {} }; struct cross_join_string { operator std::string() const { return "CROSS JOIN"; } }; /** * CROSS JOIN holder. * T is joined type which represents any mapped table. */ template<class T> struct cross_join_t : cross_join_string { using type = T; }; struct natural_join_string { operator std::string() const { return "NATURAL JOIN"; } }; /** * NATURAL JOIN holder. * T is joined type which represents any mapped table. */ template<class T> struct natural_join_t : natural_join_string { using type = T; }; struct left_join_string { operator std::string() const { return "LEFT JOIN"; } }; /** * LEFT JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template<class T, class O> struct left_join_t : left_join_string { using type = T; using on_type = O; on_type constraint; left_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} }; struct join_string { operator std::string() const { return "JOIN"; } }; /** * Simple JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template<class T, class O> struct join_t : join_string { using type = T; using on_type = O; on_type constraint; join_t(on_type constraint_) : constraint(std::move(constraint_)) {} }; struct left_outer_join_string { operator std::string() const { return "LEFT OUTER JOIN"; } }; /** * LEFT OUTER JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template<class T, class O> struct left_outer_join_t : left_outer_join_string { using type = T; using on_type = O; on_type constraint; left_outer_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} }; struct on_string { operator std::string() const { return "ON"; } }; /** * on(...) argument holder used for JOIN, LEFT JOIN, LEFT OUTER JOIN and INNER JOIN * T is on type argument. */ template<class T> struct on_t : on_string { using arg_type = T; arg_type arg; on_t(arg_type arg_) : arg(std::move(arg_)) {} }; /** * USING argument holder. */ template<class T, class M> struct using_t { column_pointer<T, M> column; operator std::string() const { return "USING"; } }; struct inner_join_string { operator std::string() const { return "INNER JOIN"; } }; /** * INNER JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template<class T, class O> struct inner_join_t : inner_join_string { using type = T; using on_type = O; on_type constraint; inner_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} }; struct cast_string { operator std::string() const { return "CAST"; } }; /** * CAST holder. * T is a type to cast to * E is an expression type * Example: cast<std::string>(&User::id) */ template<class T, class E> struct cast_t : cast_string { using to_type = T; using expression_type = E; expression_type expression; cast_t(expression_type expression_) : expression(std::move(expression_)) {} }; template<class... Args> struct from_t { using tuple_type = std::tuple<Args...>; }; template<class T> using is_from = polyfill::is_specialization_of<T, from_t>; } /** * Explicit FROM function. Usage: * `storage.select(&User::id, from<User>());` */ template<class... Args> internal::from_t<Args...> from() { static_assert(std::tuple_size<std::tuple<Args...>>::value > 0, ""); return {}; } template<class T, internal::satisfies<std::is_base_of, internal::negatable_t, T> = true> internal::negated_condition_t<T> operator!(T arg) { return {std::move(arg)}; } /** * Cute operators for columns */ template<class T, class R> internal::lesser_than_t<T, R> operator<(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::lesser_than_t<L, T> operator<(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class T, class R> internal::lesser_or_equal_t<T, R> operator<=(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::lesser_or_equal_t<L, T> operator<=(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class T, class R> internal::greater_than_t<T, R> operator>(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::greater_than_t<L, T> operator>(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class T, class R> internal::greater_or_equal_t<T, R> operator>=(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::greater_or_equal_t<L, T> operator>=(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class T, class R> internal::is_equal_t<T, R> operator==(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::is_equal_t<L, T> operator==(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class T, class R> internal::is_not_equal_t<T, R> operator!=(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::is_not_equal_t<L, T> operator!=(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class T, class R> internal::conc_t<T, R> operator||(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::conc_t<L, T> operator||(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class L, class R> internal::conc_t<L, R> operator||(internal::expression_t<L> l, internal::expression_t<R> r) { return {std::move(l.value), std::move(r.value)}; } template<class T, class R> internal::add_t<T, R> operator+(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::add_t<L, T> operator+(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class L, class R> internal::add_t<L, R> operator+(internal::expression_t<L> l, internal::expression_t<R> r) { return {std::move(l.value), std::move(r.value)}; } template<class T, class R> internal::sub_t<T, R> operator-(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::sub_t<L, T> operator-(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class L, class R> internal::sub_t<L, R> operator-(internal::expression_t<L> l, internal::expression_t<R> r) { return {std::move(l.value), std::move(r.value)}; } template<class T, class R> internal::mul_t<T, R> operator*(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::mul_t<L, T> operator*(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class L, class R> internal::mul_t<L, R> operator*(internal::expression_t<L> l, internal::expression_t<R> r) { return {std::move(l.value), std::move(r.value)}; } template<class T, class R> internal::div_t<T, R> operator/(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::div_t<L, T> operator/(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class L, class R> internal::div_t<L, R> operator/(internal::expression_t<L> l, internal::expression_t<R> r) { return {std::move(l.value), std::move(r.value)}; } template<class T, class R> internal::mod_t<T, R> operator%(internal::expression_t<T> expr, R r) { return {std::move(expr.value), std::move(r)}; } template<class L, class T> internal::mod_t<L, T> operator%(L l, internal::expression_t<T> expr) { return {std::move(l), std::move(expr.value)}; } template<class L, class R> internal::mod_t<L, R> operator%(internal::expression_t<L> l, internal::expression_t<R> r) { return {std::move(l.value), std::move(r.value)}; } template<class F, class O> internal::using_t<O, F O::*> using_(F O::*p) { return {p}; } template<class T, class M> internal::using_t<T, M> using_(internal::column_pointer<T, M> cp) { return {std::move(cp)}; } template<class T> internal::on_t<T> on(T t) { return {std::move(t)}; } template<class T> internal::cross_join_t<T> cross_join() { return {}; } template<class T> internal::natural_join_t<T> natural_join() { return {}; } template<class T, class O> internal::left_join_t<T, O> left_join(O o) { return {std::move(o)}; } template<class T, class O> internal::join_t<T, O> join(O o) { return {std::move(o)}; } template<class T, class O> internal::left_outer_join_t<T, O> left_outer_join(O o) { return {std::move(o)}; } template<class T, class O> internal::inner_join_t<T, O> inner_join(O o) { return {std::move(o)}; } template<class T> internal::offset_t<T> offset(T off) { return {std::move(off)}; } template<class T> internal::limit_t<T, false, false, void> limit(T lim) { return {std::move(lim)}; } template<class T, class O, internal::satisfies_not<internal::is_offset, T> = true> internal::limit_t<T, true, true, O> limit(O off, T lim) { return {std::move(lim), {std::move(off)}}; } template<class T, class O> internal::limit_t<T, true, false, O> limit(T lim, internal::offset_t<O> offt) { return {std::move(lim), {std::move(offt.off)}}; } template<class L, class R, std::enable_if_t<polyfill::disjunction_v<std::is_base_of<internal::condition_t, L>, std::is_base_of<internal::condition_t, R>>, bool> = true> auto operator&&(L l, R r) { using internal::get_from_expression; return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); } template<class L, class R> auto and_(L l, R r) { using internal::get_from_expression; return internal::make_and_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); } template<class L, class R, std::enable_if_t<polyfill::disjunction_v<std::is_base_of<internal::condition_t, L>, std::is_base_of<internal::condition_t, R>>, bool> = true> auto operator||(L l, R r) { using internal::get_from_expression; return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); } template<class L, class R> auto or_(L l, R r) { using internal::get_from_expression; return internal::make_or_condition(std::move(get_from_expression(l)), std::move(get_from_expression(r))); } template<class T> internal::is_not_null_t<T> is_not_null(T t) { return {std::move(t)}; } template<class T> internal::is_null_t<T> is_null(T t) { return {std::move(t)}; } template<class L, class E> internal::dynamic_in_t<L, std::vector<E>> in(L l, std::vector<E> values) { return {std::move(l), std::move(values), false}; } template<class L, class E> internal::dynamic_in_t<L, std::vector<E>> in(L l, std::initializer_list<E> values) { return {std::move(l), std::move(values), false}; } template<class L, class A> internal::dynamic_in_t<L, A> in(L l, A arg) { return {std::move(l), std::move(arg), false}; } template<class L, class E> internal::dynamic_in_t<L, std::vector<E>> not_in(L l, std::vector<E> values) { return {std::move(l), std::move(values), true}; } template<class L, class E> internal::dynamic_in_t<L, std::vector<E>> not_in(L l, std::initializer_list<E> values) { return {std::move(l), std::move(values), true}; } template<class L, class A> internal::dynamic_in_t<L, A> not_in(L l, A arg) { return {std::move(l), std::move(arg), true}; } template<class L, class R> internal::is_equal_t<L, R> is_equal(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::is_equal_t<L, R> eq(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::is_not_equal_t<L, R> is_not_equal(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::is_not_equal_t<L, R> ne(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::greater_than_t<L, R> greater_than(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::greater_than_t<L, R> gt(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::greater_or_equal_t<L, R> greater_or_equal(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::greater_or_equal_t<L, R> ge(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::lesser_than_t<L, R> lesser_than(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::lesser_than_t<L, R> lt(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::lesser_or_equal_t<L, R> lesser_or_equal(L l, R r) { return {std::move(l), std::move(r)}; } template<class L, class R> internal::lesser_or_equal_t<L, R> le(L l, R r) { return {std::move(l), std::move(r)}; } /** * ORDER BY column, column alias or expression * * Examples: * storage.select(&User::name, order_by(&User::id)) * storage.select(as<colalias_a>(&User::name), order_by(get<colalias_a>())) */ template<class O, internal::satisfies_not<std::is_base_of, integer_printer, type_printer<O>> = true> internal::order_by_t<O> order_by(O o) { return {std::move(o)}; } /** * ORDER BY positional ordinal * * Examples: * storage.select(&User::name, order_by(1)) */ template<class O, internal::satisfies<std::is_base_of, integer_printer, type_printer<O>> = true> internal::order_by_t<internal::literal_holder<O>> order_by(O o) { return {{std::move(o)}}; } /** * ORDER BY column1, column2 * Example: storage.get_all<Singer>(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc()) */ template<class... Args> internal::multi_order_by_t<Args...> multi_order_by(Args&&... args) { return {std::make_tuple(std::forward<Args>(args)...)}; } /** * ORDER BY column1, column2 * Difference from `multi_order_by` is that `dynamic_order_by` can be changed at runtime using `push_back` member * function Example: * auto orderBy = dynamic_order_by(storage); * if(someCondition) { * orderBy.push_back(&User::id); * } else { * orderBy.push_back(&User::name); * orderBy.push_back(&User::birthDate); * } */ template<class S> internal::dynamic_order_by_t<internal::serializer_context<typename S::db_objects_type>> dynamic_order_by(const S& storage) { internal::serializer_context_builder<S> builder(storage); return builder(); } /** * X BETWEEN Y AND Z * Example: storage.select(between(&User::id, 10, 20)) */ template<class A, class T> internal::between_t<A, T> between(A expr, T b1, T b2) { return {std::move(expr), std::move(b1), std::move(b2)}; } /** * X LIKE Y * Example: storage.select(like(&User::name, "T%")) */ template<class A, class T> internal::like_t<A, T, void> like(A a, T t) { return {std::move(a), std::move(t), {}}; } /** * X GLOB Y * Example: storage.select(glob(&User::name, "*S")) */ template<class A, class T> internal::glob_t<A, T> glob(A a, T t) { return {std::move(a), std::move(t)}; } /** * X LIKE Y ESCAPE Z * Example: storage.select(like(&User::name, "T%", "%")) */ template<class A, class T, class E> internal::like_t<A, T, E> like(A a, T t, E e) { return {std::move(a), std::move(t), {std::move(e)}}; } /** * CAST(X AS type). * Example: cast<std::string>(&User::id) */ template<class T, class E> internal::cast_t<T, E> cast(E e) { return {std::move(e)}; } }