discord-bot/libs/sqlite_orm-1.8.2/dev/conditions.h

1293 lines
38 KiB
C++

#pragma once
#include <string> // std::string
#include <type_traits> // std::enable_if, std::is_same, std::remove_const
#include <vector> // std::vector
#include <tuple> // std::tuple
#include <sstream> // std::stringstream
#include "functional/cxx_universal.h"
#include "functional/cxx_type_traits_polyfill.h"
#include "is_base_of_template.h"
#include "type_traits.h"
#include "collate_argument.h"
#include "constraints.h"
#include "optional_container.h"
#include "serializer_context.h"
#include "tags.h"
#include "alias_traits.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_)) {}
};
template<class T>
SQLITE_ORM_INLINE_VAR constexpr bool is_binary_condition_v = is_base_of_template_v<T, binary_condition>;
template<class T>
using is_binary_condition = polyfill::bool_constant<is_binary_condition_v<T>>;
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(std::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_, std::move(collate_argument_)}, name(std::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);
this->entries.emplace_back(std::move(columnName),
order_by.asc_desc,
std::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>;
template<class T>
using is_constrained_join = polyfill::is_detected<on_type_t, T>;
}
/**
* Explicit FROM function. Usage:
* `storage.select(&User::id, from<User>());`
*/
template<class... Tables>
internal::from_t<Tables...> from() {
static_assert(sizeof...(Tables) > 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)};
}
// Deliberately put operators for `expression_t` into the internal namespace
// to facilitate ADL (Argument Dependent Lookup)
namespace internal {
/**
* Cute operators for columns
*/
template<class T, class R>
lesser_than_t<T, R> operator<(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
lesser_than_t<L, T> operator<(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
lesser_or_equal_t<T, R> operator<=(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
lesser_or_equal_t<L, T> operator<=(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
greater_than_t<T, R> operator>(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
greater_than_t<L, T> operator>(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
greater_or_equal_t<T, R> operator>=(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
greater_or_equal_t<L, T> operator>=(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
is_equal_t<T, R> operator==(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
is_equal_t<L, T> operator==(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
is_not_equal_t<T, R> operator!=(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
is_not_equal_t<L, T> operator!=(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class T, class R>
conc_t<T, R> operator||(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
conc_t<L, T> operator||(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
conc_t<L, R> operator||(expression_t<L> l, expression_t<R> r) {
return {std::move(l.value), std::move(r.value)};
}
template<class R, class E, satisfies<std::is_base_of, conc_string, E> = true>
conc_t<E, R> operator||(E expr, R r) {
return {std::move(expr), std::move(r)};
}
template<class L, class E, satisfies<std::is_base_of, conc_string, E> = true>
conc_t<L, E> operator||(L l, E expr) {
return {std::move(l), std::move(expr)};
}
template<class T, class R>
add_t<T, R> operator+(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
add_t<L, T> operator+(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
add_t<L, R> operator+(expression_t<L> l, expression_t<R> r) {
return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
sub_t<T, R> operator-(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
sub_t<L, T> operator-(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
sub_t<L, R> operator-(expression_t<L> l, expression_t<R> r) {
return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
mul_t<T, R> operator*(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
mul_t<L, T> operator*(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
mul_t<L, R> operator*(expression_t<L> l, expression_t<R> r) {
return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
div_t<T, R> operator/(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
div_t<L, T> operator/(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
div_t<L, R> operator/(expression_t<L> l, expression_t<R> r) {
return {std::move(l.value), std::move(r.value)};
}
template<class T, class R>
mod_t<T, R> operator%(expression_t<T> expr, R r) {
return {std::move(expr.value), std::move(r)};
}
template<class L, class T>
mod_t<L, T> operator%(L l, expression_t<T> expr) {
return {std::move(l), std::move(expr.value)};
}
template<class L, class R>
mod_t<L, R> operator%(expression_t<L> l, 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)};
}
}