#pragma once #if defined(_MSC_VER) # if defined(min) __pragma(push_macro("min")) # undef min # define __RESTORE_MIN__ # endif # if defined(max) __pragma(push_macro("max")) # undef max # define __RESTORE_MAX__ # endif #endif // defined(_MSC_VER) #include // due to #166 #pragma once #include // std::error_code, std::system_error #include // std::string #include #include namespace sqlite_orm { enum class orm_error_code { not_found = 1, type_is_not_mapped_to_storage, trying_to_dereference_null_iterator, too_many_tables_specified, incorrect_set_fields_specified, column_not_found, table_has_no_primary_key_column, cannot_start_a_transaction_within_a_transaction, no_active_transaction, incorrect_journal_mode_string, }; } namespace sqlite_orm { class orm_error_category : public std::error_category { public: const char *name() const noexcept override final { return "ORM error"; } std::string message(int c) const override final { switch (static_cast(c)) { case orm_error_code::not_found: return "Not found"; case orm_error_code::type_is_not_mapped_to_storage: return "Type is not mapped to storage"; case orm_error_code::trying_to_dereference_null_iterator: return "Trying to dereference null iterator"; case orm_error_code::too_many_tables_specified: return "Too many tables specified"; case orm_error_code::incorrect_set_fields_specified: return "Incorrect set fields specified"; case orm_error_code::column_not_found: return "Column not found"; case orm_error_code::table_has_no_primary_key_column: return "Table has no primary key column"; case orm_error_code::cannot_start_a_transaction_within_a_transaction: return "Cannot start a transaction within a transaction"; case orm_error_code::no_active_transaction: return "No active transaction"; default: return "unknown error"; } } }; class sqlite_error_category : public std::error_category { public: const char *name() const noexcept override final { return "SQLite error"; } std::string message(int c) const override final { return sqlite3_errstr(c); } }; inline const orm_error_category& get_orm_error_category() { static orm_error_category res; return res; } inline const sqlite_error_category& get_sqlite_error_category() { static sqlite_error_category res; return res; } } namespace std { template <> struct is_error_code_enum : std::true_type{}; inline std::error_code make_error_code(sqlite_orm::orm_error_code errorCode) { return std::error_code(static_cast(errorCode), sqlite_orm::get_orm_error_category()); } } #pragma once #include // std::map #include // std::string #include // std::regex, std::regex_match #include // std::make_unique, std::unique_ptr #include // std::vector #include // std::toupper namespace sqlite_orm { using int64 = sqlite_int64; using uint64 = sqlite_uint64; // numeric and real are the same for c++ enum class sqlite_type { INTEGER, TEXT, BLOB, REAL, }; /** * @param str case doesn't matter - it is uppercased before comparing. */ inline std::unique_ptr to_sqlite_type(const std::string &str) { auto asciiStringToUpper = [](std::string &s){ std::transform(s.begin(), s.end(), s.begin(), [](char c){ return std::toupper(c); }); }; auto upperStr = str; asciiStringToUpper(upperStr); static std::map> typeMap = { { sqlite_type::INTEGER, { std::regex("INT"), std::regex("INT.*"), std::regex("TINYINT"), std::regex("SMALLINT"), std::regex("MEDIUMINT"), std::regex("BIGINT"), std::regex("UNSIGNED BIG INT"), std::regex("INT2"), std::regex("INT8"), } }, { sqlite_type::TEXT, { std::regex("CHARACTER\\([[:digit:]]+\\)"), std::regex("VARCHAR\\([[:digit:]]+\\)"), std::regex("VARYING CHARACTER\\([[:digit:]]+\\)"), std::regex("NCHAR\\([[:digit:]]+\\)"), std::regex("NATIVE CHARACTER\\([[:digit:]]+\\)"), std::regex("NVARCHAR\\([[:digit:]]+\\)"), std::regex("CLOB"), std::regex("TEXT"), } }, { sqlite_type::BLOB, { std::regex("BLOB"), } }, { sqlite_type::REAL, { std::regex("REAL"), std::regex("DOUBLE"), std::regex("DOUBLE PRECISION"), std::regex("FLOAT"), std::regex("NUMERIC"), std::regex("DECIMAL\\([[:digit:]]+,[[:digit:]]+\\)"), std::regex("BOOLEAN"), std::regex("DATE"), std::regex("DATETIME"), } }, }; for(auto &p : typeMap) { for(auto &r : p.second) { if(std::regex_match(upperStr, r)){ return std::make_unique(p.first); } } } return {}; } } #pragma once #include // std::tuple #include // std::false_type, std::true_type #include // std::index_sequence, std::index_sequence_for namespace sqlite_orm { // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type namespace tuple_helper { template struct has_type; template struct has_type> : std::false_type {}; template struct has_type> : has_type> {}; template struct has_type> : std::true_type {}; template using tuple_contains_type = typename has_type::type; template struct iterator { template void operator()(const std::tuple &t, L l, bool reverse = true) { if(reverse){ l(std::get(t)); iterator()(t, l, reverse); }else{ iterator()(t, l, reverse); l(std::get(t)); } } }; template struct iterator<0, Args...>{ template void operator()(const std::tuple &t, L l, bool /*reverse*/ = true) { l(std::get<0>(t)); } }; template struct iterator { template void operator()(const std::tuple<> &, L, bool /*reverse*/ = true) { //.. } }; template void tuple_for_each_impl(F&& f, const T& t, std::index_sequence){ int _[] = { (f(std::get(t)), int{}) ... }; (void)_; } template void tuple_for_each(const std::tuple& t, F&& f){ tuple_for_each_impl(std::forward(f), t, std::index_sequence_for{}); } } } #pragma once #include // std::false_type, std::true_type, std::integral_constant namespace sqlite_orm { // got from here https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co namespace static_magic { template auto static_if(std::true_type, T t, F f) { return t; } template auto static_if(std::false_type, T t, F f) { return f; } template auto static_if(T t, F f) { return static_if(std::integral_constant{}, t, f); } template auto static_if(T t) { return static_if(std::integral_constant{}, t, [](auto&&...){}); } } } #pragma once #include // std::string #include // std::shared_ptr, std::unique_ptr #include // std::vector namespace sqlite_orm { /** * This class accepts c++ type and transfers it to sqlite name (int -> INTEGER, std::string -> TEXT) */ template struct type_printer; struct integer_printer { inline const std::string& print() { static const std::string res = "INTEGER"; return res; } }; struct text_printer { inline const std::string& print() { static const std::string res = "TEXT"; return res; } }; struct real_printer { inline const std::string& print() { static const std::string res = "REAL"; return res; } }; struct blob_printer { inline const std::string& print() { static const std::string res = "BLOB"; return res; } }; //Note unsigned/signed char and simple char used for storing integer values, not char values. template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public integer_printer {}; template<> struct type_printer : public text_printer {}; template<> struct type_printer : public text_printer {}; template<> struct type_printer : public text_printer {}; template<> struct type_printer : public real_printer {}; template<> struct type_printer : public real_printer {}; template struct type_printer> : public type_printer {}; template struct type_printer> : public type_printer {}; template<> struct type_printer> : public blob_printer {}; } #pragma once namespace sqlite_orm { namespace internal { enum class collate_argument { binary, nocase, rtrim, }; } } #pragma once #include // std::string #include // std::tuple, std::make_tuple #include // std::stringstream #include // std::is_base_of, std::false_type, std::true_type #include // std::ostream namespace sqlite_orm { namespace constraints { /** * AUTOINCREMENT constraint class. */ struct autoincrement_t { operator std::string() const { return "AUTOINCREMENT"; } }; /** * PRIMARY KEY constraint class. * Cs is parameter pack which contains columns (member pointer and/or function pointers). Can be empty when used withen `make_column` function. */ template struct primary_key_t { std::tuple columns; enum class order_by { unspecified, ascending, descending, }; order_by asc_option = order_by::unspecified; primary_key_t(decltype(columns) c):columns(std::move(c)){} using field_type = void; // for column iteration. Better be deleted using constraints_type = std::tuple<>; operator std::string() const { std::string res = "PRIMARY KEY"; switch(this->asc_option){ case order_by::ascending: res += " ASC"; break; case order_by::descending: res += " DESC"; break; default: break; } return res; } primary_key_t asc() const { auto res = *this; res.asc_option = order_by::ascending; return res; } primary_key_t desc() const { auto res = *this; res.asc_option = order_by::descending; return res; } }; /** * UNIQUE constraint class. */ struct unique_t { operator std::string() const { return "UNIQUE"; } }; /** * DEFAULT constraint class. * T is a value type. */ template struct default_t { using value_type = T; value_type value; operator std::string() const { std::stringstream ss; ss << "DEFAULT "; auto needQuotes = std::is_base_of>::value; if(needQuotes){ ss << "'"; } ss << this->value; if(needQuotes){ ss << "'"; } return ss.str(); } }; #if SQLITE_VERSION_NUMBER >= 3006019 /** * FOREIGN KEY constraint class. * Cs are columns which has foreign key * Rs are column which C references to * Available in SQLite 3.6.19 or higher */ template struct foreign_key_t; enum class foreign_key_action { none, // not specified no_action, restrict_, set_null, set_default, cascade, }; inline std::ostream &operator<<(std::ostream &os, foreign_key_action action) { switch(action){ case decltype(action)::no_action: os << "NO ACTION"; break; case decltype(action)::restrict_: os << "RESTRICT"; break; case decltype(action)::set_null: os << "SET NULL"; break; case decltype(action)::set_default: os << "SET DEFAULT"; break; case decltype(action)::cascade: os << "CASCADE"; break; case decltype(action)::none: break; } return os; } /** * F - foreign key class */ template struct on_update_delete_t { using foreign_key_type = F; const foreign_key_type &fk; const bool update; // true if update and false if delete on_update_delete_t(decltype(fk) fk_, decltype(update) update_, foreign_key_action action_) : fk(fk_), update(update_), _action(action_) {} foreign_key_action _action = foreign_key_action::none; foreign_key_type no_action() const { auto res = this->fk; if(update){ res.on_update._action = foreign_key_action::no_action; }else{ res.on_delete._action = foreign_key_action::no_action; } return res; } foreign_key_type restrict_() const { auto res = this->fk; if(update){ res.on_update._action = foreign_key_action::restrict_; }else{ res.on_delete._action = foreign_key_action::restrict_; } return res; } foreign_key_type set_null() const { auto res = this->fk; if(update){ res.on_update._action = foreign_key_action::set_null; }else{ res.on_delete._action = foreign_key_action::set_null; } return res; } foreign_key_type set_default() const { auto res = this->fk; if(update){ res.on_update._action = foreign_key_action::set_default; }else{ res.on_delete._action = foreign_key_action::set_default; } return res; } foreign_key_type cascade() const { auto res = this->fk; if(update){ res.on_update._action = foreign_key_action::cascade; }else{ res.on_delete._action = foreign_key_action::cascade; } return res; } operator bool() const { return this->_action != decltype(this->_action)::none; } operator std::string() const { if(this->update){ return "ON UPDATE"; }else{ return "ON DELETE"; } } }; template struct foreign_key_t, std::tuple> { using columns_type = std::tuple; using references_type = std::tuple; using self = foreign_key_t; columns_type columns; references_type references; on_update_delete_t on_update; on_update_delete_t on_delete; static_assert(std::tuple_size::value == std::tuple_size::value, "Columns size must be equal to references tuple"); foreign_key_t(columns_type columns_, references_type references_): columns(std::move(columns_)), references(std::move(references_)), on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {} foreign_key_t(const self &other): columns(other.columns), references(other.references), on_update(*this, true, other.on_update._action), on_delete(*this, false, other.on_delete._action) {} self &operator=(const self &other) { this->columns = other.columns; this->references = other.references; this->on_update = {*this, true, other.on_update._action}; this->on_delete = {*this, false, other.on_delete._action}; return *this; } using field_type = void; // for column iteration. Better be deleted using constraints_type = std::tuple<>; template void for_each_column(L) {} template constexpr bool has_every() const { return false; } }; /** * Cs can be a class member pointer, a getter function member pointer or setter * func member pointer * Available in SQLite 3.6.19 or higher */ template struct foreign_key_intermediate_t { using tuple_type = std::tuple; tuple_type columns; foreign_key_intermediate_t(tuple_type columns_): columns(std::move(columns_)) {} template foreign_key_t, std::tuple> references(Rs ...references) { using ret_type = foreign_key_t, std::tuple>; return ret_type(std::move(this->columns), std::make_tuple(std::forward(references)...)); } }; #endif struct collate_t { internal::collate_argument argument; collate_t(internal::collate_argument argument_): argument(argument_) {} operator std::string() const { std::string res = "COLLATE " + string_from_collate_argument(this->argument); return res; } static std::string string_from_collate_argument(internal::collate_argument argument){ switch(argument){ case decltype(argument)::binary: return "BINARY"; case decltype(argument)::nocase: return "NOCASE"; case decltype(argument)::rtrim: return "RTRIM"; } } }; template struct is_constraint : std::false_type {}; template<> struct is_constraint : std::true_type {}; template struct is_constraint> : std::true_type {}; template<> struct is_constraint : std::true_type {}; template struct is_constraint> : std::true_type {}; template struct is_constraint> : std::true_type {}; template<> struct is_constraint : std::true_type {}; template struct constraints_size; template<> struct constraints_size<> { static constexpr const int value = 0; }; template struct constraints_size { static constexpr const int value = is_constraint::value + constraints_size::value; }; } #if SQLITE_VERSION_NUMBER >= 3006019 /** * FOREIGN KEY constraint construction function that takes member pointer as argument * Available in SQLite 3.6.19 or higher */ template constraints::foreign_key_intermediate_t foreign_key(Cs ...columns) { return {std::make_tuple(std::forward(columns)...)}; } #endif /** * UNIQUE constraint builder function. */ inline constraints::unique_t unique() { return {}; } inline constraints::autoincrement_t autoincrement() { return {}; } template inline constraints::primary_key_t primary_key(Cs ...cs) { using ret_type = constraints::primary_key_t; return ret_type(std::make_tuple(cs...)); } template constraints::default_t default_value(T t) { return {t}; } inline constraints::collate_t collate_nocase() { return {internal::collate_argument::nocase}; } inline constraints::collate_t collate_binary() { return {internal::collate_argument::binary}; } inline constraints::collate_t collate_rtrim() { return {internal::collate_argument::rtrim}; } namespace internal { /** * FOREIGN KEY traits. Common case */ template struct is_foreign_key : std::false_type {}; /** * FOREIGN KEY traits. Specialized case */ template struct is_foreign_key> : std::true_type {}; /** * PRIMARY KEY traits. Common case */ template struct is_primary_key : public std::false_type {}; /** * PRIMARY KEY traits. Specialized case */ template struct is_primary_key> : public std::true_type {}; } } #pragma once #include // std::false_type, std::true_type #include // std::shared_ptr, std::unique_ptr namespace sqlite_orm { /** * This is class that tells `sqlite_orm` that type is nullable. Nullable types * are mapped to sqlite database as `NULL` and not-nullable are mapped as `NOT NULL`. * Default nullability status for all types is `NOT NULL`. So if you want to map * custom type as `NULL` (for example: boost::optional) you have to create a specialiation * of type_is_nullable for your type and derive from `std::true_type`. */ template struct type_is_nullable : public std::false_type { bool operator()(const T &) const { return true; } }; /** * This is a specialization for std::shared_ptr. std::shared_ptr is nullable in sqlite_orm. */ template struct type_is_nullable> : public std::true_type { bool operator()(const std::shared_ptr &t) const { return static_cast(t); } }; /** * This is a specialization for std::unique_ptr. std::unique_ptr is nullable too. */ template struct type_is_nullable> : public std::true_type { bool operator()(const std::unique_ptr &t) const { return static_cast(t); } }; } #pragma once #include // std::unique_ptr #include // std::string #include // std::stringstream // #include "constraints.h" namespace sqlite_orm { namespace internal { /** * This class is used in tuple interation to know whether tuple constains `default_value_t` * constraint class and what it's value if it is */ struct default_value_extractor { template std::unique_ptr operator() (const A &) { return {}; } template std::unique_ptr operator() (const constraints::default_t &t) { std::stringstream ss; ss << t.value; return std::make_unique(ss.str()); } }; } } #pragma once #include // std::false_type, std::true_type namespace sqlite_orm { namespace internal { /** * Inherit this class to support arithmetic types overloading */ struct arithmetic_t {}; /** * Result of concatenation || operator */ template struct conc_t { L l; R r; }; /** * Result of addition + operator */ template struct add_t : arithmetic_t { using left_type = L; using right_type = R; left_type l; right_type r; add_t() = default; add_t(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; /** * Result of subscribe - operator */ template struct sub_t : arithmetic_t { using left_type = L; using right_type = R; left_type l; right_type r; sub_t() = default; sub_t(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; /** * Result of multiply * operator */ template struct mul_t : arithmetic_t { using left_type = L; using right_type = R; left_type l; right_type r; mul_t() = default; mul_t(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; /** * Result of divide / operator */ template struct div_t : arithmetic_t { using left_type = L; using right_type = R; left_type l; right_type r; div_t() = default; div_t(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; /** * Result of mod % operator */ template struct mod_t : arithmetic_t { using left_type = L; using right_type = R; left_type l; right_type r; mod_t() = default; mod_t(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; /** * Result of assign = operator */ template struct assign_t { L l; R r; assign_t(){} assign_t(L l_, R r_): l(l_), r(r_) {} }; /** * Assign operator traits. Common case */ template struct is_assign_t : public std::false_type {}; /** * Assign operator traits. Specialized case */ template struct is_assign_t> : public std::true_type {}; /** * Is not an operator but a result of c(...) function. Has operator= overloaded which returns assign_t */ template struct expression_t { T t; expression_t(T t_): t(t_) {} template assign_t operator=(R r) const { return {this->t, r}; } }; } /** * Public interface for syntax sugar for columns. Example: `where(c(&User::id) == 5)` or `storage.update(set(c(&User::name) = "Dua Lipa")); */ template internal::expression_t c(T t) { using result_type = internal::expression_t; return result_type(t); } /** * Public interface for || concatenation operator. Example: `select(conc(&User::name, "@gmail.com"));` => SELECT name + '@gmail.com' FROM users */ template internal::conc_t conc(L l, R r) { return {l, r}; } /** * Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users */ template internal::add_t add(L l, R r) { return {l, r}; } /** * Public interface for - operator. Example: `select(add(&User::age, 1));` => SELECT age - 1 FROM users */ template internal::sub_t sub(L l, R r) { return {l, r}; } template internal::mul_t mul(L l, R r) { return {l, r}; } template internal::div_t div(L l, R r) { return {l, r}; } template internal::mod_t mod(L l, R r) { return {l, r}; } template internal::assign_t assign(L l, R r) { return {std::move(l), std::move(r)}; } } #pragma once #include // std::tuple #include // std::string #include // std::unique_ptr #include // std::true_type, std::false_type, std::is_same, std::enable_if // #include "type_is_nullable.h" // #include "tuple_helper.h" // #include "default_value_extractor.h" // #include "constraints.h" namespace sqlite_orm { namespace internal { /** * This class stores single column info. column_t is a pair of [column_name:member_pointer] mapped to a storage * O is a mapped class, e.g. User * T is a mapped class'es field type, e.g. &User::name * Op... is a constraints pack, e.g. primary_key_t, autoincrement_t etc */ template struct column_t { using object_type = O; using field_type = T; using constraints_type = std::tuple; using member_pointer_t = field_type object_type::*; using getter_type = G; using setter_type = S; /** * Column name. Specified during construction in `make_column`. */ const std::string name; /** * Member pointer used to read/write member */ member_pointer_t member_pointer/* = nullptr*/; /** * Getter member function pointer to get a value. If member_pointer is null than * `getter` and `setter` must be not null */ getter_type getter/* = nullptr*/; /** * Setter member function */ setter_type setter/* = nullptr*/; /** * Constraints tuple */ constraints_type constraints; /** * Simplified interface for `NOT NULL` constraint */ bool not_null() const { return !type_is_nullable::value; } template constexpr bool has() const { return tuple_helper::tuple_contains_type::value; } template constexpr bool has_every() const { if(has() && has()) { return true; }else{ return has_every(); } } template constexpr bool has_every() const { return has(); } /** * Simplified interface for `DEFAULT` constraint * @return string representation of default value if it exists otherwise nullptr */ std::unique_ptr default_value() { std::unique_ptr res; tuple_helper::iterator::value - 1, Op...>()(constraints, [&res](auto &v){ auto dft = internal::default_value_extractor()(v); if(dft){ res = std::move(dft); } }); return res; } }; /** * Column traits. Common case. */ template struct is_column : public std::false_type {}; /** * Column traits. Specialized case case. */ template struct is_column> : public std::true_type {}; template using getter_by_value_const = T (O::*)() const; template using getter_by_value = T (O::*)(); template using getter_by_ref_const = T& (O::*)() const; template using getter_by_ref = T& (O::*)(); template using getter_by_const_ref_const = const T& (O::*)() const; template using getter_by_const_ref = const T& (O::*)(); template using setter_by_value = void (O::*)(T); template using setter_by_ref = void (O::*)(T&); template using setter_by_const_ref = void (O::*)(const T&); template struct is_getter : std::false_type {}; template struct is_getter> : std::true_type {}; template struct is_getter> : std::true_type {}; template struct is_getter> : std::true_type {}; template struct is_getter> : std::true_type {}; template struct is_getter> : std::true_type {}; template struct is_getter> : std::true_type {}; template struct is_setter : std::false_type {}; template struct is_setter> : std::true_type {}; template struct is_setter> : std::true_type {}; template struct is_setter> : std::true_type {}; template struct getter_traits; template struct getter_traits> { using object_type = O; using field_type = T; static constexpr const bool returns_lvalue = false; }; template struct getter_traits> { using object_type = O; using field_type = T; static constexpr const bool returns_lvalue = false; }; template struct getter_traits> { using object_type = O; using field_type = T; static constexpr const bool returns_lvalue = true; }; template struct getter_traits> { using object_type = O; using field_type = T; static constexpr const bool returns_lvalue = true; }; template struct getter_traits> { using object_type = O; using field_type = T; static constexpr const bool returns_lvalue = true; }; template struct getter_traits> { using object_type = O; using field_type = T; static constexpr const bool returns_lvalue = true; }; template struct setter_traits; template struct setter_traits> { using object_type = O; using field_type = T; }; template struct setter_traits> { using object_type = O; using field_type = T; }; template struct setter_traits> { using object_type = O; using field_type = T; }; } /** * Column builder function. You should use it to create columns instead of constructor */ template::value>::type, class ...Op> internal::column_t make_column(const std::string &name, T O::*m, Op ...constraints){ static_assert(constraints::constraints_size::value == std::tuple_size>::value, "Incorrect constraints pack"); return {name, m, nullptr, nullptr, std::make_tuple(constraints...)}; } /** * Column builder function with setter and getter. You should use it to create columns instead of constructor */ template::value>::type, typename = typename std::enable_if::value>::type, class ...Op> internal::column_t< typename internal::setter_traits::object_type, typename internal::setter_traits::field_type, G, S, Op...> make_column(const std::string &name, S setter, G getter, Op ...constraints) { static_assert(std::is_same::field_type, typename internal::getter_traits::field_type>::value, "Getter and setter must get and set same data type"); static_assert(constraints::constraints_size::value == std::tuple_size>::value, "Incorrect constraints pack"); return {name, nullptr, getter, setter, std::make_tuple(constraints...)}; } /** * Column builder function with getter and setter (reverse order). You should use it to create columns instead of constructor */ template::value>::type, typename = typename std::enable_if::value>::type, class ...Op> internal::column_t< typename internal::setter_traits::object_type, typename internal::setter_traits::field_type, G, S, Op...> make_column(const std::string &name, G getter, S setter, Op ...constraints) { static_assert(std::is_same::field_type, typename internal::getter_traits::field_type>::value, "Getter and setter must get and set same data type"); static_assert(constraints::constraints_size::value == std::tuple_size>::value, "Incorrect constraints pack"); return {name, nullptr, getter, setter, std::make_tuple(constraints...)}; } } #pragma once #include // std::string #include // std::stringstream #include // std::vector #include // std::nullptr_t #include // std::shared_ptr, std::unique_ptr namespace sqlite_orm { /** * Is used to print members mapped to objects in storage_t::dump member function. * Other developers can create own specialization to map custom types */ template struct field_printer { std::string operator()(const T &t) const { std::stringstream stream; stream << t; return stream.str(); } }; /** * Upgrade to integer is required when using unsigned char(uint8_t) */ template<> struct field_printer { std::string operator()(const unsigned char &t) const { std::stringstream stream; stream << +t; return stream.str(); } }; /** * Upgrade to integer is required when using signed char(int8_t) */ template<> struct field_printer { std::string operator()(const signed char &t) const { std::stringstream stream; stream << +t; return stream.str(); } }; /** * char is neigher signer char nor unsigned char so it has its own specialization */ template<> struct field_printer { std::string operator()(const char &t) const { std::stringstream stream; stream << +t; return stream.str(); } }; template<> struct field_printer { std::string operator()(const std::string &t) const { return t; } }; template<> struct field_printer> { std::string operator()(const std::vector &t) const { std::stringstream ss; ss << std::hex; for(auto c : t) { ss << c; } return ss.str(); } }; template<> struct field_printer { std::string operator()(const std::nullptr_t &) const { return "null"; } }; template struct field_printer> { std::string operator()(const std::shared_ptr &t) const { if(t){ return field_printer()(*t); }else{ return field_printer()(nullptr); } } }; template struct field_printer> { std::string operator()(const std::unique_ptr &t) const { if(t){ return field_printer()(*t); }else{ return field_printer()(nullptr); } } }; } #pragma once #include // std::string // #include "collate_argument.h" // #include "constraints.h" namespace sqlite_orm { namespace conditions { /** * Stores LIMIT/OFFSET info */ struct limit_t { int lim = 0; bool has_offset = false; bool offset_is_implicit = false; int off = 0; limit_t() = default; limit_t(decltype(lim) lim_): lim(lim_) {} limit_t(decltype(lim) lim_, decltype(has_offset) has_offset_, decltype(offset_is_implicit) offset_is_implicit_, decltype(off) off_): lim(lim_), has_offset(has_offset_), offset_is_implicit(offset_is_implicit_), off(off_){} operator std::string () const { return "LIMIT"; } }; /** * Stores OFFSET only info */ struct offset_t { int off; }; /** * Inherit from this class if target class can be chained with other conditions with '&&' and '||' operators */ struct condition_t {}; /** * Collated something */ template struct collate_t : public condition_t { T expr; internal::collate_argument argument; collate_t(T expr_, internal::collate_argument argument_): expr(expr_), argument(argument_) {} operator std::string () const { return constraints::collate_t{this->argument}; } }; /** * Collated something with custom collate function */ template struct named_collate { T expr; std::string name; named_collate() = default; named_collate(T expr_, std::string name_): expr(expr_), name(std::move(name_)) {} operator std::string () const { return "COLLATE " + this->name; } }; /** * Result of not operator */ template struct negated_condition_t : public condition_t { C c; negated_condition_t() = default; negated_condition_t(C c_): c(c_) {} operator std::string () const { return "NOT"; } }; /** * Result of and operator */ template struct and_condition_t : public condition_t { L l; R r; and_condition_t() = default; and_condition_t(L l_, R r_): l(l_), r(r_) {} operator std::string () const { return "AND"; } }; /** * Result of or operator */ template struct or_condition_t : public condition_t { L l; R r; or_condition_t() = default; or_condition_t(L l_, R r_): l(l_), r(r_) {} operator std::string () const { return "OR"; } }; /** * Base class for binary conditions */ template struct binary_condition : public condition_t { L l; R r; binary_condition() = default; binary_condition(L l_, R r_): l(l_), r(r_) {} }; /** * = and == operators object */ template struct is_equal_t : public binary_condition { using self = is_equal_t; using binary_condition::binary_condition; operator std::string () const { return "="; } negated_condition_t operator!() const { return {*this}; } collate_t collate_binary() const { return {*this, internal::collate_argument::binary}; } collate_t collate_nocase() const { return {*this, internal::collate_argument::nocase}; } collate_t collate_rtrim() const { return {*this, internal::collate_argument::rtrim}; } named_collate collate(std::string name) const { return {*this, std::move(name)}; } }; /** * != operator object */ template struct is_not_equal_t : public binary_condition { using self = is_not_equal_t; using binary_condition::binary_condition; operator std::string () const { return "!="; } negated_condition_t operator!() const { return {*this}; } collate_t collate_binary() const { return {*this, internal::collate_argument::binary}; } collate_t collate_nocase() const { return {*this, internal::collate_argument::nocase}; } collate_t collate_rtrim() const { return {*this, internal::collate_argument::rtrim}; } }; /** * > operator object. */ template struct greater_than_t : public binary_condition { using self = greater_than_t; using binary_condition::binary_condition; operator std::string () const { return ">"; } negated_condition_t operator!() const { return {*this}; } collate_t collate_binary() const { return {*this, internal::collate_argument::binary}; } collate_t collate_nocase() const { return {*this, internal::collate_argument::nocase}; } collate_t collate_rtrim() const { return {*this, internal::collate_argument::rtrim}; } }; /** * >= operator object. */ template struct greater_or_equal_t : public binary_condition { using self = greater_or_equal_t; using binary_condition::binary_condition; operator std::string () const { return ">="; } negated_condition_t operator!() const { return {*this}; } collate_t collate_binary() const { return {*this, internal::collate_argument::binary}; } collate_t collate_nocase() const { return {*this, internal::collate_argument::nocase}; } collate_t collate_rtrim() const { return {*this, internal::collate_argument::rtrim}; } }; /** * < operator object. */ template struct lesser_than_t : public binary_condition { using self = lesser_than_t; using binary_condition::binary_condition; operator std::string () const { return "<"; } negated_condition_t operator!() const { return {*this}; } collate_t collate_binary() const { return {*this, internal::collate_argument::binary}; } collate_t collate_nocase() const { return {*this, internal::collate_argument::nocase}; } collate_t collate_rtrim() const { return {*this, internal::collate_argument::rtrim}; } }; /** * <= operator object. */ template struct lesser_or_equal_t : public binary_condition { using self = lesser_or_equal_t; using binary_condition::binary_condition; operator std::string () const { return "<="; } negated_condition_t> operator!() const { return {*this}; } collate_t collate_binary() const { return {*this, internal::collate_argument::binary}; } collate_t collate_nocase() const { return {*this, internal::collate_argument::nocase}; } collate_t collate_rtrim() const { return {*this, internal::collate_argument::rtrim}; } }; /** * IN operator object. */ template struct in_t : public condition_t { using self = in_t; L l; // left expression A arg; // in arg bool negative = false; // used in not_in in_t() = default; in_t(L l_, A arg_, bool negative_): l(l_), arg(std::move(arg_)), negative(negative_) {} negated_condition_t operator!() const { return {*this}; } operator std::string () const { if(!this->negative){ return "IN"; }else{ return "NOT IN"; } } }; /** * IS NULL operator object. */ template struct is_null_t { using self = is_null_t; T t; negated_condition_t operator!() const { return {*this}; } operator std::string () const { return "IS NULL"; } }; /** * IS NOT NULL operator object. */ template struct is_not_null_t { using self = is_not_null_t; T t; negated_condition_t operator!() const { return {*this}; } operator std::string () const { return "IS NOT NULL"; } }; /** * WHERE argument holder. */ template struct where_t { C c; operator std::string () const { return "WHERE"; } }; /** * ORDER BY argument holder. */ template struct order_by_t { using self = order_by_t; O o; int asc_desc = 0; // 1: asc, -1: desc std::string _collate_argument; order_by_t(): o() {} order_by_t(O o_): o(o_) {} operator std::string() const { return "ORDER BY"; } self asc() { auto res = *this; res.asc_desc = 1; return res; } self desc() { auto res = *this; res.asc_desc = -1; return res; } self collate_binary() const { auto res = *this; res._collate_argument = constraints::collate_t::string_from_collate_argument(internal::collate_argument::binary); return res; } self collate_nocase() const { auto res = *this; res._collate_argument = constraints::collate_t::string_from_collate_argument(internal::collate_argument::nocase); return res; } self collate_rtrim() const { auto res = *this; res._collate_argument = constraints::collate_t::string_from_collate_argument(internal::collate_argument::rtrim); return res; } self collate(std::string name) const { auto res = *this; res._collate_argument = std::move(name); return res; } }; /** * ORDER BY pack holder. */ template struct multi_order_by_t { std::tuple args; operator std::string() const { return static_cast(order_by_t()); } }; /** * GROUP BY pack holder. */ template struct group_by_t { std::tuple args; operator std::string() const { return "GROUP BY"; } }; /** * BETWEEN operator object. */ template struct between_t : public condition_t { A expr; T b1; T b2; between_t() = default; between_t(A expr_, T b1_, T b2_): expr(expr_), b1(b1_), b2(b2_) {} operator std::string() const { return "BETWEEN"; } }; /** * LIKE operator object. */ template struct like_t : public condition_t { A a; T t; like_t() = default; like_t(A a_, T t_): a(a_), t(t_) {} operator std::string() const { return "LIKE"; } }; /** * CROSS JOIN holder. * T is joined type which represents any mapped table. */ template struct cross_join_t { using type = T; operator std::string() const { return "CROSS JOIN"; } }; /** * NATURAL JOIN holder. * T is joined type which represents any mapped table. */ template struct natural_join_t { using type = T; operator std::string() const { return "NATURAL JOIN"; } }; /** * LEFT JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template struct left_join_t { using type = T; using on_type = O; on_type constraint; operator std::string() const { return "LEFT JOIN"; } }; /** * Simple JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template struct join_t { using type = T; using on_type = O; on_type constraint; operator std::string() const { return "JOIN"; } }; /** * LEFT OUTER JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template struct left_outer_join_t { using type = T; using on_type = O; on_type constraint; operator std::string() const { return "LEFT OUTER JOIN"; } }; /** * on(...) argument holder used for JOIN, LEFT JOIN, LEFT OUTER JOIN and INNER JOIN * T is on type argument. */ template struct on_t { using type = T; type t; operator std::string() const { return "ON"; } }; /** * USING argument holder. */ template struct using_t { F O::*column; operator std::string() const { return "USING"; } }; /** * INNER JOIN holder. * T is joined type which represents any mapped table. * O is on(...) argument type. */ template struct inner_join_t { using type = T; using on_type = O; on_type constraint; operator std::string() const { return "INNER JOIN"; } }; template struct exists_t : condition_t { using type = T; using self = exists_t; type t; exists_t() = default; exists_t(T t_) : t(std::move(t_)) {} operator std::string() const { return "EXISTS"; } negated_condition_t operator!() const { return {*this}; } }; /** * HAVING holder. * T is having argument type. */ template struct having_t { using type = T; type t; operator std::string() const { return "HAVING"; } }; template struct cast_t { using to_type = T; using expression_type = E; expression_type expression; operator std::string() const { return "CAST"; } }; } /** * Cute operators for columns */ template conditions::lesser_than_t operator<(internal::expression_t expr, R r) { return {expr.t, r}; } template conditions::lesser_than_t operator<(L l, internal::expression_t expr) { return {l, expr.t}; } template conditions::lesser_or_equal_t operator<=(internal::expression_t expr, R r) { return {expr.t, r}; } template conditions::lesser_or_equal_t operator<=(L l, internal::expression_t expr) { return {l, expr.t}; } template conditions::greater_than_t operator>(internal::expression_t expr, R r) { return {expr.t, r}; } template conditions::greater_than_t operator>(L l, internal::expression_t expr) { return {l, expr.t}; } template conditions::greater_or_equal_t operator>=(internal::expression_t expr, R r) { return {expr.t, r}; } template conditions::greater_or_equal_t operator>=(L l, internal::expression_t expr) { return {l, expr.t}; } template conditions::is_equal_t operator==(internal::expression_t expr, R r) { return {expr.t, r}; } template conditions::is_equal_t operator==(L l, internal::expression_t expr) { return {l, expr.t}; } template conditions::is_not_equal_t operator!=(internal::expression_t expr, R r) { return {expr.t, r}; } template conditions::is_not_equal_t operator!=(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::conc_t operator||(internal::expression_t expr, R r) { return {expr.t, r}; } template internal::conc_t operator||(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::conc_t operator||(internal::expression_t l, internal::expression_t r) { return {l.t, r.t}; } template internal::add_t operator+(internal::expression_t expr, R r) { return {expr.t, r}; } template internal::add_t operator+(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::add_t operator+(internal::expression_t l, internal::expression_t r) { return {l.t, r.t}; } template internal::sub_t operator-(internal::expression_t expr, R r) { return {expr.t, r}; } template internal::sub_t operator-(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::sub_t operator-(internal::expression_t l, internal::expression_t r) { return {l.t, r.t}; } template internal::mul_t operator*(internal::expression_t expr, R r) { return {expr.t, r}; } template internal::mul_t operator*(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::mul_t operator*(internal::expression_t l, internal::expression_t r) { return {l.t, r.t}; } template internal::div_t operator/(internal::expression_t expr, R r) { return {expr.t, r}; } template internal::div_t operator/(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::div_t operator/(internal::expression_t l, internal::expression_t r) { return {l.t, r.t}; } template internal::mod_t operator%(internal::expression_t expr, R r) { return {expr.t, r}; } template internal::mod_t operator%(L l, internal::expression_t expr) { return {l, expr.t}; } template internal::mod_t operator%(internal::expression_t l, internal::expression_t r) { return {l.t, r.t}; } template conditions::using_t using_(F O::*p) { return {p}; } template conditions::on_t on(T t) { return {t}; } template conditions::cross_join_t cross_join() { return {}; } template conditions::natural_join_t natural_join() { return {}; } template conditions::left_join_t left_join(O o) { return {o}; } template conditions::join_t join(O o) { return {o}; } template conditions::left_outer_join_t left_outer_join(O o) { return {o}; } template conditions::inner_join_t inner_join(O o) { return {o}; } inline conditions::offset_t offset(int off) { return {off}; } inline conditions::limit_t limit(int lim) { return {lim}; } inline conditions::limit_t limit(int off, int lim) { return {lim, true, true, off}; } inline conditions::limit_t limit(int lim, conditions::offset_t offt) { return {lim, true, false, offt.off }; } template< class L, class R, typename = typename std::enable_if::value || std::is_base_of::value>::type > conditions::and_condition_t operator &&(const L &l, const R &r) { return {l, r}; } template< class L, class R, typename = typename std::enable_if::value || std::is_base_of::value>::type > conditions::or_condition_t operator ||(const L &l, const R &r) { return {l, r}; } template conditions::is_not_null_t is_not_null(T t) { return {t}; } template conditions::is_null_t is_null(T t) { return {t}; } template conditions::in_t> in(L l, std::vector values) { return {std::move(l), std::move(values), false}; } template conditions::in_t> in(L l, std::initializer_list values) { return {std::move(l), std::move(values), false}; } template conditions::in_t in(L l, A arg) { return {std::move(l), std::move(arg), false}; } template conditions::in_t> not_in(L l, std::vector values) { return {std::move(l), std::move(values), true}; } template conditions::in_t> not_in(L l, std::initializer_list values) { return {std::move(l), std::move(values), true}; } template conditions::in_t not_in(L l, A arg) { return {std::move(l), std::move(arg), true}; } template conditions::is_equal_t is_equal(L l, R r) { return {l, r}; } template conditions::is_equal_t eq(L l, R r) { return {l, r}; } template conditions::is_not_equal_t is_not_equal(L l, R r) { return {l, r}; } template conditions::is_not_equal_t ne(L l, R r) { return {l, r}; } template conditions::greater_than_t greater_than(L l, R r) { return {l, r}; } template conditions::greater_than_t gt(L l, R r) { return {l, r}; } template conditions::greater_or_equal_t greater_or_equal(L l, R r) { return {l, r}; } template conditions::greater_or_equal_t ge(L l, R r) { return {l, r}; } template conditions::lesser_than_t lesser_than(L l, R r) { return {l, r}; } template conditions::lesser_than_t lt(L l, R r) { return {l, r}; } template conditions::lesser_or_equal_t lesser_or_equal(L l, R r) { return {l, r}; } template conditions::lesser_or_equal_t le(L l, R r) { return {l, r}; } template conditions::where_t where(C c) { return {c}; } template conditions::order_by_t order_by(O o) { return {o}; } template conditions::multi_order_by_t multi_order_by(Args&& ...args) { return {std::make_tuple(std::forward(args)...)}; } template conditions::group_by_t group_by(Args&& ...args) { return {std::make_tuple(std::forward(args)...)}; } template conditions::between_t between(A expr, T b1, T b2) { return {expr, b1, b2}; } template conditions::like_t like(A a, T t) { return {a, t}; } template conditions::exists_t exists(T t) { return {std::move(t)}; } template conditions::having_t having(T t) { return {t}; } template conditions::cast_t cast(E e) { return {e}; } } #pragma once #include // std::enable_if, std::is_base_of, std::is_member_pointer #include // std::stringstream #include // std::string namespace sqlite_orm { /** * This is base class for every class which is used as a custom table alias. * For more information please look through self_join.cpp example */ struct alias_tag {}; namespace internal { /** * This is a common built-in class used for custom single character table aliases. * Also you can use language aliases `alias_a`, `alias_b` etc. instead */ template struct table_alias : alias_tag { using type = T; static char get() { return A; } }; /** * Column expression with table alias attached like 'C.ID'. This is not a column alias */ template struct alias_column_t { using alias_type = T; using column_type = C; column_type column; alias_column_t() {}; alias_column_t(column_type column_): column(column_) {} }; template struct alias_extractor; template struct alias_extractor::value>::type> { static std::string get() { std::stringstream ss; ss << T::get(); return ss.str(); } }; template struct alias_extractor::value>::type> { static std::string get() { return {}; } }; template struct as_t { using alias_type = T; using expression_type = E; expression_type expression; }; template struct alias_holder { using type = T; }; } /** * @return column with table alias attached. Place it instead of a column statement in case you need to specify a * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example */ template internal::alias_column_t alias_column(C c) { static_assert(std::is_member_pointer::value, "alias_column argument must be a member pointer mapped to a storage"); return {c}; } template internal::as_t as(E expression) { return {std::move(expression)}; } template internal::alias_holder get() { return {}; } template using alias_a = internal::table_alias; template using alias_b = internal::table_alias; template using alias_c = internal::table_alias; template using alias_d = internal::table_alias; template using alias_e = internal::table_alias; template using alias_f = internal::table_alias; template using alias_g = internal::table_alias; template using alias_h = internal::table_alias; template using alias_i = internal::table_alias; template using alias_j = internal::table_alias; template using alias_k = internal::table_alias; template using alias_l = internal::table_alias; template using alias_m = internal::table_alias; template using alias_n = internal::table_alias; template using alias_o = internal::table_alias; template using alias_p = internal::table_alias; template using alias_q = internal::table_alias; template using alias_r = internal::table_alias; template using alias_s = internal::table_alias; template using alias_t = internal::table_alias; template using alias_u = internal::table_alias; template using alias_v = internal::table_alias; template using alias_w = internal::table_alias; template using alias_x = internal::table_alias; template using alias_y = internal::table_alias; template using alias_z = internal::table_alias; } #pragma once // #include "conditions.h" namespace sqlite_orm { namespace internal { template struct join_iterator { template void operator()(L) { //.. } }; template<> struct join_iterator<> { template void operator()(L) { //.. } }; template struct join_iterator : public join_iterator{ using super = join_iterator; H h; template void operator()(L l) { this->super::operator()(l); } }; template struct join_iterator, Tail...> : public join_iterator{ using super = join_iterator; conditions::cross_join_t h; template void operator()(L l) { l(h); this->super::operator()(l); } }; template struct join_iterator, Tail...> : public join_iterator{ using super = join_iterator; conditions::natural_join_t h; template void operator()(L l) { l(h); this->super::operator()(l); } }; template struct join_iterator, Tail...> : public join_iterator { using super = join_iterator; conditions::left_join_t h; template void operator()(L l) { l(h); this->super::operator()(l); } }; template struct join_iterator, Tail...> : public join_iterator { using super = join_iterator; conditions::join_t h; template void operator()(L l) { l(h); this->super::operator()(l); } }; template struct join_iterator, Tail...> : public join_iterator { using super = join_iterator; conditions::left_outer_join_t h; template void operator()(L l) { l(h); this->super::operator()(l); } }; template struct join_iterator, Tail...> : public join_iterator { using super = join_iterator; conditions::inner_join_t h; template void operator()(L l) { l(h); this->super::operator()(l); } }; } } #pragma once #include // std::string #include // std::make_tuple #include // std::forward, std::is_base_of, std::enable_if // #include "conditions.h" // #include "operators.h" namespace sqlite_orm { namespace core_functions { /** * Base class for operator overloading */ struct core_function_t {}; /** * LENGTH(x) function https://sqlite.org/lang_corefunc.html#length */ template struct length_t : public core_function_t { T t; length_t() = default; length_t(T t_): t(t_) {} operator std::string() const { return "LENGTH"; } }; /** * ABS(x) function https://sqlite.org/lang_corefunc.html#abs */ template struct abs_t : public core_function_t { T t; abs_t() = default; abs_t(T t_): t(t_) {} operator std::string() const { return "ABS"; } }; /** * LOWER(x) function https://sqlite.org/lang_corefunc.html#lower */ template struct lower_t : public core_function_t { T t; lower_t() = default; lower_t(T t_): t(t_) {} operator std::string() const { return "LOWER"; } }; /** * UPPER(x) function https://sqlite.org/lang_corefunc.html#upper */ template struct upper_t : public core_function_t { T t; upper_t() = default; upper_t(T t_): t(t_) {} operator std::string() const { return "UPPER"; } }; /** * CHANGES() function https://sqlite.org/lang_corefunc.html#changes */ struct changes_t : public core_function_t { operator std::string() const { return "CHANGES"; } }; /** * TRIM(X) function https://sqlite.org/lang_corefunc.html#trim */ template struct trim_single_t : public core_function_t { X x; trim_single_t() = default; trim_single_t(X x_): x(x_) {} operator std::string() const { return "TRIM"; } }; /** * TRIM(X,Y) function https://sqlite.org/lang_corefunc.html#trim */ template struct trim_double_t : public core_function_t { X x; Y y; trim_double_t() = default; trim_double_t(X x_, Y y_): x(x_), y(y_) {} operator std::string() const { return static_cast(trim_single_t(0)); } }; /** * LTRIM(X) function https://sqlite.org/lang_corefunc.html#ltrim */ template struct ltrim_single_t : public core_function_t { X x; ltrim_single_t() = default; ltrim_single_t(X x_): x(x_) {} operator std::string() const { return "LTRIM"; } }; /** * LTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#ltrim */ template struct ltrim_double_t : public core_function_t { X x; Y y; ltrim_double_t() = default; ltrim_double_t(X x_, Y y_): x(x_), y(y_) {} operator std::string() const { return static_cast(ltrim_single_t(0)); } }; /** * RTRIM(X) function https://sqlite.org/lang_corefunc.html#rtrim */ template struct rtrim_single_t : public core_function_t { X x; rtrim_single_t() = default; rtrim_single_t(X x_): x(x_) {} operator std::string() const { return "RTRIM"; } }; /** * RTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#rtrim */ template struct rtrim_double_t : public core_function_t { X x; Y y; rtrim_double_t() = default; rtrim_double_t(X x_, Y y_): x(x_), y(y_) {} operator std::string() const { return static_cast(rtrim_single_t(0)); } }; #if SQLITE_VERSION_NUMBER >= 3007016 /** * CHAR(X1,X2,...,XN) function https://sqlite.org/lang_corefunc.html#char */ template struct char_t_ : public core_function_t { using args_type = std::tuple; args_type args; char_t_() = default; char_t_(args_type args_): args(args_) {} operator std::string() const { return "CHAR"; } }; struct random_t : core_function_t, internal::arithmetic_t { operator std::string() const { return "RANDOM"; } }; #endif template struct date_t : core_function_t { using modifiers_type = std::tuple; T timestring; modifiers_type modifiers; date_t() = default; date_t(T timestring_, modifiers_type modifiers_): timestring(timestring_), modifiers(modifiers_) {} operator std::string() const { return "DATE"; } }; template struct datetime_t : core_function_t { using modifiers_type = std::tuple; T timestring; modifiers_type modifiers; datetime_t() = default; datetime_t(T timestring_, modifiers_type modifiers_): timestring(timestring_), modifiers(modifiers_) {} operator std::string() const { return "DATETIME"; } }; template struct julianday_t : core_function_t, internal::arithmetic_t { using modifiers_type = std::tuple; T timestring; modifiers_type modifiers; julianday_t() = default; julianday_t(T timestring_, modifiers_type modifiers_): timestring(timestring_), modifiers(modifiers_) {} operator std::string() const { return "JULIANDAY"; } }; } /** * Cute operators for core functions */ template< class F, class R, typename = typename std::enable_if::value>::type> conditions::lesser_than_t operator<(F f, R r) { return {f, r}; } template< class F, class R, typename = typename std::enable_if::value>::type> conditions::lesser_or_equal_t operator<=(F f, R r) { return {f, r}; } template< class F, class R, typename = typename std::enable_if::value>::type> conditions::greater_than_t operator>(F f, R r) { return {f, r}; } template< class F, class R, typename = typename std::enable_if::value>::type> conditions::greater_or_equal_t operator>=(F f, R r) { return {f, r}; } template< class F, class R, typename = typename std::enable_if::value>::type> conditions::is_equal_t operator==(F f, R r) { return {f, r}; } template< class F, class R, typename = typename std::enable_if::value>::type> conditions::is_not_equal_t operator!=(F f, R r) { return {f, r}; } inline core_functions::random_t random() { return {}; } template> Res date(T timestring, Args ...modifiers) { return Res(timestring, std::make_tuple(std::forward(modifiers)...)); } template> Res datetime(T timestring, Args ...modifiers) { return Res(timestring, std::make_tuple(std::forward(modifiers)...)); } template> Res julianday(T timestring, Args ...modifiers) { return Res(timestring, std::make_tuple(std::forward(modifiers)...)); } #if SQLITE_VERSION_NUMBER >= 3007016 template core_functions::char_t_ char_(Args&& ...args) { using result_type = core_functions::char_t_; return result_type(std::make_tuple(std::forward(args)...)); } #endif template> Res trim(X x) { return Res(x); } template> Res trim(X x, Y y) { return Res(x, y); } template> Res ltrim(X x) { return Res(x); } template> Res ltrim(X x, Y y) { return Res(x, y); } template> Res rtrim(X x) { return Res(x); } template> Res rtrim(X x, Y y) { return Res(x, y); } inline core_functions::changes_t changes() { return {}; } template core_functions::length_t length(T t) { using result_type = core_functions::length_t; return result_type(t); } template core_functions::abs_t abs(T t) { using result_type = core_functions::abs_t; return result_type(t); } template> Res lower(T t) { return Res(t); } template> Res upper(T t) { return Res(t); } template< class L, class R, typename = typename std::enable_if<(std::is_base_of::value + std::is_base_of::value > 0)>::type> internal::add_t operator+(L l, R r) { return {std::move(l), std::move(r)}; } template< class L, class R, typename = typename std::enable_if<(std::is_base_of::value + std::is_base_of::value > 0)>::type> internal::sub_t operator-(L l, R r) { return {std::move(l), std::move(r)}; } template< class L, class R, typename = typename std::enable_if<(std::is_base_of::value + std::is_base_of::value > 0)>::type> internal::mul_t operator*(L l, R r) { return {std::move(l), std::move(r)}; } template< class L, class R, typename = typename std::enable_if<(std::is_base_of::value + std::is_base_of::value > 0)>::type> internal::div_t operator/(L l, R r) { return {std::move(l), std::move(r)}; } template< class L, class R, typename = typename std::enable_if<(std::is_base_of::value + std::is_base_of::value > 0)>::type> internal::mod_t operator%(L l, R r) { return {std::move(l), std::move(r)}; } } #pragma once namespace sqlite_orm { namespace aggregate_functions { template struct avg_t { T t; operator std::string() const { return "AVG"; } }; template struct count_t { T t; operator std::string() const { return "COUNT"; } }; /** * T is use to specify type explicitly for queries like * SELECT COUNT(*) FROM table_name; * T can be omitted with void. */ template struct count_asterisk_t { using type = T; operator std::string() const { return "COUNT"; } }; struct count_asterisk_without_type { operator std::string() const { return "COUNT"; } }; template struct sum_t { T t; operator std::string() const { return "SUM"; } }; template struct total_t { T t; operator std::string() const { return "TOTAL"; } }; template struct max_t { T t; operator std::string() const { return "MAX"; } }; template struct min_t { T t; operator std::string() const { return "MIN"; } }; template struct group_concat_single_t { T t; operator std::string() const { return "GROUP_CONCAT"; } }; template struct group_concat_double_t { T t; std::string y; operator std::string() const { return "GROUP_CONCAT"; } }; } template aggregate_functions::avg_t avg(T t) { return {t}; } template aggregate_functions::count_t count(T t) { return {t}; } inline aggregate_functions::count_asterisk_without_type count() { return {}; } template aggregate_functions::count_asterisk_t count() { return {}; } template aggregate_functions::sum_t sum(T t) { return {t}; } template aggregate_functions::max_t max(T t) { return {t}; } template aggregate_functions::min_t min(T t) { return {t}; } template aggregate_functions::total_t total(T t) { return {t}; } template aggregate_functions::group_concat_single_t group_concat(T t) { return {t}; } template aggregate_functions::group_concat_double_t group_concat(T t, Y y) { return {t, y}; } } #pragma once namespace sqlite_orm { namespace internal { /** * Cute class used to compare setters/getters and member pointers with each other. */ template struct typed_comparator { bool operator()(const L &, const R &) const { return false; } }; template struct typed_comparator { bool operator()(const O &lhs, const O &rhs) const { return lhs == rhs; } }; template bool compare_any(const L &lhs, const R &rhs) { return typed_comparator()(lhs, rhs); } } } #pragma once #include // std::string namespace sqlite_orm { namespace internal { /* * This is because of bug in MSVC, for more information, please visit * https://stackoverflow.com/questions/34672441/stdis-base-of-for-template-classes/34672753#34672753 */ #if defined(_MSC_VER) template