From c2f640fd97ad1b137489da4c7d22e1f1175459f9 Mon Sep 17 00:00:00 2001 From: Kamil Date: Sun, 29 Nov 2020 00:19:07 +0100 Subject: [PATCH] RIP ORM --- Makefile | 1 - src/Database.cpp | 109 +- src/Database.hpp | 52 - src/contrib/sqlite/sqlite_orm.h | 13399 ------------------------------ 4 files changed, 1 insertion(+), 13560 deletions(-) delete mode 100644 src/contrib/sqlite/sqlite_orm.h diff --git a/Makefile b/Makefile index c37561d..b4f8eab 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,6 @@ CXXSRC=\ # headers (for timestamp purposes) CHDR=\ src/contrib/sqlite/sqlite3.h\ - src/contrib/sqlite/sqlite_orm.h\ src/contrib/bcrypt/bcrypt.h\ src/contrib/bcrypt/crypt_blowfish.h\ src/contrib/bcrypt/crypt_gensalt.h\ diff --git a/src/Database.cpp b/src/Database.cpp index 6c7f277..994c60a 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -4,11 +4,11 @@ #include "CNProtocol.hpp" #include #include "contrib/JSON.hpp" +#include "contrib/sqlite/sqlite3.h" #include "CNStructs.hpp" #include "settings.hpp" #include "Player.hpp" #include "CNStructs.hpp" -#include "contrib/sqlite/sqlite_orm.h" #include "MissionManager.hpp" #if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS) @@ -17,115 +17,8 @@ #include #endif -using namespace sqlite_orm; - std::mutex dbCrit; -# pragma region DatabaseScheme -auto db = make_storage("database.db", - make_table("Accounts", - make_column("AccountID", &Database::Account::AccountID, autoincrement(), primary_key()), - make_column("Login", &Database::Account::Login), - make_column("Password", &Database::Account::Password), - make_column("Selected", &Database::Account::Selected), - make_column("Created", &Database::Account::Created), - make_column("LastLogin", &Database::Account::LastLogin) - ), - make_table("Players", - make_column("PlayerID", &Database::DbPlayer::PlayerID, autoincrement(), primary_key()), - make_column("AccountID", &Database::DbPlayer::AccountID), - make_column("Slot", &Database::DbPlayer::slot), - make_column("Firstname", &Database::DbPlayer::FirstName, collate_nocase()), - make_column("LastName", &Database::DbPlayer::LastName, collate_nocase()), - make_column("Created", &Database::DbPlayer::Created), - make_column("LastLogin", &Database::DbPlayer::LastLogin), - make_column("Level", &Database::DbPlayer::Level), - make_column("Nano1", &Database::DbPlayer::Nano1), - make_column("Nano2", &Database::DbPlayer::Nano2), - make_column("Nano3", &Database::DbPlayer::Nano3), - make_column("AppearanceFlag", &Database::DbPlayer::AppearanceFlag), - make_column("TutorialFlag", &Database::DbPlayer::TutorialFlag), - make_column("PayZoneFlag", &Database::DbPlayer::PayZoneFlag), - make_column("XCoordinates", &Database::DbPlayer::x_coordinates), - make_column("YCoordinates", &Database::DbPlayer::y_coordinates), - make_column("ZCoordinates", &Database::DbPlayer::z_coordinates), - make_column("Angle", &Database::DbPlayer::angle), - make_column("Body", &Database::DbPlayer::Body), - make_column("Class", &Database::DbPlayer::Class), - make_column("EyeColor", &Database::DbPlayer::EyeColor), - make_column("FaceStyle", &Database::DbPlayer::FaceStyle), - make_column("Gender", &Database::DbPlayer::Gender), - make_column("HP", &Database::DbPlayer::HP), - make_column("HairColor", &Database::DbPlayer::HairColor), - make_column("HairStyle", &Database::DbPlayer::HairStyle), - make_column("Height", &Database::DbPlayer::Height), - make_column("NameCheck", &Database::DbPlayer::NameCheck), - make_column("SkinColor", &Database::DbPlayer::SkinColor), - make_column("AccountLevel", &Database::DbPlayer::AccountLevel), - make_column("FusionMatter", &Database::DbPlayer::FusionMatter), - make_column("Taros", &Database::DbPlayer::Taros), - make_column("Quests", &Database::DbPlayer::QuestFlag), - make_column("BatteryW", &Database::DbPlayer::BatteryW), - make_column("BatteryN", &Database::DbPlayer::BatteryN), - make_column("Mentor", &Database::DbPlayer::Mentor), - make_column("WarpLocationFlag", &Database::DbPlayer::WarpLocationFlag), - make_column("SkywayLocationFlag1", &Database::DbPlayer::SkywayLocationFlag1), - make_column("SkywayLocationFlag2", &Database::DbPlayer::SkywayLocationFlag2), - make_column("CurrentMissionID", &Database::DbPlayer::CurrentMissionID) - ), - make_table("Inventory", - make_column("PlayerId", &Database::Inventory::playerId), - make_column("Slot", &Database::Inventory::slot), - make_column("Id", &Database::Inventory::id), - make_column("Type", &Database::Inventory::Type), - make_column("Opt", &Database::Inventory::Opt), - make_column("TimeLimit", &Database::Inventory::TimeLimit) - ), - make_table("Nanos", - make_column("PlayerId", &Database::Nano::playerId), - make_column("Id", &Database::Nano::iID), - make_column("Skill", &Database::Nano::iSkillID), - make_column("Stamina", &Database::Nano::iStamina) - ), - make_table("RunningQuests", - make_column("PlayerId", &Database::DbQuest::PlayerId), - make_column("TaskId", &Database::DbQuest::TaskId), - make_column("RemainingNPCCount1", &Database::DbQuest::RemainingNPCCount1), - make_column("RemainingNPCCount2", &Database::DbQuest::RemainingNPCCount2), - make_column("RemainingNPCCount3", &Database::DbQuest::RemainingNPCCount3) - ), - make_table("Buddyships", - make_column("PlayerAId", &Database::Buddyship::PlayerAId), - make_column("PlayerBId", &Database::Buddyship::PlayerBId), - make_column("Status", &Database::Buddyship::Status) - ), - make_table("EmailData", - make_column("PlayerId", &Database::EmailData::PlayerId), - make_column("MsgIndex", &Database::EmailData::MsgIndex), - make_column("ReadFlag", &Database::EmailData::ReadFlag), - make_column("ItemFlag", &Database::EmailData::ItemFlag), - make_column("SenderId", &Database::EmailData::SenderId), - make_column("SenderFirstName", &Database::EmailData::SenderFirstName, collate_nocase()), - make_column("SenderLastName", &Database::EmailData::SenderLastName, collate_nocase()), - make_column("SubjectLine", &Database::EmailData::SubjectLine), - make_column("MsgBody", &Database::EmailData::MsgBody), - make_column("Taros", &Database::EmailData::Taros), - make_column("SendTime", &Database::EmailData::SendTime), - make_column("DeleteTime", &Database::EmailData::DeleteTime) - ), - make_table("EmailItems", - make_column("PlayerId", &Database::EmailItem::PlayerId), - make_column("MsgIndex", &Database::EmailItem::MsgIndex), - make_column("Slot", &Database::EmailItem::Slot), - make_column("Id", &Database::EmailItem::Id), - make_column("Type", &Database::EmailItem::Type), - make_column("Opt", &Database::EmailItem::Opt), - make_column("TimeLimit", &Database::EmailItem::TimeLimit) - ) -); - -# pragma endregion DatabaseScheme - #pragma region LoginServer void Database::open() { diff --git a/src/Database.hpp b/src/Database.hpp index d1b4c77..425ce9d 100644 --- a/src/Database.hpp +++ b/src/Database.hpp @@ -29,49 +29,6 @@ namespace Database { int16_t iSkillID; int16_t iStamina; }; - struct DbPlayer { - int PlayerID; - int AccountID; - short int slot; - std::string FirstName; - std::string LastName; - uint64_t Created; - uint64_t LastLogin; - short int Level; - int Nano1; - int Nano2; - int Nano3; - short int AppearanceFlag; - short int Body; - short int Class; - short int EyeColor; - short int FaceStyle; - short int Gender; - int HP; - short int HairColor; - short int HairStyle; - short int Height; - short int NameCheck; - short int PayZoneFlag; - short int SkinColor; - bool TutorialFlag; - int AccountLevel; - int FusionMatter; - int Taros; - int x_coordinates; - int y_coordinates; - int z_coordinates; - int angle; - short int PCState; - int BatteryW; - int BatteryN; - int16_t Mentor; - std::vector QuestFlag; - int32_t CurrentMissionID; - int32_t WarpLocationFlag; - int64_t SkywayLocationFlag1; - int64_t SkywayLocationFlag2; - }; struct DbQuest { int PlayerId; int32_t TaskId; @@ -140,12 +97,7 @@ namespace Database { void evaluateCustomName(int characterID, CustomName decision); void changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save); - // parsing DbPlayer - DbPlayer playerToDb(Player *player); - Player DbToPlayer(DbPlayer player); - // getting players - DbPlayer getDbPlayerById(int id); Player getPlayer(int id); void updatePlayer(Player *player); @@ -161,10 +113,6 @@ namespace Database { void getBuddies(Player* player); int getNumBuddies(Player* player); - // parsing blobs - void appendBlob(std::vector*blob, int64_t input); - int64_t blobToInt64(std::vector::iterator it); - // buddies void addBuddyship(int playerA, int playerB); void removeBuddyship(int playerA, int playerB); diff --git a/src/contrib/sqlite/sqlite_orm.h b/src/contrib/sqlite/sqlite_orm.h deleted file mode 100644 index c0c97e6..0000000 --- a/src/contrib/sqlite/sqlite_orm.h +++ /dev/null @@ -1,13399 +0,0 @@ -#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 - -#if __cplusplus >= 201703L // use of C++17 or higher -// Enables use of std::optional in SQLITE_ORM. -#define SQLITE_ORM_OPTIONAL_SUPPORTED -#endif -#pragma once - -#include // std::error_code, std::system_error -#include // std::string -#include "sqlite3.h" -#include -#include // std::ostringstream - - 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, - invalid_collate_argument_enum, - failed_to_init_a_backup, - unknown_member_value, - incorrect_order, - }; -} - -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"; - case orm_error_code::invalid_collate_argument_enum: - return "Invalid collate_argument enum"; - case orm_error_code::failed_to_init_a_backup: - return "Failed to init a backup"; - case orm_error_code::unknown_member_value: - return "Unknown member value"; - case orm_error_code::incorrect_order: - return "Incorrect order"; - 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; - } - - template - std::string get_error_message(sqlite3 *db, T &&... args) { - std::ostringstream stream; - using unpack = int[]; - static_cast(unpack{0, (static_cast(static_cast(stream << args)), 0)...}); - stream << sqlite3_errmsg(db); - return stream.str(); - } - - template - [[noreturn]] void throw_error(sqlite3 *db, T &&... args) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - get_error_message(db, std::forward(args)...)); - } -} - -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::tuple, std::get -#include // std::false_type, std::true_type - -// #include "static_magic.h" - -#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 internal { - - static inline decltype(auto) empty_callable() { - static auto res = [](auto &&...) {}; - return (res); - } - - template - decltype(auto) static_if(std::true_type, const T &t, const F &) { - return (t); - } - - template - decltype(auto) static_if(std::false_type, const T &, const F &f) { - return (f); - } - - template - decltype(auto) static_if(const T &t, const F &f) { - return static_if(std::integral_constant{}, t, f); - } - - template - decltype(auto) static_if(const T &t) { - return static_if(std::integral_constant{}, t, empty_callable()); - } - - template - using static_not = std::integral_constant; - } - -} - -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, const 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, const L &l, bool /*reverse*/ = true) { - l(std::get<0>(t)); - } - }; - - template - struct iterator { - - template - void operator()(const std::tuple<> &, const L &, bool /*reverse*/ = true) { - //.. - } - }; - - template - void move_tuple_impl(L &lhs, R &rhs) { - std::get(lhs) = std::move(std::get(rhs)); - internal::static_if{}>([](auto &l, auto &r) { - move_tuple_impl(l, r); - })(lhs, rhs); - } - } - - namespace internal { - - template - void move_tuple(L &lhs, R &rhs) { - using bool_type = std::integral_constant; - static_if([](auto &l, auto &r) { - tuple_helper::move_tuple_impl(l, r); - })(lhs, rhs); - } - - template - void iterate_tuple(const std::tuple &t, const L &l) { - using tuple_type = std::tuple; - tuple_helper::iterator::value - 1, Args...>()(t, l, false); - } - - template - using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); - - template - struct conc_tuple { - using type = tuple_cat_t; - }; - - template class C> - struct count_tuple; - - template class C> - struct count_tuple, C> { - static constexpr const int value = 0; - }; - - template class C> - struct count_tuple, C> { - static constexpr const int value = C::value + count_tuple, C>::value; - }; - } -} -#pragma once - -#include // std::string -#include // std::shared_ptr, std::unique_ptr -#include // std::vector -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - -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, void> : public type_printer {}; - - template - struct type_printer, void> : public type_printer {}; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct type_printer, void> : public type_printer {}; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template<> - struct type_printer, void> : 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"; - } - }; - - struct primary_key_base { - enum class order_by { - unspecified, - ascending, - descending, - }; - - order_by asc_option = order_by::unspecified; - - 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 constraint class. - * Cs is parameter pack which contains columns (member pointers and/or function pointers). Can be empty when - * used withen `make_column` function. - */ - template - struct primary_key_t : primary_key_base { - using order_by = primary_key_base::order_by; - using columns_tuple = std::tuple; - - columns_tuple columns; - - primary_key_t(decltype(columns) c) : columns(move(c)) {} - - 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; - } - }; - - struct unique_base { - operator std::string() const { - return "UNIQUE"; - } - }; - - /** - * UNIQUE constraint class. - */ - template - struct unique_t : unique_base { - using columns_tuple = std::tuple; - - columns_tuple columns; - - unique_t(columns_tuple columns_) : columns(move(columns_)) {} - }; - - /** - * DEFAULT constraint class. - * T is a value type. - */ - template - struct default_t { - using value_type = T; - - value_type value; - - operator std::string() const { - return "DEFAULT"; - } - }; - -#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; - } - - struct on_update_delete_base { - const bool update; // true if update and false if delete - - operator std::string() const { - if(this->update) { - return "ON UPDATE"; - } else { - return "ON DELETE"; - } - } - }; - - /** - * F - foreign key class - */ - template - struct on_update_delete_t : on_update_delete_base { - using foreign_key_type = F; - - const foreign_key_type &fk; - - on_update_delete_t(decltype(fk) fk_, decltype(update) update_, foreign_key_action action_) : - on_update_delete_base{update_}, fk(fk_), _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; - } - }; - - 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; - } - - template - void for_each_column(const 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... refs) { - return {std::move(this->columns), std::make_tuple(std::forward(refs)...)}; - } - }; -#endif - - struct collate_t { - internal::collate_argument argument = internal::collate_argument::binary; - - collate_t(internal::collate_argument argument_) : argument(argument_) {} - - operator std::string() const { - std::string res = "COLLATE " + this->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"; - } - throw std::system_error(std::make_error_code(orm_error_code::invalid_collate_argument_enum)); - } - }; - - struct check_string { - operator std::string() const { - return "CHECK"; - } - }; - - template - struct check_t : check_string { - using expression_type = T; - - expression_type expression; - - check_t(expression_type expression_) : expression(std::move(expression_)) {} - }; - - 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 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. - */ - template - constraints::unique_t unique(Args... args) { - return {std::make_tuple(std::forward(args)...)}; - } - - inline constraints::unique_t<> unique() { - return {{}}; - } - - inline constraints::autoincrement_t autoincrement() { - return {}; - } - - template - constraints::primary_key_t primary_key(Cs... cs) { - return {std::make_tuple(std::forward(cs)...)}; - } - - inline constraints::primary_key_t<> primary_key() { - return {{}}; - } - - template - constraints::default_t default_value(T t) { - return {std::move(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}; - } - - template - constraints::check_t check(T t) { - return {std::move(t)}; - } - - 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 -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - -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); - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * This is a specialization for std::optional. std::optional is nullable. - */ - template - struct type_is_nullable> : public std::true_type { - bool operator()(const std::optional &t) const { - return t.has_value(); - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - -} -#pragma once - -#include // std::unique_ptr -#include // std::string -#include // std::stringstream - -// #include "constraints.h" - -// #include "serializator_context.h" - -namespace sqlite_orm { - - namespace internal { - - struct serializator_context_base { - bool replace_bindable_with_question = false; - bool skip_table_name = true; - bool use_parentheses = true; - - template - std::string column_name(F O::*) const { - return {}; - } - }; - - template - struct serializator_context : serializator_context_base { - using impl_type = I; - - const impl_type &impl; - - serializator_context(const impl_type &impl_) : impl(impl_) {} - - template - std::string column_name(F O::*m) const { - return this->impl.column_name(m); - } - }; - - template - struct serializator_context_builder { - using storage_type = S; - using impl_type = typename storage_type::impl_type; - - serializator_context_builder(const storage_type &storage_) : storage(storage_) {} - - serializator_context operator()() const { - return {this->storage.impl}; - } - - const storage_type &storage; - }; - - } - -} - -namespace sqlite_orm { - - namespace internal { - - template - std::string serialize(const T &t); - - /** - * 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) { - serializator_context_base context; - return std::make_unique(serialize(t.value, context)); - } - }; - - } - -} -#pragma once - -#include // std::false_type, std::true_type - -// #include "negatable.h" - -namespace sqlite_orm { - namespace internal { - struct negatable_t {}; - } -} - -namespace sqlite_orm { - - namespace internal { - - /** - * Inherit this class to support arithmetic types overloading - */ - struct arithmetic_t {}; - - template - struct binary_operator : Ds... { - using left_type = L; - using right_type = R; - - left_type lhs; - right_type rhs; - - binary_operator(left_type lhs_, right_type rhs_) : lhs(std::move(lhs_)), rhs(std::move(rhs_)) {} - }; - - struct conc_string { - operator std::string() const { - return "||"; - } - }; - - /** - * Result of concatenation || operator - */ - template - using conc_t = binary_operator; - - struct add_string { - operator std::string() const { - return "+"; - } - }; - - /** - * Result of addition + operator - */ - template - using add_t = binary_operator; - - struct sub_string { - operator std::string() const { - return "-"; - } - }; - - /** - * Result of substitute - operator - */ - template - using sub_t = binary_operator; - - struct mul_string { - operator std::string() const { - return "*"; - } - }; - - /** - * Result of multiply * operator - */ - template - using mul_t = binary_operator; - - struct div_string { - operator std::string() const { - return "/"; - } - }; - - /** - * Result of divide / operator - */ - template - using div_t = binary_operator; - - struct mod_string { - operator std::string() const { - return "%"; - } - }; - - /** - * Result of mod % operator - */ - template - using mod_t = binary_operator; - - struct bitwise_shift_left_string { - operator std::string() const { - return "<<"; - } - }; - - /** - * Result of bitwise shift left << operator - */ - template - using bitwise_shift_left_t = binary_operator; - - struct bitwise_shift_right_string { - operator std::string() const { - return ">>"; - } - }; - - /** - * Result of bitwise shift right >> operator - */ - template - using bitwise_shift_right_t = binary_operator; - - struct bitwise_and_string { - operator std::string() const { - return "&"; - } - }; - - /** - * Result of bitwise and & operator - */ - template - using bitwise_and_t = binary_operator; - - struct bitwise_or_string { - operator std::string() const { - return "|"; - } - }; - - /** - * Result of bitwise or | operator - */ - template - using bitwise_or_t = binary_operator; - - struct bitwise_not_string { - operator std::string() const { - return "~"; - } - }; - - /** - * Result of bitwise not ~ operator - */ - template - struct bitwise_not_t : bitwise_not_string, arithmetic_t, negatable_t { - using argument_type = T; - - argument_type argument; - - bitwise_not_t(argument_type argument_) : argument(std::move(argument_)) {} - }; - - struct assign_string { - operator std::string() const { - return "="; - } - }; - /** - * Result of assign = operator - */ - template - using assign_t = binary_operator; - - /** - * 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(std::move(t_)) {} - - template - assign_t operator=(R r) const { - return {this->t, std::move(r)}; - } - - assign_t operator=(std::nullptr_t) const { - return {this->t, nullptr}; - } - }; - - } - - /** - * 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) { - return {std::move(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 {std::move(l), std::move(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 {std::move(l), std::move(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 {std::move(l), std::move(r)}; - } - - template - internal::mul_t mul(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::div_t div(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::mod_t mod(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::bitwise_shift_left_t bitwise_shift_left(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::bitwise_shift_right_t bitwise_shift_right(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::bitwise_and_t bitwise_and(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::bitwise_or_t bitwise_or(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::bitwise_not_t bitwise_not(T t) { - return {std::move(t)}; - } - - 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, std::is_member_pointer, std::is_member_function_pointer - -// #include "type_is_nullable.h" - -// #include "tuple_helper.h" - -// #include "default_value_extractor.h" - -// #include "constraints.h" - -// #include "getter_traits.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct is_field_member_pointer : std::false_type {}; - - template - struct is_field_member_pointer::value && - !std::is_member_function_pointer::value>::type> - : std::true_type {}; - - template - struct field_member_traits; - - template - struct field_member_traits::value>::type> { - using object_type = O; - using field_type = F; - }; - - /** - * Getters aliases - */ - 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::*)(); - - /** - * Setters aliases - */ - 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; - }; - - template - struct member_traits; - - template - struct member_traits::value>::type> { - using object_type = typename field_member_traits::object_type; - using field_type = typename field_member_traits::field_type; - }; - - template - struct member_traits::value>::type> { - using object_type = typename getter_traits::object_type; - using field_type = typename getter_traits::field_type; - }; - - template - struct member_traits::value>::type> { - using object_type = typename setter_traits::object_type; - using field_type = typename setter_traits::field_type; - }; - } -} - -namespace sqlite_orm { - - namespace internal { - - struct column_base { - - /** - * Column name. Specified during construction in `make_column`. - */ - const std::string name; - }; - - /** - * 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 : column_base { - 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; - - /** - * 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; - - column_t(std::string name_, - member_pointer_t member_pointer_, - getter_type getter_, - setter_type setter_, - constraints_type constraints_) : - column_base{std::move(name_)}, - member_pointer(member_pointer_), getter(getter_), setter(setter_), constraints(move(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() const { - std::unique_ptr res; - iterate_tuple(this->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 - struct column_field_type { - using type = void; - }; - - template - struct column_field_type> { - using type = typename column_t::field_type; - }; - - template - struct column_constraints_type { - using type = std::tuple<>; - }; - - template - struct column_constraints_type> { - using type = typename column_t::constraints_type; - }; - - } - - /** - * 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::template constraints_size::value == std::tuple_size>::value, - "Incorrect constraints pack"); - static_assert(internal::is_field_member_pointer::value, - "second argument expected as a member field pointer, not member function pointer"); - 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::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::template 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::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::template 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 -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - -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); - } - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct field_printer> { - std::string operator()(const std::optional &t) const { - if(t.has_value()) { - return field_printer()(*t); - } else { - return field_printer()(nullptr); - } - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED -} -#pragma once - -#include // std::string -#include // std::enable_if, std::is_same -#include // std::vector -#include // std::tuple - -// #include "collate_argument.h" - -// #include "constraints.h" - -// #include "optional_container.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * This is a cute class which allows storing something or nothing - * depending on template argument. Useful for optional class members - */ - template - struct optional_container { - using type = T; - - type field; - - template - void apply(const L &l) const { - l(this->field); - } - }; - - template<> - struct optional_container { - using type = void; - - template - void apply(const L &) const { - //.. - } - }; - } -} - -// #include "negatable.h" - -namespace sqlite_orm { - - namespace internal { - struct arithmetic_t; - } - - namespace internal { - - struct limit_string { - operator std::string() const { - return "LIMIT"; - } - }; - - /** - * Stores LIMIT/OFFSET info - */ - template - struct limit_t : limit_string { - T lim; - internal::optional_container off; - - limit_t() = default; - - limit_t(decltype(lim) lim_) : lim(std::move(lim_)) {} - - limit_t(decltype(lim) lim_, decltype(off) off_) : lim(std::move(lim_)), off(std::move(off_)) {} - }; - - template - struct is_limit : std::false_type {}; - - template - struct is_limit> : std::true_type {}; - - /** - * Stores OFFSET only info - */ - template - struct offset_t { - T off; - }; - - template - struct is_offset : std::false_type {}; - - template - struct is_offset> : std::true_type {}; - - /** - * 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(std::move(expr_)), argument(argument_) {} - - operator std::string() const { - return constraints::collate_t{this->argument}; - } - }; - - struct named_collate_base { - std::string name; - - operator std::string() const { - return "COLLATE " + this->name; - } - }; - - /** - * Collated something with custom collate function - */ - template - struct named_collate : named_collate_base { - T expr; - - named_collate(T expr_, std::string name_) : named_collate_base{std::move(name_)}, expr(std::move(expr_)) {} - }; - - struct negated_condition_string { - operator std::string() const { - return "NOT"; - } - }; - - /** - * Result of not operator - */ - template - struct negated_condition_t : condition_t, negated_condition_string { - C c; - - negated_condition_t(C c_) : c(std::move(c_)) {} - }; - - /** - * Base class for binary conditions - */ - template - struct binary_condition : public condition_t { - using left_type = L; - using right_type = R; - - left_type l; - right_type r; - - binary_condition() = default; - - binary_condition(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} - }; - - struct and_condition_string { - operator std::string() const { - return "AND"; - } - }; - - /** - * Result of and operator - */ - template - struct and_condition_t : binary_condition, and_condition_string { - using super = binary_condition; - - using super::super; - }; - - struct or_condition_string { - operator std::string() const { - return "OR"; - } - }; - - /** - * Result of or operator - */ - template - struct or_condition_t : binary_condition, or_condition_string { - using super = binary_condition; - - using super::super; - }; - - struct is_equal_string { - operator std::string() const { - return "="; - } - }; - - /** - * = and == operators object - */ - template - struct is_equal_t : binary_condition, is_equal_string, internal::negatable_t { - using self = is_equal_t; - - using binary_condition::binary_condition; - - 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)}; - } - }; - - struct is_not_equal_string { - operator std::string() const { - return "!="; - } - }; - - /** - * != operator object - */ - template - struct is_not_equal_t : binary_condition, is_not_equal_string, internal::negatable_t { - using self = is_not_equal_t; - - using binary_condition::binary_condition; - - 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}; - } - }; - - struct greater_than_string { - operator std::string() const { - return ">"; - } - }; - - /** - * > operator object. - */ - template - struct greater_than_t : binary_condition, greater_than_string, internal::negatable_t { - using self = greater_than_t; - - using binary_condition::binary_condition; - - 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}; - } - }; - - struct greater_or_equal_string { - operator std::string() const { - return ">="; - } - }; - - /** - * >= operator object. - */ - template - struct greater_or_equal_t : binary_condition, greater_or_equal_string, internal::negatable_t { - using self = greater_or_equal_t; - - using binary_condition::binary_condition; - - 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}; - } - }; - - struct lesser_than_string { - operator std::string() const { - return "<"; - } - }; - - /** - * < operator object. - */ - template - struct lesser_than_t : binary_condition, lesser_than_string, internal::negatable_t { - using self = lesser_than_t; - - using binary_condition::binary_condition; - - 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}; - } - }; - - struct lesser_or_equal_string { - operator std::string() const { - return "<="; - } - }; - - /** - * <= operator object. - */ - template - struct lesser_or_equal_t : binary_condition, lesser_or_equal_string, internal::negatable_t { - using self = lesser_or_equal_t; - - using binary_condition::binary_condition; - - 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}; - } - }; - - struct in_base { - bool negative = false; // used in not_in - - operator std::string() const { - if(!this->negative) { - return "IN"; - } else { - return "NOT IN"; - } - } - }; - - /** - * IN operator object. - */ - template - struct in_t : condition_t, in_base, internal::negatable_t { - using self = in_t; - - L l; // left expression - A arg; // in arg - - in_t(L l_, A arg_, bool negative_) : in_base{negative_}, l(l_), arg(std::move(arg_)) {} - }; - - struct is_null_string { - operator std::string() const { - return "IS NULL"; - } - }; - - /** - * IS NULL operator object. - */ - template - struct is_null_t : is_null_string, internal::negatable_t { - using self = is_null_t; - - T t; - - is_null_t(T t_) : t(std::move(t_)) {} - }; - - struct is_not_null_string { - operator std::string() const { - return "IS NOT NULL"; - } - }; - - /** - * IS NOT NULL operator object. - */ - template - struct is_not_null_t : is_not_null_string, internal::negatable_t { - using self = is_not_null_t; - - T t; - - is_not_null_t(T t_) : t(std::move(t_)) {} - }; - - struct where_string { - operator std::string() const { - return "WHERE"; - } - }; - - /** - * WHERE argument holder. - * C is conditions type. Can be any condition like: is_equal_t, is_null_t, exists_t etc - */ - template - struct where_t : where_string { - C c; - - where_t(C c_) : c(std::move(c_)) {} - }; - - template - struct is_where : std::false_type {}; - - template - struct is_where> : std::true_type {}; - - struct order_by_base { - int asc_desc = 0; // 1: asc, -1: desc - std::string _collate_argument; - }; - - struct order_by_string { - operator std::string() const { - return "ORDER BY"; - } - }; - - /** - * ORDER BY argument holder. - */ - template - struct order_by_t : order_by_base, order_by_string { - using self = order_by_t; - - O o; - - order_by_t(O o_) : o(std::move(o_)) {} - - 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( - sqlite_orm::internal::collate_argument::binary); - return res; - } - - self collate_nocase() const { - auto res = *this; - res._collate_argument = constraints::collate_t::string_from_collate_argument( - sqlite_orm::internal::collate_argument::nocase); - return res; - } - - self collate_rtrim() const { - auto res = *this; - res._collate_argument = - constraints::collate_t::string_from_collate_argument(sqlite_orm::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 : order_by_string { - using args_type = std::tuple; - - args_type args; - - multi_order_by_t(args_type &&args_) : args(std::move(args_)) {} - }; - - struct dynamic_order_by_entry_t : order_by_base { - std::string name; - - dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) : - order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {} - }; - - /** - * C - serializator context class - */ - template - struct dynamic_order_by_t : order_by_string { - using context_t = C; - using entry_t = dynamic_order_by_entry_t; - using const_iterator = typename std::vector::const_iterator; - - dynamic_order_by_t(const context_t &context_) : context(context_) {} - - template - void push_back(order_by_t order_by) { - auto newContext = this->context; - newContext.skip_table_name = true; - auto columnName = serialize(order_by.o, newContext); - entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); - } - - const_iterator begin() const { - return this->entries.begin(); - } - - const_iterator end() const { - return this->entries.end(); - } - - void clear() { - this->entries.clear(); - } - - protected: - std::vector entries; - context_t context; - }; - - template - struct is_order_by : std::false_type {}; - - template - struct is_order_by> : std::true_type {}; - - template - struct is_order_by> : std::true_type {}; - - template - struct is_order_by> : std::true_type {}; - - struct group_by_string { - operator std::string() const { - return "GROUP BY"; - } - }; - - /** - * GROUP BY pack holder. - */ - template - struct group_by_t : group_by_string { - using args_type = std::tuple; - args_type args; - - group_by_t(args_type &&args_) : args(std::move(args_)) {} - }; - - template - struct is_group_by : std::false_type {}; - - template - struct is_group_by> : std::true_type {}; - - struct between_string { - operator std::string() const { - return "BETWEEN"; - } - }; - - /** - * BETWEEN operator object. - */ - template - struct between_t : condition_t, between_string { - using expression_type = A; - using lower_type = T; - using upper_type = T; - - expression_type expr; - lower_type b1; - upper_type b2; - - between_t(expression_type expr_, lower_type b1_, upper_type b2_) : - expr(std::move(expr_)), b1(std::move(b1_)), b2(std::move(b2_)) {} - }; - - struct like_string { - operator std::string() const { - return "LIKE"; - } - }; - - /** - * LIKE operator object. - */ - template - struct like_t : condition_t, like_string, internal::negatable_t { - using self = like_t; - using arg_t = A; - using pattern_t = T; - using escape_t = E; - - arg_t arg; - pattern_t pattern; - sqlite_orm::internal::optional_container - arg3; // not escape cause escape exists as a function here - - like_t(arg_t arg_, pattern_t pattern_, sqlite_orm::internal::optional_container escape_) : - arg(std::move(arg_)), pattern(std::move(pattern_)), arg3(std::move(escape_)) {} - - template - like_t escape(C c) const { - sqlite_orm::internal::optional_container newArg3{std::move(c)}; - return {std::move(this->arg), std::move(this->pattern), std::move(newArg3)}; - } - }; - - struct glob_string { - operator std::string() const { - return "GLOB"; - } - }; - - template - struct glob_t : condition_t, glob_string, internal::negatable_t { - using self = glob_t; - using arg_t = A; - using pattern_t = T; - - arg_t arg; - pattern_t pattern; - - glob_t(arg_t arg_, pattern_t pattern_) : arg(std::move(arg_)), pattern(std::move(pattern_)) {} - }; - - struct cross_join_string { - operator std::string() const { - return "CROSS JOIN"; - } - }; - - /** - * CROSS JOIN holder. - * T is joined type which represents any mapped table. - */ - template - struct cross_join_t : cross_join_string { - using type = T; - }; - - struct natural_join_string { - operator std::string() const { - return "NATURAL JOIN"; - } - }; - - /** - * NATURAL JOIN holder. - * T is joined type which represents any mapped table. - */ - template - struct natural_join_t : natural_join_string { - using type = T; - }; - - struct left_join_string { - operator std::string() const { - return "LEFT JOIN"; - } - }; - - /** - * LEFT JOIN holder. - * T is joined type which represents any mapped table. - * O is on(...) argument type. - */ - template - struct left_join_t : left_join_string { - using type = T; - using on_type = O; - - on_type constraint; - - left_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} - }; - - struct join_string { - operator std::string() const { - return "JOIN"; - } - }; - - /** - * Simple JOIN holder. - * T is joined type which represents any mapped table. - * O is on(...) argument type. - */ - template - struct join_t : join_string { - using type = T; - using on_type = O; - - on_type constraint; - - join_t(on_type constraint_) : constraint(std::move(constraint_)) {} - }; - - struct left_outer_join_string { - operator std::string() const { - return "LEFT OUTER JOIN"; - } - }; - - /** - * LEFT OUTER JOIN holder. - * T is joined type which represents any mapped table. - * O is on(...) argument type. - */ - template - struct left_outer_join_t : left_outer_join_string { - using type = T; - using on_type = O; - - on_type constraint; - - left_outer_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} - }; - - struct on_string { - operator std::string() const { - return "ON"; - } - }; - - /** - * on(...) argument holder used for JOIN, LEFT JOIN, LEFT OUTER JOIN and INNER JOIN - * T is on type argument. - */ - template - struct on_t : on_string { - using arg_type = T; - - arg_type arg; - - on_t(arg_type arg_) : arg(std::move(arg_)) {} - }; - - /** - * USING argument holder. - */ - template - struct using_t { - F O::*column = nullptr; - - operator std::string() const { - return "USING"; - } - }; - - struct inner_join_string { - operator std::string() const { - return "INNER JOIN"; - } - }; - - /** - * INNER JOIN holder. - * T is joined type which represents any mapped table. - * O is on(...) argument type. - */ - template - struct inner_join_t : inner_join_string { - using type = T; - using on_type = O; - - on_type constraint; - - inner_join_t(on_type constraint_) : constraint(std::move(constraint_)) {} - }; - - struct exists_string { - operator std::string() const { - return "EXISTS"; - } - }; - - template - struct exists_t : condition_t, exists_string, internal::negatable_t { - using type = T; - using self = exists_t; - - type t; - - exists_t(T t_) : t(std::move(t_)) {} - }; - - struct having_string { - operator std::string() const { - return "HAVING"; - } - }; - - /** - * HAVING holder. - * T is having argument type. - */ - template - struct having_t : having_string { - using type = T; - - type t; - - having_t(type t_) : t(std::move(t_)) {} - }; - - template - struct is_having : std::false_type {}; - - template - struct is_having> : std::true_type {}; - - struct cast_string { - operator std::string() const { - return "CAST"; - } - }; - - /** - * CAST holder. - * T is a type to cast to - * E is an expression type - * Example: cast(&User::id) - */ - template - struct cast_t : cast_string { - using to_type = T; - using expression_type = E; - - expression_type expression; - - cast_t(expression_type expression_) : expression(std::move(expression_)) {} - }; - - } - - template::value>::type> - internal::negated_condition_t operator!(T arg) { - return {std::move(arg)}; - } - - /** - * Cute operators for columns - */ - template - internal::lesser_than_t operator<(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::lesser_than_t operator<(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::lesser_or_equal_t operator<=(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::lesser_or_equal_t operator<=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::greater_than_t operator>(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::greater_than_t operator>(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::greater_or_equal_t operator>=(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::greater_or_equal_t operator>=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::is_equal_t operator==(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::is_equal_t operator==(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::is_not_equal_t operator!=(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::is_not_equal_t operator!=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::conc_t operator||(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::conc_t operator||(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::conc_t operator||(internal::expression_t l, internal::expression_t r) { - return {std::move(l.t), std::move(r.t)}; - } - - template - internal::add_t operator+(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::add_t operator+(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::add_t operator+(internal::expression_t l, internal::expression_t r) { - return {std::move(l.t), std::move(r.t)}; - } - - template - internal::sub_t operator-(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::sub_t operator-(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::sub_t operator-(internal::expression_t l, internal::expression_t r) { - return {std::move(l.t), std::move(r.t)}; - } - - template - internal::mul_t operator*(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::mul_t operator*(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::mul_t operator*(internal::expression_t l, internal::expression_t r) { - return {std::move(l.t), std::move(r.t)}; - } - - template - internal::div_t operator/(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::div_t operator/(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::div_t operator/(internal::expression_t l, internal::expression_t r) { - return {std::move(l.t), std::move(r.t)}; - } - - template - internal::mod_t operator%(internal::expression_t expr, R r) { - return {std::move(expr.t), std::move(r)}; - } - - template - internal::mod_t operator%(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.t)}; - } - - template - internal::mod_t operator%(internal::expression_t l, internal::expression_t r) { - return {std::move(l.t), std::move(r.t)}; - } - - template - internal::using_t using_(F O::*p) { - return {std::move(p)}; - } - - template - internal::on_t on(T t) { - return {std::move(t)}; - } - - template - internal::cross_join_t cross_join() { - return {}; - } - - template - internal::natural_join_t natural_join() { - return {}; - } - - template - internal::left_join_t left_join(O o) { - return {std::move(o)}; - } - - template - internal::join_t join(O o) { - return {std::move(o)}; - } - - template - internal::left_outer_join_t left_outer_join(O o) { - return {std::move(o)}; - } - - template - internal::inner_join_t inner_join(O o) { - return {std::move(o)}; - } - - template - internal::offset_t offset(T off) { - return {std::move(off)}; - } - - template - internal::limit_t limit(T lim) { - return {std::move(lim)}; - } - - template - typename std::enable_if::value, internal::limit_t>::type limit(O off, - T lim) { - return {std::move(lim), {std::move(off)}}; - } - - template - internal::limit_t limit(T lim, internal::offset_t offt) { - return {std::move(lim), {std::move(offt.off)}}; - } - - template::value || - std::is_base_of::value>::type> - internal::and_condition_t operator&&(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template::value || - std::is_base_of::value>::type> - internal::or_condition_t operator||(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::is_not_null_t is_not_null(T t) { - return {std::move(t)}; - } - - template - internal::is_null_t is_null(T t) { - return {std::move(t)}; - } - - template - internal::in_t> in(L l, std::vector values) { - return {std::move(l), std::move(values), false}; - } - - template - internal::in_t> in(L l, std::initializer_list values) { - return {std::move(l), std::move(values), false}; - } - - template - internal::in_t in(L l, A arg) { - return {std::move(l), std::move(arg), false}; - } - - template - internal::in_t> not_in(L l, std::vector values) { - return {std::move(l), std::move(values), true}; - } - - template - internal::in_t> not_in(L l, std::initializer_list values) { - return {std::move(l), std::move(values), true}; - } - - template - internal::in_t not_in(L l, A arg) { - return {std::move(l), std::move(arg), true}; - } - - template - internal::is_equal_t is_equal(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::is_equal_t eq(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::is_not_equal_t is_not_equal(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::is_not_equal_t ne(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::greater_than_t greater_than(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::greater_than_t gt(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::greater_or_equal_t greater_or_equal(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::greater_or_equal_t ge(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::lesser_than_t lesser_than(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::lesser_than_t lt(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::lesser_or_equal_t lesser_or_equal(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::lesser_or_equal_t le(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template - internal::where_t where(C c) { - return {std::move(c)}; - } - - /** - * ORDER BY column - * Example: storage.select(&User::name, order_by(&User::id)) - */ - template - internal::order_by_t order_by(O o) { - return {std::move(o)}; - } - - /** - * ORDER BY column1, column2 - * Example: storage.get_all(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc()) - */ - template - internal::multi_order_by_t multi_order_by(Args &&... args) { - return {std::make_tuple(std::forward(args)...)}; - } - - /** - * ORDER BY column1, column2 - * Difference from `multi_order_by` is that `dynamic_order_by` can be changed at runtime using `push_back` member - * function Example: - * auto orderBy = dynamic_order_by(storage); - * if(someCondition) { - * orderBy.push_back(&User::id); - * } else { - * orderBy.push_back(&User::name); - * orderBy.push_back(&User::birthDate); - * } - */ - template - internal::dynamic_order_by_t> - dynamic_order_by(const S &storage) { - internal::serializator_context_builder builder(storage); - return builder(); - } - - /** - * GROUP BY column. - * Example: storage.get_all(group_by(&Employee::name)) - */ - template - internal::group_by_t group_by(Args &&... args) { - return {std::make_tuple(std::forward(args)...)}; - } - - /** - * X BETWEEN Y AND Z - * Example: storage.select(between(&User::id, 10, 20)) - */ - template - internal::between_t between(A expr, T b1, T b2) { - return {std::move(expr), std::move(b1), std::move(b2)}; - } - - /** - * X LIKE Y - * Example: storage.select(like(&User::name, "T%")) - */ - template - internal::like_t like(A a, T t) { - return {std::move(a), std::move(t), {}}; - } - - /** - * X GLOB Y - * Example: storage.select(glob(&User::name, "*S")) - */ - template - internal::glob_t glob(A a, T t) { - return {std::move(a), std::move(t)}; - } - - /** - * X LIKE Y ESCAPE Z - * Example: storage.select(like(&User::name, "T%", "%")) - */ - template - internal::like_t like(A a, T t, E e) { - return {std::move(a), std::move(t), {std::move(e)}}; - } - - /** - * EXISTS(condition). - * Example: storage.select(columns(&Agent::code, &Agent::name, &Agent::workingArea, &Agent::comission), - where(exists(select(asterisk(), - where(is_equal(&Customer::grade, 3) and - is_equal(&Agent::code, &Customer::agentCode))))), - order_by(&Agent::comission)); - */ - template - internal::exists_t exists(T t) { - return {std::move(t)}; - } - - /** - * HAVING(expression). - * Example: storage.get_all(group_by(&Employee::name), having(greater_than(count(&Employee::name), 2))); - */ - template - internal::having_t having(T t) { - return {std::move(t)}; - } - - /** - * CAST(X AS type). - * Example: cast(&User::id) - */ - template - internal::cast_t cast(E e) { - return {std::move(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()(const L &) { - //.. - } - }; - - template<> - struct join_iterator<> { - - template - void operator()(const L &) { - //.. - } - }; - - template - struct join_iterator : public join_iterator { - using super = join_iterator; - - template - void operator()(const L &l) { - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = cross_join_t; - - template - void operator()(const L &l) { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = natural_join_t; - - template - void operator()(const L &l) { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_join_t; - - template - void operator()(const L &l) { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = join_t; - - template - void operator()(const L &l) { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_outer_join_t; - - template - void operator()(const L &l) { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = inner_join_t; - - template - void operator()(const L &l) { - l(*this); - this->super::operator()(l); - } - }; - } -} -#pragma once - -#include // std::string -#include // std::make_tuple, std::tuple_size -#include // std::forward, std::is_base_of, std::enable_if -#include // std::unique_ptr -#include // std::vector - -// #include "conditions.h" - -// #include "operators.h" - -// #include "is_base_of_template.h" - -#include // std::true_type, std::false_type, std::declval - -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 class Base, typename Derived> - struct is_base_of_template_impl { - template - static constexpr std::true_type test(const Base *); - - static constexpr std::false_type test(...); - - using type = decltype(test(std::declval())); - }; - - template class Base> - using is_base_of_template = typename is_base_of_template_impl::type; - -#else - template class C, typename... Ts> - std::true_type is_base_of_template_impl(const C *); - - template class C> - std::false_type is_base_of_template_impl(...); - - template class C> - using is_base_of_template = decltype(is_base_of_template_impl(std::declval())); -#endif - } -} - -namespace sqlite_orm { - - namespace internal { - - template - struct unique_ptr_result_of {}; - - /** - * Base class for operator overloading - * R - return type - * S - class with operator std::string - * Args - function arguments types - */ - template - struct core_function_t : S, internal::arithmetic_t { - using return_type = R; - using string_type = S; - using args_type = std::tuple; - - static constexpr const size_t args_size = std::tuple_size::value; - - args_type args; - - core_function_t(args_type &&args_) : args(std::move(args_)) {} - }; - - struct length_string { - operator std::string() const { - return "LENGTH"; - } - }; - - struct abs_string { - operator std::string() const { - return "ABS"; - } - }; - - struct lower_string { - operator std::string() const { - return "LOWER"; - } - }; - - struct upper_string { - operator std::string() const { - return "UPPER"; - } - }; - - struct changes_string { - operator std::string() const { - return "CHANGES"; - } - }; - - struct trim_string { - operator std::string() const { - return "TRIM"; - } - }; - - struct ltrim_string { - operator std::string() const { - return "LTRIM"; - } - }; - - struct rtrim_string { - operator std::string() const { - return "RTRIM"; - } - }; - - struct hex_string { - operator std::string() const { - return "HEX"; - } - }; - - struct quote_string { - operator std::string() const { - return "QUOTE"; - } - }; - - struct randomblob_string { - operator std::string() const { - return "RANDOMBLOB"; - } - }; - - struct instr_string { - operator std::string() const { - return "INSTR"; - } - }; - - struct replace_string { - operator std::string() const { - return "REPLACE"; - } - }; - - struct round_string { - operator std::string() const { - return "ROUND"; - } - }; - -#if SQLITE_VERSION_NUMBER >= 3007016 - - struct char_string { - operator std::string() const { - return "CHAR"; - } - }; - - struct random_string { - operator std::string() const { - return "RANDOM"; - } - }; - -#endif - - struct coalesce_string { - operator std::string() const { - return "COALESCE"; - } - }; - - struct date_string { - operator std::string() const { - return "DATE"; - } - }; - - struct time_string { - operator std::string() const { - return "TIME"; - } - }; - - struct datetime_string { - operator std::string() const { - return "DATETIME"; - } - }; - - struct julianday_string { - operator std::string() const { - return "JULIANDAY"; - } - }; - - struct strftime_string { - operator std::string() const { - return "STRFTIME"; - } - }; - - struct zeroblob_string { - operator std::string() const { - return "ZEROBLOB"; - } - }; - - struct substr_string { - operator std::string() const { - return "SUBSTR"; - } - }; -#ifdef SQLITE_SOUNDEX - struct soundex_string { - operator std::string() const { - return "SOUNDEX"; - } - }; -#endif - struct total_string { - operator std::string() const { - return "TOTAL"; - } - }; - - struct sum_string { - operator std::string() const { - return "SUM"; - } - }; - - struct count_string { - 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 : count_string { - using type = T; - }; - - /** - * The same thing as count() but without T arg. - * Is used in cases like this: - * SELECT cust_code, cust_name, cust_city, grade - * FROM customer - * WHERE grade=2 AND EXISTS - * (SELECT COUNT(*) - * FROM customer - * WHERE grade=2 - * GROUP BY grade - * HAVING COUNT(*)>2); - * `c++` - * auto rows = - * storage.select(columns(&Customer::code, &Customer::name, &Customer::city, &Customer::grade), - * where(is_equal(&Customer::grade, 2) - * and exists(select(count(), - * where(is_equal(&Customer::grade, 2)), - * group_by(&Customer::grade), - * having(greater_than(count(), 2)))))); - */ - struct count_asterisk_without_type : count_string {}; - - struct avg_string { - operator std::string() const { - return "AVG"; - } - }; - - struct max_string { - operator std::string() const { - return "MAX"; - } - }; - - struct min_string { - operator std::string() const { - return "MIN"; - } - }; - - struct group_concat_string { - operator std::string() const { - return "GROUP_CONCAT"; - } - }; - - } - - /** - * Cute operators for core functions - */ - - template< - class F, - class R, - typename = typename std::enable_if::value>::type> - internal::lesser_than_t operator<(F f, R r) { - return {std::move(f), std::move(r)}; - } - - template< - class F, - class R, - typename = typename std::enable_if::value>::type> - internal::lesser_or_equal_t operator<=(F f, R r) { - return {std::move(f), std::move(r)}; - } - - template< - class F, - class R, - typename = typename std::enable_if::value>::type> - internal::greater_than_t operator>(F f, R r) { - return {std::move(f), std::move(r)}; - } - - template< - class F, - class R, - typename = typename std::enable_if::value>::type> - internal::greater_or_equal_t operator>=(F f, R r) { - return {std::move(f), std::move(r)}; - } - - template< - class F, - class R, - typename = typename std::enable_if::value>::type> - internal::is_equal_t operator==(F f, R r) { - return {std::move(f), std::move(r)}; - } - - template< - class F, - class R, - typename = typename std::enable_if::value>::type> - internal::is_not_equal_t operator!=(F f, R r) { - return {std::move(f), std::move(r)}; - } - - /** - * LENGTH(x) function https://sqlite.org/lang_corefunc.html#length - */ - template - internal::core_function_t length(T t) { - std::tuple args{std::forward(t)}; - return {move(args)}; - } - - /** - * ABS(x) function https://sqlite.org/lang_corefunc.html#abs - */ - template - internal::core_function_t, internal::abs_string, T> abs(T t) { - std::tuple args{std::forward(t)}; - return {move(args)}; - } - - /** - * LOWER(x) function https://sqlite.org/lang_corefunc.html#lower - */ - template - internal::core_function_t lower(T t) { - std::tuple args{std::forward(t)}; - return {move(args)}; - } - - /** - * UPPER(x) function https://sqlite.org/lang_corefunc.html#upper - */ - template - internal::core_function_t upper(T t) { - std::tuple args{std::forward(t)}; - return {move(args)}; - } - - /** - * CHANGES() function https://sqlite.org/lang_corefunc.html#changes - */ - inline internal::core_function_t changes() { - return {{}}; - } - - /** - * TRIM(X) function https://sqlite.org/lang_corefunc.html#trim - */ - template - internal::core_function_t trim(T t) { - std::tuple args{std::forward(t)}; - return {move(args)}; - } - - /** - * TRIM(X,Y) function https://sqlite.org/lang_corefunc.html#trim - */ - template - internal::core_function_t trim(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - - /** - * LTRIM(X) function https://sqlite.org/lang_corefunc.html#ltrim - */ - template - internal::core_function_t ltrim(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * LTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#ltrim - */ - template - internal::core_function_t ltrim(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - - /** - * RTRIM(X) function https://sqlite.org/lang_corefunc.html#rtrim - */ - template - internal::core_function_t rtrim(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * RTRIM(X,Y) function https://sqlite.org/lang_corefunc.html#rtrim - */ - template - internal::core_function_t rtrim(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - - /** - * HEX(X) function https://sqlite.org/lang_corefunc.html#hex - */ - template - internal::core_function_t hex(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * QUOTE(X) function https://sqlite.org/lang_corefunc.html#quote - */ - template - internal::core_function_t quote(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * RANDOMBLOB(X) function https://sqlite.org/lang_corefunc.html#randomblob - */ - template - internal::core_function_t, internal::randomblob_string, X> randomblob(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * INSTR(X) function https://sqlite.org/lang_corefunc.html#instr - */ - template - internal::core_function_t instr(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - - /** - * REPLACE(X) function https://sqlite.org/lang_corefunc.html#replace - */ - template - internal::core_function_t replace(X x, Y y, Z z) { - std::tuple args{std::forward(x), std::forward(y), std::forward(z)}; - return {move(args)}; - } - - /** - * ROUND(X) function https://sqlite.org/lang_corefunc.html#round - */ - template - internal::core_function_t round(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * ROUND(X, Y) function https://sqlite.org/lang_corefunc.html#round - */ - template - internal::core_function_t round(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - -#if SQLITE_VERSION_NUMBER >= 3007016 - - /** - * CHAR(X1,X2,...,XN) function https://sqlite.org/lang_corefunc.html#char - */ - template - internal::core_function_t char_(Args... args) { - return {std::make_tuple(std::forward(args)...)}; - } - - /** - * RANDOM() function https://www.sqlite.org/lang_corefunc.html#random - */ - inline internal::core_function_t random() { - return {{}}; - } - -#endif - - /** - * COALESCE(X,Y,...) function https://www.sqlite.org/lang_corefunc.html#coalesce - */ - template - internal::core_function_t coalesce(Args... args) { - return {std::make_tuple(std::forward(args)...)}; - } - - /** - * DATE(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html - */ - template - internal::core_function_t date(Args... args) { - std::tuple t{std::forward(args)...}; - return {move(t)}; - } - - /** - * TIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html - */ - template - internal::core_function_t time(Args... args) { - std::tuple t{std::forward(args)...}; - return {move(t)}; - } - - /** - * DATETIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html - */ - template - internal::core_function_t datetime(Args... args) { - std::tuple t{std::forward(args)...}; - return {move(t)}; - } - - /** - * JULIANDAY(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html - */ - template - internal::core_function_t julianday(Args... args) { - std::tuple t{std::forward(args)...}; - return {move(t)}; - } - - /** - * STRFTIME(timestring, modifier, modifier, ...) function https://www.sqlite.org/lang_datefunc.html - */ - template - internal::core_function_t strftime(Args... args) { - std::tuple t{std::forward(args)...}; - return {move(t)}; - } - - /** - * ZEROBLOB(N) function https://www.sqlite.org/lang_corefunc.html#zeroblob - */ - template - internal::core_function_t, internal::zeroblob_string, N> zeroblob(N n) { - std::tuple args{std::forward(n)}; - return {move(args)}; - } - - /** - * SUBSTR(X,Y) function https://www.sqlite.org/lang_corefunc.html#substr - */ - template - internal::core_function_t substr(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - - /** - * SUBSTR(X,Y,Z) function https://www.sqlite.org/lang_corefunc.html#substr - */ - template - internal::core_function_t substr(X x, Y y, Z z) { - std::tuple args{std::forward(x), std::forward(y), std::forward(z)}; - return {move(args)}; - } - -#ifdef SQLITE_SOUNDEX - /** - * SOUNDEX(X) function https://www.sqlite.org/lang_corefunc.html#soundex - */ - template - internal::core_function_t soundex(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } -#endif - - /** - * TOTAL(X) aggregate function. - */ - template - internal::core_function_t total(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * SUM(X) aggregate function. - */ - template - internal::core_function_t, internal::sum_string, X> sum(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * COUNT(X) aggregate function. - */ - template - internal::core_function_t count(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * COUNT(*) without FROM function. - */ - inline internal::count_asterisk_without_type count() { - return {}; - } - - /** - * COUNT(*) with FROM function. Specified type T will be serializeed as - * a from argument. - */ - template - internal::count_asterisk_t count() { - return {}; - } - - /** - * AVG(X) aggregate function. - */ - template - internal::core_function_t avg(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * MAX(X) aggregate function. - */ - template - internal::core_function_t, internal::max_string, X> max(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * MIN(X) aggregate function. - */ - template - internal::core_function_t, internal::min_string, X> min(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * GROUP_CONCAT(X) aggregate function. - */ - template - internal::core_function_t group_concat(X x) { - std::tuple args{std::forward(x)}; - return {move(args)}; - } - - /** - * GROUP_CONCAT(X, Y) aggregate function. - */ - template - internal::core_function_t group_concat(X x, Y y) { - std::tuple args{std::forward(x), std::forward(y)}; - return {move(args)}; - } - - template::value + - std::is_base_of::value > - 0)>::type> - internal::add_t operator+(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template::value + - std::is_base_of::value > - 0)>::type> - internal::sub_t operator-(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template::value + - std::is_base_of::value > - 0)>::type> - internal::mul_t operator*(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template::value + - std::is_base_of::value > - 0)>::type> - internal::div_t operator/(L l, R r) { - return {std::move(l), std::move(r)}; - } - - template::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 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 -#include // std::declval -#include // std::tuple, std::get, std::tuple_size - -// #include "is_base_of_template.h" - -// #include "tuple_helper.h" - -// #include "optional_container.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * DISCTINCT generic container. - */ - template - struct distinct_t { - T t; - - operator std::string() const { - return "DISTINCT"; - } - }; - - /** - * ALL generic container. - */ - template - struct all_t { - T t; - - operator std::string() const { - return "ALL"; - } - }; - - template - struct columns_t { - using columns_type = std::tuple; - - columns_type columns; - bool distinct = false; - - static constexpr const int count = std::tuple_size::value; - }; - - struct set_string { - operator std::string() const { - return "SET"; - } - }; - - template - struct set_t : set_string { - using assigns_type = std::tuple; - - assigns_type assigns; - - set_t(assigns_type assigns_) : assigns(move(assigns_)) {} - }; - - /** - * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). - * Is useful when mapped type is derived from other type and base class has members mapped to a storage. - */ - template - struct column_pointer { - using type = T; - using field_type = F; - - field_type field; - }; - - /** - * Subselect object type. - */ - template - struct select_t { - using return_type = T; - using conditions_type = std::tuple; - - return_type col; - conditions_type conditions; - bool highest_level = false; - }; - - /** - * Base for UNION, UNION ALL, EXCEPT and INTERSECT - */ - template - struct compound_operator { - using left_type = L; - using right_type = R; - - left_type left; - right_type right; - - compound_operator(left_type l, right_type r) : left(std::move(l)), right(std::move(r)) { - this->left.highest_level = true; - this->right.highest_level = true; - } - }; - - struct union_base { - bool all = false; - - operator std::string() const { - if(!this->all) { - return "UNION"; - } else { - return "UNION ALL"; - } - } - }; - - /** - * UNION object type. - */ - template - struct union_t : public compound_operator, union_base { - using left_type = typename compound_operator::left_type; - using right_type = typename compound_operator::right_type; - - union_t(left_type l, right_type r, decltype(all) all_) : - compound_operator(std::move(l), std::move(r)), union_base{all_} {} - - union_t(left_type l, right_type r) : union_t(std::move(l), std::move(r), false) {} - }; - - /** - * EXCEPT object type. - */ - template - struct except_t : public compound_operator { - using super = compound_operator; - using left_type = typename super::left_type; - using right_type = typename super::right_type; - - using super::super; - - operator std::string() const { - return "EXCEPT"; - } - }; - - /** - * INTERSECT object type. - */ - template - struct intersect_t : public compound_operator { - using super = compound_operator; - using left_type = typename super::left_type; - using right_type = typename super::right_type; - - using super::super; - - operator std::string() const { - return "INTERSECT"; - } - }; - - /** - * Generic way to get DISTINCT value from any type. - */ - template - bool get_distinct(const T &) { - return false; - } - - template - bool get_distinct(const columns_t &cols) { - return cols.distinct; - } - - template - struct asterisk_t { - using type = T; - }; - - template - struct object_t { - using type = T; - }; - - template - struct then_t { - using expression_type = T; - - expression_type expression; - }; - - template - struct simple_case_t { - using return_type = R; - using case_expression_type = T; - using args_type = std::tuple; - using else_expression_type = E; - - optional_container case_expression; - args_type args; - optional_container else_expression; - }; - - /** - * T is a case expression type - * E is else type (void is ELSE is omitted) - * Args... is a pack of WHEN expressions - */ - template - struct simple_case_builder { - using return_type = R; - using case_expression_type = T; - using args_type = std::tuple; - using else_expression_type = E; - - optional_container case_expression; - args_type args; - optional_container else_expression; - - template - simple_case_builder> when(W w, then_t t) { - using result_args_type = std::tuple>; - std::pair newPair{std::move(w), std::move(t.expression)}; - result_args_type result_args = - std::tuple_cat(std::move(this->args), std::move(std::make_tuple(newPair))); - std::get::value - 1>(result_args) = std::move(newPair); - return {std::move(this->case_expression), std::move(result_args), std::move(this->else_expression)}; - } - - simple_case_t end() { - return {std::move(this->case_expression), std::move(args), std::move(this->else_expression)}; - } - - template - simple_case_builder else_(El el) { - return {{std::move(this->case_expression)}, std::move(args), {std::move(el)}}; - } - }; - - template - void validate_conditions() { - static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 WHERE blocks"); - static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 GROUP BY blocks"); - static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 ORDER BY blocks"); - static_assert(count_tuple::value <= 1, "a single query cannot contain > 1 LIMIT blocks"); - } - } - - template - internal::then_t then(T t) { - return {std::move(t)}; - } - - template - internal::simple_case_builder case_(T t) { - return {{std::move(t)}}; - } - - template - internal::simple_case_builder case_() { - return {}; - } - - template - internal::distinct_t distinct(T t) { - return {std::move(t)}; - } - - template - internal::all_t all(T t) { - return {std::move(t)}; - } - - template - internal::columns_t distinct(internal::columns_t cols) { - cols.distinct = true; - return cols; - } - - /** - * SET keyword used in UPDATE ... SET queries. - * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) - */ - template - internal::set_t set(Args... args) { - using arg_tuple = std::tuple; - static_assert(std::tuple_size::value == - internal::count_tuple::value, - "set function accepts assign operators only"); - return {std::make_tuple(std::forward(args)...)}; - } - - template - internal::columns_t columns(Args... args) { - return {std::make_tuple(std::forward(args)...)}; - } - - /** - * Use it like this: - * struct MyType : BaseType { ... }; - * storage.select(column(&BaseType::id)); - */ - template - internal::column_pointer column(F f) { - return {std::move(f)}; - } - - /** - * Public function for subselect query. Is useful in UNION queries. - */ - template - internal::select_t select(T t, Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - return {std::move(t), std::make_tuple(std::forward(args)...)}; - } - - /** - * Public function for UNION operator. - * lhs and rhs are subselect objects. - * Look through example in examples/union.cpp - */ - template - internal::union_t union_(L lhs, R rhs) { - return {std::move(lhs), std::move(rhs)}; - } - - /** - * Public function for EXCEPT operator. - * lhs and rhs are subselect objects. - * Look through example in examples/except.cpp - */ - template - internal::except_t except(L lhs, R rhs) { - return {std::move(lhs), std::move(rhs)}; - } - - template - internal::intersect_t intersect(L lhs, R rhs) { - return {std::move(lhs), std::move(rhs)}; - } - - /** - * Public function for UNION ALL operator. - * lhs and rhs are subselect objects. - * Look through example in examples/union.cpp - */ - template - internal::union_t union_all(L lhs, R rhs) { - return {std::move(lhs), std::move(rhs), true}; - } - - /** - * SELECT * FROM T function. - * T is typed mapped to a storage. - * Example: auto rows = storage.select(asterisk()); - * // decltype(rows) is std::vector> - * If you need to fetch result as objects not tuple please use `object` instead. - */ - template - internal::asterisk_t asterisk() { - return {}; - } - - /** - * SELECT * FROM T function. - * T is typed mapped to a storage. - * Example: auto rows = storage.select(object()); - * // decltype(rows) is std::vector - * If you need to fetch result as tuples not objects please use `asterisk` instead. - */ - template - internal::object_t object() { - return {}; - } -} -#pragma once - -#include // std::enable_if, std::is_member_pointer - -// #include "select_constraints.h" - -// #include "column.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * Trait class used to define table mapped type by setter/getter/member - * T - member pointer - */ - template - struct table_type; - - template - struct table_type::value && - !std::is_member_function_pointer::value>::type> { - using type = O; - }; - - template - struct table_type::value>::type> { - using type = typename getter_traits::object_type; - }; - - template - struct table_type::value>::type> { - using type = typename setter_traits::object_type; - }; - - template - struct table_type, void> { - using type = T; - }; - } -} -#pragma once - -#include // std::string - -namespace sqlite_orm { - - struct table_info { - int cid = 0; - std::string name; - std::string type; - bool notnull = false; - std::string dflt_value; - int pk = 0; - }; - -} -#pragma once - -#include "sqlite3.h" - -namespace sqlite_orm { - - /** - * Guard class which finalizes `sqlite3_stmt` in dtor - */ - struct statement_finalizer { - sqlite3_stmt *stmt = nullptr; - - statement_finalizer(decltype(stmt) stmt_) : stmt(stmt_) {} - - inline ~statement_finalizer() { - sqlite3_finalize(this->stmt); - } - }; -} -#pragma once - -namespace sqlite_orm { - - /** - * Helper classes used by statement_binder and row_extractor. - */ - struct int_or_smaller_tag {}; - struct bigint_tag {}; - struct real_tag {}; - - template - struct arithmetic_tag { - using type = std::conditional_t::value, - // Integer class - std::conditional_t, - // Floating-point class - real_tag>; - }; - - template - using arithmetic_tag_t = typename arithmetic_tag::type; -} -#pragma once - -#include "sqlite3.h" -#include // std::enable_if_t, std::is_arithmetic, std::is_same, std::true_type, std::false_type -#include // std::string, std::wstring -#ifndef SQLITE_ORM_OMITS_CODECVT -#include // std::codecvt_utf8_utf16 -#endif // SQLITE_ORM_OMITS_CODECVT -#include // std::vector -#include // std::nullptr_t -#include // std::declval -#include // std::wstring_convert - -// #include "is_std_ptr.h" - -namespace sqlite_orm { - - /** - * Specialization for optional type (std::shared_ptr / std::unique_ptr). - */ - template - struct is_std_ptr : std::false_type {}; - - template - struct is_std_ptr> : std::true_type { - using element_type = T; - - static std::shared_ptr make(const T &v) { - return std::make_shared(v); - } - }; - - template - struct is_std_ptr> : std::true_type { - using element_type = T; - - static std::unique_ptr make(const T &v) { - return std::make_unique(v); - } - }; -} - -namespace sqlite_orm { - - /** - * Helper class used for binding fields to sqlite3 statements. - */ - template - struct statement_binder : std::false_type {}; - - /** - * Specialization for arithmetic types. - */ - template - struct statement_binder::value>> { - int bind(sqlite3_stmt *stmt, int index, const V &value) { - return bind(stmt, index, value, tag()); - } - - private: - using tag = arithmetic_tag_t; - - int bind(sqlite3_stmt *stmt, int index, const V &value, const int_or_smaller_tag &) { - return sqlite3_bind_int(stmt, index, static_cast(value)); - } - - int bind(sqlite3_stmt *stmt, int index, const V &value, const bigint_tag &) { - return sqlite3_bind_int64(stmt, index, static_cast(value)); - } - - int bind(sqlite3_stmt *stmt, int index, const V &value, const real_tag &) { - return sqlite3_bind_double(stmt, index, static_cast(value)); - } - }; - - /** - * Specialization for std::string and C-string. - */ - template - struct statement_binder< - V, - std::enable_if_t::value || std::is_same::value>> { - int bind(sqlite3_stmt *stmt, int index, const V &value) { - return sqlite3_bind_text(stmt, index, string_data(value), -1, SQLITE_TRANSIENT); - } - - private: - const char *string_data(const std::string &s) const { - return s.c_str(); - } - - const char *string_data(const char *s) const { - return s; - } - }; - -#ifndef SQLITE_ORM_OMITS_CODECVT - /** - * Specialization for std::wstring and C-wstring. - */ - template - struct statement_binder< - V, - std::enable_if_t::value || std::is_same::value>> { - int bind(sqlite3_stmt *stmt, int index, const V &value) { - std::wstring_convert> converter; - std::string utf8Str = converter.to_bytes(value); - return statement_binder().bind(stmt, index, utf8Str); - } - }; -#endif // SQLITE_ORM_OMITS_CODECVT - - /** - * Specialization for std::nullptr_t. - */ - template<> - struct statement_binder { - int bind(sqlite3_stmt *stmt, int index, const std::nullptr_t &) { - return sqlite3_bind_null(stmt, index); - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template<> - struct statement_binder { - int bind(sqlite3_stmt *stmt, int index, const std::nullopt_t &) { - return sqlite3_bind_null(stmt, index); - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct statement_binder::value>> { - using value_type = typename is_std_ptr::element_type; - - int bind(sqlite3_stmt *stmt, int index, const V &value) { - if(value) { - return statement_binder().bind(stmt, index, *value); - } else { - return statement_binder().bind(stmt, index, nullptr); - } - } - }; - - /** - * Specialization for optional type (std::vector). - */ - template<> - struct statement_binder, void> { - int bind(sqlite3_stmt *stmt, int index, const std::vector &value) { - if(value.size()) { - return sqlite3_bind_blob(stmt, - index, - (const void *)&value.front(), - int(value.size()), - SQLITE_TRANSIENT); - } else { - return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT); - } - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct statement_binder, void> { - using value_type = T; - - int bind(sqlite3_stmt *stmt, int index, const std::optional &value) { - if(value) { - return statement_binder().bind(stmt, index, *value); - } else { - return statement_binder().bind(stmt, index, std::nullopt); - } - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - namespace internal { - - template - using is_bindable = std::integral_constant>::value>; - - struct conditional_binder_base { - sqlite3_stmt *stmt = nullptr; - int &index; - - conditional_binder_base(decltype(stmt) stmt_, decltype(index) index_) : stmt(stmt_), index(index_) {} - }; - - template - struct conditional_binder; - - template - struct conditional_binder : conditional_binder_base { - - using conditional_binder_base::conditional_binder_base; - - int operator()(const T &t) const { - return statement_binder().bind(this->stmt, this->index++, t); - } - }; - - template - struct conditional_binder : conditional_binder_base { - using conditional_binder_base::conditional_binder_base; - - int operator()(const T &) const { - return SQLITE_OK; - } - }; - - template - struct bindable_filter_single; - - template - struct bindable_filter_single::value>::type> { - using type = std::tuple; - }; - - template - struct bindable_filter_single::value>::type> { - using type = std::tuple<>; - }; - - template - struct bindable_filter; - - template - struct bindable_filter> { - using type = typename conc_tuple::type...>::type; - }; - } -} -#pragma once - -#include "sqlite3.h" -#include // std::enable_if_t, std::is_arithmetic, std::is_same, std::enable_if -#include // atof, atoi, atoll -#include // std::string, std::wstring -#ifndef SQLITE_ORM_OMITS_CODECVT -#include // std::wstring_convert, std::codecvt_utf8_utf16 -#endif // SQLITE_ORM_OMITS_CODECVT -#include // std::vector -#include // strlen -#include // std::copy -#include // std::back_inserter -#include // std::tuple, std::tuple_size, std::tuple_element - -// #include "arithmetic_tag.h" - -// #include "journal_mode.h" - -#include // std::string -#include // std::unique_ptr -#include // std::array -#include // std::transform -#include // std::toupper - -namespace sqlite_orm { - -/** - * Caps case cause of 1) delete keyword; 2) https://www.sqlite.org/pragma.html#pragma_journal_mode original spelling - */ -#ifdef DELETE -#undef DELETE -#endif - enum class journal_mode : signed char { - DELETE = 0, - TRUNCATE = 1, - PERSIST = 2, - MEMORY = 3, - WAL = 4, - OFF = 5, - }; - - namespace internal { - - inline const std::string &to_string(journal_mode j) { - static std::string res[] = { - "DELETE", - "TRUNCATE", - "PERSIST", - "MEMORY", - "WAL", - "OFF", - }; - return res[static_cast(j)]; - } - - inline std::unique_ptr journal_mode_from_string(const std::string &str) { - std::string upper_str; - std::transform(str.begin(), str.end(), std::back_inserter(upper_str), [](char c) { - return static_cast(std::toupper(static_cast(c))); - }); - static std::array all = {{ - journal_mode::DELETE, - journal_mode::TRUNCATE, - journal_mode::PERSIST, - journal_mode::MEMORY, - journal_mode::WAL, - journal_mode::OFF, - }}; - for(auto j: all) { - if(to_string(j) == upper_str) { - return std::make_unique(j); - } - } - return {}; - } - } -} - -// #include "error_code.h" - -namespace sqlite_orm { - - /** - * Helper class used to cast values from argv to V class - * which depends from column type. - * - */ - template - struct row_extractor { - // used in sqlite3_exec (select) - V extract(const char *row_value); - - // used in sqlite_column (iteration, get_all) - V extract(sqlite3_stmt *stmt, int columnIndex); - }; - - /** - * Specialization for arithmetic types. - */ - template - struct row_extractor::value>> { - V extract(const char *row_value) { - return extract(row_value, tag()); - } - - V extract(sqlite3_stmt *stmt, int columnIndex) { - return extract(stmt, columnIndex, tag()); - } - - private: - using tag = arithmetic_tag_t; - - V extract(const char *row_value, const int_or_smaller_tag &) { - return static_cast(atoi(row_value)); - } - - V extract(sqlite3_stmt *stmt, int columnIndex, const int_or_smaller_tag &) { - return static_cast(sqlite3_column_int(stmt, columnIndex)); - } - - V extract(const char *row_value, const bigint_tag &) { - return static_cast(atoll(row_value)); - } - - V extract(sqlite3_stmt *stmt, int columnIndex, const bigint_tag &) { - return static_cast(sqlite3_column_int64(stmt, columnIndex)); - } - - V extract(const char *row_value, const real_tag &) { - return static_cast(atof(row_value)); - } - - V extract(sqlite3_stmt *stmt, int columnIndex, const real_tag &) { - return static_cast(sqlite3_column_double(stmt, columnIndex)); - } - }; - - /** - * Specialization for std::string. - */ - template<> - struct row_extractor { - std::string extract(const char *row_value) { - if(row_value) { - return row_value; - } else { - return {}; - } - } - - std::string extract(sqlite3_stmt *stmt, int columnIndex) { - auto cStr = (const char *)sqlite3_column_text(stmt, columnIndex); - if(cStr) { - return cStr; - } else { - return {}; - } - } - }; -#ifndef SQLITE_ORM_OMITS_CODECVT - /** - * Specialization for std::wstring. - */ - template<> - struct row_extractor { - std::wstring extract(const char *row_value) { - if(row_value) { - std::wstring_convert> converter; - return converter.from_bytes(row_value); - } else { - return {}; - } - } - - std::wstring extract(sqlite3_stmt *stmt, int columnIndex) { - auto cStr = (const char *)sqlite3_column_text(stmt, columnIndex); - if(cStr) { - std::wstring_convert> converter; - return converter.from_bytes(cStr); - } else { - return {}; - } - } - }; -#endif // SQLITE_ORM_OMITS_CODECVT - - template - struct row_extractor::value>> { - using value_type = typename is_std_ptr::element_type; - - V extract(const char *row_value) { - if(row_value) { - return is_std_ptr::make(row_extractor().extract(row_value)); - } else { - return {}; - } - } - - V extract(sqlite3_stmt *stmt, int columnIndex) { - auto type = sqlite3_column_type(stmt, columnIndex); - if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(stmt, columnIndex)); - } else { - return {}; - } - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct row_extractor, void> { - using value_type = T; - - std::optional extract(const char *row_value) { - if(row_value) { - return std::make_optional(row_extractor().extract(row_value)); - } else { - return std::nullopt; - } - } - - std::optional extract(sqlite3_stmt *stmt, int columnIndex) { - auto type = sqlite3_column_type(stmt, columnIndex); - if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(stmt, columnIndex)); - } else { - return std::nullopt; - } - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * Specialization for std::vector. - */ - template<> - struct row_extractor> { - std::vector extract(const char *row_value) { - if(row_value) { - auto len = ::strlen(row_value); - return this->go(row_value, len); - } else { - return {}; - } - } - - std::vector extract(sqlite3_stmt *stmt, int columnIndex) { - auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); - auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); - return this->go(bytes, len); - } - - protected: - std::vector go(const char *bytes, size_t len) { - if(len) { - std::vector res; - res.reserve(len); - std::copy(bytes, bytes + len, std::back_inserter(res)); - return res; - } else { - return {}; - } - } - }; - - template - struct row_extractor> { - - std::tuple extract(char **argv) { - std::tuple res; - this->extract::value>(res, argv); - return res; - } - - std::tuple extract(sqlite3_stmt *stmt, int /*columnIndex*/) { - std::tuple res; - this->extract::value>(res, stmt); - return res; - } - - protected: - template::type * = nullptr> - void extract(std::tuple &t, sqlite3_stmt *stmt) { - using tuple_type = typename std::tuple_element>::type; - std::get(t) = row_extractor().extract(stmt, I - 1); - this->extract(t, stmt); - } - - template::type * = nullptr> - void extract(std::tuple &, sqlite3_stmt *) { - //.. - } - - template::type * = nullptr> - void extract(std::tuple &t, char **argv) { - using tuple_type = typename std::tuple_element>::type; - std::get(t) = row_extractor().extract(argv[I - 1]); - this->extract(t, argv); - } - - template::type * = nullptr> - void extract(std::tuple &, char **) { - //.. - } - }; - - /** - * Specialization for journal_mode. - */ - template<> - struct row_extractor { - journal_mode extract(const char *row_value) { - if(row_value) { - if(auto res = internal::journal_mode_from_string(row_value)) { - return std::move(*res); - } else { - throw std::system_error(std::make_error_code(orm_error_code::incorrect_journal_mode_string)); - } - } else { - throw std::system_error(std::make_error_code(orm_error_code::incorrect_journal_mode_string)); - } - } - - journal_mode extract(sqlite3_stmt *stmt, int columnIndex) { - auto cStr = (const char *)sqlite3_column_text(stmt, columnIndex); - return this->extract(cStr); - } - }; -} -#pragma once - -#include - -namespace sqlite_orm { - - enum class sync_schema_result { - - /** - * created new table, table with the same tablename did not exist - */ - new_table_created, - - /** - * table schema is the same as storage, nothing to be done - */ - already_in_sync, - - /** - * removed excess columns in table (than storage) without dropping a table - */ - old_columns_removed, - - /** - * lacking columns in table (than storage) added without dropping a table - */ - new_columns_added, - - /** - * both old_columns_removed and new_columns_added - */ - new_columns_added_and_old_columns_removed, - - /** - * old table is dropped and new is recreated. Reasons : - * 1. delete excess columns in the table than storage if preseve = false - * 2. Lacking columns in the table cannot be added due to NULL and DEFAULT constraint - * 3. Reasons 1 and 2 both together - * 4. data_type mismatch between table and storage. - */ - dropped_and_recreated, - }; - - inline std::ostream &operator<<(std::ostream &os, sync_schema_result value) { - switch(value) { - case sync_schema_result::new_table_created: - return os << "new table created"; - case sync_schema_result::already_in_sync: - return os << "table and storage is already in sync."; - case sync_schema_result::old_columns_removed: - return os << "old excess columns removed"; - case sync_schema_result::new_columns_added: - return os << "new columns added"; - case sync_schema_result::new_columns_added_and_old_columns_removed: - return os << "old excess columns removed and new columns added"; - case sync_schema_result::dropped_and_recreated: - return os << "old table dropped and recreated"; - } - return os; - } -} -#pragma once - -#include // std::tuple, std::make_tuple -#include // std::string -#include // std::forward - -// #include "indexed_column.h" - -#include // std::string - -namespace sqlite_orm { - - namespace internal { - - template - struct indexed_column_t { - using column_type = C; - - column_type column_or_expression; - std::string _collation_name; - int _order = 0; // -1 = desc, 1 = asc, 0 = not specified - - indexed_column_t collate(std::string name) { - auto res = std::move(*this); - res._collation_name = move(name); - return res; - } - - indexed_column_t asc() { - auto res = std::move(*this); - res._order = 1; - return res; - } - - indexed_column_t desc() { - auto res = std::move(*this); - res._order = -1; - return res; - } - }; - - template - struct indexed_column_maker { - using type = indexed_column_t; - - indexed_column_t operator()(C col) const { - return {std::move(col)}; - } - }; - - template - struct indexed_column_maker> { - using type = indexed_column_t; - - indexed_column_t operator()(indexed_column_t col) const { - return std::move(col); - } - }; - - template - auto make_indexed_column(C col) { - indexed_column_maker maker; - return maker(std::move(col)); - } - - } - - /** - * Use this function to specify indexed column inside `make_index` function call. - * Example: make_index("index_name", indexed_column(&User::id).asc()) - */ - template - internal::indexed_column_t indexed_column(C column_or_expression) { - return {std::move(column_or_expression)}; - } - -} - -namespace sqlite_orm { - - namespace internal { - - struct index_base { - std::string name; - bool unique = false; - }; - - template - struct index_t : index_base { - using columns_type = std::tuple; - using object_type = void; - - index_t(std::string name_, bool unique_, columns_type columns_) : - index_base{move(name_), unique_}, columns(move(columns_)) {} - - columns_type columns; - }; - } - - template - internal::index_t::type...> make_index(const std::string &name, - Cols... cols) { - return {name, false, std::make_tuple(internal::make_indexed_column(cols)...)}; - } - - template - internal::index_t::type...> make_unique_index(const std::string &name, - Cols... cols) { - return {name, true, std::make_tuple(internal::make_indexed_column(cols)...)}; - } -} -#pragma once - -// #include "alias.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * If T is alias than mapped_type_proxy::type is alias::type - * otherwise T is T. - */ - template - struct mapped_type_proxy { - using type = T; - }; - - template - struct mapped_type_proxy::value>::type> { - using type = typename T::type; - }; - } -} -#pragma once - -#include // std::string - -namespace sqlite_orm { - - namespace internal { - - struct rowid_t { - operator std::string() const { - return "rowid"; - } - }; - - struct oid_t { - operator std::string() const { - return "oid"; - } - }; - - struct _rowid_t { - operator std::string() const { - return "_rowid_"; - } - }; - - template - struct table_rowid_t : public rowid_t { - using type = T; - }; - - template - struct table_oid_t : public oid_t { - using type = T; - }; - template - struct table__rowid_t : public _rowid_t { - using type = T; - }; - - } - - inline internal::rowid_t rowid() { - return {}; - } - - inline internal::oid_t oid() { - return {}; - } - - inline internal::_rowid_t _rowid_() { - return {}; - } - - template - internal::table_rowid_t rowid() { - return {}; - } - - template - internal::table_oid_t oid() { - return {}; - } - - template - internal::table__rowid_t _rowid_() { - return {}; - } -} -#pragma once - -#include // std::enable_if, std::is_same, std::decay, std::is_arithmetic -#include // std::tuple -#include // std::reference_wrapper - -// #include "core_functions.h" - -// #include "select_constraints.h" - -// #include "operators.h" - -// #include "rowid.h" - -// #include "alias.h" - -// #include "column.h" - -// #include "storage_traits.h" -#include // std::is_same, std::enable_if, std::true_type, std::false_type, std::integral_constant -#include // std::tuple - -namespace sqlite_orm { - - namespace internal { - - template - struct storage_impl; - - template - struct table_t; - - namespace storage_traits { - - /** - * S - storage_impl type - * T - mapped or not mapped data type - */ - template - struct type_is_mapped_impl; - - /** - * S - storage - * T - mapped or not mapped data type - */ - template - struct type_is_mapped : type_is_mapped_impl {}; - - /** - * Final specialisation - */ - template - struct type_is_mapped_impl, T, void> : std::false_type {}; - - template - struct type_is_mapped_impl< - S, - T, - typename std::enable_if::value>::type> - : std::true_type {}; - - template - struct type_is_mapped_impl< - S, - T, - typename std::enable_if::value>::type> - : type_is_mapped_impl {}; - - /** - * S - storage_impl type - * T - mapped or not mapped data type - */ - template - struct storage_columns_count_impl; - - /** - * S - storage - * T - mapped or not mapped data type - */ - template - struct storage_columns_count : storage_columns_count_impl {}; - - /** - * Final specialisation - */ - template - struct storage_columns_count_impl, T, void> : std::integral_constant {}; - - template - struct storage_columns_count_impl< - S, - T, - typename std::enable_if::value>::type> - : std::integral_constant {}; - - template - struct storage_columns_count_impl< - S, - T, - typename std::enable_if::value>::type> - : storage_columns_count_impl {}; - - /** - * T - table type. - */ - template - struct table_types; - - /** - * type is std::tuple of field types of mapped colums. - */ - template - struct table_types> { - using type = std::tuple; - }; - - /** - * S - storage_impl type - * T - mapped or not mapped data type - */ - template - struct storage_mapped_columns_impl; - - /** - * S - storage - * T - mapped or not mapped data type - */ - template - struct storage_mapped_columns : storage_mapped_columns_impl {}; - - /** - * Final specialisation - */ - template - struct storage_mapped_columns_impl, T, void> { - using type = std::tuple<>; - }; - - template - struct storage_mapped_columns_impl< - S, - T, - typename std::enable_if::value>::type> { - using table_type = typename S::table_type; - using type = typename table_types::type; - }; - - template - struct storage_mapped_columns_impl< - S, - T, - typename std::enable_if::value>::type> - : storage_mapped_columns_impl {}; - - } - } -} - -namespace sqlite_orm { - - using int64 = sqlite_int64; - using uint64 = sqlite_uint64; - - namespace internal { - - /** - * This is a proxy class used to define what type must have result type depending on select - * arguments (member pointer, aggregate functions, etc). Below you can see specializations - * for different types. E.g. specialization for internal::length_t has `type` int cause - * LENGTH returns INTEGER in sqlite. Every column_result_t must have `type` type that equals - * c++ SELECT return type for T - * T - C++ type - * SFINAE - sfinae argument - */ - template - struct column_result_t; - - template - struct column_result_t::value && - !std::is_member_function_pointer::value>::type> { - using type = F; - }; - - /** - * Common case for all getter types. Getter types are defined in column.h file - */ - template - struct column_result_t::value>::type> { - using type = typename getter_traits::field_type; - }; - - /** - * Common case for all setter types. Setter types are defined in column.h file - */ - template - struct column_result_t::value>::type> { - using type = typename setter_traits::field_type; - }; - - template - struct column_result_t, void> { - using type = R; - }; - - template - struct column_result_t, S, X>, void> { - using type = std::unique_ptr::type>; - }; - - template - struct column_result_t, void> { - using type = int; - }; - - template - struct column_result_t { - using type = int; - }; - - template - struct column_result_t, void> { - using type = typename column_result_t::type; - }; - - template - struct column_result_t, void> { - using type = typename column_result_t::type; - }; - - template - struct column_result_t, void> { - using type = std::string; - }; - - template - struct column_result_t, void> { - using type = double; - }; - - template - struct column_result_t, void> { - using type = double; - }; - - template - struct column_result_t, void> { - using type = double; - }; - - template - struct column_result_t, void> { - using type = double; - }; - - template - struct column_result_t, void> { - using type = double; - }; - - template - struct column_result_t, void> { - using type = int; - }; - - template - struct column_result_t, void> { - using type = int; - }; - - template - struct column_result_t, void> { - using type = int; - }; - - template - struct column_result_t, void> { - using type = int; - }; - - template - struct column_result_t, void> { - using type = int; - }; - - template - struct column_result_t { - using type = int64; - }; - - template - struct column_result_t { - using type = int64; - }; - - template - struct column_result_t { - using type = int64; - }; - - template - struct column_result_t, void> { - using type = int64; - }; - - template - struct column_result_t, void> { - using type = int64; - }; - - template - struct column_result_t, void> { - using type = int64; - }; - - template - struct column_result_t, void> { - using type = typename column_result_t::type; - }; - - template - struct column_result_t> : column_result_t {}; - - template - struct column_result_t, void> { - using type = std::tuple::type>::type...>; - }; - - template - struct column_result_t> : column_result_t {}; - - template - struct column_result_t::value>::type> { - using left_type = typename T::left_type; - using right_type = typename T::right_type; - using left_result = typename column_result_t::type; - using right_result = typename column_result_t::type; - static_assert(std::is_same::value, - "Compound subselect queries must return same types"); - using type = left_result; - }; - - /** - * Result for the most simple queries like `SELECT 1` - */ - template - struct column_result_t::value>::type> { - using type = T; - }; - - /** - * Result for the most simple queries like `SELECT 'ototo'` - */ - template - struct column_result_t { - using type = std::string; - }; - - template - struct column_result_t { - using type = std::string; - }; - - template - struct column_result_t, void> : column_result_t::type, void> {}; - - template - struct column_result_t, void> { - using type = typename storage_traits::storage_mapped_columns::type; - }; - - template - struct column_result_t, void> { - using type = T; - }; - - template - struct column_result_t, void> { - using type = T; - }; - - template - struct column_result_t, void> { - using type = R; - }; - - template - struct column_result_t, void> { - using type = bool; - }; - - template - struct column_result_t, void> { - using type = bool; - }; - - template - struct column_result_t, void> { - using type = bool; - }; - - template - struct column_result_t, void> : column_result_t {}; - } -} -#pragma once - -#include // std::string -#include // std::remove_reference, std::is_same, std::is_base_of -#include // std::vector -#include // std::tuple_size, std::tuple_element -#include // std::reverse, std::find_if - -// #include "column_result.h" - -// #include "static_magic.h" - -// #include "typed_comparator.h" - -// #include "constraints.h" - -// #include "tuple_helper.h" - -// #include "table_info.h" - -// #include "type_printer.h" - -// #include "column.h" - -namespace sqlite_orm { - - namespace internal { - - struct table_base { - - /** - * Table name. - */ - std::string name; - - bool _without_rowid = false; - }; - - /** - * Table interface class. Implementation is hidden in `table_impl` class. - */ - template - struct table_t : table_base { - using object_type = T; - using columns_type = std::tuple; - - static constexpr const int columns_count = static_cast(std::tuple_size::value); - - columns_type columns; - - table_t(decltype(name) name_, columns_type columns_) : - table_base{std::move(name_)}, columns(std::move(columns_)) {} - - table_t without_rowid() const { - auto res = *this; - res._without_rowid = true; - return res; - } - - /** - * Function used to get field value from object by mapped member pointer/setter/getter - */ - template - const F *get_object_field_pointer(const object_type &obj, C c) const { - const F *res = nullptr; - this->for_each_column_with_field_type([&res, &c, &obj](auto &col) { - using column_type = typename std::remove_reference::type; - using member_pointer_t = typename column_type::member_pointer_t; - using getter_type = typename column_type::getter_type; - using setter_type = typename column_type::setter_type; - // Make static_if have at least one input as a workaround for GCC bug: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095 - if(!res) { - static_if{}>([&res, &obj, &col](const C &c_) { - if(compare_any(col.member_pointer, c_)) { - res = &(obj.*col.member_pointer); - } - })(c); - } - if(!res) { - static_if{}>([&res, &obj, &col](const C &c_) { - if(compare_any(col.getter, c_)) { - res = &((obj).*(col.getter))(); - } - })(c); - } - if(!res) { - static_if{}>([&res, &obj, &col](const C &c_) { - if(compare_any(col.setter, c_)) { - res = &((obj).*(col.getter))(); - } - })(c); - } - }); - return res; - } - - /** - * @return vector of column names of table. - */ - std::vector column_names() const { - std::vector res; - this->for_each_column([&res](auto &c) { - res.push_back(c.name); - }); - return res; - } - - /** - * Calls **l** with every primary key dedicated constraint - */ - template - void for_each_primary_key(const L &l) const { - iterate_tuple(this->columns, [&l](auto &column) { - using column_type = typename std::decay::type; - static_if{}>(l)(column); - }); - } - - std::vector composite_key_columns_names() const { - std::vector res; - this->for_each_primary_key([this, &res](auto &c) { - res = this->composite_key_columns_names(c); - }); - return res; - } - - std::vector primary_key_column_names() const { - std::vector res; - this->for_each_column_with>([&res](auto &c) { - res.push_back(c.name); - }); - if(!res.size()) { - res = this->composite_key_columns_names(); - } - return res; - } - - template - std::vector composite_key_columns_names(const constraints::primary_key_t &pk) const { - std::vector res; - using pk_columns_tuple = decltype(pk.columns); - res.reserve(std::tuple_size::value); - iterate_tuple(pk.columns, [this, &res](auto &v) { - res.push_back(this->find_column_name(v)); - }); - return res; - } - - /** - * Searches column name by class member pointer passed as the first argument. - * @return column name or empty string if nothing found. - */ - template::value && - !std::is_member_function_pointer::value>::type> - std::string find_column_name(F O::*m) const { - std::string res; - this->template for_each_column_with_field_type([&res, m](auto &c) { - if(c.member_pointer == m) { - res = c.name; - } - }); - return res; - } - - /** - * Searches column name by class getter function member pointer passed as first argument. - * @return column name or empty string if nothing found. - */ - template - std::string find_column_name(G getter, - typename std::enable_if::value>::type * = nullptr) const { - std::string res; - using field_type = typename getter_traits::field_type; - this->template for_each_column_with_field_type([&res, getter](auto &c) { - if(compare_any(c.getter, getter)) { - res = c.name; - } - }); - return res; - } - - /** - * Searches column name by class setter function member pointer passed as first argument. - * @return column name or empty string if nothing found. - */ - template - std::string find_column_name(S setter, - typename std::enable_if::value>::type * = nullptr) const { - std::string res; - using field_type = typename setter_traits::field_type; - this->template for_each_column_with_field_type([&res, setter](auto &c) { - if(compare_any(c.setter, setter)) { - res = c.name; - } - }); - return res; - } - - /** - * Iterates all columns and fires passed lambda. Lambda must have one and only templated argument Otherwise - * code will not compile. Excludes table constraints (e.g. foreign_key_t) at the end of the columns list. To - * iterate columns with table constraints use iterate_tuple(columns, ...) instead. L is lambda type. Do - * not specify it explicitly. - * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {} - */ - template - void for_each_column(const L &l) const { - iterate_tuple(this->columns, [&l](auto &column) { - using column_type = typename std::decay::type; - static_if{}>(l)(column); - }); - } - - template - void for_each_column_with_field_type(const L &l) const { - iterate_tuple(this->columns, [&l](auto &column) { - using column_type = typename std::decay::type; - using field_type = typename column_field_type::type; - static_if{}>(l)(column); - }); - } - - /** - * Iterates all columns that have specified constraints and fires passed lambda. - * Lambda must have one and only templated argument Otherwise code will not compile. - * L is lambda type. Do not specify it explicitly. - * @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {} - */ - template - void for_each_column_with(const L &l) const { - using tuple_helper::tuple_contains_type; - iterate_tuple(this->columns, [&l](auto &column) { - using column_type = typename std::decay::type; - using constraints_type = typename column_constraints_type::type; - static_if{}>(l)(column); - }); - } - - std::vector get_table_info() const { - std::vector res; - res.reserve(size_t(this->columns_count)); - this->for_each_column([&res](auto &col) { - std::string dft; - using field_type = typename std::decay::type::field_type; - if(auto d = col.default_value()) { - dft = *d; - } - table_info i{ - -1, - col.name, - type_printer().print(), - col.not_null(), - dft, - col.template has>(), - }; - res.emplace_back(i); - }); - auto compositeKeyColumnNames = this->composite_key_columns_names(); - for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) { - auto &columnName = compositeKeyColumnNames[i]; - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_info &ti) { - return ti.name == columnName; - }); - if(it != res.end()) { - it->pk = static_cast(i + 1); - } - } - return res; - } - }; - } - - /** - * Function used for table creation. Do not use table constructor - use this function - * cause table class is templated and its constructing too (just like std::make_unique or std::make_pair). - */ - template>::type::object_type> - internal::table_t make_table(const std::string &name, Cs... args) { - return {name, std::make_tuple(std::forward(args)...)}; - } - - template - internal::table_t make_table(const std::string &name, Cs... args) { - return {name, std::make_tuple(std::forward(args)...)}; - } -} -#pragma once - -#include // std::string -#include "sqlite3.h" -#include // std::nullptr_t -#include // std::system_error, std::error_code -#include // std::stringstream -#include // std::atoi -#include // std::forward, std::enable_if, std::is_same, std::remove_reference, std::false_type, std::true_type -#include // std::pair, std::make_pair -#include // std::vector -#include // std::find_if -#include // std::type_index - -// #include "error_code.h" - -// #include "statement_finalizer.h" - -// #include "row_extractor.h" - -// #include "constraints.h" - -// #include "select_constraints.h" - -// #include "field_printer.h" - -// #include "table_info.h" - -// #include "sync_schema_result.h" - -// #include "field_value_holder.h" - -#include // std::enable_if - -// #include "column.h" - -namespace sqlite_orm { - namespace internal { - - template - struct field_value_holder; - - template - struct field_value_holder::returns_lvalue>::type> { - using type = typename getter_traits::field_type; - - const type &value; - }; - - template - struct field_value_holder::returns_lvalue>::type> { - using type = typename getter_traits::field_type; - - type value; - }; - } -} - -namespace sqlite_orm { - - namespace internal { - - struct storage_impl_base { - - bool table_exists(const std::string &tableName, sqlite3 *db) const { - auto result = false; - std::stringstream ss; - ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = '" - << "table" - << "' AND name = '" << tableName << "'"; - auto query = ss.str(); - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void *data, int argc, char **argv, char * * /*azColName*/) -> int { - auto &res = *(bool *)data; - if(argc) { - res = !!std::atoi(argv[0]); - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return result; - } - - void rename_table(sqlite3 *db, const std::string &oldName, const std::string &newName) const { - std::stringstream ss; - ss << "ALTER TABLE " << oldName << " RENAME TO " << newName; - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - static bool get_remove_add_columns(std::vector &columnsToAdd, - std::vector &storageTableInfo, - std::vector &dbTableInfo) { - bool notEqual = false; - - // iterate through storage columns - for(size_t storageColumnInfoIndex = 0; storageColumnInfoIndex < storageTableInfo.size(); - ++storageColumnInfoIndex) { - - // get storage's column info - auto &storageColumnInfo = storageTableInfo[storageColumnInfoIndex]; - auto &columnName = storageColumnInfo.name; - - // search for a column in db eith the same name - auto dbColumnInfoIt = std::find_if(dbTableInfo.begin(), dbTableInfo.end(), [&columnName](auto &ti) { - return ti.name == columnName; - }); - if(dbColumnInfoIt != dbTableInfo.end()) { - auto &dbColumnInfo = *dbColumnInfoIt; - auto columnsAreEqual = - dbColumnInfo.name == storageColumnInfo.name && - dbColumnInfo.notnull == storageColumnInfo.notnull && - (dbColumnInfo.dflt_value.length() > 0) == (storageColumnInfo.dflt_value.length() > 0) && - dbColumnInfo.pk == storageColumnInfo.pk; - if(!columnsAreEqual) { - notEqual = true; - break; - } - dbTableInfo.erase(dbColumnInfoIt); - storageTableInfo.erase(storageTableInfo.begin() + - static_cast(storageColumnInfoIndex)); - --storageColumnInfoIndex; - } else { - columnsToAdd.push_back(&storageColumnInfo); - } - } - return notEqual; - } - - std::vector get_table_info(const std::string &tableName, sqlite3 *db) const { - std::vector result; - auto query = "PRAGMA table_info('" + tableName + "')"; - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void *data, int argc, char **argv, char **) -> int { - auto &res = *(std::vector *)data; - if(argc) { - auto index = 0; - auto cid = std::atoi(argv[index++]); - std::string name = argv[index++]; - std::string type = argv[index++]; - bool notnull = !!std::atoi(argv[index++]); - std::string dflt_value = argv[index] ? argv[index] : ""; - index++; - auto pk = std::atoi(argv[index++]); - res.push_back(table_info{cid, name, type, notnull, dflt_value, pk}); - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return result; - } - }; - - /** - * This is a generic implementation. Used as a tail in storage_impl inheritance chain - */ - template - struct storage_impl; - - template - struct storage_impl : public storage_impl { - using table_type = H; - using super = storage_impl; - - storage_impl(H h, Ts... ts) : super(std::forward(ts)...), table(std::move(h)) {} - - table_type table; - - template - void for_each(const L &l) { - this->super::for_each(l); - l(*this); - } - -#if SQLITE_VERSION_NUMBER >= 3006019 - - /** - * Returns foreign keys count in table definition - */ - int foreign_keys_count() { - auto res = 0; - iterate_tuple(this->table.columns, [&res](auto &c) { - if(internal::is_foreign_key::type>::value) { - ++res; - } - }); - return res; - } - -#endif - - /** - * Is used to get column name by member pointer to a base class. - * Main difference between `column_name` and `column_name_simple` is that - * `column_name` has SFINAE check for type equality but `column_name_simple` has not. - */ - template - std::string column_name_simple(F O::*m) const { - return this->table.find_column_name(m); - } - - /** - * Cute function used to find column name by its type and member pointer. Uses SFINAE to - * skip inequal type O. - */ - template - std::string column_name(F O::*m, - typename std::enable_if::value>::type * = nullptr) const { - return this->table.find_column_name(m); - } - - /** - * Opposite version of function defined above. Just calls same function in superclass. - */ - template - std::string column_name(F O::*m, - typename std::enable_if::value>::type * = nullptr) const { - return this->super::column_name(m); - } - - template - std::string column_name(const column_pointer &c, - typename std::enable_if::value>::type * = nullptr) const { - return this->column_name_simple(c.field); - } - - template - std::string column_name(const column_pointer &c, - typename std::enable_if::value>::type * = nullptr) const { - return this->super::column_name(c); - } - - template - const auto &get_impl(typename std::enable_if::value>::type * = nullptr) const { - return *this; - } - - template - const auto &get_impl(typename std::enable_if::value>::type * = nullptr) const { - return this->super::template get_impl(); - } - - template - auto &get_impl(typename std::enable_if::value>::type * = nullptr) { - return *this; - } - - template - auto &get_impl(typename std::enable_if::value>::type * = nullptr) { - return this->super::template get_impl(); - } - - template - const auto *find_table(typename std::enable_if::value>::type * = nullptr) const { - return &this->table; - } - - template - const auto *find_table(typename std::enable_if::value>::type * = nullptr) const { - return this->super::template find_table(); - } - - std::string find_table_name(std::type_index ti) const { - std::type_index thisTypeIndex{typeid(typename H::object_type)}; - if(thisTypeIndex == ti) { - return this->table.name; - } else { - return this->super::find_table_name(ti); - } - } - - void add_column(const table_info &ti, sqlite3 *db) const { - std::stringstream ss; - ss << "ALTER TABLE " << this->table.name << " ADD COLUMN " << ti.name << " "; - ss << ti.type << " "; - if(ti.pk) { - ss << "PRIMARY KEY "; - } - if(ti.notnull) { - ss << "NOT NULL "; - } - if(ti.dflt_value.length()) { - ss << "DEFAULT " << ti.dflt_value << " "; - } - auto query = ss.str(); - sqlite3_stmt *stmt; - auto prepareResult = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr); - if(prepareResult == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - //.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - /** - * Copies current table to another table with a given **name**. - * Performs CREATE TABLE %name% AS SELECT %this->table.columns_names()% FROM &this->table.name%; - */ - void - copy_table(sqlite3 *db, const std::string &name, const std::vector &columnsToIgnore) const { - std::ignore = columnsToIgnore; - - std::stringstream ss; - std::vector columnNames; - this->table.for_each_column([&columnNames, &columnsToIgnore](auto &c) { - auto &columnName = c.name; - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](auto tableInfoPointer) { - return columnName == tableInfoPointer->name; - }); - if(columnToIgnoreIt == columnsToIgnore.end()) { - columnNames.emplace_back(columnName); - } - }); - auto columnNamesCount = columnNames.size(); - ss << "INSERT INTO " << name << " ("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << columnNames[i]; - if(i < columnNamesCount - 1) { - ss << ","; - } - ss << " "; - } - ss << ") "; - ss << "SELECT "; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << columnNames[i]; - if(i < columnNamesCount - 1) { - ss << ","; - } - ss << " "; - } - ss << "FROM '" << this->table.name << "' "; - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - //.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - sync_schema_result schema_status(sqlite3 *db, bool preserve) const { - - auto res = sync_schema_result::already_in_sync; - - // first let's see if table with such name exists.. - auto gottaCreateTable = !this->table_exists(this->table.name, db); - if(!gottaCreateTable) { - - // get table info provided in `make_table` call.. - auto storageTableInfo = this->table.get_table_info(); - - // now get current table info from db using `PRAGMA table_info` query.. - auto dbTableInfo = this->get_table_info(this->table.name, db); - - // this vector will contain pointers to columns that gotta be added.. - std::vector columnsToAdd; - - if(this->get_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo)) { - gottaCreateTable = true; - } - - if(!gottaCreateTable) { // if all storage columns are equal to actual db columns but there are - // excess columns at the db.. - if(dbTableInfo.size() > 0) { - // extra table columns than storage columns - if(!preserve) { - gottaCreateTable = true; - } else { - res = decltype(res)::old_columns_removed; - } - } - } - if(gottaCreateTable) { - res = decltype(res)::dropped_and_recreated; - } else { - if(columnsToAdd.size()) { - // extra storage columns than table columns - for(auto columnPointer: columnsToAdd) { - if(columnPointer->notnull && columnPointer->dflt_value.empty()) { - gottaCreateTable = true; - break; - } - } - if(!gottaCreateTable) { - if(res == decltype(res)::old_columns_removed) { - res = decltype(res)::new_columns_added_and_old_columns_removed; - } else { - res = decltype(res)::new_columns_added; - } - } else { - res = decltype(res)::dropped_and_recreated; - } - } else { - if(res != decltype(res)::old_columns_removed) { - res = decltype(res)::already_in_sync; - } - } - } - } else { - res = decltype(res)::new_table_created; - } - return res; - } - - private: - using self = storage_impl; - }; - - template<> - struct storage_impl<> : storage_impl_base { - - std::string find_table_name(std::type_index) const { - return {}; - } - - template - void for_each(const L &) {} - - int foreign_keys_count() { - return 0; - } - - template - const void *find_table() const { - return nullptr; - } - }; - - template - struct is_storage_impl : std::false_type {}; - - template - struct is_storage_impl> : std::true_type {}; - } -} -#pragma once - -#include // std::unique/shared_ptr, std::make_unique/shared -#include // std::string -#include "sqlite3.h" -#include // std::remove_reference, std::is_base_of, std::decay, std::false_type, std::true_type -#include // std::ptrdiff_t -#include // std::input_iterator_tag, std::iterator_traits, std::distance -#include // std::function -#include // std::stringstream -#include // std::map -#include // std::vector -#include // std::tuple_size, std::tuple, std::make_tuple -#include // std::forward, std::pair -#include // std::find - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED -#include // std::optional -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - -// #include "alias.h" - -// #include "row_extractor_builder.h" - -// #include "row_extractor.h" - -// #include "mapped_row_extractor.h" - -#include "sqlite3.h" - -// #include "object_from_column_builder.h" - -#include "sqlite3.h" - -// #include "row_extractor.h" - -namespace sqlite_orm { - - namespace internal { - - struct object_from_column_builder_base { - sqlite3_stmt *stmt = nullptr; - mutable int index = 0; - }; - - /** - * This is a cute lambda replacement which is used in several places. - */ - template - struct object_from_column_builder : object_from_column_builder_base { - using object_type = O; - - object_type &object; - - object_from_column_builder(object_type &object_, sqlite3_stmt *stmt_) : - object_from_column_builder_base{stmt_}, object(object_) {} - - template - void operator()(const C &c) const { - using field_type = typename C::field_type; - auto value = row_extractor().extract(this->stmt, this->index++); - if(c.member_pointer) { - this->object.*c.member_pointer = std::move(value); - } else { - ((this->object).*(c.setter))(std::move(value)); - } - } - }; - - } -} - -namespace sqlite_orm { - - namespace internal { - - /** - * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. - * Main difference from regular `row_extractor` is that this class takes table info which is required - * for constructing objects by member pointers. To construct please use `row_extractor_builder` class - * Type arguments: - * V is value type just like regular `row_extractor` has - * T is table info class `table_t` - */ - template - struct mapped_row_extractor { - using table_info_t = T; - - mapped_row_extractor(const table_info_t &tableInfo_) : tableInfo(tableInfo_) {} - - V extract(sqlite3_stmt *stmt, int /*columnIndex*/) { - V res; - object_from_column_builder builder{res, stmt}; - this->tableInfo.for_each_column(builder); - return res; - } - - const table_info_t &tableInfo; - }; - - } - -} - -namespace sqlite_orm { - - namespace internal { - - /** - * This builder is used to construct different row extractors depending on type. - * It has two specializations: for mapped to storage types (e.g. User, Visit etc) and - * for non-mapped (e.g. std::string, QString, int etc). For non mapped its operator() returns - * generic `row_extractor`, for mapped it returns `mapped_row_extractor` instance. - */ - template - struct row_extractor_builder; - - template - struct row_extractor_builder { - - row_extractor operator()(const I * /*tableInfo*/) const { - return {}; - } - }; - - template - struct row_extractor_builder { - - mapped_row_extractor operator()(const I *tableInfo) const { - return {*tableInfo}; - } - }; - - template - auto make_row_extractor(const I *tableInfo) { - using builder_t = row_extractor_builder; - return builder_t{}(tableInfo); - } - - } - -} - -// #include "error_code.h" - -// #include "type_printer.h" - -// #include "tuple_helper.h" - -// #include "constraints.h" - -// #include "type_is_nullable.h" - -// #include "field_printer.h" - -// #include "rowid.h" - -// #include "operators.h" - -// #include "select_constraints.h" - -// #include "core_functions.h" - -// #include "conditions.h" - -// #include "statement_binder.h" - -// #include "column_result.h" - -// #include "mapped_type_proxy.h" - -// #include "sync_schema_result.h" - -// #include "table_info.h" - -// #include "storage_impl.h" - -// #include "journal_mode.h" - -// #include "field_value_holder.h" - -// #include "view.h" - -#include // std::shared_ptr -#include // std::string -#include // std::forward, std::move -#include "sqlite3.h" -#include // std::system_error -#include // std::tuple, std::make_tuple - -// #include "row_extractor.h" - -// #include "statement_finalizer.h" - -// #include "error_code.h" - -// #include "iterator.h" - -#include // std::shared_ptr, std::unique_ptr, std::make_shared -#include "sqlite3.h" -#include // std::decay -#include // std::move -#include // std::ptrdiff_t -#include // std::input_iterator_tag -#include // std::system_error -#include // std::make_error_code - -// #include "row_extractor.h" - -// #include "statement_finalizer.h" - -// #include "error_code.h" - -// #include "object_from_column_builder.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct iterator_t { - using view_type = V; - using value_type = typename view_type::mapped_type; - - protected: - /** - * The double-indirection is so that copies of the iterator - * share the same sqlite3_stmt from a sqlite3_prepare_v2() - * call. When one finishes iterating it the pointer - * inside the shared_ptr is nulled out in all copies. - */ - std::shared_ptr stmt; - view_type &view; - - /** - * shared_ptr is used over unique_ptr here - * so that the iterator can be copyable. - */ - std::shared_ptr current; - - void extract_value(std::unique_ptr &temp) { - temp = std::make_unique(); - auto &storage = this->view.storage; - auto &impl = storage.template get_impl(); - object_from_column_builder builder{*temp, *this->stmt}; - impl.table.for_each_column(builder); - } - - public: - using difference_type = std::ptrdiff_t; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::input_iterator_tag; - - iterator_t(sqlite3_stmt *stmt_, view_type &view_) : - stmt(std::make_shared(stmt_)), view(view_) { - this->operator++(); - } - - iterator_t(const iterator_t &) = default; - - iterator_t(iterator_t &&) = default; - - iterator_t &operator=(iterator_t &&) = default; - - iterator_t &operator=(const iterator_t &) = default; - - ~iterator_t() { - if(this->stmt) { - statement_finalizer f{*this->stmt}; - } - } - - value_type &operator*() { - if(!this->stmt) { - throw std::system_error(std::make_error_code(orm_error_code::trying_to_dereference_null_iterator)); - } - if(!this->current) { - std::unique_ptr value; - this->extract_value(value); - this->current = move(value); - } - return *this->current; - } - - value_type *operator->() { - return &(this->operator*()); - } - - void operator++() { - if(this->stmt && *this->stmt) { - auto ret = sqlite3_step(*this->stmt); - switch(ret) { - case SQLITE_ROW: - this->current = nullptr; - break; - case SQLITE_DONE: { - statement_finalizer f{*this->stmt}; - *this->stmt = nullptr; - } break; - default: { - auto db = this->view.connection.get(); - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - } - - void operator++(int) { - this->operator++(); - } - - bool operator==(const iterator_t &other) const { - if(this->stmt && other.stmt) { - return *this->stmt == *other.stmt; - } else { - if(!this->stmt && !other.stmt) { - return true; - } else { - return false; - } - } - } - - bool operator!=(const iterator_t &other) const { - return !(*this == other); - } - }; - } -} - -// #include "ast_iterator.h" - -#include // std::vector -#include // std::reference_wrapper - -// #include "conditions.h" - -// #include "select_constraints.h" - -// #include "operators.h" - -// #include "tuple_helper.h" - -// #include "core_functions.h" - -// #include "prepared_statement.h" - -#include "sqlite3.h" -#include // std::iterator_traits -#include // std::string -#include // std::true_type, std::false_type -#include // std::pair - -// #include "connection_holder.h" - -#include "sqlite3.h" -#include // std::string -#include // std::system_error - -// #include "error_code.h" - -namespace sqlite_orm { - - namespace internal { - - struct connection_holder { - - connection_holder(std::string filename_) : filename(move(filename_)) {} - - void retain() { - ++this->_retain_count; - if(1 == this->_retain_count) { - auto rc = sqlite3_open(this->filename.c_str(), &this->db); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(this->db), get_sqlite_error_category()), - sqlite3_errmsg(this->db)); - } - } - } - - void release() { - --this->_retain_count; - if(0 == this->_retain_count) { - auto rc = sqlite3_close(this->db); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(this->db), get_sqlite_error_category()), - sqlite3_errmsg(this->db)); - } - } - } - - sqlite3 *get() const { - return this->db; - } - - int retain_count() const { - return this->_retain_count; - } - - const std::string filename; - - protected: - sqlite3 *db = nullptr; - int _retain_count = 0; - }; - - struct connection_ref { - connection_ref(connection_holder &holder_) : holder(holder_) { - this->holder.retain(); - } - - connection_ref(const connection_ref &other) : holder(other.holder) { - this->holder.retain(); - } - - connection_ref(connection_ref &&other) : holder(other.holder) { - this->holder.retain(); - } - - ~connection_ref() { - this->holder.release(); - } - - sqlite3 *get() const { - return this->holder.get(); - } - - protected: - connection_holder &holder; - }; - } -} - -// #include "select_constraints.h" - -namespace sqlite_orm { - - namespace internal { - - struct prepared_statement_base { - sqlite3_stmt *stmt = nullptr; - connection_ref con; - - ~prepared_statement_base() { - if(this->stmt) { - sqlite3_finalize(this->stmt); - this->stmt = nullptr; - } - } - - std::string sql() const { - if(this->stmt) { - if(auto res = sqlite3_sql(this->stmt)) { - return res; - } else { - return {}; - } - } else { - return {}; - } - } - -#if SQLITE_VERSION_NUMBER >= 3014000 - std::string expanded_sql() const { - if(this->stmt) { - if(auto res = sqlite3_expanded_sql(this->stmt)) { - std::string result = res; - sqlite3_free(res); - return result; - } else { - return {}; - } - } else { - return {}; - } - } -#endif -#if SQLITE_VERSION_NUMBER >= 3026000 and defined(SQLITE_ENABLE_NORMALIZE) - std::string normalized_sql() const { - if(this->stmt) { - if(auto res = sqlite3_normalized_sql(this->stmt)) { - return res; - } else { - return {}; - } - } else { - return {}; - } - } -#endif - }; - - template - struct prepared_statement_t : prepared_statement_base { - using expression_type = T; - - expression_type t; - - prepared_statement_t(T t_, sqlite3_stmt *stmt_, connection_ref con_) : - prepared_statement_base{stmt_, std::move(con_)}, t(std::move(t_)) {} - }; - - template - struct is_prepared_statement : std::false_type {}; - - template - struct is_prepared_statement> : std::true_type {}; - - /** - * T - type of object to obtain from a database - */ - template - struct get_all_t { - using type = T; - using return_type = R; - - using conditions_type = std::tuple; - - conditions_type conditions; - }; - - template - struct get_all_pointer_t { - using type = T; - using return_type = R; - - using conditions_type = std::tuple; - - conditions_type conditions; - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct get_all_optional_t { - using type = T; - using return_type = R; - - using conditions_type = std::tuple; - - conditions_type conditions; - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct update_all_t; - - template - struct update_all_t, Wargs...> { - using set_type = set_t; - using conditions_type = std::tuple; - - set_type set; - conditions_type conditions; - }; - - template - struct remove_all_t { - using type = T; - using conditions_type = std::tuple; - - conditions_type conditions; - }; - - template - struct get_t { - using type = T; - using ids_type = std::tuple; - - ids_type ids; - }; - - template - struct get_pointer_t { - using type = T; - using ids_type = std::tuple; - - ids_type ids; - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct get_optional_t { - using type = T; - using ids_type = std::tuple; - - ids_type ids; - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct update_t { - using type = T; - - type obj; - }; - - template - struct remove_t { - using type = T; - using ids_type = std::tuple; - - ids_type ids; - }; - - template - struct insert_t { - using type = T; - - type obj; - }; - - template - struct insert_explicit { - using type = T; - using columns_type = columns_t; - - type obj; - columns_type columns; - }; - - template - struct replace_t { - using type = T; - - type obj; - }; - - template - struct insert_range_t { - using iterator_type = It; - using object_type = typename std::iterator_traits::value_type; - - std::pair range; - }; - - template - struct replace_range_t { - using iterator_type = It; - using object_type = typename std::iterator_traits::value_type; - - std::pair range; - }; - } - - /** - * Create a replace range statement - */ - template - internal::replace_range_t replace_range(It from, It to) { - return {{std::move(from), std::move(to)}}; - } - - /** - * Create an insert range statement - */ - template - internal::insert_range_t insert_range(It from, It to) { - return {{std::move(from), std::move(to)}}; - } - - /** - * Create a replace statement. - * T is an object type mapped to a storage. - * Usage: storage.replace(myUserInstance); - * Parameter obj is accepted by value. If you want to accept it by ref - * please use std::ref function: storage.replace(std::ref(myUserInstance)); - */ - template - internal::replace_t replace(T obj) { - return {std::move(obj)}; - } - - /** - * Create an insert statement. - * T is an object type mapped to a storage. - * Usage: storage.insert(myUserInstance); - * Parameter obj is accepted by value. If you want to accept it by ref - * please use std::ref function: storage.insert(std::ref(myUserInstance)); - */ - template - internal::insert_t insert(T obj) { - return {std::move(obj)}; - } - - /** - * Create an explicit insert statement. - * T is an object type mapped to a storage. - * Cols is columns types aparameter pack. Must contain member pointers - * Usage: storage.insert(myUserInstance, columns(&User::id, &User::name)); - * Parameter obj is accepted by value. If you want to accept it by ref - * please use std::ref function: storage.insert(std::ref(myUserInstance), columns(&User::id, &User::name)); - */ - template - internal::insert_explicit insert(T obj, internal::columns_t cols) { - return {std::move(obj), std::move(cols)}; - } - - /** - * Create a remove statement - * T is an object type mapped to a storage. - * Usage: remove(5); - */ - template - internal::remove_t remove(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; - } - - /** - * Create an update statement. - * T is an object type mapped to a storage. - * Usage: storage.update(myUserInstance); - * Parameter obj is accepted by value. If you want to accept it by ref - * please use std::ref function: storage.update(std::ref(myUserInstance)); - */ - template - internal::update_t update(T obj) { - return {std::move(obj)}; - } - - /** - * Create a get statement. - * T is an object type mapped to a storage. - * Usage: get(5); - */ - template - internal::get_t get(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; - } - - /** - * Create a get pointer statement. - * T is an object type mapped to a storage. - * Usage: get_pointer(5); - */ - template - internal::get_pointer_t get_pointer(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * Create a get optional statement. - * T is an object type mapped to a storage. - * Usage: get_optional(5); - */ - template - internal::get_optional_t get_optional(Ids... ids) { - std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - /** - * Create a remove all statement. - * T is an object type mapped to a storage. - * Usage: storage.remove_all(...); - */ - template - internal::remove_all_t remove_all(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - - /** - * Create a get all statement. - * T is an object type mapped to a storage. - * Usage: storage.get_all(...); - */ - template - internal::get_all_t, Args...> get_all(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - - /** - * Create a get all statement. - * T is an object type mapped to a storage. - * R is a container type. std::vector is default - * Usage: storage.get_all(...); - */ - template - internal::get_all_t get_all(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - - /** - * Create an update all statement. - * Usage: storage.update_all(set(...), ...); - */ - template - internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(wh)...}; - return {std::move(set), move(conditions)}; - } - - /** - * Create a get all pointer statement. - * T is an object type mapped to a storage. - * Usage: storage.get_all_pointer(...); - */ - template - internal::get_all_pointer_t>, Args...> get_all_pointer(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - /** - * Create a get all pointer statement. - * T is an object type mapped to a storage. - * R is a container return type. std::vector> is default - * Usage: storage.get_all_pointer(...); - */ - template - internal::get_all_pointer_t get_all_pointer(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * Create a get all optional statement. - * T is an object type mapped to a storage. - * Usage: storage.get_all_optional(...); - */ - template - internal::get_all_optional_t>, Args...> get_all_optional(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } - - /** - * Create a get all optional statement. - * T is an object type mapped to a storage. - * R is a container return type. std::vector> is default - * Usage: storage.get_all_optional(...); - */ - template - internal::get_all_optional_t get_all_optional(Args... args) { - using args_tuple = std::tuple; - internal::validate_conditions(); - args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED -} - -// #include "values.h" - -#include // std::vector -#include -#include // std::tuple - -namespace sqlite_orm { - - namespace internal { - - template - struct values_t { - std::tuple tuple; - }; - - template - struct dynamic_values_t { - std::vector vector; - }; - - } - - template - internal::values_t values(Args... args) { - return {{std::forward(args)...}}; - } - - template - internal::dynamic_values_t values(std::vector vector) { - return {{move(vector)}}; - } - -} - -namespace sqlite_orm { - - namespace internal { - - /** - * ast_iterator accepts any expression and a callable object - * which will be called for any node of provided expression. - * E.g. if we pass `where(is_equal(5, max(&User::id, 10))` then - * callable object will be called with 5, &User::id and 10. - * ast_iterator is used mostly in finding literals to be bound to - * a statement. To use it just call `iterate_ast(object, callable);` - * T is an ast element. E.g. where_t - */ - template - struct ast_iterator { - using node_type = T; - - /** - * L is a callable type. Mostly is a templated lambda - */ - template - void operator()(const T &t, const L &l) const { - l(t); - } - }; - - /** - * Simplified API - */ - template - void iterate_ast(const T &t, const L &l) { - ast_iterator iterator; - iterator(t, l); - } - - template - struct ast_iterator, void> { - using node_type = std::reference_wrapper; - - template - void operator()(const node_type &r, const L &l) const { - iterate_ast(r.get(), l); - } - }; - - template - struct ast_iterator, void> { - using node_type = where_t; - - template - void operator()(const node_type &where, const L &l) const { - iterate_ast(where.c, l); - } - }; - - template - struct ast_iterator::value>::type> { - using node_type = T; - - template - void operator()(const node_type &binaryCondition, const L &l) const { - iterate_ast(binaryCondition.l, l); - iterate_ast(binaryCondition.r, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = binary_operator; - - template - void operator()(const node_type &binaryOperator, const C &l) const { - iterate_ast(binaryOperator.lhs, l); - iterate_ast(binaryOperator.rhs, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = columns_t; - - template - void operator()(const node_type &cols, const L &l) const { - iterate_ast(cols.columns, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = in_t; - - template - void operator()(const node_type &in, const C &l) const { - iterate_ast(in.l, l); - iterate_ast(in.arg, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = std::vector; - - template - void operator()(const node_type &vec, const L &l) const { - for(auto &i: vec) { - iterate_ast(i, l); - } - } - }; - - template<> - struct ast_iterator, void> { - using node_type = std::vector; - - template - void operator()(const node_type &vec, const L &l) const { - l(vec); - } - }; - - template - struct ast_iterator::value>::type> { - using node_type = T; - - template - void operator()(const node_type &c, const L &l) const { - iterate_ast(c.left, l); - iterate_ast(c.right, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = select_t; - - template - void operator()(const node_type &sel, const L &l) const { - iterate_ast(sel.col, l); - iterate_ast(sel.conditions, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = get_all_t; - - template - void operator()(const node_type &get, const L &l) const { - iterate_ast(get.conditions, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = get_all_pointer_t; - - template - void operator()(const node_type &get, const L &l) const { - iterate_ast(get.conditions, l); - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct ast_iterator, void> { - using node_type = get_all_optional_t; - - template - void operator()(const node_type &get, const L &l) const { - iterate_ast(get.conditions, l); - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct ast_iterator, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; - - template - void operator()(const node_type &u, const L &l) const { - iterate_ast(u.set, l); - iterate_ast(u.conditions, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = remove_all_t; - - template - void operator()(const node_type &r, const L &l) const { - iterate_ast(r.conditions, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = set_t; - - template - void operator()(const node_type &s, const L &l) const { - iterate_ast(s.assigns, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = std::tuple; - - template - void operator()(const node_type &tuple, const L &l) const { - iterate_tuple(tuple, [&l](auto &v) { - iterate_ast(v, l); - }); - } - }; - - template - struct ast_iterator, void> { - using node_type = having_t; - - template - void operator()(const node_type &hav, const L &l) const { - iterate_ast(hav.t, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = cast_t; - - template - void operator()(const node_type &c, const L &l) const { - iterate_ast(c.expression, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = exists_t; - - template - void operator()(const node_type &e, const L &l) const { - iterate_ast(e.t, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = like_t; - - template - void operator()(const node_type &lk, const L &l) const { - iterate_ast(lk.arg, l); - iterate_ast(lk.pattern, l); - lk.arg3.apply([&l](auto &value) { - iterate_ast(value, l); - }); - } - }; - - template - struct ast_iterator, void> { - using node_type = glob_t; - - template - void operator()(const node_type &lk, const L &l) const { - iterate_ast(lk.arg, l); - iterate_ast(lk.pattern, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = between_t; - - template - void operator()(const node_type &b, const L &l) const { - iterate_ast(b.expr, l); - iterate_ast(b.b1, l); - iterate_ast(b.b2, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = named_collate; - - template - void operator()(const node_type &col, const L &l) const { - iterate_ast(col.expr, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = negated_condition_t; - - template - void operator()(const node_type &neg, const L &l) const { - iterate_ast(neg.c, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = is_null_t; - - template - void operator()(const node_type &i, const L &l) const { - iterate_ast(i.t, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = is_not_null_t; - - template - void operator()(const node_type &i, const L &l) const { - iterate_ast(i.t, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = core_function_t; - - template - void operator()(const node_type &f, const L &l) const { - iterate_ast(f.args, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = left_join_t; - - template - void operator()(const node_type &j, const L &l) const { - iterate_ast(j.constraint, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = on_t; - - template - void operator()(const node_type &o, const L &l) const { - iterate_ast(o.arg, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = join_t; - - template - void operator()(const node_type &j, const L &l) const { - iterate_ast(j.constraint, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = left_outer_join_t; - - template - void operator()(const node_type &j, const L &l) const { - iterate_ast(j.constraint, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = inner_join_t; - - template - void operator()(const node_type &j, const L &l) const { - iterate_ast(j.constraint, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = simple_case_t; - - template - void operator()(const node_type &c, const L &l) const { - c.case_expression.apply([&l](auto &c_) { - iterate_ast(c_, l); - }); - iterate_tuple(c.args, [&l](auto &pair) { - iterate_ast(pair.first, l); - iterate_ast(pair.second, l); - }); - c.else_expression.apply([&l](auto &el) { - iterate_ast(el, l); - }); - } - }; - - template - struct ast_iterator, void> { - using node_type = as_t; - - template - void operator()(const node_type &a, const L &l) const { - iterate_ast(a.expression, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = limit_t; - - template - void operator()(const node_type &a, const L &l) const { - iterate_ast(a.lim, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = limit_t; - - template - void operator()(const node_type &a, const L &l) const { - iterate_ast(a.lim, l); - a.off.apply([&l](auto &value) { - iterate_ast(value, l); - }); - } - }; - - template - struct ast_iterator, void> { - using node_type = limit_t; - - template - void operator()(const node_type &a, const L &l) const { - a.off.apply([&l](auto &value) { - iterate_ast(value, l); - }); - iterate_ast(a.lim, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = distinct_t; - - template - void operator()(const node_type &a, const L &l) const { - iterate_ast(a.t, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = all_t; - - template - void operator()(const node_type &a, const L &l) const { - iterate_ast(a.t, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = bitwise_not_t; - - template - void operator()(const node_type &a, const L &l) const { - iterate_ast(a.argument, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = values_t; - - template - void operator()(const node_type &node, const L &l) const { - iterate_ast(node.tuple, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = dynamic_values_t; - - template - void operator()(const node_type &node, const L &l) const { - iterate_ast(node.vector, l); - } - }; - - template - struct ast_iterator, void> { - using node_type = collate_t; - - template - void operator()(const node_type &node, const L &l) const { - iterate_ast(node.expr, l); - } - }; - - } -} - -// #include "prepared_statement.h" - -// #include "connection_holder.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct view_t { - using mapped_type = T; - using storage_type = S; - using self = view_t; - - storage_type &storage; - connection_ref connection; - get_all_t, Args...> args; - - view_t(storage_type &stor, decltype(connection) conn, Args &&... args_) : - storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} - - size_t size() { - return this->storage.template count(); - } - - bool empty() { - return !this->size(); - } - - iterator_t end() { - return {nullptr, *this}; - } - - iterator_t begin() { - sqlite3_stmt *stmt = nullptr; - auto db = this->connection.get(); - using context_t = serializator_context; - context_t context{this->storage.impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(this->args, context); - auto ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr); - if(ret == SQLITE_OK) { - auto index = 1; - iterate_ast(this->args.conditions, [&index, stmt, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - return {stmt, *this}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - }; - } -} - -// #include "ast_iterator.h" - -// #include "storage_base.h" - -#include // std::function, std::bind -#include "sqlite3.h" -#include // std::string -#include // std::stringstream -#include // std::move -#include // std::system_error, std::error_code, std::make_error_code -#include // std::vector -#include // std::make_shared, std::shared_ptr -#include // std::map -#include // std::decay, std::is_same -#include // std::iter_swap - -// #include "pragma.h" - -#include // std::string -#include "sqlite3.h" -#include // std::function -#include // std::shared_ptr - -// #include "error_code.h" - -// #include "row_extractor.h" - -// #include "journal_mode.h" - -// #include "connection_holder.h" - -namespace sqlite_orm { - - namespace internal { - struct storage_base; - } - - struct pragma_t { - using get_connection_t = std::function; - - pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} - - void busy_timeout(int value) { - this->set_pragma("busy_timeout", value); - } - - int busy_timeout() { - return this->get_pragma("busy_timeout"); - } - - sqlite_orm::journal_mode journal_mode() { - return this->get_pragma("journal_mode"); - } - - void journal_mode(sqlite_orm::journal_mode value) { - this->_journal_mode = -1; - this->set_pragma("journal_mode", value); - this->_journal_mode = static_cast_journal_mode)>(value); - } - - int synchronous() { - return this->get_pragma("synchronous"); - } - - void synchronous(int value) { - this->_synchronous = -1; - this->set_pragma("synchronous", value); - this->_synchronous = value; - } - - int user_version() { - return this->get_pragma("user_version"); - } - - void user_version(int value) { - this->set_pragma("user_version", value); - } - - int auto_vacuum() { - return this->get_pragma("auto_vacuum"); - } - - void auto_vacuum(int value) { - this->set_pragma("auto_vacuum", value); - } - - protected: - friend struct storage_base; - - public: - int _synchronous = -1; - signed char _journal_mode = -1; // if != -1 stores static_cast(journal_mode) - get_connection_t get_connection; - - template - T get_pragma(const std::string &name) { - auto connection = this->get_connection(); - auto query = "PRAGMA " + name; - T result; - auto db = connection.get(); - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void *data, int argc, char **argv, char **) -> int { - auto &res = *(T *)data; - if(argc) { - res = row_extractor().extract(argv[0]); - } - return 0; - }, - &result, - nullptr); - if(rc == SQLITE_OK) { - return result; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - /** - * Yevgeniy Zakharov: I wanted to refactore this function with statements and value bindings - * but it turns out that bindings in pragma statements are not supported. - */ - template - void set_pragma(const std::string &name, const T &value, sqlite3 *db = nullptr) { - auto con = this->get_connection(); - if(!db) { - db = con.get(); - } - std::stringstream ss; - ss << "PRAGMA " << name << " = " << value; - auto query = ss.str(); - auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - void set_pragma(const std::string &name, const sqlite_orm::journal_mode &value, sqlite3 *db = nullptr) { - auto con = this->get_connection(); - if(!db) { - db = con.get(); - } - std::stringstream ss; - ss << "PRAGMA " << name << " = " << internal::to_string(value); - auto query = ss.str(); - auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - }; -} - -// #include "limit_accesor.h" - -#include "sqlite3.h" -#include // std::map -#include // std::function -#include // std::shared_ptr - -// #include "connection_holder.h" - -namespace sqlite_orm { - - namespace internal { - - struct limit_accesor { - using get_connection_t = std::function; - - limit_accesor(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} - - int length() { - return this->get(SQLITE_LIMIT_LENGTH); - } - - void length(int newValue) { - this->set(SQLITE_LIMIT_LENGTH, newValue); - } - - int sql_length() { - return this->get(SQLITE_LIMIT_SQL_LENGTH); - } - - void sql_length(int newValue) { - this->set(SQLITE_LIMIT_SQL_LENGTH, newValue); - } - - int column() { - return this->get(SQLITE_LIMIT_COLUMN); - } - - void column(int newValue) { - this->set(SQLITE_LIMIT_COLUMN, newValue); - } - - int expr_depth() { - return this->get(SQLITE_LIMIT_EXPR_DEPTH); - } - - void expr_depth(int newValue) { - this->set(SQLITE_LIMIT_EXPR_DEPTH, newValue); - } - - int compound_select() { - return this->get(SQLITE_LIMIT_COMPOUND_SELECT); - } - - void compound_select(int newValue) { - this->set(SQLITE_LIMIT_COMPOUND_SELECT, newValue); - } - - int vdbe_op() { - return this->get(SQLITE_LIMIT_VDBE_OP); - } - - void vdbe_op(int newValue) { - this->set(SQLITE_LIMIT_VDBE_OP, newValue); - } - - int function_arg() { - return this->get(SQLITE_LIMIT_FUNCTION_ARG); - } - - void function_arg(int newValue) { - this->set(SQLITE_LIMIT_FUNCTION_ARG, newValue); - } - - int attached() { - return this->get(SQLITE_LIMIT_ATTACHED); - } - - void attached(int newValue) { - this->set(SQLITE_LIMIT_ATTACHED, newValue); - } - - int like_pattern_length() { - return this->get(SQLITE_LIMIT_LIKE_PATTERN_LENGTH); - } - - void like_pattern_length(int newValue) { - this->set(SQLITE_LIMIT_LIKE_PATTERN_LENGTH, newValue); - } - - int variable_number() { - return this->get(SQLITE_LIMIT_VARIABLE_NUMBER); - } - - void variable_number(int newValue) { - this->set(SQLITE_LIMIT_VARIABLE_NUMBER, newValue); - } - - int trigger_depth() { - return this->get(SQLITE_LIMIT_TRIGGER_DEPTH); - } - - void trigger_depth(int newValue) { - this->set(SQLITE_LIMIT_TRIGGER_DEPTH, newValue); - } - -#if SQLITE_VERSION_NUMBER >= 3008007 - int worker_threads() { - return this->get(SQLITE_LIMIT_WORKER_THREADS); - } - - void worker_threads(int newValue) { - this->set(SQLITE_LIMIT_WORKER_THREADS, newValue); - } -#endif - - protected: - get_connection_t get_connection; - - friend struct storage_base; - - /** - * Stores limit set between connections. - */ - std::map limits; - - int get(int id) { - auto connection = this->get_connection(); - return sqlite3_limit(connection.get(), id, -1); - } - - void set(int id, int newValue) { - this->limits[id] = newValue; - auto connection = this->get_connection(); - sqlite3_limit(connection.get(), id, newValue); - } - }; - } -} - -// #include "transaction_guard.h" - -#include // std::function - -// #include "connection_holder.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * Class used as a guard for a transaction. Calls `ROLLBACK` in destructor. - * Has explicit `commit()` and `rollback()` functions. After explicit function is fired - * guard won't do anything in d-tor. Also you can set `commit_on_destroy` to true to - * make it call `COMMIT` on destroy. - */ - struct transaction_guard_t { - /** - * This is a public lever to tell a guard what it must do in its destructor - * if `gotta_fire` is true - */ - bool commit_on_destroy = false; - - transaction_guard_t(connection_ref connection_, - std::function commit_func_, - std::function rollback_func_) : - connection(std::move(connection_)), - commit_func(std::move(commit_func_)), rollback_func(std::move(rollback_func_)) {} - - ~transaction_guard_t() { - if(this->gotta_fire) { - if(!this->commit_on_destroy) { - this->rollback_func(); - } else { - this->commit_func(); - } - } - } - - /** - * Call `COMMIT` explicitly. After this call - * guard will not call `COMMIT` or `ROLLBACK` - * in its destructor. - */ - void commit() { - this->commit_func(); - this->gotta_fire = false; - } - - /** - * Call `ROLLBACK` explicitly. After this call - * guard will not call `COMMIT` or `ROLLBACK` - * in its destructor. - */ - void rollback() { - this->rollback_func(); - this->gotta_fire = false; - } - - protected: - connection_ref connection; - std::function commit_func; - std::function rollback_func; - bool gotta_fire = true; - }; - } -} - -// #include "statement_finalizer.h" - -// #include "type_printer.h" - -// #include "tuple_helper.h" - -// #include "row_extractor.h" - -// #include "connection_holder.h" - -// #include "backup.h" - -#include "sqlite3.h" -#include // std::string -#include - -// #include "error_code.h" - -// #include "connection_holder.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * A backup class. Don't construct it as is, call storage.make_backup_from or storage.make_backup_to instead. - * An instance of this class represents a wrapper around sqlite3_backup pointer. Use this class - * to have maximum control on a backup operation. In case you need a single backup in one line you - * can skip creating a backup_t instance and just call storage.backup_from or storage.backup_to function. - */ - struct backup_t { - backup_t(connection_ref to_, - const std::string &zDestName, - connection_ref from_, - const std::string &zSourceName, - std::unique_ptr holder_) : - handle(sqlite3_backup_init(to_.get(), zDestName.c_str(), from_.get(), zSourceName.c_str())), - to(to_), from(from_), holder(move(holder_)) { - if(!this->handle) { - throw std::system_error(std::make_error_code(orm_error_code::failed_to_init_a_backup)); - } - } - - backup_t(backup_t &&other) : - handle(other.handle), to(other.to), from(other.from), holder(move(other.holder)) { - other.handle = nullptr; - } - - ~backup_t() { - if(this->handle) { - (void)sqlite3_backup_finish(this->handle); - this->handle = nullptr; - } - } - - /** - * Calls sqlite3_backup_step with pages argument - */ - int step(int pages) { - return sqlite3_backup_step(this->handle, pages); - } - - /** - * Returns sqlite3_backup_remaining result - */ - int remaining() const { - return sqlite3_backup_remaining(this->handle); - } - - /** - * Returns sqlite3_backup_pagecount result - */ - int pagecount() const { - return sqlite3_backup_pagecount(this->handle); - } - - protected: - sqlite3_backup *handle = nullptr; - connection_ref to; - connection_ref from; - std::unique_ptr holder; - }; - } -} - -namespace sqlite_orm { - - namespace internal { - - struct storage_base { - using collating_function = std::function; - - std::function on_open; - pragma_t pragma; - limit_accesor limit; - - transaction_guard_t transaction_guard() { - this->begin_transaction(); - auto commitFunc = std::bind(static_cast(&storage_base::commit), this); - auto rollbackFunc = std::bind(static_cast(&storage_base::rollback), this); - return {this->get_connection(), move(commitFunc), move(rollbackFunc)}; - } - - void drop_index(const std::string &indexName) { - auto con = this->get_connection(); - auto db = con.get(); - std::stringstream ss; - ss << "DROP INDEX '" << indexName + "'"; - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - void vacuum() { - auto con = this->get_connection(); - auto db = con.get(); - std::string query = "VACUUM"; - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - /** - * Drops table with given name. - */ - void drop_table(const std::string &tableName) { - auto con = this->get_connection(); - this->drop_table_internal(tableName, con.get()); - } - - /** - * Rename table named `from` to `to`. - */ - void rename_table(const std::string &from, const std::string &to) { - auto con = this->get_connection(); - std::stringstream ss; - ss << "ALTER TABLE '" << from << "' RENAME TO '" << to << "'"; - this->perform_query_without_result(ss.str(), con.get()); - } - - /** - * sqlite3_changes function. - */ - int changes() { - auto con = this->get_connection(); - return sqlite3_changes(con.get()); - } - - /** - * sqlite3_total_changes function. - */ - int total_changes() { - auto con = this->get_connection(); - return sqlite3_total_changes(con.get()); - } - - int64 last_insert_rowid() { - auto con = this->get_connection(); - return sqlite3_last_insert_rowid(con.get()); - } - - int busy_timeout(int ms) { - auto con = this->get_connection(); - return sqlite3_busy_timeout(con.get(), ms); - } - - /** - * Returns libsqltie3 lib version, not sqlite_orm - */ - std::string libversion() { - return sqlite3_libversion(); - } - - bool transaction(const std::function &f) { - this->begin_transaction(); - auto shouldCommit = f(); - if(shouldCommit) { - this->commit(); - } else { - this->rollback(); - } - return shouldCommit; - } - - std::string current_timestamp() { - auto con = this->get_connection(); - return this->current_timestamp(con.get()); - } - -#if SQLITE_VERSION_NUMBER >= 3007010 - /** - * \fn db_release_memory - * \brief Releases freeable memory of database. It is function can/should be called periodically by - * application, if application has less memory usage constraint. \note sqlite3_db_release_memory added - * in 3.7.10 https://sqlite.org/changes.html - */ - int db_release_memory() { - auto con = this->get_connection(); - return sqlite3_db_release_memory(con.get()); - } -#endif - - /** - * Returns existing permanent table names in database. Doesn't check storage itself - works only with - * actual database. - * @return Returns list of tables in database. - */ - std::vector table_names() { - auto con = this->get_connection(); - std::vector tableNames; - std::string sql = "SELECT name FROM sqlite_master WHERE type='table'"; - using data_t = std::vector; - auto db = con.get(); - int res = sqlite3_exec( - db, - sql.c_str(), - [](void *data, int argc, char **argv, char * * /*columnName*/) -> int { - auto &tableNames_ = *(data_t *)data; - for(int i = 0; i < argc; i++) { - if(argv[i]) { - tableNames_.push_back(argv[i]); - } - } - return 0; - }, - &tableNames, - nullptr); - - if(res != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return tableNames; - } - - void open_forever() { - this->isOpenedForever = true; - this->connection->retain(); - if(1 == this->connection->retain_count()) { - this->on_open_internal(this->connection->get()); - } - } - - void create_collation(const std::string &name, collating_function f) { - collating_function *functionPointer = nullptr; - if(f) { - functionPointer = &(collatingFunctions[name] = std::move(f)); - } else { - collatingFunctions.erase(name); - } - - // create collations if db is open - if(this->connection->retain_count() > 0) { - auto db = this->connection->get(); - if(sqlite3_create_collation(db, - name.c_str(), - SQLITE_UTF8, - functionPointer, - f ? collate_callback : nullptr) != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - - void begin_transaction() { - this->connection->retain(); - if(1 == this->connection->retain_count()) { - this->on_open_internal(this->connection->get()); - } - auto db = this->connection->get(); - this->begin_transaction(db); - } - - void commit() { - auto db = this->connection->get(); - this->commit(db); - this->connection->release(); - if(this->connection->retain_count() < 0) { - throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction)); - } - } - - void rollback() { - auto db = this->connection->get(); - this->rollback(db); - this->connection->release(); - if(this->connection->retain_count() < 0) { - throw std::system_error(std::make_error_code(orm_error_code::no_active_transaction)); - } - } - - void backup_to(const std::string &filename) { - auto backup = this->make_backup_to(filename); - backup.step(-1); - } - - void backup_to(storage_base &other) { - auto backup = this->make_backup_to(other); - backup.step(-1); - } - - void backup_from(const std::string &filename) { - auto backup = this->make_backup_from(filename); - backup.step(-1); - } - - void backup_from(storage_base &other) { - auto backup = this->make_backup_from(other); - backup.step(-1); - } - - backup_t make_backup_to(const std::string &filename) { - auto holder = std::make_unique(filename); - connection_ref conRef{*holder}; - return {conRef, "main", this->get_connection(), "main", move(holder)}; - } - - backup_t make_backup_to(storage_base &other) { - return {other.get_connection(), "main", this->get_connection(), "main", {}}; - } - - backup_t make_backup_from(const std::string &filename) { - auto holder = std::make_unique(filename); - connection_ref conRef{*holder}; - return {this->get_connection(), "main", conRef, "main", move(holder)}; - } - - backup_t make_backup_from(storage_base &other) { - return {this->get_connection(), "main", other.get_connection(), "main", {}}; - } - - const std::string &filename() const { - return this->connection->filename; - } - - /** - * Checks whether connection to database is opened right now. - * Returns always `true` for in memory databases. - */ - bool is_opened() const { - return this->connection->retain_count() > 0; - } - - int busy_handler(std::function handler) { - _busy_handler = move(handler); - if(this->is_opened()) { - if(_busy_handler) { - return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); - } else { - return sqlite3_busy_handler(this->connection->get(), nullptr, nullptr); - } - } else { - return SQLITE_OK; - } - } - - protected: - storage_base(const std::string &filename_, int foreignKeysCount) : - pragma(std::bind(&storage_base::get_connection, this)), - limit(std::bind(&storage_base::get_connection, this)), - inMemory(filename_.empty() || filename_ == ":memory:"), - connection(std::make_unique(filename_)), cachedForeignKeysCount(foreignKeysCount) { - if(this->inMemory) { - this->connection->retain(); - this->on_open_internal(this->connection->get()); - } - } - - storage_base(const storage_base &other) : - on_open(other.on_open), pragma(std::bind(&storage_base::get_connection, this)), - limit(std::bind(&storage_base::get_connection, this)), inMemory(other.inMemory), - connection(std::make_unique(other.connection->filename)), - cachedForeignKeysCount(other.cachedForeignKeysCount) { - if(this->inMemory) { - this->connection->retain(); - this->on_open_internal(this->connection->get()); - } - } - - ~storage_base() { - if(this->isOpenedForever) { - this->connection->release(); - } - if(this->inMemory) { - this->connection->release(); - } - } - - const bool inMemory; - bool isOpenedForever = false; - std::unique_ptr connection; - std::map collatingFunctions; - const int cachedForeignKeysCount; - std::function _busy_handler; - - connection_ref get_connection() { - connection_ref res{*this->connection}; - if(1 == this->connection->retain_count()) { - this->on_open_internal(this->connection->get()); - } - return res; - } - -#if SQLITE_VERSION_NUMBER >= 3006019 - - void foreign_keys(sqlite3 *db, bool value) { - std::stringstream ss; - ss << "PRAGMA foreign_keys = " << value; - auto query = ss.str(); - auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - bool foreign_keys(sqlite3 *db) { - std::string query = "PRAGMA foreign_keys"; - auto result = false; - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void *data, int argc, char **argv, char **) -> int { - auto &res = *(bool *)data; - if(argc) { - res = row_extractor().extract(argv[0]); - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return result; - } - -#endif - void on_open_internal(sqlite3 *db) { - -#if SQLITE_VERSION_NUMBER >= 3006019 - if(this->cachedForeignKeysCount) { - this->foreign_keys(db, true); - } -#endif - if(this->pragma._synchronous != -1) { - this->pragma.synchronous(this->pragma._synchronous); - } - - if(this->pragma._journal_mode != -1) { - this->pragma.set_pragma("journal_mode", static_cast(this->pragma._journal_mode), db); - } - - for(auto &p: this->collatingFunctions) { - if(sqlite3_create_collation(db, p.first.c_str(), SQLITE_UTF8, &p.second, collate_callback) != - SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - for(auto &p: this->limit.limits) { - sqlite3_limit(db, p.first, p.second); - } - - if(_busy_handler) { - sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); - } - - if(this->on_open) { - this->on_open(db); - } - } - - void begin_transaction(sqlite3 *db) { - std::stringstream ss; - ss << "BEGIN TRANSACTION"; - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - void commit(sqlite3 *db) { - std::stringstream ss; - ss << "COMMIT"; - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - void rollback(sqlite3 *db) { - std::stringstream ss; - ss << "ROLLBACK"; - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - std::string current_timestamp(sqlite3 *db) { - std::string result; - std::stringstream ss; - ss << "SELECT CURRENT_TIMESTAMP"; - auto query = ss.str(); - auto rc = sqlite3_exec( - db, - query.c_str(), - [](void *data, int argc, char **argv, char **) -> int { - auto &res = *(std::string *)data; - if(argc) { - if(argv[0]) { - res = row_extractor().extract(argv[0]); - } - } - return 0; - }, - &result, - nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return result; - } - - void drop_table_internal(const std::string &tableName, sqlite3 *db) { - std::stringstream ss; - ss << "DROP TABLE '" << tableName + "'"; - this->perform_query_without_result(ss.str(), db); - } - - void perform_query_without_result(const std::string &query, sqlite3 *db) { - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - static int collate_callback(void *arg, int leftLen, const void *lhs, int rightLen, const void *rhs) { - auto &f = *(collating_function *)arg; - return f(leftLen, lhs, rightLen, rhs); - } - - static int busy_handler_callback(void *selfPointer, int triesCount) { - auto &storage = *static_cast(selfPointer); - if(storage._busy_handler) { - return storage._busy_handler(triesCount); - } else { - return 0; - } - } - - // returns foreign keys count in storage definition - template - static int foreign_keys_count(T &storageImpl) { - auto res = 0; - storageImpl.for_each([&res](auto &impl) { - res += impl.foreign_keys_count(); - }); - return res; - } - }; - } -} - -// #include "prepared_statement.h" - -// #include "expression_object_type.h" - -#include // std::decay -#include // std::reference_wrapper - -// #include "prepared_statement.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct expression_object_type; - - template - struct expression_object_type> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type>> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type>> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type>> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type> { - using type = typename std::decay::type; - }; - - template - struct expression_object_type, Cols...>> { - using type = typename std::decay::type; - }; - - template - struct get_ref_t { - - template - auto &operator()(O &t) const { - return t; - } - }; - - template - struct get_ref_t> { - - template - auto &operator()(O &t) const { - return t.get(); - } - }; - - template - auto &get_ref(T &t) { - using arg_type = typename std::decay::type; - get_ref_t g; - return g(t); - } - - template - struct get_object_t; - - template - struct get_object_t : get_object_t {}; - - template - auto &get_object(T &t) { - using expression_type = typename std::decay::type; - get_object_t obj; - return obj(t); - } - - template - struct get_object_t> { - using expression_type = replace_t; - - template - auto &operator()(O &e) const { - return get_ref(e.obj); - } - }; - - template - struct get_object_t> { - using expression_type = insert_t; - - template - auto &operator()(O &e) const { - return get_ref(e.obj); - } - }; - - template - struct get_object_t> { - using expression_type = update_t; - - template - auto &operator()(O &e) const { - return get_ref(e.obj); - } - }; - } -} - -// #include "statement_serializator.h" - -#include // std::stringstream -#include // std::string -#include // std::enable_if -#include // std::vector -#include // std::iter_swap - -// #include "core_functions.h" - -// #include "constraints.h" - -// #include "conditions.h" - -// #include "column.h" - -// #include "rowid.h" - -// #include "type_printer.h" - -// #include "table_name_collector.h" - -#include // std::set -#include // std::string -#include // std::function -#include // std::type_index - -// #include "select_constraints.h" - -// #include "alias.h" - -// #include "core_functions.h" - -namespace sqlite_orm { - - namespace internal { - - struct table_name_collector { - using table_name_set = std::set>; - using find_table_name_t = std::function; - - find_table_name_t find_table_name; - mutable table_name_set table_names; - - template - table_name_set operator()(const T &) const { - return {}; - } - - template - void operator()(F O::*, std::string alias = {}) const { - if(this->find_table_name) { - table_names.insert(std::make_pair(this->find_table_name(typeid(O)), move(alias))); - } - } - - template - void operator()(const column_pointer &) const { - if(this->find_table_name) { - table_names.insert({this->find_table_name(typeid(T)), ""}); - } - } - - template - void operator()(const alias_column_t &a) const { - (*this)(a.column, alias_extractor::get()); - } - - template - void operator()(const count_asterisk_t &) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - if(!tableName.empty()) { - table_names.insert(std::make_pair(move(tableName), "")); - } - } - } - - template - void operator()(const asterisk_t &) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } - - template - void operator()(const object_t &) const { - if(this->find_table_name) { - auto tableName = this->find_table_name(typeid(T)); - table_names.insert(std::make_pair(move(tableName), "")); - } - } - }; - - } - -} - -// #include "column_names_getter.h" - -#include // std::string -#include // std::vector -#include // std::reference_wrapper - -// #include "error_code.h" - -// #include "select_constraints.h" - -namespace sqlite_orm { - - namespace internal { - - template - std::string serialize(const T &t, const C &context); - - template - struct column_names_getter { - using expression_type = T; - - template - std::vector operator()(const expression_type &t, const C &context) { - auto newContext = context; - newContext.skip_table_name = false; - auto columnName = serialize(t, newContext); - if(columnName.length()) { - return {move(columnName)}; - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - } - }; - - template - std::vector get_column_names(const T &t, const C &context) { - column_names_getter serializator; - return serializator(t, context); - } - - template - struct column_names_getter, void> { - using expression_type = std::reference_wrapper; - - template - std::vector operator()(const expression_type &expression, const C &context) { - return get_column_names(expression.get(), context); - } - }; - - template - struct column_names_getter, void> { - using expression_type = asterisk_t; - - template - std::vector operator()(const expression_type &, const C &) { - std::vector res; - res.push_back("*"); - return res; - } - }; - - template - struct column_names_getter, void> { - using expression_type = object_t; - - template - std::vector operator()(const expression_type &, const C &) { - std::vector res; - res.push_back("*"); - return res; - } - }; - - template - struct column_names_getter, void> { - using expression_type = columns_t; - - template - std::vector operator()(const expression_type &cols, const C &context) { - std::vector columnNames; - columnNames.reserve(static_cast(cols.count)); - auto newContext = context; - newContext.skip_table_name = false; - iterate_tuple(cols.columns, [&columnNames, &newContext](auto &m) { - auto columnName = serialize(m, newContext); - if(columnName.length()) { - columnNames.push_back(columnName); - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - }); - return columnNames; - } - }; - - } -} - -// #include "order_by_serializator.h" - -#include // std::string -#include // std::vector -#include // std::stringstream - -namespace sqlite_orm { - - namespace internal { - - template - struct order_by_serializator; - - template - std::string serialize_order_by(const T &t, const C &context) { - order_by_serializator serializator; - return serializator(t, context); - } - - template - struct order_by_serializator, void> { - using statement_type = order_by_t; - - template - std::string operator()(const statement_type &orderBy, const C &context) const { - std::stringstream ss; - auto newContext = context; - newContext.skip_table_name = false; - auto columnName = serialize(orderBy.o, newContext); - ss << columnName << " "; - if(orderBy._collate_argument.length()) { - ss << "COLLATE " << orderBy._collate_argument << " "; - } - switch(orderBy.asc_desc) { - case 1: - ss << "ASC"; - break; - case -1: - ss << "DESC"; - break; - } - return ss.str(); - } - }; - - template - struct order_by_serializator, void> { - using statement_type = dynamic_order_by_t; - - template - std::string operator()(const statement_type &orderBy, const C &) const { - std::vector expressions; - for(auto &entry: orderBy) { - std::string entryString; - { - std::stringstream ss; - ss << entry.name << " "; - if(!entry._collate_argument.empty()) { - ss << "COLLATE " << entry._collate_argument << " "; - } - switch(entry.asc_desc) { - case 1: - ss << "ASC"; - break; - case -1: - ss << "DESC"; - break; - } - entryString = ss.str(); - } - expressions.push_back(move(entryString)); - }; - std::stringstream ss; - ss << static_cast(orderBy) << " "; - for(size_t i = 0; i < expressions.size(); ++i) { - ss << expressions[i]; - if(i < expressions.size() - 1) { - ss << ", "; - } - } - ss << " "; - return ss.str(); - } - }; - - } -} - -// #include "values.h" - -// #include "table_type.h" - -// #include "indexed_column.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct statement_serializator; - - template - std::string serialize(const T &t, const C &context) { - statement_serializator serializator; - return serializator(t, context); - } - - template - struct statement_serializator::value>::type> { - using statement_type = T; - - template - std::string operator()(const statement_type &statement, const C &context) { - if(context.replace_bindable_with_question) { - return "?"; - } else { - return field_printer{}(statement); - } - } - }; - - template - struct statement_serializator, void> { - using statement_type = std::reference_wrapper; - - template - std::string operator()(const statement_type &s, const C &context) { - return serialize(s.get(), context); - } - }; - - template<> - struct statement_serializator { - using statement_type = std::nullptr_t; - - template - std::string operator()(const statement_type &, const C &) { - return "?"; - } - }; - - template - struct statement_serializator, void> { - using statement_type = alias_holder; - - template - std::string operator()(const statement_type &, const C &) { - return T::get(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = core_function_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << "("; - std::vector args; - using args_type = typename std::decay::type::args_type; - args.reserve(std::tuple_size::value); - iterate_tuple(c.args, [&args, &context](auto &v) { - args.push_back(serialize(v, context)); - }); - for(size_t i = 0; i < args.size(); ++i) { - ss << args[i]; - if(i < args.size() - 1) { - ss << ", "; - } - } - ss << ")"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = as_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto tableAliasString = alias_extractor::get(); - return serialize(c.expression, context) + " AS " + tableAliasString; - } - }; - - template - struct statement_serializator, void> { - using statement_type = alias_column_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "'" << T::get() << "'."; - } - auto newContext = context; - newContext.skip_table_name = true; - ss << serialize(c.column, newContext); - return ss.str(); - } - }; - - template<> - struct statement_serializator { - using statement_type = std::string; - - template - std::string operator()(const statement_type &c, const C &context) const { - if(context.replace_bindable_with_question) { - return "?"; - } else { - return "\"" + c + "\""; - } - } - }; - - template<> - struct statement_serializator { - using statement_type = const char *; - - template - std::string operator()(const char *c, const C &context) const { - if(context.replace_bindable_with_question) { - return "?"; - } else { - return std::string("'") + c + "'"; - } - } - }; - - template - struct statement_serializator { - using statement_type = F O::*; - - template - std::string operator()(const statement_type &m, const C &context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "\"" << context.impl.find_table_name(typeid(O)) << "\"."; - } - ss << "\"" << context.column_name(m) << "\""; - return ss.str(); - } - }; - - template<> - struct statement_serializator { - using statement_type = rowid_t; - - template - std::string operator()(const statement_type &s, const C &) { - return static_cast(s); - } - }; - - template<> - struct statement_serializator { - using statement_type = oid_t; - - template - std::string operator()(const statement_type &s, const C &) { - return static_cast(s); - } - }; - - template<> - struct statement_serializator<_rowid_t, void> { - using statement_type = _rowid_t; - - template - std::string operator()(const statement_type &s, const C &) { - return static_cast(s); - } - }; - - template - struct statement_serializator, void> { - using statement_type = table_rowid_t; - - template - std::string operator()(const statement_type &s, const C &context) { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; - } - ss << static_cast(s); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = table_oid_t; - - template - std::string operator()(const statement_type &s, const C &context) { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; - } - ss << static_cast(s); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = table__rowid_t; - - template - std::string operator()(const statement_type &s, const C &context) { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(O)) << "'."; - } - ss << static_cast(s); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = binary_operator; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto lhs = serialize(c.lhs, context); - auto rhs = serialize(c.rhs, context); - std::stringstream ss; - ss << "(" << lhs << " " << static_cast(c) << " " << rhs << ")"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = count_asterisk_t; - - template - std::string operator()(const statement_type &, const C &context) const { - return serialize(count_asterisk_without_type{}, context); - } - }; - - template<> - struct statement_serializator { - using statement_type = count_asterisk_without_type; - - template - std::string operator()(const statement_type &c, const C &) const { - std::stringstream ss; - ss << static_cast(c) << "(*)"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = distinct_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - auto expr = serialize(c.t, context); - ss << static_cast(c) << "(" << expr << ")"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = all_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - auto expr = serialize(c.t, context); - ss << static_cast(c) << "(" << expr << ")"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = column_pointer; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << "'" << context.impl.find_table_name(typeid(T)) << "'."; - } - ss << "\"" << context.impl.column_name_simple(c.field) << "\""; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = cast_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << " ("; - ss << serialize(c.expression, context) << " AS " << type_printer().print() << ")"; - return ss.str(); - } - }; - - template - struct statement_serializator::value>::type> { - using statement_type = T; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << serialize(c.left, context) << " "; - ss << static_cast(c) << " "; - ss << serialize(c.right, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = simple_case_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << "CASE "; - c.case_expression.apply([&ss, context](auto &c_) { - ss << serialize(c_, context) << " "; - }); - iterate_tuple(c.args, [&ss, context](auto &pair) { - ss << "WHEN " << serialize(pair.first, context) << " "; - ss << "THEN " << serialize(pair.second, context) << " "; - }); - c.else_expression.apply([&ss, context](auto &el) { - ss << "ELSE " << serialize(el, context) << " "; - }); - ss << "END"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = is_null_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << serialize(c.t, context) << " " << static_cast(c); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = is_not_null_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << serialize(c.t, context) << " " << static_cast(c); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = bitwise_not_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << " "; - auto cString = serialize(c.argument, context); - ss << " (" << cString << " )"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = negated_condition_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << " "; - auto cString = serialize(c.c, context); - ss << " (" << cString << " )"; - return ss.str(); - } - }; - - template - struct statement_serializator::value>::type> { - using statement_type = T; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto leftString = serialize(c.l, context); - auto rightString = serialize(c.r, context); - std::stringstream ss; - if(context.use_parentheses) { - ss << "("; - } - ss << leftString << " " << static_cast(c) << " " << rightString; - if(context.use_parentheses) { - ss << ")"; - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = named_collate; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto newContext = context; - newContext.use_parentheses = false; - auto res = serialize(c.expr, newContext); - return res + " " + static_cast(c); - } - }; - - template - struct statement_serializator, void> { - using statement_type = collate_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto newContext = context; - newContext.use_parentheses = false; - auto res = serialize(c.expr, newContext); - return res + " " + static_cast(c); - } - }; - - template - struct statement_serializator, void> { - using statement_type = in_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - auto leftString = serialize(c.l, context); - ss << leftString << " " << static_cast(c) << " "; - auto newContext = context; - newContext.use_parentheses = true; - ss << serialize(c.arg, newContext); - return ss.str(); - } - }; - - template - struct statement_serializator>, void> { - using statement_type = in_t>; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - auto leftString = serialize(c.l, context); - ss << leftString << " " << static_cast(c) << " ( "; - for(size_t index = 0; index < c.arg.size(); ++index) { - auto &value = c.arg[index]; - ss << " " << serialize(value, context); - if(index < c.arg.size() - 1) { - ss << ", "; - } - } - ss << " )"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = like_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << serialize(c.arg, context) << " "; - ss << static_cast(c) << " "; - ss << serialize(c.pattern, context); - c.arg3.apply([&ss, &context](auto &value) { - ss << " ESCAPE " << serialize(value, context); - }); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = glob_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << serialize(c.arg, context) << " "; - ss << static_cast(c) << " "; - ss << serialize(c.pattern, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = between_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - auto expr = serialize(c.expr, context); - ss << expr << " " << static_cast(c) << " "; - ss << serialize(c.b1, context); - ss << " AND "; - ss << serialize(c.b2, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = exists_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << " "; - ss << serialize(c.t, context); - return ss.str(); - } - }; - - template<> - struct statement_serializator { - using statement_type = constraints::autoincrement_t; - - template - std::string operator()(const statement_type &c, const C &) const { - return static_cast(c); - } - }; - - template - struct statement_serializator, void> { - using statement_type = constraints::primary_key_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto res = static_cast(c); - using columns_tuple = typename statement_type::columns_tuple; - auto columnsCount = std::tuple_size::value; - if(columnsCount) { - res += "("; - decltype(columnsCount) columnIndex = 0; - iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto &column) { - res += context.column_name(column); - if(columnIndex < columnsCount - 1) { - res += ", "; - } - ++columnIndex; - }); - res += ")"; - } - return res; - } - }; - - template - struct statement_serializator, void> { - using statement_type = constraints::unique_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - auto res = static_cast(c); - using columns_tuple = typename statement_type::columns_tuple; - auto columnsCount = std::tuple_size::value; - if(columnsCount) { - res += "("; - decltype(columnsCount) columnIndex = 0; - iterate_tuple(c.columns, [&context, &res, &columnIndex, columnsCount](auto &column) { - res += context.column_name(column); - if(columnIndex < columnsCount - 1) { - res += ", "; - } - ++columnIndex; - }); - res += ")"; - } - return res; - } - }; - - template<> - struct statement_serializator { - using statement_type = constraints::collate_t; - - template - std::string operator()(const statement_type &c, const C &) const { - return static_cast(c); - } - }; - - template - struct statement_serializator, void> { - using statement_type = constraints::default_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - return static_cast(c) + " (" + serialize(c.value, context) + ")"; - } - }; - - template - struct statement_serializator, std::tuple>, void> { - using statement_type = constraints::foreign_key_t, std::tuple>; - - template - std::string operator()(const statement_type &fk, const C &context) const { - std::stringstream ss; - std::vector columnNames; - using columns_type_t = typename std::decay::type::columns_type; - constexpr const size_t columnsCount = std::tuple_size::value; - columnNames.reserve(columnsCount); - iterate_tuple(fk.columns, [&columnNames, &context](auto &v) { - columnNames.push_back(context.impl.column_name(v)); - }); - ss << "FOREIGN KEY("; - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "'" << columnNames[i] << "'"; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - ss << ") REFERENCES "; - std::vector referencesNames; - using references_type_t = typename std::decay::type::references_type; - constexpr const size_t referencesCount = std::tuple_size::value; - referencesNames.reserve(referencesCount); - { - using first_reference_t = typename std::tuple_element<0, references_type_t>::type; - using first_reference_mapped_type = typename internal::table_type::type; - auto refTableName = context.impl.find_table_name(typeid(first_reference_mapped_type)); - ss << '\'' << refTableName << '\''; - } - iterate_tuple(fk.references, [&referencesNames, &context](auto &v) { - referencesNames.push_back(context.impl.column_name(v)); - }); - ss << "("; - for(size_t i = 0; i < referencesNames.size(); ++i) { - ss << "'" << referencesNames[i] << "'"; - if(i < referencesNames.size() - 1) { - ss << ", "; - } - } - ss << ")"; - if(fk.on_update) { - ss << ' ' << static_cast(fk.on_update) << " " << fk.on_update._action; - } - if(fk.on_delete) { - ss << ' ' << static_cast(fk.on_delete) << " " << fk.on_delete._action; - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = constraints::check_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - return static_cast(c) + " " + serialize(c.expression, context); - } - }; - - template - struct statement_serializator, void> { - using statement_type = column_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << "'" << c.name << "' "; - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - using constraints_type = typename column_type::constraints_type; - ss << type_printer().print() << " "; - { - std::vector constraintsStrings; - constexpr const size_t constraintsCount = std::tuple_size::value; - constraintsStrings.reserve(constraintsCount); - int primaryKeyIndex = -1; - int autoincrementIndex = -1; - int tupleIndex = 0; - iterate_tuple( - c.constraints, - [&constraintsStrings, &primaryKeyIndex, &autoincrementIndex, &tupleIndex, &context](auto &v) { - using constraint_type = typename std::decay::type; - constraintsStrings.push_back(serialize(v, context)); - if(is_primary_key::value) { - primaryKeyIndex = tupleIndex; - } else if(std::is_same::value) { - autoincrementIndex = tupleIndex; - } - ++tupleIndex; - }); - if(primaryKeyIndex != -1 && autoincrementIndex != -1 && autoincrementIndex < primaryKeyIndex) { - iter_swap(constraintsStrings.begin() + primaryKeyIndex, - constraintsStrings.begin() + autoincrementIndex); - } - for(auto &str: constraintsStrings) { - ss << str << ' '; - } - } - if(c.not_null()) { - ss << "NOT NULL "; - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = remove_all_t; - - template - std::string operator()(const statement_type &rem, const C &context) const { - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "DELETE FROM '" << tImpl.table.name << "' "; - iterate_tuple(rem.conditions, [&context, &ss](auto &v) { - ss << serialize(v, context); - }); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = replace_t; - - template - std::string operator()(const statement_type &rep, const C &context) const { - using expression_type = typename std::decay::type; - using object_type = typename expression_object_type::type; - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "REPLACE INTO '" << tImpl.table.name << "' ("; - auto columnNames = tImpl.table.column_names(); - auto columnNamesCount = columnNames.size(); - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNamesCount - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - ss << "VALUES("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "?"; - if(i < columnNamesCount - 1) { - ss << ", "; - } else { - ss << ")"; - } - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = insert_explicit; - - template - std::string operator()(const statement_type &ins, const C &context) const { - constexpr const size_t colsCount = std::tuple_size>::value; - static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); - using expression_type = typename std::decay::type; - using object_type = typename expression_object_type::type; - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "INSERT INTO '" << tImpl.table.name << "' "; - std::vector columnNames; - columnNames.reserve(colsCount); - { - auto columnsContext = context; - columnsContext.skip_table_name = true; - iterate_tuple(ins.columns.columns, [&columnNames, &columnsContext](auto &m) { - auto columnName = serialize(m, columnsContext); - if(!columnName.empty()) { - columnNames.push_back(columnName); - } else { - throw std::system_error(std::make_error_code(orm_error_code::column_not_found)); - } - }); - } - ss << "("; - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - ss << "VALUES ("; - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "?"; - if(i < columnNames.size() - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = update_t; - - template - std::string operator()(const statement_type &upd, const C &context) const { - using expression_type = typename std::decay::type; - using object_type = typename expression_object_type::type; - auto &tImpl = context.impl.template get_impl(); - - std::stringstream ss; - ss << "UPDATE '" << tImpl.table.name << "' SET "; - std::vector setColumnNames; - tImpl.table.for_each_column([&setColumnNames](auto &c) { - if(!c.template has>()) { - setColumnNames.emplace_back(c.name); - } - }); - for(size_t i = 0; i < setColumnNames.size(); ++i) { - ss << "\"" << setColumnNames[i] << "\"" - << " = ?"; - if(i < setColumnNames.size() - 1) { - ss << ","; - } - ss << " "; - } - ss << "WHERE "; - auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); - for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { - ss << "\"" << primaryKeyColumnNames[i] << "\"" - << " = ?"; - if(i < primaryKeyColumnNames.size() - 1) { - ss << " AND"; - } - ss << " "; - } - return ss.str(); - } - }; - - template - struct statement_serializator, Wargs...>, void> { - using statement_type = update_all_t, Wargs...>; - - template - std::string operator()(const statement_type &upd, const C &context) const { - std::stringstream ss; - ss << "UPDATE "; - table_name_collector collector{[&context](std::type_index ti) { - return context.impl.find_table_name(ti); - }}; - iterate_ast(upd.set.assigns, collector); - if(!collector.table_names.empty()) { - if(collector.table_names.size() == 1) { - ss << " '" << collector.table_names.begin()->first << "' "; - ss << static_cast(upd.set) << " "; - std::vector setPairs; - auto leftContext = context; - leftContext.skip_table_name = true; - iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto &asgn) { - std::stringstream sss; - sss << serialize(asgn.lhs, leftContext); - sss << " " << static_cast(asgn) << " "; - sss << serialize(asgn.rhs, context) << " "; - setPairs.push_back(sss.str()); - }); - auto setPairsCount = setPairs.size(); - for(size_t i = 0; i < setPairsCount; ++i) { - ss << setPairs[i] << " "; - if(i < setPairsCount - 1) { - ss << ", "; - } - } - iterate_tuple(upd.conditions, [&context, &ss](auto &v) { - ss << serialize(v, context); - }); - return ss.str(); - } else { - throw std::system_error(std::make_error_code(orm_error_code::too_many_tables_specified)); - } - } else { - throw std::system_error(std::make_error_code(orm_error_code::incorrect_set_fields_specified)); - } - } - }; - - template - struct statement_serializator, void> { - using statement_type = insert_t; - - template - std::string operator()(const statement_type &, const C &context) const { - using object_type = typename expression_object_type::type; - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "INSERT INTO '" << tImpl.table.name << "' "; - std::vector columnNames; - auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names(); - - tImpl.table.for_each_column([&tImpl, &columnNames, &compositeKeyColumnNames](auto &c) { - if(tImpl.table._without_rowid || !c.template has>()) { - auto it = find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name); - if(it == compositeKeyColumnNames.end()) { - columnNames.emplace_back(c.name); - } - } - }); - - auto columnNamesCount = columnNames.size(); - if(columnNamesCount) { - ss << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNamesCount - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - } else { - ss << "DEFAULT "; - } - ss << "VALUES "; - if(columnNamesCount) { - ss << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "?"; - if(i < columnNamesCount - 1) { - ss << ", "; - } else { - ss << ")"; - } - } - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = remove_t; - - template - std::string operator()(const statement_type &, const C &context) const { - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "DELETE FROM '" << tImpl.table.name << "' "; - ss << "WHERE "; - auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); - for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { - ss << "\"" << primaryKeyColumnNames[i] << "\"" - << " = ? "; - if(i < primaryKeyColumnNames.size() - 1) { - ss << "AND "; - } - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = replace_range_t; - - template - std::string operator()(const statement_type &rep, const C &context) const { - using expression_type = typename std::decay::type; - using object_type = typename expression_type::object_type; - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "REPLACE INTO '" << tImpl.table.name << "' ("; - auto columnNames = tImpl.table.column_names(); - auto columnNamesCount = columnNames.size(); - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNamesCount - 1) { - ss << ", "; - } else { - ss << ") "; - } - } - ss << "VALUES "; - auto valuesString = [columnNamesCount] { - std::stringstream ss_; - ss_ << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss_ << "?"; - if(i < columnNamesCount - 1) { - ss_ << ", "; - } else { - ss_ << ")"; - } - } - return ss_.str(); - }(); - auto valuesCount = static_cast(std::distance(rep.range.first, rep.range.second)); - for(auto i = 0; i < valuesCount; ++i) { - ss << valuesString; - if(i < valuesCount - 1) { - ss << ","; - } - ss << " "; - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = insert_range_t; - - template - std::string operator()(const statement_type &statement, const C &context) const { - using expression_type = typename std::decay::type; - using object_type = typename expression_type::object_type; - auto &tImpl = context.impl.template get_impl(); - - std::stringstream ss; - ss << "INSERT INTO '" << tImpl.table.name << "' ("; - std::vector columnNames; - tImpl.table.for_each_column([&columnNames](auto &c) { - if(!c.template has>()) { - columnNames.emplace_back(c.name); - } - }); - - auto columnNamesCount = columnNames.size(); - for(size_t i = 0; i < columnNamesCount; ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNamesCount - 1) { - ss << ","; - } else { - ss << ")"; - } - ss << " "; - } - ss << "VALUES "; - auto valuesString = [columnNamesCount] { - std::stringstream ss_; - ss_ << "("; - for(size_t i = 0; i < columnNamesCount; ++i) { - ss_ << "?"; - if(i < columnNamesCount - 1) { - ss_ << ", "; - } else { - ss_ << ")"; - } - } - return ss_.str(); - }(); - auto valuesCount = static_cast(std::distance(statement.range.first, statement.range.second)); - for(auto i = 0; i < valuesCount; ++i) { - ss << valuesString; - if(i < valuesCount - 1) { - ss << ","; - } - ss << " "; - } - return ss.str(); - } - }; - - template - std::string serialize_get_all_impl(const T &get, const C &context) { - using primary_type = typename T::type; - - table_name_collector collector; - collector.table_names.insert( - std::make_pair(context.impl.find_table_name(typeid(primary_type)), std::string{})); - iterate_ast(get.conditions, collector); - std::stringstream ss; - ss << "SELECT "; - auto &tImpl = context.impl.template get_impl(); - auto columnNames = tImpl.table.column_names(); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "\"" << tImpl.table.name << "\"." - << "\"" << columnNames[i] << "\""; - if(i < columnNames.size() - 1) { - ss << ", "; - } else { - ss << " "; - } - } - ss << "FROM "; - std::vector> tableNames(collector.table_names.begin(), - collector.table_names.end()); - for(size_t i = 0; i < tableNames.size(); ++i) { - auto &tableNamePair = tableNames[i]; - ss << "'" << tableNamePair.first << "' "; - if(!tableNamePair.second.empty()) { - ss << tableNamePair.second << " "; - } - if(int(i) < int(tableNames.size()) - 1) { - ss << ","; - } - ss << " "; - } - iterate_tuple(get.conditions, [&context, &ss](auto &v) { - ss << serialize(v, context); - }); - return ss.str(); - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct statement_serializator, void> { - using statement_type = get_all_optional_t; - - template - std::string operator()(const statement_type &get, const C &context) const { - return serialize_get_all_impl(get, context); - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct statement_serializator, void> { - using statement_type = get_all_pointer_t; - - template - std::string operator()(const statement_type &get, const C &context) const { - return serialize_get_all_impl(get, context); - } - }; - - template - struct statement_serializator, void> { - using statement_type = get_all_t; - - template - std::string operator()(const statement_type &get, const C &context) const { - return serialize_get_all_impl(get, context); - } - }; - - template - std::string serialize_get_impl(const T &, const C &context) { - using primary_type = typename T::type; - auto &tImpl = context.impl.template get_impl(); - std::stringstream ss; - ss << "SELECT "; - auto columnNames = tImpl.table.column_names(); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "\"" << columnNames[i] << "\""; - if(i < columnNames.size() - 1) { - ss << ","; - } - ss << " "; - } - ss << "FROM '" << tImpl.table.name << "' WHERE "; - auto primaryKeyColumnNames = tImpl.table.primary_key_column_names(); - if(!primaryKeyColumnNames.empty()) { - for(size_t i = 0; i < primaryKeyColumnNames.size(); ++i) { - ss << "\"" << primaryKeyColumnNames[i] << "\"" - << " = ? "; - if(i < primaryKeyColumnNames.size() - 1) { - ss << "AND"; - } - ss << ' '; - } - return ss.str(); - } else { - throw std::system_error(std::make_error_code(orm_error_code::table_has_no_primary_key_column)); - } - } - - template - struct statement_serializator, void> { - using statement_type = get_t; - - template - std::string operator()(const statement_type &get, const C &context) const { - return serialize_get_impl(get, context); - } - }; - - template - struct statement_serializator, void> { - using statement_type = get_pointer_t; - - template - std::string operator()(const statement_type &get, const C &context) const { - return serialize_get_impl(get, context); - } - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct statement_serializator, void> { - using statement_type = get_optional_t; - - template - std::string operator()(const statement_type &get, const C &context) const { - return serialize_get_impl(get, context); - } - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct statement_serializator, void> { - using statement_type = select_t; - - template - std::string operator()(const statement_type &sel, const C &context) const { - std::stringstream ss; - if(!is_base_of_template::value) { - if(!sel.highest_level) { - ss << "( "; - } - ss << "SELECT "; - } - if(get_distinct(sel.col)) { - ss << static_cast(distinct(0)) << " "; - } - auto columnNames = get_column_names(sel.col, context); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ","; - } - ss << " "; - } - table_name_collector collector{[&context](std::type_index ti) { - return context.impl.find_table_name(ti); - }}; - iterate_ast(sel.col, collector); - iterate_ast(sel.conditions, collector); - internal::join_iterator()([&collector, &context](const auto &c) { - using original_join_type = typename std::decay::type::join_type::type; - using cross_join_type = typename internal::mapped_type_proxy::type; - auto crossJoinedTableName = context.impl.find_table_name(typeid(cross_join_type)); - auto tableAliasString = alias_extractor::get(); - std::pair tableNameWithAlias(std::move(crossJoinedTableName), - std::move(tableAliasString)); - collector.table_names.erase(tableNameWithAlias); - }); - if(!collector.table_names.empty()) { - ss << "FROM "; - std::vector> tableNames(collector.table_names.begin(), - collector.table_names.end()); - for(size_t i = 0; i < tableNames.size(); ++i) { - auto &tableNamePair = tableNames[i]; - ss << "'" << tableNamePair.first << "' "; - if(!tableNamePair.second.empty()) { - ss << tableNamePair.second << " "; - } - if(int(i) < int(tableNames.size()) - 1) { - ss << ","; - } - ss << " "; - } - } - iterate_tuple(sel.conditions, [&context, &ss](auto &v) { - ss << serialize(v, context); - }); - if(!is_base_of_template::value) { - if(!sel.highest_level) { - ss << ") "; - } - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = indexed_column_t; - - template - std::string operator()(const statement_type &statement, const C &context) const { - std::stringstream ss; - ss << serialize(statement.column_or_expression, context); - if(!statement._collation_name.empty()) { - ss << " COLLATE " << statement._collation_name; - } - if(statement._order) { - switch(statement._order) { - case -1: - ss << " DESC"; - break; - case 1: - ss << " ASC"; - break; - default: - throw std::system_error(std::make_error_code(orm_error_code::incorrect_order)); - } - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = index_t; - - template - std::string operator()(const statement_type &statement, const C &context) const { - std::stringstream ss; - ss << "CREATE "; - if(statement.unique) { - ss << "UNIQUE "; - } - using columns_type = typename std::decay::type::columns_type; - using head_t = typename std::tuple_element<0, columns_type>::type::column_type; - using indexed_type = typename table_type::type; - ss << "INDEX IF NOT EXISTS '" << statement.name << "' ON '" - << context.impl.find_table_name(typeid(indexed_type)) << "' ("; - std::vector columnNames; - iterate_tuple(statement.columns, [&columnNames, &context](auto &v) { - columnNames.push_back(context.column_name(v.column_or_expression)); - }); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << "'" << columnNames[i] << "'"; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - ss << ")"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = where_t; - - template - std::string operator()(const statement_type &w, const C &context) const { - std::stringstream ss; - ss << static_cast(w) << " "; - auto whereString = serialize(w.c, context); - ss << "( " << whereString << ") "; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = order_by_t; - - template - std::string operator()(const statement_type &orderBy, const C &context) const { - std::stringstream ss; - ss << static_cast(orderBy) << " "; - auto orderByString = serialize_order_by(orderBy, context); - ss << orderByString << " "; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = dynamic_order_by_t; - - template - std::string operator()(const statement_type &orderBy, const CC &context) const { - return serialize_order_by(orderBy, context); - } - }; - - template - struct statement_serializator, void> { - using statement_type = multi_order_by_t; - - template - std::string operator()(const statement_type &orderBy, const C &context) const { - std::stringstream ss; - std::vector expressions; - iterate_tuple(orderBy.args, [&expressions, &context](auto &v) { - auto expression = serialize_order_by(v, context); - expressions.push_back(move(expression)); - }); - ss << static_cast(orderBy) << " "; - for(size_t i = 0; i < expressions.size(); ++i) { - ss << expressions[i]; - if(i < expressions.size() - 1) { - ss << ", "; - } - } - ss << " "; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = cross_join_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << " "; - ss << " '" << context.impl.find_table_name(typeid(O)) << "'"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = inner_join_t; - - template - std::string operator()(const statement_type &l, const C &context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - auto aliasString = alias_extractor::get(); - ss << " '" << context.impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; - if(aliasString.length()) { - ss << "'" << aliasString << "' "; - } - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = on_t; - - template - std::string operator()(const statement_type &t, const C &context) const { - std::stringstream ss; - auto newContext = context; - newContext.skip_table_name = false; - ss << static_cast(t) << " " << serialize(t.arg, newContext) << " "; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = join_t; - - template - std::string operator()(const statement_type &l, const C &context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - ss << " '" << context.impl.find_table_name(typeid(T)) << "' "; - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = left_join_t; - - template - std::string operator()(const statement_type &l, const C &context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - ss << " '" << context.impl.find_table_name(typeid(T)) << "' "; - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = left_outer_join_t; - - template - std::string operator()(const statement_type &l, const C &context) const { - std::stringstream ss; - ss << static_cast(l) << " "; - ss << " '" << context.impl.find_table_name(typeid(T)) << "' "; - ss << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = natural_join_t; - - template - std::string operator()(const statement_type &c, const C &context) const { - std::stringstream ss; - ss << static_cast(c) << " "; - ss << " '" << context.impl.find_table_name(typeid(O)) << "'"; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = group_by_t; - - template - std::string operator()(const statement_type &groupBy, const C &context) const { - std::stringstream ss; - std::vector expressions; - auto newContext = context; - newContext.skip_table_name = false; - iterate_tuple(groupBy.args, [&expressions, &newContext](auto &v) { - auto expression = serialize(v, newContext); - expressions.push_back(expression); - }); - ss << static_cast(groupBy) << " "; - for(size_t i = 0; i < expressions.size(); ++i) { - ss << expressions[i]; - if(i < expressions.size() - 1) { - ss << ", "; - } - } - ss << " "; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = having_t; - - template - std::string operator()(const statement_type &hav, const C &context) const { - std::stringstream ss; - auto newContext = context; - newContext.skip_table_name = false; - ss << static_cast(hav) << " "; - ss << serialize(hav.t, newContext) << " "; - return ss.str(); - } - }; - - /** - * HO - has offset - * OI - offset is implicit - */ - template - struct statement_serializator, void> { - using statement_type = limit_t; - - template - std::string operator()(const statement_type &limt, const C &context) const { - auto newContext = context; - newContext.skip_table_name = false; - std::stringstream ss; - ss << static_cast(limt) << " "; - if(HO) { - if(OI) { - limt.off.apply([&newContext, &ss](auto &value) { - ss << serialize(value, newContext); - }); - ss << ", "; - ss << serialize(limt.lim, newContext); - } else { - ss << serialize(limt.lim, newContext) << " OFFSET "; - limt.off.apply([&newContext, &ss](auto &value) { - ss << serialize(value, newContext); - }); - } - } else { - ss << serialize(limt.lim, newContext); - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = using_t; - - template - std::string operator()(const statement_type &statement, const C &context) const { - auto newContext = context; - newContext.skip_table_name = true; - return static_cast(statement) + " (" + serialize(statement.column, newContext) + " )"; - } - }; - - template - struct statement_serializator, void> { - using statement_type = std::tuple; - - template - std::string operator()(const statement_type &statement, const C &context) const { - std::stringstream ss; - ss << '('; - auto index = 0; - using TupleSize = std::tuple_size; - iterate_tuple(statement, [&context, &index, &ss](auto &value) { - ss << serialize(value, context); - if(index < TupleSize::value - 1) { - ss << ", "; - } - ++index; - }); - ss << ')'; - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = values_t; - - template - std::string operator()(const statement_type &statement, const C &context) const { - std::stringstream ss; - if(context.use_parentheses) { - ss << '('; - } - ss << "VALUES "; - { - auto index = 0; - auto &tuple = statement.tuple; - using tuple_type = typename std::decay::type; - using TupleSize = std::tuple_size; - iterate_tuple(tuple, [&context, &index, &ss](auto &value) { - ss << serialize(value, context); - if(index < TupleSize::value - 1) { - ss << ", "; - } - ++index; - }); - } - if(context.use_parentheses) { - ss << ')'; - } - return ss.str(); - } - }; - - template - struct statement_serializator, void> { - using statement_type = dynamic_values_t; - - template - std::string operator()(const statement_type &statement, const C &context) const { - std::stringstream ss; - if(context.use_parentheses) { - ss << '('; - } - ss << "VALUES "; - { - auto vectorSize = statement.vector.size(); - for(decltype(vectorSize) index = 0; index < vectorSize; ++index) { - auto &value = statement.vector[index]; - ss << serialize(value, context); - if(index < vectorSize - 1) { - ss << ", "; - } - } - } - if(context.use_parentheses) { - ss << ')'; - } - return ss.str(); - } - }; - - } -} - -// #include "table_name_collector.h" - -// #include "object_from_column_builder.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * Storage class itself. Create an instanse to use it as an interfacto to sqlite db by calling `make_storage` - * function. - */ - template - struct storage_t : storage_base { - using self = storage_t; - using impl_type = storage_impl; - - /** - * @param filename database filename. - * @param impl_ storage_impl head - */ - storage_t(const std::string &filename, impl_type impl_) : - storage_base{filename, foreign_keys_count(impl_)}, impl(std::move(impl_)) {} - - storage_t(const storage_t &other) : storage_base(other), impl(other.impl) {} - - protected: - impl_type impl; - - template - friend struct view_t; - - template - friend struct dynamic_order_by_t; - - template - friend struct iterator_t; - - template - friend struct serializator_context_builder; - - template - void create_table(sqlite3 *db, const std::string &tableName, const I &tableImpl) { - std::stringstream ss; - ss << "CREATE TABLE '" << tableName << "' ( "; - auto columnsCount = tableImpl.table.columns_count; - auto index = 0; - using context_t = serializator_context; - context_t context{this->impl}; - iterate_tuple(tableImpl.table.columns, [columnsCount, &index, &ss, &context](auto &c) { - ss << serialize(c, context); - if(index < columnsCount - 1) { - ss << ", "; - } - index++; - }); - ss << ") "; - if(tableImpl.table._without_rowid) { - ss << "WITHOUT ROWID "; - } - auto query = ss.str(); - sqlite3_stmt *stmt; - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - statement_finalizer finalizer{stmt}; - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - void backup_table(sqlite3 *db, const I &tableImpl, const std::vector &columnsToIgnore) { - - // here we copy source table to another with a name with '_backup' suffix, but in case table with such - // a name already exists we append suffix 1, then 2, etc until we find a free name.. - auto backupTableName = tableImpl.table.name + "_backup"; - if(tableImpl.table_exists(backupTableName, db)) { - int suffix = 1; - do { - std::stringstream stream; - stream << suffix; - auto anotherBackupTableName = backupTableName + stream.str(); - if(!tableImpl.table_exists(anotherBackupTableName, db)) { - backupTableName = anotherBackupTableName; - break; - } - ++suffix; - } while(true); - } - - this->create_table(db, backupTableName, tableImpl); - - tableImpl.copy_table(db, backupTableName, columnsToIgnore); - - this->drop_table_internal(tableImpl.table.name, db); - - tableImpl.rename_table(db, backupTableName, tableImpl.table.name); - } - - template - void assert_mapped_type() const { - using mapped_types_tuples = std::tuple; - static_assert(tuple_helper::has_type::value, "type is not mapped to a storage"); - } - - template - auto &get_impl() const { - return this->impl.template get_impl(); - } - - template - auto &get_impl() { - return this->impl.template get_impl(); - } - - public: - template - view_t iterate(Args &&... args) { - this->assert_mapped_type(); - - auto con = this->get_connection(); - return {*this, std::move(con), std::forward(args)...}; - } - - /** - * Delete from routine. - * O is an object's type. Must be specified explicitly. - * @param args optional conditions: `where`, `join` etc - * @example: storage.remove_all(); - DELETE FROM users - * @example: storage.remove_all(where(in(&User::id, {5, 6, 7}))); - DELETE FROM users WHERE id IN (5, 6, 7) - */ - template - void remove_all(Args &&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::remove_all(std::forward(args)...)); - this->execute(statement); - } - - /** - * Delete routine. - * O is an object's type. Must be specified explicitly. - * @param ids ids of object to be removed. - */ - template - void remove(Ids... ids) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::remove(std::forward(ids)...)); - this->execute(statement); - } - - /** - * Update routine. Sets all non primary key fields where primary key is equal. - * O is an object type. May be not specified explicitly cause it can be deduced by - * compiler from first parameter. - * @param o object to be updated. - */ - template - void update(const O &o) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::update(std::ref(o))); - this->execute(statement); - } - - template - void update_all(internal::set_t set, Wargs... wh) { - auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); - this->execute(statement); - } - - protected: - template - std::string group_concat_internal(F O::*m, std::unique_ptr y, Args &&... args) { - this->assert_mapped_type(); - std::vector rows; - if(y) { - rows = this->select(sqlite_orm::group_concat(m, move(*y)), std::forward(args)...); - } else { - rows = this->select(sqlite_orm::group_concat(m), std::forward(args)...); - } - if(!rows.empty()) { - return move(rows.front()); - } else { - return {}; - } - } - - public: - /** - * SELECT * routine. - * O is an object type to be extracted. Must be specified explicitly. - * @return All objects of type O stored in database at the moment in `std::vector`. - * @note If you need to return the result in a different container type then use a different `get_all` function overload `get_all>` - * @example: storage.get_all() - SELECT * FROM users - * @example: storage.get_all(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id - */ - template - auto get_all(Args &&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); - return this->execute(statement); - } - - /** - * SELECT * routine. - * O is an object type to be extracted. Must be specified explicitly. - * R is an explicit return type. This type must have `push_back(O &&)` function. - * @return All objects of type O stored in database at the moment in `R`. - * @example: storage.get_all>(); - SELECT * FROM users - * @example: storage.get_all>(where(like(&User::name, "N%")), order_by(&User::id)); - SELECT * FROM users WHERE name LIKE 'N%' ORDER BY id - */ - template - auto get_all(Args &&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_all(std::forward(args)...)); - return this->execute(statement); - } - - /** - * SELECT * routine. - * O is an object type to be extracted. Must be specified explicitly. - * @return All objects of type O as `std::unique_ptr` inside a `std::vector` stored in database at the moment. - * @note If you need to return the result in a different container type then use a different `get_all_pointer` function overload `get_all_pointer>` - * @example: storage.get_all_pointer(); - SELECT * FROM users - * @example: storage.get_all_pointer(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 - */ - template - auto get_all_pointer(Args &&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_all_pointer(std::forward(args)...)); - return this->execute(statement); - } - - /** - * SELECT * routine. - * O is an object type to be extracted. Must be specified explicitly. - * R is a container type. std::vector> is default - * @return All objects of type O as std::unique_ptr stored in database at the moment. - * @example: storage.get_all_pointer>(); - SELECT * FROM users - * @example: storage.get_all_pointer>(where(length(&User::name) > 6)); - SELECT * FROM users WHERE LENGTH(name) > 6 - */ - template - auto get_all_pointer(Args &&... args) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_all_pointer(std::forward(args)...)); - return this->execute(statement); - } - - /** - * Select * by id routine. - * throws std::system_error(orm_error_code::not_found, orm_error_category) if object not found with given - * id. throws std::system_error with orm_error_category in case of db error. O is an object type to be - * extracted. Must be specified explicitly. - * @return Object of type O where id is equal parameter passed or throws - * `std::system_error(orm_error_code::not_found, orm_error_category)` if there is no object with such id. - */ - template - O get(Ids... ids) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get(std::forward(ids)...)); - return this->execute(statement); - } - - /** - * The same as `get` function but doesn't throw an exception if noting found but returns std::unique_ptr - * with null value. throws std::system_error in case of db error. - */ - template - std::unique_ptr get_pointer(Ids... ids) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_pointer(std::forward(ids)...)); - return this->execute(statement); - } - - /** - * A previous version of get_pointer() that returns a shared_ptr - * instead of a unique_ptr. New code should prefer get_pointer() - * unless the data needs to be shared. - * - * @note - * Most scenarios don't need shared ownership of data, so we should prefer - * unique_ptr when possible. It's more efficient, doesn't require atomic - * ops for a reference count (which can cause major slowdowns on - * weakly-ordered platforms like ARM), and can be easily promoted to a - * shared_ptr, exactly like we're doing here. - * (Conversely, you _can't_ go from shared back to unique.) - */ - template - std::shared_ptr get_no_throw(Ids... ids) { - return std::shared_ptr(get_pointer(std::forward(ids)...)); - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - /** - * The same as `get` function but doesn't throw an exception if noting found but - * returns an empty std::optional. throws std::system_error in case of db error. - */ - template - std::optional get_optional(Ids... ids) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::get_optional(std::forward(ids)...)); - return this->execute(statement); - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - /** - * SELECT COUNT(*) https://www.sqlite.org/lang_aggfunc.html#count - * @return Number of O object in table. - */ - template::type> - int count(Args &&... args) { - this->assert_mapped_type(); - auto rows = this->select(sqlite_orm::count(), std::forward(args)...); - if(!rows.empty()) { - return rows.front(); - } else { - return 0; - } - } - - /** - * SELECT COUNT(X) https://www.sqlite.org/lang_aggfunc.html#count - * @param m member pointer to class mapped to the storage. - */ - template - int count(F O::*m, Args &&... args) { - this->assert_mapped_type(); - auto rows = this->select(sqlite_orm::count(m), std::forward(args)...); - if(!rows.empty()) { - return rows.front(); - } else { - return 0; - } - } - - /** - * AVG(X) query. https://www.sqlite.org/lang_aggfunc.html#avg - * @param m is a class member pointer (the same you passed into make_column). - * @return average value from db. - */ - template - double avg(F O::*m, Args &&... args) { - this->assert_mapped_type(); - auto rows = this->select(sqlite_orm::avg(m), std::forward(args)...); - if(!rows.empty()) { - return rows.front(); - } else { - return 0; - } - } - - template - std::string group_concat(F O::*m) { - return this->group_concat_internal(m, {}); - } - - /** - * GROUP_CONCAT(X) query. https://www.sqlite.org/lang_aggfunc.html#groupconcat - * @param m is a class member pointer (the same you passed into make_column). - * @return group_concat query result. - */ - template, - typename sfinae = typename std::enable_if::value >= 1>::type> - std::string group_concat(F O::*m, Args &&... args) { - return this->group_concat_internal(m, {}, std::forward(args)...); - } - - /** - * GROUP_CONCAT(X, Y) query. https://www.sqlite.org/lang_aggfunc.html#groupconcat - * @param m is a class member pointer (the same you passed into make_column). - * @return group_concat query result. - */ - template - std::string group_concat(F O::*m, std::string y, Args &&... args) { - return this->group_concat_internal(m, - std::make_unique(move(y)), - std::forward(args)...); - } - - template - std::string group_concat(F O::*m, const char *y, Args &&... args) { - std::unique_ptr str; - if(y) { - str = std::make_unique(y); - } else { - str = std::make_unique(); - } - return this->group_concat_internal(m, move(str), std::forward(args)...); - } - - /** - * MAX(x) query. - * @param m is a class member pointer (the same you passed into make_column). - * @return std::unique_ptr with max value or null if sqlite engine returned null. - */ - template::type> - std::unique_ptr max(F O::*m, Args &&... args) { - this->assert_mapped_type(); - auto rows = this->select(sqlite_orm::max(m), std::forward(args)...); - if(!rows.empty()) { - return std::move(rows.front()); - } else { - return {}; - } - } - - /** - * MIN(x) query. - * @param m is a class member pointer (the same you passed into make_column). - * @return std::unique_ptr with min value or null if sqlite engine returned null. - */ - template::type> - std::unique_ptr min(F O::*m, Args &&... args) { - this->assert_mapped_type(); - auto rows = this->select(sqlite_orm::min(m), std::forward(args)...); - if(!rows.empty()) { - return std::move(rows.front()); - } else { - return {}; - } - } - - /** - * SUM(x) query. - * @param m is a class member pointer (the same you passed into make_column). - * @return std::unique_ptr with sum value or null if sqlite engine returned null. - */ - template::type> - std::unique_ptr sum(F O::*m, Args &&... args) { - this->assert_mapped_type(); - std::vector> rows = - this->select(sqlite_orm::sum(m), std::forward(args)...); - if(!rows.empty()) { - if(rows.front()) { - return std::make_unique(std::move(*rows.front())); - } else { - return {}; - } - } else { - return {}; - } - } - - /** - * TOTAL(x) query. - * @param m is a class member pointer (the same you passed into make_column). - * @return total value (the same as SUM but not nullable. More details here - * https://www.sqlite.org/lang_aggfunc.html) - */ - template - double total(F O::*m, Args &&... args) { - this->assert_mapped_type(); - auto rows = this->select(sqlite_orm::total(m), std::forward(args)...); - if(!rows.empty()) { - return std::move(rows.front()); - } else { - return {}; - } - } - - /** - * Select a single column into std::vector or multiple columns into std::vector>. - * For a single column use `auto rows = storage.select(&User::id, where(...)); - * For multicolumns use `auto rows = storage.select(columns(&User::id, &User::name), where(...)); - */ - template::type> - std::vector select(T m, Args... args) { - static_assert(!is_base_of_template::value || - std::tuple_size>::value == 0, - "Cannot use args with a compound operator"); - auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); - return this->execute(statement); - } - - template - typename std::enable_if::value, std::string>::type - dump(const T &preparedStatement) const { - using context_t = serializator_context; - context_t context{this->impl}; - return serialize(preparedStatement.t, context); - } - - /** - * Returns a string representation of object of a class mapped to the storage. - * Type of string has json-like style. - */ - template - typename std::enable_if::value, std::string>::type - dump(const O &o) { - auto &tImpl = this->get_impl(); - std::stringstream ss; - ss << "{ "; - using pair = std::pair; - std::vector pairs; - tImpl.table.for_each_column([&pairs, &o](auto &c) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - pair p{c.name, std::string()}; - if(c.member_pointer) { - p.second = field_printer()(o.*c.member_pointer); - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - p.second = field_printer()(valueHolder.value); - } - pairs.push_back(move(p)); - }); - for(size_t i = 0; i < pairs.size(); ++i) { - auto &p = pairs[i]; - ss << p.first << " : '" << p.second << "'"; - if(i < pairs.size() - 1) { - ss << ", "; - } else { - ss << " }"; - } - } - return ss.str(); - } - - /** - * This is REPLACE (INSERT OR REPLACE) function. - * Also if you need to insert value with knows id you should - * also you this function instead of insert cause inserts ignores - * id and creates own one. - */ - template - void replace(const O &o) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::replace(std::ref(o))); - this->execute(statement); - } - - template - void replace_range(It from, It to) { - using O = typename std::iterator_traits::value_type; - this->assert_mapped_type(); - if(from == to) { - return; - } - - auto statement = this->prepare(sqlite_orm::replace_range(from, to)); - this->execute(statement); - } - - template - int insert(const O &o, columns_t cols) { - constexpr const size_t colsCount = std::tuple_size>::value; - static_assert(colsCount > 0, "Use insert or replace with 1 argument instead"); - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::insert(std::ref(o), std::move(cols))); - return int(this->execute(statement)); - } - - /** - * Insert routine. Inserts object with all non primary key fields in passed object. Id of passed - * object doesn't matter. - * @return id of just created object. - */ - template - int insert(const O &o) { - this->assert_mapped_type(); - auto statement = this->prepare(sqlite_orm::insert(std::ref(o))); - return int(this->execute(statement)); - } - - template - void insert_range(It from, It to) { - using O = typename std::iterator_traits::value_type; - this->assert_mapped_type(); - if(from == to) { - return; - } - - auto statement = this->prepare(sqlite_orm::insert_range(from, to)); - this->execute(statement); - } - - /** - * Change table name inside storage's schema info. This function does not - * affect database - */ - template - void rename_table(std::string name) { - this->assert_mapped_type(); - auto &tImpl = this->get_impl(); - tImpl.table.name = move(name); - } - - using storage_base::rename_table; - - /** - * Get table's name stored in storage's schema info. This function does not call - * any SQLite queries - */ - template - const std::string &tablename() const { - this->assert_mapped_type(); - auto &tImpl = this->get_impl(); - return tImpl.table.name; - } - - protected: - template - sync_schema_result sync_table(const storage_impl, Tss...> &tableImpl, sqlite3 *db, bool) { - auto res = sync_schema_result::already_in_sync; - using context_t = serializator_context; - context_t context{this->impl}; - auto query = serialize(tableImpl.table, context); - auto rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, nullptr); - if(rc != SQLITE_OK) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return res; - } - - template - sync_schema_result - sync_table(const storage_impl, Tss...> &tImpl, sqlite3 *db, bool preserve) { - auto res = sync_schema_result::already_in_sync; - - auto schema_stat = tImpl.schema_status(db, preserve); - if(schema_stat != decltype(schema_stat)::already_in_sync) { - if(schema_stat == decltype(schema_stat)::new_table_created) { - this->create_table(db, tImpl.table.name, tImpl); - res = decltype(res)::new_table_created; - } else { - if(schema_stat == sync_schema_result::old_columns_removed || - schema_stat == sync_schema_result::new_columns_added || - schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { - - // get table info provided in `make_table` call.. - auto storageTableInfo = tImpl.table.get_table_info(); - - // now get current table info from db using `PRAGMA table_info` query.. - auto dbTableInfo = tImpl.get_table_info(tImpl.table.name, db); - - // this vector will contain pointers to columns that gotta be added.. - std::vector columnsToAdd; - - tImpl.get_remove_add_columns(columnsToAdd, storageTableInfo, dbTableInfo); - - if(schema_stat == sync_schema_result::old_columns_removed) { - - // extra table columns than storage columns - this->backup_table(db, tImpl, {}); - res = decltype(res)::old_columns_removed; - } - - if(schema_stat == sync_schema_result::new_columns_added) { - for(auto columnPointer: columnsToAdd) { - tImpl.add_column(*columnPointer, db); - } - res = decltype(res)::new_columns_added; - } - - if(schema_stat == sync_schema_result::new_columns_added_and_old_columns_removed) { - - // remove extra columns - this->backup_table(db, tImpl, columnsToAdd); - res = decltype(res)::new_columns_added_and_old_columns_removed; - } - } else if(schema_stat == sync_schema_result::dropped_and_recreated) { - this->drop_table_internal(tImpl.table.name, db); - this->create_table(db, tImpl.table.name, tImpl); - res = decltype(res)::dropped_and_recreated; - } - } - } - return res; - } - - public: - /** - * This is a cute function used to replace migration up/down functionality. - * It performs check storage schema with actual db schema and: - * * if there are excess tables exist in db they are ignored (not dropped) - * * every table from storage is compared with it's db analog and - * * if table doesn't exist it is being created - * * if table exists its colums are being compared with table_info from db and - * * if there are columns in db that do not exist in storage (excess) table will be dropped and - * recreated - * * if there are columns in storage that do not exist in db they will be added using `ALTER TABLE - * ... ADD COLUMN ...' command - * * if there is any column existing in both db and storage but differs by any of - * properties/constraints (type, pk, notnull, dflt_value) table will be dropped and recreated Be aware that - * `sync_schema` doesn't guarantee that data will not be dropped. It guarantees only that it will make db - * schema the same as you specified in `make_storage` function call. A good point is that if you have no db - * file at all it will be created and all tables also will be created with exact tables and columns you - * specified in `make_storage`, `make_table` and `make_column` call. The best practice is to call this - * function right after storage creation. - * @param preserve affects on function behaviour in case it is needed to remove a column. If it is `false` - * so table will be dropped if there is column to remove, if `true` - table is being copied into another - * table, dropped and copied table is renamed with source table name. Warning: sync_schema doesn't check - * foreign keys cause it is unable to do so in sqlite3. If you know how to get foreign key info please - * submit an issue https://github.com/fnc12/sqlite_orm/issues - * @return std::map with std::string key equal table name and `sync_schema_result` as value. - * `sync_schema_result` is a enum value that stores table state after syncing a schema. `sync_schema_result` - * can be printed out on std::ostream with `operator<<`. - */ - std::map sync_schema(bool preserve = false) { - auto con = this->get_connection(); - std::map result; - auto db = con.get(); - this->impl.for_each([&result, db, preserve, this](auto &tableImpl) { - auto res = this->sync_table(tableImpl, db, preserve); - result.insert({tableImpl.table.name, res}); - }); - return result; - } - - /** - * This function returns the same map that `sync_schema` returns but it - * doesn't perform `sync_schema` actually - just simulates it in case you want to know - * what will happen if you sync your schema. - */ - std::map sync_schema_simulate(bool preserve = false) { - auto con = this->get_connection(); - std::map result; - auto db = con.get(); - this->impl.for_each([&result, db, preserve](auto tableImpl) { - result.insert({tableImpl.table.name, tableImpl.schema_status(db, preserve)}); - }); - return result; - } - - /** - * Checks whether table exists in db. Doesn't check storage itself - works only with actual database. - * Note: table can be not mapped to a storage - * @return true if table with a given name exists in db, false otherwise. - */ - bool table_exists(const std::string &tableName) { - auto con = this->get_connection(); - return this->impl.table_exists(tableName, con.get()); - } - - template - prepared_statement_t> prepare(select_t sel) { - sel.highest_level = true; - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(sel, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(sel), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(get_all_t get_) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(get_, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(get_), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(get_all_pointer_t get_) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(get_, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(get_), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - prepared_statement_t> prepare(get_all_optional_t get_) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(get_, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(get_), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - prepared_statement_t, Wargs...>> - prepare(update_all_t, Wargs...> upd) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(upd, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(upd), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(remove_all_t rem) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(rem, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(rem), stmt, std::move(con)}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(get_t get_) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(get_, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(get_), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(get_pointer_t get_) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(get_, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(get_), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - prepared_statement_t> prepare(get_optional_t get_) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(get_, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(get_), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - prepared_statement_t> prepare(update_t upd) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(upd, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(upd), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(remove_t rem) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(rem, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(rem), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(insert_t ins) { - using object_type = typename expression_object_type::type; - this->assert_mapped_type(); - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(ins, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(ins), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(replace_t rep) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - using object_type = typename expression_object_type::type; - this->assert_mapped_type(); - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(rep, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(rep), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(insert_range_t statement) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(statement, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(statement), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(replace_range_t rep) { - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(rep, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(rep), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - prepared_statement_t> prepare(insert_explicit ins) { - using object_type = typename expression_object_type::type; - this->assert_mapped_type(); - auto con = this->get_connection(); - sqlite3_stmt *stmt; - auto db = con.get(); - using context_t = serializator_context; - context_t context{this->impl}; - context.skip_table_name = false; - context.replace_bindable_with_question = true; - auto query = serialize(ins, context); - if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) { - return {std::move(ins), stmt, con}; - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - int64 execute(const prepared_statement_t> &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using object_type = typename expression_object_type::type; - auto index = 1; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto &tImpl = this->get_impl(); - auto &o = statement.t.obj; - sqlite3_reset(stmt); - iterate_tuple(statement.t.columns.columns, [&o, &index, &stmt, &tImpl, db](auto &m) { - using column_type = typename std::decay::type; - using field_type = typename column_result_t::type; - const field_type *value = tImpl.table.template get_object_field_pointer(o, m); - if(SQLITE_OK != statement_binder().bind(stmt, index++, *value)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - return sqlite3_last_insert_rowid(db); - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - void execute(const prepared_statement_t> &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using object_type = typename expression_type::object_type; - auto &tImpl = this->get_impl(); - auto index = 1; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - sqlite3_reset(stmt); - for(auto it = statement.t.range.first; it != statement.t.range.second; ++it) { - auto &o = *it; - tImpl.table.for_each_column([&o, &index, &stmt, db](auto &c) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - }); - } - if(sqlite3_step(stmt) == SQLITE_DONE) { - //.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - void execute(const prepared_statement_t> &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using object_type = typename expression_type::object_type; - auto index = 1; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto &tImpl = this->get_impl(); - sqlite3_reset(stmt); - for(auto it = statement.t.range.first; it != statement.t.range.second; ++it) { - auto &o = *it; - tImpl.table.for_each_column([&o, &index, &stmt, db](auto &c) { - if(!c.template has>()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != - statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - }); - } - if(sqlite3_step(stmt) == SQLITE_DONE) { - //.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - void execute(const prepared_statement_t> &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using object_type = typename expression_object_type::type; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - auto &o = get_object(statement.t); - auto &tImpl = this->get_impl(); - sqlite3_reset(stmt); - tImpl.table.for_each_column([&o, &index, &stmt, db](auto &c) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - //.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - int64 execute(const prepared_statement_t> &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using object_type = typename expression_object_type::type; - int64 res = 0; - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - auto &tImpl = this->get_impl(); - auto &o = get_object(statement.t); - auto compositeKeyColumnNames = tImpl.table.composite_key_columns_names(); - sqlite3_reset(stmt); - tImpl.table.for_each_column([&o, &index, &stmt, &tImpl, &compositeKeyColumnNames, db](auto &c) { - if(tImpl.table._without_rowid || !c.template has>()) { - auto it = std::find(compositeKeyColumnNames.begin(), compositeKeyColumnNames.end(), c.name); - if(it == compositeKeyColumnNames.end()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != - statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - res = sqlite3_last_insert_rowid(db); - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - return res; - } - - template - void execute(const prepared_statement_t> &statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - void execute(const prepared_statement_t> &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using object_type = typename expression_object_type::type; - auto con = this->get_connection(); - auto db = con.get(); - auto &tImpl = this->get_impl(); - auto stmt = statement.stmt; - auto index = 1; - auto &o = get_object(statement.t); - sqlite3_reset(stmt); - tImpl.table.for_each_column([&o, stmt, &index, db](auto &c) { - if(!c.template has>()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - auto bind_res = statement_binder().bind(stmt, index++, o.*c.member_pointer); - if(SQLITE_OK != bind_res) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - }); - tImpl.table.for_each_column([&o, stmt, &index, db](auto &c) { - if(c.template has>()) { - using column_type = typename std::decay::type; - using field_type = typename column_type::field_type; - if(c.member_pointer) { - if(SQLITE_OK != statement_binder().bind(stmt, index++, o.*c.member_pointer)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } else { - using getter_type = typename column_type::getter_type; - field_value_holder valueHolder{((o).*(c.getter))()}; - if(SQLITE_OK != statement_binder().bind(stmt, index++, valueHolder.value)) { - throw std::system_error( - std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - std::unique_ptr execute(const prepared_statement_t> &statement) { - auto &tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto res = std::make_unique(); - object_from_column_builder builder{*res, stmt}; - tImpl.table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - return {}; - } break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - std::optional execute(const prepared_statement_t> &statement) { - auto &tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto res = std::make_optional(); - object_from_column_builder builder{res.value(), stmt}; - tImpl.table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - return {}; - } break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - T execute(const prepared_statement_t> &statement) { - auto &tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.ids, [stmt, &index, db](auto &v) { - using field_type = typename std::decay::type; - if(SQLITE_OK != statement_binder().bind(stmt, index++, v)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - tImpl.table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error(std::make_error_code(sqlite_orm::orm_error_code::not_found)); - } break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } - - template - void execute(const prepared_statement_t> &statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t.conditions, [stmt, &index, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template - void execute(const prepared_statement_t, Wargs...>> &statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_tuple(statement.t.set.assigns, [&index, stmt, db](auto &setArg) { - iterate_ast(setArg, [&index, stmt, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - }); - iterate_ast(statement.t.conditions, [stmt, &index, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - if(sqlite3_step(stmt) == SQLITE_DONE) { - // done.. - } else { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - - template::type> - std::vector execute(const prepared_statement_t> &statement) { - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - std::vector res; - auto tableInfoPointer = this->impl.template find_table(); - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - using table_info_pointer_t = typename std::remove_pointer::type; - using table_info_t = typename std::decay::type; - row_extractor_builder::value, table_info_t> - builder; - auto rowExtractor = builder(tableInfoPointer); - res.push_back(rowExtractor.extract(stmt, 0)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); - return res; - } - - template - R execute(const prepared_statement_t> &statement) { - auto &tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - R res; - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T obj; - object_from_column_builder builder{obj, stmt}; - tImpl.table.for_each_column(builder); - res.push_back(std::move(obj)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); - return res; - } - - template - R execute(const prepared_statement_t> &statement) { - auto &tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - R res; - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto obj = std::make_unique(); - object_from_column_builder builder{*obj, stmt}; - tImpl.table.for_each_column(builder); - res.push_back(move(obj)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); - return res; - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - R execute(const prepared_statement_t> &statement) { - auto &tImpl = this->get_impl(); - auto con = this->get_connection(); - auto db = con.get(); - auto stmt = statement.stmt; - auto index = 1; - sqlite3_reset(stmt); - iterate_ast(statement.t, [stmt, &index, db](auto &node) { - using node_type = typename std::decay::type; - conditional_binder> binder{stmt, index}; - if(SQLITE_OK != binder(node)) { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - }); - R res; - int stepRes; - do { - stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - auto obj = std::make_optional(); - object_from_column_builder builder{*obj, stmt}; - tImpl.table.for_each_column(builder); - res.push_back(move(obj)); - } break; - case SQLITE_DONE: - break; - default: { - throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()), - sqlite3_errmsg(db)); - } - } - } while(stepRes != SQLITE_DONE); - return res; - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - }; // struct storage_t - - template - struct is_storage : std::false_type {}; - - template - struct is_storage> : std::true_type {}; - } - - template - internal::storage_t make_storage(const std::string &filename, Ts... tables) { - return {filename, internal::storage_impl(tables...)}; - } - - /** - * sqlite3_threadsafe() interface. - */ - inline int threadsafe() { - return sqlite3_threadsafe(); - } -} -#pragma once - -#if defined(_MSC_VER) -#if defined(__RESTORE_MIN__) -__pragma(pop_macro("min")) -#undef __RESTORE_MIN__ -#endif -#if defined(__RESTORE_MAX__) - __pragma(pop_macro("max")) -#undef __RESTORE_MAX__ -#endif -#endif // defined(_MSC_VER) -#pragma once - -#include // std::tuple -#include // std::pair -#include // std::reference_wrapper - - // #include "conditions.h" - - // #include "operators.h" - - // #include "select_constraints.h" - - // #include "prepared_statement.h" - - // #include "optional_container.h" - - // #include "core_functions.h" - - namespace sqlite_orm { - - namespace internal { - - template - struct node_tuple { - using type = std::tuple; - }; - - template<> - struct node_tuple { - using type = std::tuple<>; - }; - - template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = where_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple::value>::type> { - using node_type = T; - using left_type = typename node_type::left_type; - using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = binary_operator; - using left_type = typename node_type::left_type; - using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = columns_t; - using type = typename conc_tuple::type...>::type; - }; - - template - struct node_tuple, void> { - using node_type = in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple::value>::type> { - using node_type = T; - using left_type = typename node_type::left_type; - using right_type = typename node_type::right_type; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = select_t; - using columns_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = get_all_t; - using type = typename conc_tuple::type...>::type; - }; - - template - struct node_tuple, void> { - using node_type = get_all_pointer_t; - using type = typename conc_tuple::type...>::type; - }; - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct node_tuple, void> { - using node_type = get_all_optional_t; - using type = typename conc_tuple::type...>::type; - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - struct node_tuple, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; - using set_tuple = typename conc_tuple::type...>::type; - using conditions_tuple = typename conc_tuple::type...>::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = remove_all_t; - using type = typename conc_tuple::type...>::type; - }; - - template - struct node_tuple, void> { - using node_type = having_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = cast_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = exists_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = optional_container; - using type = typename node_tuple::type; - }; - - template<> - struct node_tuple, void> { - using node_type = optional_container; - using type = std::tuple<>; - }; - - template - struct node_tuple, void> { - using node_type = like_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; - using escape_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = glob_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = between_t; - using expression_tuple = typename node_tuple::type; - using lower_tuple = typename node_tuple::type; - using upper_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = named_collate; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = is_null_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = is_not_null_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = negated_condition_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = core_function_t; - using type = typename conc_tuple::type...>::type; - }; - - template - struct node_tuple, void> { - using node_type = left_join_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = on_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = join_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = left_outer_join_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = inner_join_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = simple_case_t; - using case_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; - using else_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = std::pair; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; - using type = typename conc_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = as_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = limit_t; - using type = typename node_tuple::type; - }; - - template - struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; - }; - - template - struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; - }; - } -} -#pragma once - -#include // std::is_same, std::decay, std::remove_reference - -// #include "prepared_statement.h" - -// #include "ast_iterator.h" - -// #include "static_magic.h" - -// #include "expression_object_type.h" - -namespace sqlite_orm { - - template - auto &get(internal::prepared_statement_t> &statement) { - return std::get(statement.t.range); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - return std::get(statement.t.range); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - return std::get(statement.t.range); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - return std::get(statement.t.range); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - auto &get(internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED - - template - auto &get(internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - return internal::get_ref(std::get(statement.t.ids)); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for update statement"); - return internal::get_ref(statement.t.obj); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for update statement"); - return internal::get_ref(statement.t.obj); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for replace statement"); - return internal::get_ref(statement.t.obj); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for replace statement"); - return internal::get_ref(statement.t.obj); - } - - template - auto &get(internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); - } - - template - const auto &get(const internal::prepared_statement_t> &statement) { - static_assert(N == 0, "get<> works only with 0 argument for insert statement"); - return internal::get_ref(statement.t.obj); - } - - template - const auto &get(const internal::prepared_statement_t &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; - using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element::type; - const result_tupe *result = nullptr; - auto index = -1; - internal::iterate_ast(statement.t, [&result, &index](auto &node) { - using node_type = typename std::decay::type; - if(internal::is_bindable::value) { - ++index; - } - if(index == N) { - internal::static_if{}>([](auto &r, auto &n) { - r = const_cast::type>(&n); - })(result, node); - } - }); - return internal::get_ref(*result); - } - - template - auto &get(internal::prepared_statement_t &statement) { - using statement_type = typename std::decay::type; - using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; - using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element::type; - result_tupe *result = nullptr; - auto index = -1; - internal::iterate_ast(statement.t, [&result, &index](auto &node) { - using node_type = typename std::decay::type; - if(internal::is_bindable::value) { - ++index; - } - if(index == N) { - internal::static_if{}>([](auto &r, auto &n) { - r = const_cast::type>(&n); - })(result, node); - } - }); - return internal::get_ref(*result); - } -}