diff --git a/3th-party/sqlite_orm.h b/3th-party/sqlite_orm.h new file mode 100644 index 0000000..a1de475 --- /dev/null +++ b/3th-party/sqlite_orm.h @@ -0,0 +1,9711 @@ +#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