From ad7dba322073cb47f7788904d97fe22438bd1e00 Mon Sep 17 00:00:00 2001 From: fnc12 Date: Sun, 2 Feb 2020 13:39:18 +0300 Subject: [PATCH 1/3] added check constraint --- dev/column.h | 152 +-- dev/constraints.h | 34 +- dev/default_value_extractor.h | 4 +- dev/error_code.h | 3 + dev/getter_traits.h | 184 +++ dev/index.h | 3 - dev/serializator_context.h | 31 + dev/statement_serializator.h | 231 +++- dev/static_magic.h | 3 + dev/storage.h | 154 +-- dev/storage_impl.h | 75 +- dev/table.h | 15 +- examples/check.cpp | 62 + examples/in_memory.cpp | 1 - include/sqlite_orm/sqlite_orm.h | 1119 +++++++++-------- tests/CMakeLists.txt | 2 +- tests/constraints/check.cpp | 40 + tests/explicit_columns.cpp | 2 +- tests/operators/is_null.cpp | 4 +- .../arithmetic_operators.cpp | 58 + .../autoincrement.cpp | 11 + tests/statement_serializator_tests/check.cpp | 52 + .../statement_serializator_tests/collate.cpp | 23 + .../column_names.cpp | 106 ++ .../comparison_operators.cpp | 86 ++ .../core_functions.cpp | 122 ++ .../statement_serializator_tests/default.cpp | 23 + .../foreign_key.cpp | 313 +++++ .../primary_key.cpp | 44 + tests/statement_serializator_tests/unique.cpp | 11 + tests/static_if_tests.cpp | 67 + tests/static_tests.cpp | 2 +- tests/static_tests/member_traits_tests.cpp | 109 ++ tests/table_tests.cpp | 125 ++ tests/tests2.cpp | 52 + tests/tests3.cpp | 14 +- tests/tests4.cpp | 8 + third_party/amalgamate/config.json | 3 +- 38 files changed, 2462 insertions(+), 886 deletions(-) create mode 100644 dev/getter_traits.h create mode 100644 dev/serializator_context.h create mode 100644 examples/check.cpp create mode 100644 tests/constraints/check.cpp create mode 100644 tests/statement_serializator_tests/arithmetic_operators.cpp create mode 100644 tests/statement_serializator_tests/autoincrement.cpp create mode 100644 tests/statement_serializator_tests/check.cpp create mode 100644 tests/statement_serializator_tests/collate.cpp create mode 100644 tests/statement_serializator_tests/column_names.cpp create mode 100644 tests/statement_serializator_tests/comparison_operators.cpp create mode 100644 tests/statement_serializator_tests/core_functions.cpp create mode 100644 tests/statement_serializator_tests/default.cpp create mode 100644 tests/statement_serializator_tests/foreign_key.cpp create mode 100644 tests/statement_serializator_tests/primary_key.cpp create mode 100644 tests/statement_serializator_tests/unique.cpp create mode 100644 tests/static_if_tests.cpp create mode 100644 tests/static_tests/member_traits_tests.cpp create mode 100644 tests/table_tests.cpp diff --git a/dev/column.h b/dev/column.h index 3b02d9440..b42ce4a0a 100644 --- a/dev/column.h +++ b/dev/column.h @@ -9,6 +9,7 @@ #include "tuple_helper.h" #include "default_value_extractor.h" #include "constraints.h" +#include "getter_traits.h" namespace sqlite_orm { @@ -64,8 +65,7 @@ namespace sqlite_orm { setter_type setter_, constraints_type constraints_) : column_base{std::move(name)}, - member_pointer(member_pointer_), getter(getter_), setter(setter_), - constraints(std::move(constraints_)) {} + member_pointer(member_pointer_), getter(getter_), setter(setter_), constraints(move(constraints_)) {} /** * Simplified interface for `NOT NULL` constraint @@ -121,152 +121,26 @@ namespace sqlite_orm { template struct is_column> : public std::true_type {}; - 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 {}; - - /** - * 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; + struct column_field_type { + using type = void; }; - 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 column_field_type> { + using type = typename column_t::field_type; }; template - struct setter_traits; - - template - struct setter_traits> { - using object_type = O; - using field_type = T; + struct column_constraints_type { + using type = std::tuple<>; }; - template - struct setter_traits> { - using object_type = O; - using field_type = T; + template + struct column_constraints_type> { + using type = typename column_t::constraints_type; }; - template - struct setter_traits> { - using object_type = O; - using field_type = T; - }; } /** @@ -280,6 +154,8 @@ namespace sqlite_orm { make_column(const std::string &name, T O::*m, Op... constraints) { static_assert(constraints::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...)}; } diff --git a/dev/constraints.h b/dev/constraints.h index 6ba75e7b6..3657eec3d 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -53,13 +53,13 @@ namespace sqlite_orm { template struct primary_key_t : primary_key_base { using order_by = primary_key_base::order_by; + using columns_tuple = std::tuple; - std::tuple columns; + columns_tuple columns; - primary_key_t(decltype(columns) c) : columns(std::move(c)) {} + primary_key_t(decltype(columns) c) : columns(move(c)) {} - using field_type = void; // for column iteration. Better be deleted - using constraints_type = std::tuple<>; + // using constraints_type = std::tuple<>; primary_key_t asc() const { auto res = *this; @@ -255,8 +255,7 @@ namespace sqlite_orm { return *this; } - using field_type = void; // for column iteration. Better be deleted - using constraints_type = std::tuple<>; + // using constraints_type = std::tuple<>; template void for_each_column(const L &) {} @@ -310,6 +309,21 @@ namespace sqlite_orm { } }; + 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 {}; @@ -331,6 +345,9 @@ namespace sqlite_orm { template<> struct is_constraint : std::true_type {}; + template + struct is_constraint> : std::true_type {}; + template struct constraints_size; @@ -391,6 +408,11 @@ namespace sqlite_orm { return {internal::collate_argument::rtrim}; } + template + constraints::check_t check(T t) { + return {std::move(t)}; + } + namespace internal { /** diff --git a/dev/default_value_extractor.h b/dev/default_value_extractor.h index dd5ad9733..1c231e140 100644 --- a/dev/default_value_extractor.h +++ b/dev/default_value_extractor.h @@ -5,6 +5,7 @@ #include // std::stringstream #include "constraints.h" +#include "serializator_context.h" namespace sqlite_orm { @@ -26,7 +27,8 @@ namespace sqlite_orm { template std::unique_ptr operator()(const constraints::default_t &t) { - return std::make_unique(serialize(t.value)); + serializator_context_base context; + return std::make_unique(serialize(t.value, context)); } }; diff --git a/dev/error_code.h b/dev/error_code.h index a862ab754..0dd1f1b25 100644 --- a/dev/error_code.h +++ b/dev/error_code.h @@ -21,6 +21,7 @@ namespace sqlite_orm { incorrect_journal_mode_string, invalid_collate_argument_enum, failed_to_init_a_backup, + unknown_member_value, }; } @@ -57,6 +58,8 @@ namespace sqlite_orm { 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"; default: return "unknown error"; } diff --git a/dev/getter_traits.h b/dev/getter_traits.h new file mode 100644 index 000000000..07b1b7585 --- /dev/null +++ b/dev/getter_traits.h @@ -0,0 +1,184 @@ +#pragma once + +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; + }; + } +} diff --git a/dev/index.h b/dev/index.h index ba6c3e0fd..2b68750f1 100644 --- a/dev/index.h +++ b/dev/index.h @@ -16,9 +16,6 @@ namespace sqlite_orm { std::string name; bool unique; columns_type columns; - - template - void for_each_column_with_constraints(const L &) {} }; } diff --git a/dev/serializator_context.h b/dev/serializator_context.h new file mode 100644 index 000000000..fa679eacd --- /dev/null +++ b/dev/serializator_context.h @@ -0,0 +1,31 @@ +#pragma once + +namespace sqlite_orm { + + namespace internal { + + struct serializator_context_base { + + template + std::string column_name(F O::*m) 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); + } + }; + + } + +} diff --git a/dev/statement_serializator.h b/dev/statement_serializator.h index ac0a18342..d0e41a9ed 100644 --- a/dev/statement_serializator.h +++ b/dev/statement_serializator.h @@ -1,44 +1,52 @@ #pragma once -#include +#include // std::stringstream #include // std::string +#include // std::is_arithmetic, std::enable_if +#include // std::vector +#include // std::iter_swap #include "core_functions.h" #include "constraints.h" +#include "conditions.h" +#include "column.h" namespace sqlite_orm { namespace internal { template - struct statement_serializator { - using statement_type = T; + struct statement_serializator; - std::string operator()(const statement_type &t) const { - std::stringstream ss; - ss << t; - return ss.str(); - } - }; - - template - std::string serialize(const T &t) { + template + std::string serialize(const T &t, const C &context) { statement_serializator serializator; - return serializator(t); + return serializator(t, context); } + template + struct statement_serializator { + using statement_type = F O::*; + + template + std::string operator()(const statement_type &c, const C &context) const { + return context.impl.column_name(c); + } + }; + template struct statement_serializator, void> { using statement_type = core_functions::core_function_t; - std::string operator()(const statement_type &c) const { + 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](auto &v) { - args.push_back(serialize(v)); + 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]; @@ -55,7 +63,8 @@ namespace sqlite_orm { struct statement_serializator { using statement_type = constraints::autoincrement_t; - std::string operator()(const statement_type &c) const { + template + std::string operator()(const statement_type &c, const C &context) const { return static_cast(c); } }; @@ -64,8 +73,24 @@ namespace sqlite_orm { struct statement_serializator, void> { using statement_type = constraints::primary_key_t; - std::string operator()(const statement_type &c) const { - return static_cast(c); + 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; } }; @@ -73,7 +98,8 @@ namespace sqlite_orm { struct statement_serializator { using statement_type = constraints::unique_t; - std::string operator()(const statement_type &c) const { + template + std::string operator()(const statement_type &c, const C &context) const { return static_cast(c); } }; @@ -82,7 +108,8 @@ namespace sqlite_orm { struct statement_serializator { using statement_type = constraints::collate_t; - std::string operator()(const statement_type &c) const { + template + std::string operator()(const statement_type &c, const C &context) const { return static_cast(c); } }; @@ -91,8 +118,9 @@ namespace sqlite_orm { struct statement_serializator, void> { using statement_type = constraints::default_t; - std::string operator()(const statement_type &c) const { - return static_cast(c) + " (" + serialize(c.value) + ")"; + template + std::string operator()(const statement_type &c, const C &context) const { + return static_cast(c) + " (" + serialize(c.value, context) + ")"; } }; @@ -100,7 +128,8 @@ namespace sqlite_orm { struct statement_serializator { using statement_type = std::string; - std::string operator()(const statement_type &c) const { + template + std::string operator()(const statement_type &c, const C &context) const { return "\"" + c + "\""; } }; @@ -109,10 +138,162 @@ namespace sqlite_orm { struct statement_serializator { using statement_type = const char *; - std::string operator()(const char *c) const { + template + std::string operator()(const char *c, const C &context) const { return std::string("'") + c + "'"; } }; + 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< + T, + typename std::enable_if::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; + ss << "(" << leftString << " " << static_cast(c) << " " << rightString << ")"; + return ss.str(); + } + }; + + template + struct statement_serializator::value>::type> { + using statement_type = T; + + template + std::string operator()(const statement_type &t, const C &context) const { + std::stringstream ss; + ss << t; + 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(); + } + }; + } } diff --git a/dev/static_magic.h b/dev/static_magic.h index 198f42297..96187120e 100644 --- a/dev/static_magic.h +++ b/dev/static_magic.h @@ -27,6 +27,9 @@ namespace sqlite_orm { auto static_if(T t) { return static_if(std::integral_constant{}, t, [](auto &&...) {}); } + + template + using static_not = std::integral_constant; } } diff --git a/dev/storage.h b/dev/storage.h index 2544642d8..3b1e24a4f 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -47,6 +47,7 @@ #include "storage_base.h" #include "prepared_statement.h" #include "expression_object_type.h" +#include "statement_serializator.h" namespace sqlite_orm { @@ -88,127 +89,16 @@ namespace sqlite_orm { template friend struct iterator_t; - template - std::string serialize_column_schema(const internal::column_t &c) { - 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](auto &v) { - using constraint_type = typename std::decay::type; - constraintsStrings.push_back(serialize(v)); - 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 - std::string serialize_column_schema(const constraints::primary_key_t &fk) { - std::stringstream ss; - ss << static_cast(fk) << " ("; - std::vector columnNames; - columnNames.reserve(std::tuple_size::value); - iterate_tuple(fk.columns, [&columnNames, this](auto &c) { - columnNames.push_back(this->impl.column_name(c)); - }); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - ss << ") "; - return ss.str(); - } - -#if SQLITE_VERSION_NUMBER >= 3006019 - - template - std::string - serialize_column_schema(const constraints::foreign_key_t, std::tuple> &fk) { - 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, this](auto &v) { - columnNames.push_back(this->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 << " "; - } - 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 = this->impl.template find_table_name(); - ss << refTableName << " "; - } - iterate_tuple(fk.references, [&referencesNames, this](auto &v) { - referencesNames.push_back(this->impl.column_name(v)); - }); - ss << "( "; - for(size_t i = 0; i < referencesNames.size(); ++i) { - ss << referencesNames[i]; - if(i < referencesNames.size() - 1) { - ss << ","; - } - 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(); - } -#endif - template void create_table(sqlite3 *db, const std::string &tableName, I *impl) { std::stringstream ss; ss << "CREATE TABLE '" << tableName << "' ( "; auto columnsCount = impl->table.columns_count; auto index = 0; - impl->table.for_each_column_with_constraints([columnsCount, &index, &ss, this](auto &c) { - ss << this->serialize_column_schema(c); + using context_t = serializator_context; + context_t context{this->impl}; + iterate_tuple(impl->table.columns, [columnsCount, &index, &ss, &context](auto &c) { + ss << serialize(c, context); if(index < columnsCount - 1) { ss << ", "; } @@ -343,7 +233,7 @@ namespace sqlite_orm { std::string string_from_expression(F O::*m, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << "\"" << this->impl.column_name(m) << "\""; return ss.str(); @@ -365,7 +255,7 @@ namespace sqlite_orm { std::string string_from_expression(const table_rowid_t &rid, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << static_cast(rid); return ss.str(); @@ -375,7 +265,7 @@ namespace sqlite_orm { std::string string_from_expression(const table_oid_t &rid, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << static_cast(rid); return ss.str(); @@ -385,7 +275,7 @@ namespace sqlite_orm { std::string string_from_expression(const table__rowid_t &rid, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << static_cast(rid); return ss.str(); @@ -500,7 +390,7 @@ namespace sqlite_orm { std::string string_from_expression(const column_pointer &c, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(T)) << "'."; } auto &impl = this->get_impl(); ss << "\"" << impl.column_name_simple(c.field) << "\""; @@ -571,7 +461,7 @@ namespace sqlite_orm { internal::join_iterator()([&tableNamesSet, this](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 = this->impl.template find_table_name(); + auto crossJoinedTableName = this->impl.find_table_name(typeid(cross_join_type)); auto tableAliasString = alias_extractor::get(); std::pair tableNameWithAlias(std::move(crossJoinedTableName), std::move(tableAliasString)); @@ -1227,20 +1117,20 @@ namespace sqlite_orm { template void process_single_condition(std::stringstream &ss, const conditions::cross_join_t &c) const { ss << static_cast(c) << " "; - ss << " '" << this->impl.template find_table_name() << "'"; + ss << " '" << this->impl.find_table_name(typeid(O)) << "'"; } template void process_single_condition(std::stringstream &ss, const conditions::natural_join_t &c) const { ss << static_cast(c) << " "; - ss << " '" << this->impl.template find_table_name() << "'"; + ss << " '" << this->impl.find_table_name(typeid(O)) << "'"; } template void process_single_condition(std::stringstream &ss, const conditions::inner_join_t &l) const { ss << static_cast(l) << " "; auto aliasString = alias_extractor::get(); - ss << " '" << this->impl.template find_table_name::type>() << "' "; + ss << " '" << this->impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; if(aliasString.length()) { ss << "'" << aliasString << "' "; } @@ -1250,21 +1140,21 @@ namespace sqlite_orm { template void process_single_condition(std::stringstream &ss, const conditions::left_outer_join_t &l) const { ss << static_cast(l) << " "; - ss << " '" << this->impl.template find_table_name() << "' "; + ss << " '" << this->impl.find_table_name(typeid(T)) << "' "; this->process_join_constraint(ss, l.constraint); } template void process_single_condition(std::stringstream &ss, const conditions::left_join_t &l) const { ss << static_cast(l) << " "; - ss << " '" << this->impl.template find_table_name() << "' "; + ss << " '" << this->impl.find_table_name(typeid(T)) << "' "; this->process_join_constraint(ss, l.constraint); } template void process_single_condition(std::stringstream &ss, const conditions::join_t &l) const { ss << static_cast(l) << " "; - ss << " '" << this->impl.template find_table_name() << "' "; + ss << " '" << this->impl.find_table_name(typeid(T)) << "' "; this->process_join_constraint(ss, l.constraint); } @@ -1391,7 +1281,7 @@ namespace sqlite_orm { template std::set> parse_table_name(F O::*, std::string alias = {}) const { - return {std::make_pair(this->impl.template find_table_name(), std::move(alias))}; + return {std::make_pair(this->impl.find_table_name(typeid(O)), std::move(alias))}; } template @@ -1480,7 +1370,7 @@ namespace sqlite_orm { template std::set> parse_table_name(const column_pointer &) const { std::set> res; - res.insert({this->impl.template find_table_name(), ""}); + res.insert({this->impl.find_table_name(typeid(T)), ""}); return res; } @@ -1492,7 +1382,7 @@ namespace sqlite_orm { template std::set> parse_table_name(const aggregate_functions::count_asterisk_t &) const { - auto tableName = this->impl.template find_table_name(); + auto tableName = this->impl.find_table_name(typeid(T)); if(!tableName.empty()) { return {std::make_pair(std::move(tableName), "")}; } else { @@ -1507,7 +1397,7 @@ namespace sqlite_orm { template std::set> parse_table_name(const asterisk_t &) const { - auto tableName = this->impl.template find_table_name(); + auto tableName = this->impl.find_table_name(typeid(T)); return {std::make_pair(std::move(tableName), "")}; } @@ -2022,7 +1912,7 @@ namespace sqlite_orm { using head_t = typename std::tuple_element<0, columns_type>::type; using indexed_type = typename internal::table_type::type; ss << "INDEX IF NOT EXISTS '" << impl->table.name << "' ON '" - << this->impl.template find_table_name() << "' ( "; + << this->impl.find_table_name(typeid(indexed_type)) << "' ( "; std::vector columnNames; iterate_tuple(impl->table.columns, [&columnNames, this](auto &v) { columnNames.push_back(this->impl.column_name(v)); diff --git a/dev/storage_impl.h b/dev/storage_impl.h index 0be48cfe5..2cf029180 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -10,6 +10,7 @@ #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" @@ -181,7 +182,7 @@ namespace sqlite_orm { */ int foreign_keys_count() { auto res = 0; - this->table.for_each_column_with_constraints([&res](auto &c) { + iterate_tuple(this->table.columns, [&res](auto &c) { if(internal::is_foreign_key::type>::value) { ++res; } @@ -201,22 +202,6 @@ namespace sqlite_orm { return this->table.find_column_name(m); } - /** - * Same thing as above for getter. - */ - template::value>::type> - std::string column_name_simple(T g) const { - return this->table.find_column_name(g); - } - - /** - * Same thing as above for setter. - */ - template::value>::type> - std::string column_name_simple(T s) const { - return this->table.find_column_name(s); - } - /** * Cute function used to find column name by its type and member pointer. Uses SFINAE to * skip inequal type O. @@ -236,44 +221,6 @@ namespace sqlite_orm { return this->super::column_name(m); } - /** - * Cute function used to find column name by its type and getter pointer. Uses SFINAE to - * skip inequal type O. - */ - template - std::string column_name(const F &(O::*g)() const, - typename std::enable_if::value>::type * = nullptr) const { - return this->table.find_column_name(g); - } - - /** - * Opposite version of function defined above. Just calls same function in superclass. - */ - template - std::string column_name(const F &(O::*g)() const, - typename std::enable_if::value>::type * = nullptr) const { - return this->super::column_name(g); - } - - /** - * Cute function used to find column name by its type and setter pointer. Uses SFINAE to - * skip inequal type O. - */ - template - std::string column_name(void (O::*s)(F), - typename std::enable_if::value>::type * = nullptr) const { - return this->table.find_column_name(s); - } - - /** - * Opposite version of function defined above. Just calls same function in superclass. - */ - template - std::string column_name(void (O::*s)(F), - typename std::enable_if::value>::type * = nullptr) const { - return this->super::column_name(s); - } - template std::string column_name(const column_pointer &c, typename std::enable_if::value>::type * = nullptr) const { @@ -296,14 +243,13 @@ namespace sqlite_orm { return this->super::template get_impl(); } - template - std::string find_table_name(typename std::enable_if::value>::type * = nullptr) const { - return this->table.name; - } - - template - std::string find_table_name(typename std::enable_if::value>::type * = nullptr) const { - return this->super::template find_table_name(); + 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); + } } template @@ -488,8 +434,7 @@ namespace sqlite_orm { template<> struct storage_impl<> : storage_impl_base { - template - std::string find_table_name() const { + std::string find_table_name(std::type_index ti) const { return {}; } diff --git a/dev/table.h b/dev/table.h index 05e0124ac..a82c5cb81 100644 --- a/dev/table.h +++ b/dev/table.h @@ -141,7 +141,7 @@ namespace sqlite_orm { } /** - * Searches column name by class member pointer passed as first argument. + * Searches column name by class member pointer passed as the first argument. * @return column name or empty string if nothing found. */ template void {} */ @@ -207,16 +207,12 @@ namespace sqlite_orm { }); } - template - void for_each_column_with_constraints(const L &l) const { - iterate_tuple(this->columns, l); - } - 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; - static_if{}>(l)(column); + using field_type = typename column_field_type::type; + static_if{}>(l)(column); }); } @@ -231,7 +227,8 @@ namespace sqlite_orm { using tuple_helper::tuple_contains_type; iterate_tuple(this->columns, [&l](auto &column) { using column_type = typename std::decay::type; - static_if{}>(l)(column); + using constraints_type = typename column_constraints_type::type; + static_if{}>(l)(column); }); } diff --git a/examples/check.cpp b/examples/check.cpp new file mode 100644 index 000000000..865a6f16a --- /dev/null +++ b/examples/check.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +using namespace sqlite_orm; +using std::cout; +using std::endl; + +int main() { + struct Contact { + int id = 0; + std::string firstName; + std::string lastName; + std::string email; + std::string phone; + }; + + struct Product { + int id = 0; + std::string name; + float listPrice = 0; + float discount = 0; + }; + + auto storage = make_storage(":memory:", + make_table("contacts", + make_column("contact_id", &Contact::id, primary_key()), + make_column("first_name", &Contact::firstName), + make_column("last_name", &Contact::lastName), + make_column("email", &Contact::email), + make_column("phone", &Contact::phone), + check(length(&Contact::phone) >= 10)), + make_table("products", + make_column("product_id", &Product::id, primary_key()), + make_column("product_name", &Product::name), + make_column("list_price", &Product::listPrice), + make_column("discount", &Product::discount, default_value(0)), + check(c(&Product::listPrice) >= &Product::discount and + c(&Product::discount) >= 0 and c(&Product::listPrice) >= 0))); + storage.sync_schema(); + + try { + storage.insert(Contact{0, "John", "Doe", {}, "408123456"}); + } catch(const std::system_error &e) { + cout << e.what() << endl; + } + storage.insert(Contact{0, "John", "Doe", {}, "(408)-123-456"}); + + try { + storage.insert(Product{0, "New Product", 900, 1000}); + } catch(const std::system_error &e) { + cout << e.what() << endl; + } + + try { + storage.insert(Product{0, "New XFactor", 1000, -10}); + } catch(const std::system_error &e) { + cout << e.what() << endl; + } + + return 0; +} diff --git a/examples/in_memory.cpp b/examples/in_memory.cpp index 95c7a9ad8..f3f534aff 100644 --- a/examples/in_memory.cpp +++ b/examples/in_memory.cpp @@ -1,4 +1,3 @@ - #include #include diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 2c9a01536..dba54e630 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -42,6 +42,7 @@ __pragma(push_macro("min")) incorrect_journal_mode_string, invalid_collate_argument_enum, failed_to_init_a_backup, + unknown_member_value, }; } @@ -77,6 +78,8 @@ namespace sqlite_orm { 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"; default: return "unknown error"; } @@ -248,6 +251,9 @@ namespace sqlite_orm { auto static_if(T t) { return static_if(std::integral_constant{}, t, [](auto &&...) {}); } + + template + using static_not = std::integral_constant; } } @@ -532,13 +538,13 @@ namespace sqlite_orm { template struct primary_key_t : primary_key_base { using order_by = primary_key_base::order_by; + using columns_tuple = std::tuple; - std::tuple columns; + columns_tuple columns; - primary_key_t(decltype(columns) c) : columns(std::move(c)) {} + primary_key_t(decltype(columns) c) : columns(move(c)) {} - using field_type = void; // for column iteration. Better be deleted - using constraints_type = std::tuple<>; + // using constraints_type = std::tuple<>; primary_key_t asc() const { auto res = *this; @@ -734,8 +740,7 @@ namespace sqlite_orm { return *this; } - using field_type = void; // for column iteration. Better be deleted - using constraints_type = std::tuple<>; + // using constraints_type = std::tuple<>; template void for_each_column(const L &) {} @@ -789,6 +794,21 @@ namespace sqlite_orm { } }; + 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 {}; @@ -810,6 +830,9 @@ namespace sqlite_orm { template<> struct is_constraint : std::true_type {}; + template + struct is_constraint> : std::true_type {}; + template struct constraints_size; @@ -870,6 +893,11 @@ namespace sqlite_orm { return {internal::collate_argument::rtrim}; } + template + constraints::check_t check(T t) { + return {std::move(t)}; + } + namespace internal { /** @@ -963,6 +991,38 @@ namespace sqlite_orm { // #include "constraints.h" +// #include "serializator_context.h" + +namespace sqlite_orm { + + namespace internal { + + struct serializator_context_base { + + template + std::string column_name(F O::*m) 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); + } + }; + + } + +} + namespace sqlite_orm { namespace internal { @@ -983,7 +1043,8 @@ namespace sqlite_orm { template std::unique_ptr operator()(const constraints::default_t &t) { - return std::make_unique(serialize(t.value)); + serializator_context_base context; + return std::make_unique(serialize(t.value, context)); } }; @@ -1201,117 +1262,12 @@ namespace sqlite_orm { // #include "constraints.h" +// #include "getter_traits.h" + 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(std::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 is_field_member_pointer : std::false_type {}; @@ -1321,9 +1277,18 @@ namespace sqlite_orm { !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 - */ + * Getters aliases + */ template using getter_by_value_const = T (O::*)() const; @@ -1343,8 +1308,8 @@ namespace sqlite_orm { using getter_by_const_ref = const T &(O::*)(); /** - * Setters aliases - */ + * Setters aliases + */ template using setter_by_value = void (O::*)(T); @@ -1458,6 +1423,160 @@ namespace sqlite_orm { 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; + }; + } /** @@ -1471,6 +1590,8 @@ namespace sqlite_orm { make_column(const std::string &name, T O::*m, Op... constraints) { static_assert(constraints::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...)}; } @@ -5276,9 +5397,6 @@ namespace sqlite_orm { std::string name; bool unique; columns_type columns; - - template - void for_each_column_with_constraints(const L &) {} }; } @@ -5947,7 +6065,7 @@ namespace sqlite_orm { } /** - * Searches column name by class member pointer passed as first argument. + * Searches column name by class member pointer passed as the first argument. * @return column name or empty string if nothing found. */ template void {} */ @@ -6013,16 +6131,12 @@ namespace sqlite_orm { }); } - template - void for_each_column_with_constraints(const L &l) const { - iterate_tuple(this->columns, l); - } - 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; - static_if{}>(l)(column); + using field_type = typename column_field_type::type; + static_if{}>(l)(column); }); } @@ -6037,7 +6151,8 @@ namespace sqlite_orm { using tuple_helper::tuple_contains_type; iterate_tuple(this->columns, [&l](auto &column) { using column_type = typename std::decay::type; - static_if{}>(l)(column); + using constraints_type = typename column_constraints_type::type; + static_if{}>(l)(column); }); } @@ -6101,6 +6216,7 @@ namespace sqlite_orm { #include // std::pair, std::make_pair #include // std::vector #include // std::find_if +#include // std::type_index // #include "error_code.h" @@ -6307,7 +6423,7 @@ namespace sqlite_orm { */ int foreign_keys_count() { auto res = 0; - this->table.for_each_column_with_constraints([&res](auto &c) { + iterate_tuple(this->table.columns, [&res](auto &c) { if(internal::is_foreign_key::type>::value) { ++res; } @@ -6327,22 +6443,6 @@ namespace sqlite_orm { return this->table.find_column_name(m); } - /** - * Same thing as above for getter. - */ - template::value>::type> - std::string column_name_simple(T g) const { - return this->table.find_column_name(g); - } - - /** - * Same thing as above for setter. - */ - template::value>::type> - std::string column_name_simple(T s) const { - return this->table.find_column_name(s); - } - /** * Cute function used to find column name by its type and member pointer. Uses SFINAE to * skip inequal type O. @@ -6350,54 +6450,16 @@ namespace sqlite_orm { 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); - } - - /** - * Cute function used to find column name by its type and getter pointer. Uses SFINAE to - * skip inequal type O. - */ - template - std::string column_name(const F &(O::*g)() const, - typename std::enable_if::value>::type * = nullptr) const { - return this->table.find_column_name(g); - } - - /** - * Opposite version of function defined above. Just calls same function in superclass. - */ - template - std::string column_name(const F &(O::*g)() const, - typename std::enable_if::value>::type * = nullptr) const { - return this->super::column_name(g); - } - - /** - * Cute function used to find column name by its type and setter pointer. Uses SFINAE to - * skip inequal type O. - */ - template - std::string column_name(void (O::*s)(F), - typename std::enable_if::value>::type * = nullptr) const { - return this->table.find_column_name(s); + return this->table.find_column_name(m); } /** * Opposite version of function defined above. Just calls same function in superclass. */ template - std::string column_name(void (O::*s)(F), + std::string column_name(F O::*m, typename std::enable_if::value>::type * = nullptr) const { - return this->super::column_name(s); + return this->super::column_name(m); } template @@ -6422,14 +6484,13 @@ namespace sqlite_orm { return this->super::template get_impl(); } - template - std::string find_table_name(typename std::enable_if::value>::type * = nullptr) const { - return this->table.name; - } - - template - std::string find_table_name(typename std::enable_if::value>::type * = nullptr) const { - return this->super::template find_table_name(); + 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); + } } template @@ -6614,8 +6675,7 @@ namespace sqlite_orm { template<> struct storage_impl<> : storage_impl_base { - template - std::string find_table_name() const { + std::string find_table_name(std::type_index ti) const { return {}; } @@ -8890,63 +8950,366 @@ namespace sqlite_orm { }; template - struct get_ref_t> { + 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::is_arithmetic, std::enable_if +#include // std::vector +#include // std::iter_swap + +// #include "core_functions.h" + +// #include "constraints.h" + +// #include "conditions.h" + +// #include "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 { + using statement_type = F O::*; + + template + std::string operator()(const statement_type &c, const C &context) const { + return context.impl.column_name(c); + } + }; + + template + struct statement_serializator, void> { + using statement_type = core_functions::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 { + using statement_type = constraints::autoincrement_t; + + template + std::string operator()(const statement_type &c, const C &context) 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 { + using statement_type = constraints::unique_t; + + template + std::string operator()(const statement_type &c, const C &context) const { + return static_cast(c); + } + }; + + template<> + struct statement_serializator { + using statement_type = constraints::collate_t; + + template + std::string operator()(const statement_type &c, const C &context) 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 { + using statement_type = std::string; + + template + std::string operator()(const statement_type &c, const C &context) const { + return "\"" + c + "\""; + } + }; + + template<> + struct statement_serializator { + using statement_type = const char *; + + template + std::string operator()(const char *c, const C &context) const { + return std::string("'") + c + "'"; + } + }; + + 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< + T, + typename std::enable_if::value>::type> { + using statement_type = T; - template - auto &operator()(O &t) const { - return t.get(); + 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; + ss << "(" << leftString << " " << static_cast(c) << " " << rightString << ")"; + return ss.str(); } }; 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; + struct statement_serializator::value>::type> { + using statement_type = T; - template - auto &operator()(O &e) const { - return get_ref(e.obj); + template + std::string operator()(const statement_type &t, const C &context) const { + std::stringstream ss; + ss << t; + return ss.str(); } }; - template - struct get_object_t> { - using expression_type = insert_t; + template + struct statement_serializator, void> { + using statement_type = binary_operator; - template - auto &operator()(O &e) const { - return get_ref(e.obj); + 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 get_object_t> { - using expression_type = update_t; - - template - auto &operator()(O &e) const { - return get_ref(e.obj); - } - }; } } @@ -8990,127 +9353,16 @@ namespace sqlite_orm { template friend struct iterator_t; - template - std::string serialize_column_schema(const internal::column_t &c) { - 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](auto &v) { - using constraint_type = typename std::decay::type; - constraintsStrings.push_back(serialize(v)); - 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 - std::string serialize_column_schema(const constraints::primary_key_t &fk) { - std::stringstream ss; - ss << static_cast(fk) << " ("; - std::vector columnNames; - columnNames.reserve(std::tuple_size::value); - iterate_tuple(fk.columns, [&columnNames, this](auto &c) { - columnNames.push_back(this->impl.column_name(c)); - }); - for(size_t i = 0; i < columnNames.size(); ++i) { - ss << columnNames[i]; - if(i < columnNames.size() - 1) { - ss << ", "; - } - } - ss << ") "; - return ss.str(); - } - -#if SQLITE_VERSION_NUMBER >= 3006019 - - template - std::string - serialize_column_schema(const constraints::foreign_key_t, std::tuple> &fk) { - 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, this](auto &v) { - columnNames.push_back(this->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 << " "; - } - 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 = this->impl.template find_table_name(); - ss << refTableName << " "; - } - iterate_tuple(fk.references, [&referencesNames, this](auto &v) { - referencesNames.push_back(this->impl.column_name(v)); - }); - ss << "( "; - for(size_t i = 0; i < referencesNames.size(); ++i) { - ss << referencesNames[i]; - if(i < referencesNames.size() - 1) { - ss << ","; - } - 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(); - } -#endif - template void create_table(sqlite3 *db, const std::string &tableName, I *impl) { std::stringstream ss; ss << "CREATE TABLE '" << tableName << "' ( "; auto columnsCount = impl->table.columns_count; auto index = 0; - impl->table.for_each_column_with_constraints([columnsCount, &index, &ss, this](auto &c) { - ss << this->serialize_column_schema(c); + using context_t = serializator_context; + context_t context{this->impl}; + iterate_tuple(impl->table.columns, [columnsCount, &index, &ss, &context](auto &c) { + ss << serialize(c, context); if(index < columnsCount - 1) { ss << ", "; } @@ -9245,7 +9497,7 @@ namespace sqlite_orm { std::string string_from_expression(F O::*m, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << "\"" << this->impl.column_name(m) << "\""; return ss.str(); @@ -9267,7 +9519,7 @@ namespace sqlite_orm { std::string string_from_expression(const table_rowid_t &rid, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << static_cast(rid); return ss.str(); @@ -9277,7 +9529,7 @@ namespace sqlite_orm { std::string string_from_expression(const table_oid_t &rid, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << static_cast(rid); return ss.str(); @@ -9287,7 +9539,7 @@ namespace sqlite_orm { std::string string_from_expression(const table__rowid_t &rid, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(O)) << "'."; } ss << static_cast(rid); return ss.str(); @@ -9402,7 +9654,7 @@ namespace sqlite_orm { std::string string_from_expression(const column_pointer &c, bool noTableName) const { std::stringstream ss; if(!noTableName) { - ss << "'" << this->impl.template find_table_name() << "'."; + ss << "'" << this->impl.find_table_name(typeid(T)) << "'."; } auto &impl = this->get_impl(); ss << "\"" << impl.column_name_simple(c.field) << "\""; @@ -9473,7 +9725,7 @@ namespace sqlite_orm { internal::join_iterator()([&tableNamesSet, this](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 = this->impl.template find_table_name(); + auto crossJoinedTableName = this->impl.find_table_name(typeid(cross_join_type)); auto tableAliasString = alias_extractor::get(); std::pair tableNameWithAlias(std::move(crossJoinedTableName), std::move(tableAliasString)); @@ -10129,20 +10381,20 @@ namespace sqlite_orm { template void process_single_condition(std::stringstream &ss, const conditions::cross_join_t &c) const { ss << static_cast(c) << " "; - ss << " '" << this->impl.template find_table_name() << "'"; + ss << " '" << this->impl.find_table_name(typeid(O)) << "'"; } template void process_single_condition(std::stringstream &ss, const conditions::natural_join_t &c) const { ss << static_cast(c) << " "; - ss << " '" << this->impl.template find_table_name() << "'"; + ss << " '" << this->impl.find_table_name(typeid(O)) << "'"; } template void process_single_condition(std::stringstream &ss, const conditions::inner_join_t &l) const { ss << static_cast(l) << " "; auto aliasString = alias_extractor::get(); - ss << " '" << this->impl.template find_table_name::type>() << "' "; + ss << " '" << this->impl.find_table_name(typeid(typename mapped_type_proxy::type)) << "' "; if(aliasString.length()) { ss << "'" << aliasString << "' "; } @@ -10152,21 +10404,21 @@ namespace sqlite_orm { template void process_single_condition(std::stringstream &ss, const conditions::left_outer_join_t &l) const { ss << static_cast(l) << " "; - ss << " '" << this->impl.template find_table_name() << "' "; + ss << " '" << this->impl.find_table_name(typeid(T)) << "' "; this->process_join_constraint(ss, l.constraint); } template void process_single_condition(std::stringstream &ss, const conditions::left_join_t &l) const { ss << static_cast(l) << " "; - ss << " '" << this->impl.template find_table_name() << "' "; + ss << " '" << this->impl.find_table_name(typeid(T)) << "' "; this->process_join_constraint(ss, l.constraint); } template void process_single_condition(std::stringstream &ss, const conditions::join_t &l) const { ss << static_cast(l) << " "; - ss << " '" << this->impl.template find_table_name() << "' "; + ss << " '" << this->impl.find_table_name(typeid(T)) << "' "; this->process_join_constraint(ss, l.constraint); } @@ -10293,7 +10545,7 @@ namespace sqlite_orm { template std::set> parse_table_name(F O::*, std::string alias = {}) const { - return {std::make_pair(this->impl.template find_table_name(), std::move(alias))}; + return {std::make_pair(this->impl.find_table_name(typeid(O)), std::move(alias))}; } template @@ -10382,7 +10634,7 @@ namespace sqlite_orm { template std::set> parse_table_name(const column_pointer &) const { std::set> res; - res.insert({this->impl.template find_table_name(), ""}); + res.insert({this->impl.find_table_name(typeid(T)), ""}); return res; } @@ -10394,7 +10646,7 @@ namespace sqlite_orm { template std::set> parse_table_name(const aggregate_functions::count_asterisk_t &) const { - auto tableName = this->impl.template find_table_name(); + auto tableName = this->impl.find_table_name(typeid(T)); if(!tableName.empty()) { return {std::make_pair(std::move(tableName), "")}; } else { @@ -10409,7 +10661,7 @@ namespace sqlite_orm { template std::set> parse_table_name(const asterisk_t &) const { - auto tableName = this->impl.template find_table_name(); + auto tableName = this->impl.find_table_name(typeid(T)); return {std::make_pair(std::move(tableName), "")}; } @@ -10924,7 +11176,7 @@ namespace sqlite_orm { using head_t = typename std::tuple_element<0, columns_type>::type; using indexed_type = typename internal::table_type::type; ss << "INDEX IF NOT EXISTS '" << impl->table.name << "' ON '" - << this->impl.template find_table_name() << "' ( "; + << this->impl.find_table_name(typeid(indexed_type)) << "' ( "; std::vector columnNames; iterate_tuple(impl->table.columns, [&columnNames, this](auto &v) { columnNames.push_back(this->impl.column_name(v)); @@ -12430,122 +12682,3 @@ namespace sqlite_orm { return internal::get_ref(*result); } } -#pragma once - -#include -#include // std::string - -// #include "core_functions.h" - -// #include "constraints.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct statement_serializator { - using statement_type = T; - - std::string operator()(const statement_type &t) const { - std::stringstream ss; - ss << t; - return ss.str(); - } - }; - - template - std::string serialize(const T &t) { - statement_serializator serializator; - return serializator(t); - } - - template - struct statement_serializator, void> { - using statement_type = core_functions::core_function_t; - - std::string operator()(const statement_type &c) 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](auto &v) { - args.push_back(serialize(v)); - }); - 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 { - using statement_type = constraints::autoincrement_t; - - std::string operator()(const statement_type &c) const { - return static_cast(c); - } - }; - - template - struct statement_serializator, void> { - using statement_type = constraints::primary_key_t; - - std::string operator()(const statement_type &c) const { - return static_cast(c); - } - }; - - template<> - struct statement_serializator { - using statement_type = constraints::unique_t; - - std::string operator()(const statement_type &c) const { - return static_cast(c); - } - }; - - template<> - struct statement_serializator { - using statement_type = constraints::collate_t; - - std::string operator()(const statement_type &c) const { - return static_cast(c); - } - }; - - template - struct statement_serializator, void> { - using statement_type = constraints::default_t; - - std::string operator()(const statement_type &c) const { - return static_cast(c) + " (" + serialize(c.value) + ")"; - } - }; - - template<> - struct statement_serializator { - using statement_type = std::string; - - std::string operator()(const statement_type &c) const { - return "\"" + c + "\""; - } - }; - - template<> - struct statement_serializator { - using statement_type = const char *; - - std::string operator()(const char *c) const { - return std::string("'") + c + "'"; - } - }; - - } -} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 768caf4aa..17c01152e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ else() add_subdirectory(third_party/sqlite) endif() -add_executable(unit_tests tests.cpp tests2.cpp tests3.cpp tests4.cpp tests4.cpp private_getters_tests.cpp pragma_tests.cpp explicit_columns.cpp core_functions_tests.cpp composite_key.cpp static_tests.cpp operators/arithmetic_operators.cpp operators/like.cpp operators/glob.cpp operators/in.cpp operators/cast.cpp operators/is_null.cpp dynamic_order_by.cpp prepared_statement_tests/select.cpp prepared_statement_tests/get_all.cpp prepared_statement_tests/get_all_pointer.cpp prepared_statement_tests/get_all_optional.cpp prepared_statement_tests/update_all.cpp prepared_statement_tests/remove_all.cpp prepared_statement_tests/get.cpp prepared_statement_tests/get_pointer.cpp prepared_statement_tests/get_optional.cpp prepared_statement_tests/update.cpp prepared_statement_tests/remove.cpp prepared_statement_tests/insert.cpp prepared_statement_tests/replace.cpp prepared_statement_tests/insert_range.cpp prepared_statement_tests/replace_range.cpp prepared_statement_tests/insert_explicit.cpp pragma_tests.cpp simple_query.cpp static_tests/is_bindable.cpp static_tests/arithmetic_operators_result_type.cpp static_tests/tuple_conc.cpp static_tests/node_tuple.cpp static_tests/bindable_filter.cpp static_tests/count_tuple.cpp constraints/default.cpp constraints/foreign_key.cpp) +add_executable(unit_tests tests.cpp tests2.cpp tests3.cpp tests4.cpp tests4.cpp private_getters_tests.cpp pragma_tests.cpp explicit_columns.cpp core_functions_tests.cpp composite_key.cpp static_tests.cpp operators/arithmetic_operators.cpp operators/like.cpp operators/glob.cpp operators/in.cpp operators/cast.cpp operators/is_null.cpp dynamic_order_by.cpp prepared_statement_tests/select.cpp prepared_statement_tests/get_all.cpp prepared_statement_tests/get_all_pointer.cpp prepared_statement_tests/get_all_optional.cpp prepared_statement_tests/update_all.cpp prepared_statement_tests/remove_all.cpp prepared_statement_tests/get.cpp prepared_statement_tests/get_pointer.cpp prepared_statement_tests/get_optional.cpp prepared_statement_tests/update.cpp prepared_statement_tests/remove.cpp prepared_statement_tests/insert.cpp prepared_statement_tests/replace.cpp prepared_statement_tests/insert_range.cpp prepared_statement_tests/replace_range.cpp prepared_statement_tests/insert_explicit.cpp pragma_tests.cpp simple_query.cpp static_tests/is_bindable.cpp static_tests/arithmetic_operators_result_type.cpp static_tests/tuple_conc.cpp static_tests/node_tuple.cpp static_tests/bindable_filter.cpp static_tests/count_tuple.cpp static_tests/member_traits_tests.cpp constraints/default.cpp constraints/foreign_key.cpp constraints/check.cpp table_tests.cpp statement_serializator_tests/primary_key.cpp statement_serializator_tests/column_names.cpp statement_serializator_tests/autoincrement.cpp statement_serializator_tests/arithmetic_operators.cpp statement_serializator_tests/core_functions.cpp statement_serializator_tests/comparison_operators.cpp statement_serializator_tests/unique.cpp statement_serializator_tests/foreign_key.cpp statement_serializator_tests/collate.cpp statement_serializator_tests/check.cpp) if(SQLITE_ORM_OMITS_CODECVT) diff --git a/tests/constraints/check.cpp b/tests/constraints/check.cpp new file mode 100644 index 000000000..083c4da17 --- /dev/null +++ b/tests/constraints/check.cpp @@ -0,0 +1,40 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("check") { + { + struct Contact { + int id = 0; + std::string firstName; + std::string lastName; + std::unique_ptr email; + std::string phone; + }; + auto storage = make_storage({}, + make_table("contacts", + make_column("contact_id", &Contact::id, primary_key()), + make_column("first_name", &Contact::firstName), + make_column("last_name", &Contact::lastName), + make_column("email", &Contact::email), + make_column("phone", &Contact::phone), + check(length(&Contact::phone) >= 10))); + storage.sync_schema(); + } + { + struct Book { + int id = 0; + std::string name; + std::string pubName; + int price = 0; + }; + auto storage = make_storage({}, + make_table("BOOK", + make_column("Book_id", &Book::id, primary_key()), + make_column("Book_name", &Book::name), + make_column("Pub_name", &Book::pubName), + make_column("PRICE", &Book::price, check(c(&Book::price) > 0)))); + storage.sync_schema(); + } +} diff --git a/tests/explicit_columns.cpp b/tests/explicit_columns.cpp index 665adc6f3..3ea6e77c5 100644 --- a/tests/explicit_columns.cpp +++ b/tests/explicit_columns.cpp @@ -28,7 +28,7 @@ TEST_CASE("Explicit colums") { make_table("tokens", make_column("id", &Token::id, primary_key()), make_column("token", &Token::token), - make_column("used_id", &Token::usedId), + make_column("user_id", &Token::usedId), foreign_key(&Token::usedId).references(column(&User::id)))); storage.sync_schema(); REQUIRE(storage.table_exists("users")); diff --git a/tests/operators/is_null.cpp b/tests/operators/is_null.cpp index d7137f5ac..5d7b7e6e9 100644 --- a/tests/operators/is_null.cpp +++ b/tests/operators/is_null.cpp @@ -13,10 +13,12 @@ TEST_CASE("Is null") { make_table("users", make_column("id", &User::id, primary_key()), make_column("name", &User::name))); storage.sync_schema(); + REQUIRE(storage.count() == 0); storage.replace(User{1, std::make_unique("Sheldon")}); + REQUIRE(storage.count() == 1); storage.replace(User{2}); + REQUIRE(storage.count() == 2); storage.replace(User{3, std::make_unique("Leonard")}); - REQUIRE(storage.count() == 3); REQUIRE(storage.count(where(is_null(&User::name))) == 1); REQUIRE(storage.count(where(is_not_null(&User::name))) == 2); diff --git a/tests/statement_serializator_tests/arithmetic_operators.cpp b/tests/statement_serializator_tests/arithmetic_operators.cpp new file mode 100644 index 000000000..5c82413d5 --- /dev/null +++ b/tests/statement_serializator_tests/arithmetic_operators.cpp @@ -0,0 +1,58 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator arithmetic operators") { + internal::serializator_context_base context; + SECTION("add") { + std::string value; + SECTION("func") { + value = serialize(add(3, 5), context); + } + SECTION("operator") { + value = serialize(c(3) + 5, context); + } + REQUIRE(value == "(3 + 5)"); + } + SECTION("sub") { + std::string value; + SECTION("func") { + value = serialize(sub(5, -9), context); + } + SECTION("operator") { + value = serialize(c(5) - -9, context); + } + REQUIRE(value == "(5 - -9)"); + } + SECTION("mul") { + std::string value; + SECTION("func") { + value = serialize(mul(10, 0.5), context); + } + SECTION("operator") { + value = serialize(c(10) * 0.5, context); + } + REQUIRE(value == "(10 * 0.5)"); + } + SECTION("div") { + std::string value; + SECTION("func") { + value = serialize(sqlite_orm::div(10, 2), context); + } + SECTION("operator") { + value = serialize(c(10) / 2, context); + } + REQUIRE(value == "(10 / 2)"); + } + SECTION("mod") { + std::string value; + SECTION("func") { + value = serialize(mod(20, 3), context); + } + SECTION("operator") { + value = serialize(c(20) % 3, context); + } + REQUIRE(value == "(20 % 3)"); + } +} diff --git a/tests/statement_serializator_tests/autoincrement.cpp b/tests/statement_serializator_tests/autoincrement.cpp new file mode 100644 index 000000000..a1e2f4f50 --- /dev/null +++ b/tests/statement_serializator_tests/autoincrement.cpp @@ -0,0 +1,11 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator autoincrement") { + internal::serializator_context_base context; + auto autoinc = autoincrement(); + auto value = serialize(autoinc, context); + REQUIRE(value == "AUTOINCREMENT"); +} diff --git a/tests/statement_serializator_tests/check.cpp b/tests/statement_serializator_tests/check.cpp new file mode 100644 index 000000000..12a649606 --- /dev/null +++ b/tests/statement_serializator_tests/check.cpp @@ -0,0 +1,52 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator check") { + { + struct Table { + int col1 = 0; + std::string col2; + int col3 = 0; + }; + auto ch = check(greater_than(&Table::col3, 0)); + auto table = make_table("tablename", + make_column("col1", &Table::col1, primary_key()), + make_column("col2", &Table::col2), + make_column("col3", &Table::col3, ch)); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{table}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(ch, context); + REQUIRE(value == "CHECK (col3 > 0)"); + } + { + struct Book { + int id = 0; + std::string name; + std::string pubName; + int price = 0; + }; + auto ch = check(lesser_than(0, &Book::price)); + auto table = make_table("BOOK", + make_column("Book_id", &Book::id, primary_key()), + make_column("Book_name", &Book::name), + make_column("Pub_name", &Book::pubName), + make_column("PRICE", &Book::price, ch)); + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{table}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(ch, context); + REQUIRE(value == "CHECK (0 < PRICE)"); + } +} diff --git a/tests/statement_serializator_tests/collate.cpp b/tests/statement_serializator_tests/collate.cpp new file mode 100644 index 000000000..4d1b97d39 --- /dev/null +++ b/tests/statement_serializator_tests/collate.cpp @@ -0,0 +1,23 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator collate") { + internal::serializator_context_base context; + { + auto col = collate_nocase(); + auto value = serialize(col, context); + REQUIRE(value == "COLLATE NOCASE"); + } + { + auto col = collate_binary(); + auto value = serialize(col, context); + REQUIRE(value == "COLLATE BINARY"); + } + { + auto col = collate_rtrim(); + auto value = serialize(col, context); + REQUIRE(value == "COLLATE RTRIM"); + } +} diff --git a/tests/statement_serializator_tests/column_names.cpp b/tests/statement_serializator_tests/column_names.cpp new file mode 100644 index 000000000..d6b12248e --- /dev/null +++ b/tests/statement_serializator_tests/column_names.cpp @@ -0,0 +1,106 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator column names") { + { // by member field pointer + struct User { + int id = 0; + std::string name; + }; + auto table = make_table("users", make_column("id", &User::id), make_column("name", &User::name)); + using storage_impl_t = internal::storage_impl; + storage_impl_t storageImpl{table}; + { + using context_t = internal::serializator_context; + context_t context{storageImpl}; + { + auto value = serialize(&User::id, context); + REQUIRE(value == "id"); + } + { + auto value = serialize(&User::name, context); + REQUIRE(value == "name"); + } + } + } + { // by getters and setters pointers + struct User { + + int getId() const { + return this->id; + } + + void setId(int value) { + this->id = value; + } + + const std::string &getName() const { + return this->name; + } + + void setName(std::string value) { + this->name = move(value); + } + + private: + int id = 0; + std::string name; + }; + { + auto table = make_table("users", + make_column("id", &User::getId, &User::setId), + make_column("name", &User::getName, &User::setName)); + using storage_impl_t = internal::storage_impl; + storage_impl_t storageImpl{table}; + { + using context_t = internal::serializator_context; + context_t context{storageImpl}; + { + auto value = serialize(&User::getId, context); + REQUIRE(value == "id"); + } + { + auto value = serialize(&User::setId, context); + REQUIRE(value == "id"); + } + { + auto value = serialize(&User::getName, context); + REQUIRE(value == "name"); + } + { + auto value = serialize(&User::setName, context); + REQUIRE(value == "name"); + } + } + } + { // column names by setters and getters pointers (reverse order) + auto table = make_table("users", + make_column("id", &User::setId, &User::getId), + make_column("name", &User::setName, &User::getName)); + using storage_impl_t = internal::storage_impl; + storage_impl_t storageImpl{table}; + { + using context_t = internal::serializator_context; + context_t context{storageImpl}; + { + auto value = serialize(&User::getId, context); + REQUIRE(value == "id"); + } + { + auto value = serialize(&User::setId, context); + REQUIRE(value == "id"); + } + { + auto value = serialize(&User::getName, context); + REQUIRE(value == "name"); + } + { + auto value = serialize(&User::setName, context); + REQUIRE(value == "name"); + } + } + } + } +} diff --git a/tests/statement_serializator_tests/comparison_operators.cpp b/tests/statement_serializator_tests/comparison_operators.cpp new file mode 100644 index 000000000..d4839046a --- /dev/null +++ b/tests/statement_serializator_tests/comparison_operators.cpp @@ -0,0 +1,86 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator comparison operators") { + internal::serializator_context_base context; + SECTION("lesser_than") { + std::string value; + SECTION("func") { + value = serialize(lesser_than(4, 5), context); + } + SECTION("short func") { + value = serialize(lt(4, 5), context); + } + SECTION("operator") { + value = serialize(c(4) < 5, context); + } + REQUIRE(value == "(4 < 5)"); + } + SECTION("lesser_or_equal") { + std::string value; + SECTION("func") { + value = serialize(lesser_or_equal(10, 15), context); + } + SECTION("short func") { + value = serialize(le(10, 15), context); + } + SECTION("operator") { + value = serialize(c(10) <= 15, context); + } + REQUIRE(value == "(10 <= 15)"); + } + SECTION("greater_than") { + std::string value; + SECTION("func") { + value = serialize(greater_than(1, 0.5), context); + } + SECTION("short func") { + value = serialize(gt(1, 0.5), context); + } + SECTION("operator") { + value = serialize(c(1) > 0.5, context); + } + REQUIRE(value == "(1 > 0.5)"); + } + SECTION("greater_or_equal") { + std::string value; + SECTION("func") { + value = serialize(greater_or_equal(10, -5), context); + } + SECTION("short func") { + value = serialize(ge(10, -5), context); + } + SECTION("operator") { + value = serialize(c(10) >= -5, context); + } + REQUIRE(value == "(10 >= -5)"); + } + SECTION("is_equal") { + std::string value; + SECTION("func") { + value = serialize(is_equal("ototo", "Hey"), context); + } + SECTION("short func") { + value = serialize(eq("ototo", "Hey"), context); + } + SECTION("operator") { + value = serialize(c("ototo") == "Hey", context); + } + REQUIRE(value == "('ototo' = 'Hey')"); + } + SECTION("is_not_equal") { + std::string value; + SECTION("func") { + value = serialize(is_not_equal("lala", 7), context); + } + SECTION("short func") { + value = serialize(ne("lala", 7), context); + } + SECTION("operator") { + value = serialize(c("lala") != 7, context); + } + REQUIRE(value == "('lala' != 7)"); + } +} diff --git a/tests/statement_serializator_tests/core_functions.cpp b/tests/statement_serializator_tests/core_functions.cpp new file mode 100644 index 000000000..9ebae58a2 --- /dev/null +++ b/tests/statement_serializator_tests/core_functions.cpp @@ -0,0 +1,122 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator core functions") { + internal::serializator_context_base context; + { + auto value = serialize(length("hi"), context); + REQUIRE(value == "LENGTH('hi')"); + } + { + auto value = serialize(sqlite_orm::abs(-100), context); + REQUIRE(value == "ABS(-100)"); + } + { + auto value = serialize(lower("dancefloor"), context); + REQUIRE(value == "LOWER('dancefloor')"); + } + { + auto value = serialize(upper("call"), context); + REQUIRE(value == "UPPER('call')"); + } + { + auto value = serialize(changes(), context); + REQUIRE(value == "CHANGES()"); + } + { + auto value = serialize(trim("hey"), context); + REQUIRE(value == "TRIM('hey')"); + } + { + auto value = serialize(trim("hey", "h"), context); + REQUIRE(value == "TRIM('hey', 'h')"); + } + { + auto value = serialize(ltrim("hey"), context); + REQUIRE(value == "LTRIM('hey')"); + } + { + auto value = serialize(ltrim("hey", "h"), context); + REQUIRE(value == "LTRIM('hey', 'h')"); + } + { + auto value = serialize(rtrim("hey"), context); + REQUIRE(value == "RTRIM('hey')"); + } + { + auto value = serialize(rtrim("hey", "h"), context); + REQUIRE(value == "RTRIM('hey', 'h')"); + } + { + auto value = serialize(hex("love"), context); + REQUIRE(value == "HEX('love')"); + } + { + auto value = serialize(quote("one"), context); + REQUIRE(value == "QUOTE('one')"); + } + { + auto value = serialize(randomblob(5), context); + REQUIRE(value == "RANDOMBLOB(5)"); + } + { + auto value = serialize(instr("hi", "i"), context); + REQUIRE(value == "INSTR('hi', 'i')"); + } + { + auto value = serialize(replace("contigo", "o", "a"), context); + REQUIRE(value == "REPLACE('contigo', 'o', 'a')"); + } + { + auto value = serialize(sqlite_orm::round(10.5), context); + REQUIRE(value == "ROUND(10.5)"); + } + { + auto value = serialize(sqlite_orm::round(10.5, 0.5), context); + REQUIRE(value == "ROUND(10.5, 0.5)"); + } +#if SQLITE_VERSION_NUMBER >= 3007016 + { + auto value = serialize(char_(40, 45), context); + REQUIRE(value == "CHAR(40, 45)"); + } + { + auto value = serialize(sqlite_orm::random(), context); + REQUIRE(value == "RANDOM()"); + } +#endif + { + auto value = serialize(coalesce(10, 15), context); + REQUIRE(value == "COALESCE(10, 15)"); + } + { + auto value = serialize(date("now"), context); + REQUIRE(value == "DATE('now')"); + } + { + auto value = serialize(time("12:00", "localtime"), context); + REQUIRE(value == "TIME('12:00', 'localtime')"); + } + { + auto value = serialize(datetime("now"), context); + REQUIRE(value == "DATETIME('now')"); + } + { + auto value = serialize(julianday("now"), context); + REQUIRE(value == "JULIANDAY('now')"); + } + { + auto value = serialize(zeroblob(5), context); + REQUIRE(value == "ZEROBLOB(5)"); + } + { + auto value = serialize(substr("Zara", 2), context); + REQUIRE(value == "SUBSTR('Zara', 2)"); + } + { + auto value = serialize(substr("Natasha", 3, 2), context); + REQUIRE(value == "SUBSTR('Natasha', 3, 2)"); + } +} diff --git a/tests/statement_serializator_tests/default.cpp b/tests/statement_serializator_tests/default.cpp new file mode 100644 index 000000000..f7a9146c1 --- /dev/null +++ b/tests/statement_serializator_tests/default.cpp @@ -0,0 +1,23 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator default") { + internal::serializator_context_base context; + { // int literal + auto def = default_value(1); + auto value = serialize(def, context); + REQUIRE(value == "DEFAULT (1)"); + } + { // string literal + auto def = default_value("hi"); + auto value = serialize(def, context); + REQUIRE(value == "DEFAULT ('hi')"); + } + { // func + auto def = default_value(datetime("now")); + auto value = serialize(def, context); + REQUIRE(value == "DEFAULT (DATETIME('now'))"); + } +} diff --git a/tests/statement_serializator_tests/foreign_key.cpp b/tests/statement_serializator_tests/foreign_key.cpp new file mode 100644 index 000000000..a6e4715b4 --- /dev/null +++ b/tests/statement_serializator_tests/foreign_key.cpp @@ -0,0 +1,313 @@ +#include +#include + +using namespace sqlite_orm; + +#if SQLITE_VERSION_NUMBER >= 3006019 + +TEST_CASE("statement_serializator foreign key") { + SECTION("one to one") { + struct User { + int id = 0; + std::string name; + }; + + struct Visit { + int id = 0; + decltype(User::id) userId; + long time = 0; + }; + + auto usersTable = make_table("users", + make_column("id", &User::id, primary_key(), autoincrement()), + make_column("name", &User::name)); + + SECTION("simple") { + auto fk = foreign_key(&Visit::userId).references(&User::id); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id)"); + } + SECTION("on update") { + SECTION("no_action") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_update.no_action(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON UPDATE NO ACTION"); + } + SECTION("restrict_") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_update.restrict_(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON UPDATE RESTRICT"); + } + SECTION("set_null") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_update.set_null(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON UPDATE SET NULL"); + } + SECTION("set_default") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_update.set_default(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON UPDATE SET DEFAULT"); + } + SECTION("cascade") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_update.cascade(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON UPDATE CASCADE"); + } + } + SECTION("on delete") { + SECTION("no_action") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_delete.no_action(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE NO ACTION"); + } + SECTION("restrict_") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_delete.restrict_(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE RESTRICT"); + } + SECTION("set_null") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_delete.set_null(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET NULL"); + } + SECTION("set_default") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_delete.set_default(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE SET DEFAULT"); + } + SECTION("cascade") { + auto fk = foreign_key(&Visit::userId).references(&User::id).on_delete.cascade(); + + auto visitsTable = make_table("visits", + make_column("id", &Visit::id, primary_key(), autoincrement()), + make_column("user_id", &Visit::userId), + make_column("time", &Visit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE"); + } + } + } + SECTION("one to explicit one") { + struct Object { + int id = 0; + }; + + struct User : Object { + std::string name; + + User(decltype(id) id_, decltype(name) name_) : Object{id_}, name(move(name_)) {} + }; + + struct Token : Object { + std::string token; + int usedId = 0; + + Token(decltype(id) id_, decltype(token) token_, decltype(usedId) usedId_) : + Object{id_}, token(std::move(token_)), usedId(usedId_) {} + }; + auto fk = foreign_key(&Token::usedId).references(column(&User::id)); + auto usersTable = + make_table("users", make_column("id", &User::id, primary_key()), make_column("name", &User::name)); + auto tokensTable = make_table("tokens", + make_column("id", &Token::id, primary_key()), + make_column("token", &Token::token), + make_column("user_id", &Token::usedId), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, tokensTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id) REFERENCES users(id)"); + } + SECTION("composite key") { + struct User { + int id = 0; + std::string firstName; + std::string lastName; + }; + + struct UserVisit { + int userId = 0; + std::string userFirstName; + time_t time = 0; + }; + + auto fk = foreign_key(&UserVisit::userId, &UserVisit::userFirstName).references(&User::id, &User::firstName); + auto usersTable = make_table("users", + make_column("id", &User::id), + make_column("first_name", &User::firstName), + make_column("last_name", &User::lastName), + primary_key(&User::id, &User::firstName)); + auto visitsTable = make_table("visits", + make_column("user_id", &UserVisit::userId), + make_column("user_first_name", &UserVisit::userFirstName), + make_column("time", &UserVisit::time), + fk); + + using storage_impl_t = internal::storage_impl; + + storage_impl_t storageImpl{usersTable, visitsTable}; + + using context_t = internal::serializator_context; + + context_t context{storageImpl}; + auto value = serialize(fk, context); + REQUIRE(value == "FOREIGN KEY(user_id, user_first_name) REFERENCES users(id, first_name)"); + } +} + +#endif // SQLITE_VERSION_NUMBER diff --git a/tests/statement_serializator_tests/primary_key.cpp b/tests/statement_serializator_tests/primary_key.cpp new file mode 100644 index 000000000..e6593d19f --- /dev/null +++ b/tests/statement_serializator_tests/primary_key.cpp @@ -0,0 +1,44 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator primary key") { + { // empty pk + internal::serializator_context_base context; + auto pk = primary_key(); + auto value = serialize(pk, context); + REQUIRE(value == "PRIMARY KEY"); + } + { + struct User { + int id = 0; + std::string name; + }; + auto table = make_table("users", make_column("id", &User::id), make_column("name", &User::name)); + using storage_impl_t = internal::storage_impl; + auto storageImpl = storage_impl_t{table}; + using context_t = internal::serializator_context; + context_t context{storageImpl}; + { // single column pk + auto pk = primary_key(&User::id); + auto value = serialize(pk, context); + REQUIRE(value == "PRIMARY KEY(id)"); + } + { // double column pk + auto pk = primary_key(&User::id, &User::name); + auto value = serialize(pk, context); + REQUIRE(value == "PRIMARY KEY(id, name)"); + } + { // empty pk asc + auto pk = primary_key().asc(); + auto value = serialize(pk, context); + REQUIRE(value == "PRIMARY KEY ASC"); + } + { // empty pk desc + auto pk = primary_key().desc(); + auto value = serialize(pk, context); + REQUIRE(value == "PRIMARY KEY DESC"); + } + } +} diff --git a/tests/statement_serializator_tests/unique.cpp b/tests/statement_serializator_tests/unique.cpp new file mode 100644 index 000000000..4f64be198 --- /dev/null +++ b/tests/statement_serializator_tests/unique.cpp @@ -0,0 +1,11 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator unique") { + internal::serializator_context_base context; + auto un = unique(); + auto value = serialize(un, context); + REQUIRE(value == "UNIQUE"); +} diff --git a/tests/static_if_tests.cpp b/tests/static_if_tests.cpp new file mode 100644 index 000000000..f56fffafb --- /dev/null +++ b/tests/static_if_tests.cpp @@ -0,0 +1,67 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("static_if") { + { // simple true + auto value = 0; + internal::static_if( + [&value] { + value = 1; + }, + [&value] { + value = -1; + })(); + REQUIRE(value == 1); + } + { // simple false + auto value = 0; + internal::static_if( + [&value] { + value = 1; + }, + [&value] { + value = -1; + })(); + REQUIRE(value == -1); + } + { // tuple is empty + auto value = 0; + internal::static_if>{}>( + [&value] { + value = 1; + }, + [&value] { + value = -1; + })(); + REQUIRE(value == 1); + } + { // tuple is not empty + auto value = 0; + internal::static_if>>{}>( + [&value] { + value = 1; + }, + [&value] { + value = -1; + })(); + REQUIRE(value == -1); + } + { + struct User { + std::string name; + }; + auto ch = check(length(&User::name) > 5); + static_assert(!internal::is_column::value, ""); + int called = 0; + internal::static_if{}>( + [&called] { + called = 1; + }, + [&called] { + called = -1; + })(); + REQUIRE(called == -1); + } +} diff --git a/tests/static_tests.cpp b/tests/static_tests.cpp index f78062115..fb91fec04 100644 --- a/tests/static_tests.cpp +++ b/tests/static_tests.cpp @@ -291,7 +291,7 @@ TEST_CASE("Select return types") { { // test storage traits struct Visit { - int id; + int id = 0; std::string date; }; using namespace sqlite_orm::internal::storage_traits; diff --git a/tests/static_tests/member_traits_tests.cpp b/tests/static_tests/member_traits_tests.cpp new file mode 100644 index 000000000..4a5a335c5 --- /dev/null +++ b/tests/static_tests/member_traits_tests.cpp @@ -0,0 +1,109 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("member_traits_tests") { + using internal::field_member_traits; + using internal::getter_traits; + using internal::is_field_member_pointer; + using internal::is_getter; + using internal::is_setter; + using internal::member_traits; + using internal::setter_traits; + using std::is_same; + + struct User { + int id; + + const int &getIdByRefConst() const { + return this->id; + } + + const int &getIdByRef() { + return this->id; + } + + int getIdByValConst() const { + return this->id; + } + + void setIdByVal(int id) { + this->id = id; + } + + void setIdByConstRef(const int &id) { + this->id = id; + } + + void setIdByRef(int &id) { + this->id = id; + } + }; + + static_assert(is_field_member_pointer::value, ""); + static_assert(!is_field_member_pointer::value, ""); + static_assert(!is_field_member_pointer::value, ""); + static_assert(!is_field_member_pointer::value, ""); + static_assert(!is_field_member_pointer::value, ""); + static_assert(!is_field_member_pointer::value, ""); + static_assert(!is_field_member_pointer::value, ""); + + static_assert(!is_getter::value, ""); + static_assert(is_getter::value, ""); + static_assert(is_getter::value, ""); + static_assert(is_getter::value, ""); + static_assert(!is_getter::value, ""); + static_assert(!is_getter::value, ""); + static_assert(!is_getter::value, ""); + + static_assert(!is_setter::value, ""); + static_assert(!is_setter::value, ""); + static_assert(!is_setter::value, ""); + static_assert(!is_setter::value, ""); + static_assert(is_setter::value, ""); + static_assert(is_setter::value, ""); + static_assert(is_setter::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); + + static_assert(is_same::object_type, User>::value, ""); + static_assert(is_same::field_type, int>::value, ""); +} diff --git a/tests/table_tests.cpp b/tests/table_tests.cpp new file mode 100644 index 000000000..21aa89b69 --- /dev/null +++ b/tests/table_tests.cpp @@ -0,0 +1,125 @@ +#include +#include +#include + +using namespace sqlite_orm; +using std::cout; +using std::endl; + +TEST_CASE("table") { + { + struct Contact { + int id = 0; + std::string firstName; + std::string lastName; + int countryCode = 0; + std::string phoneNumber; + int visitsCount = 0; + }; + auto contactIdColumn = make_column("contact_id", &Contact::id, primary_key(), autoincrement()); + { + using column_type = decltype(contactIdColumn); + static_assert(internal::is_column::value, ""); + } + + auto table = make_table("contacts", + contactIdColumn, + make_column("first_name", &Contact::firstName), + make_column("last_name", &Contact::lastName), + make_column("country_code", &Contact::countryCode), + make_column("phone_number", &Contact::phoneNumber), + make_column("visits_count", &Contact::visitsCount)); + REQUIRE(table.find_column_name(&Contact::id) == "contact_id"); + REQUIRE(table.find_column_name(&Contact::firstName) == "first_name"); + REQUIRE(table.find_column_name(&Contact::lastName) == "last_name"); + REQUIRE(table.find_column_name(&Contact::countryCode) == "country_code"); + REQUIRE(table.find_column_name(&Contact::phoneNumber) == "phone_number"); + REQUIRE(table.find_column_name(&Contact::visitsCount) == "visits_count"); + } + { + struct Contact { + private: + int _id = 0; + std::string _firstName; + std::string _lastName; + int _countryCode = 0; + std::string _phoneNumber; + int _visitsCount = 0; + + public: + int id() const { + return this->_id; + } + + void setId(int value) { + this->_id = value; + } + + const std::string &firstName() const { + return this->_firstName; + } + + void setFirstName(std::string value) { + this->_firstName = move(value); + } + + const std::string &lastName() const { + return this->_lastName; + } + + void setLastName(std::string value) { + this->_lastName = move(value); + } + + int countryCode() const { + return this->_countryCode; + } + + void setCountryCode(int value) { + this->_countryCode = value; + } + + const std::string &phoneNumber() const { + return this->_phoneNumber; + } + + void setPhoneNumber(std::string value) { + this->_phoneNumber = move(value); + } + + int visitsCount() const { + return this->_visitsCount; + } + + void setVisitsCount(int value) { + this->_visitsCount = value; + } + }; + auto table = + make_table("contacts", + make_column("contact_id", &Contact::id, &Contact::setId, primary_key(), autoincrement()), + make_column("first_name", &Contact::firstName, &Contact::setFirstName), + make_column("last_name", &Contact::lastName, &Contact::setLastName), + make_column("country_code", &Contact::countryCode, &Contact::setCountryCode), + make_column("phone_number", &Contact::phoneNumber, &Contact::setPhoneNumber), + make_column("visits_count", &Contact::visitsCount, &Contact::setVisitsCount)); + + REQUIRE(table.find_column_name(&Contact::id) == "contact_id"); + REQUIRE(table.find_column_name(&Contact::setId) == "contact_id"); + + REQUIRE(table.find_column_name(&Contact::firstName) == "first_name"); + REQUIRE(table.find_column_name(&Contact::setFirstName) == "first_name"); + + REQUIRE(table.find_column_name(&Contact::lastName) == "last_name"); + REQUIRE(table.find_column_name(&Contact::setLastName) == "last_name"); + + REQUIRE(table.find_column_name(&Contact::countryCode) == "country_code"); + REQUIRE(table.find_column_name(&Contact::setCountryCode) == "country_code"); + + REQUIRE(table.find_column_name(&Contact::phoneNumber) == "phone_number"); + REQUIRE(table.find_column_name(&Contact::setPhoneNumber) == "phone_number"); + + REQUIRE(table.find_column_name(&Contact::visitsCount) == "visits_count"); + REQUIRE(table.find_column_name(&Contact::setVisitsCount) == "visits_count"); + } +} diff --git a/tests/tests2.cpp b/tests/tests2.cpp index 9b1172768..d7aeb6e69 100644 --- a/tests/tests2.cpp +++ b/tests/tests2.cpp @@ -254,6 +254,58 @@ TEST_CASE("Select") { REQUIRE(storage.get(firstId).currentWord == "ototo"); } +TEST_CASE("select asterisk") { + using Catch::Matchers::UnorderedEquals; + + struct Employee { + int id; + std::string name; + int age; + std::string address; // optional + double salary; // optional + }; + + auto storage = make_storage({}, + make_table("COMPANY", + make_column("ID", &Employee::id, primary_key()), + make_column("NAME", &Employee::name), + make_column("AGE", &Employee::age), + make_column("ADDRESS", &Employee::address), + make_column("SALARY", &Employee::salary))); + storage.sync_schema(); + + // create employees.. + Employee paul{-1, "Paul", 32, "California", 20000.0}; + Employee allen{-1, "Allen", 25, "Texas", 15000.0}; + Employee teddy{-1, "Teddy", 23, "Norway", 20000.0}; + Employee mark{-1, "Mark", 25, "Rich-Mond", 65000.0}; + Employee david{-1, "David", 27, "Texas", 85000.0}; + Employee kim{-1, "Kim", 22, "South-Hall", 45000.0}; + Employee james{-1, "James", 24, "Houston", 10000.0}; + + // insert employees. `insert` function returns id of inserted object.. + paul.id = storage.insert(paul); + allen.id = storage.insert(allen); + teddy.id = storage.insert(teddy); + mark.id = storage.insert(mark); + david.id = storage.insert(david); + kim.id = storage.insert(kim); + james.id = storage.insert(james); + + auto allEmployeesTuples = storage.select(asterisk()); + + std::vector> expected; + + expected.push_back(std::make_tuple(paul.id, "Paul", 32, "California", 20000.0)); + expected.push_back(std::make_tuple(allen.id, "Allen", 25, "Texas", 15000.0)); + expected.push_back(std::make_tuple(teddy.id, "Teddy", 23, "Norway", 20000.0)); + expected.push_back(std::make_tuple(mark.id, "Mark", 25, "Rich-Mond", 65000.0)); + expected.push_back(std::make_tuple(david.id, "David", 27, "Texas", 85000.0)); + expected.push_back(std::make_tuple(kim.id, "Kim", 22, "South-Hall", 45000.0)); + expected.push_back(std::make_tuple(james.id, "James", 24, "Houston", 10000.0)); + REQUIRE_THAT(allEmployeesTuples, UnorderedEquals(expected)); +} + TEST_CASE("Replace query") { struct Object { int id; diff --git a/tests/tests3.cpp b/tests/tests3.cpp index 0ca8b9de5..1cd65daa7 100644 --- a/tests/tests3.cpp +++ b/tests/tests3.cpp @@ -98,13 +98,13 @@ TEST_CASE("Row id") { TEST_CASE("Issue 87") { struct Data { - uint8_t mDefault; /**< 0=User or 1=Default*/ - uint8_t mAppLang; // en_GB - uint8_t mContentLang1; // de_DE - uint8_t mContentLang2; // en_GB - uint8_t mContentLang3; - uint8_t mContentLang4; - uint8_t mContentLang5; + uint8_t mDefault = 0; /**< 0=User or 1=Default*/ + uint8_t mAppLang = 0; // en_GB + uint8_t mContentLang1 = 0; // de_DE + uint8_t mContentLang2 = 0; // en_GB + uint8_t mContentLang3 = 0; + uint8_t mContentLang4 = 0; + uint8_t mContentLang5 = 0; }; Data data; diff --git a/tests/tests4.cpp b/tests/tests4.cpp index 210a14aa0..998f97438 100644 --- a/tests/tests4.cpp +++ b/tests/tests4.cpp @@ -226,6 +226,14 @@ TEST_CASE("Join") { auto rows = storage.get_all(inner_join(on(is_equal(&Visit::userId, 2)))); REQUIRE(rows.size() == 6); } + { + auto rows = storage.get_all(cross_join()); + REQUIRE(rows.size() == 15); + } + { + auto rows = storage.get_all(natural_join()); + REQUIRE(rows.size() == 3); + } } TEST_CASE("Storage copy") { diff --git a/third_party/amalgamate/config.json b/third_party/amalgamate/config.json index b5345fc1e..ff567afee 100755 --- a/third_party/amalgamate/config.json +++ b/third_party/amalgamate/config.json @@ -37,8 +37,7 @@ "dev/storage.h", "dev/finish_macros.h", "dev/node_tuple.h", - "dev/get_prepared_statement.h", - "dev/statement_serializator.h" + "dev/get_prepared_statement.h" ], "include_paths": ["dev"] } From 46c732a90197b01e20ec8e6850fedc9e062f55e9 Mon Sep 17 00:00:00 2001 From: fnc12 Date: Sun, 2 Feb 2020 13:45:20 +0300 Subject: [PATCH 2/3] removed comments --- dev/constraints.h | 4 -- include/sqlite_orm/sqlite_orm.h | 71 +++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/dev/constraints.h b/dev/constraints.h index 3657eec3d..ea9b6c0d2 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -59,8 +59,6 @@ namespace sqlite_orm { primary_key_t(decltype(columns) c) : columns(move(c)) {} - // using constraints_type = std::tuple<>; - primary_key_t asc() const { auto res = *this; res.asc_option = order_by::ascending; @@ -255,8 +253,6 @@ namespace sqlite_orm { return *this; } - // using constraints_type = std::tuple<>; - template void for_each_column(const L &) {} diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index dba54e630..479ff9616 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -27,7 +27,7 @@ __pragma(push_macro("min")) #include #include // std::ostringstream - namespace sqlite_orm { +namespace sqlite_orm { enum class orm_error_code { not_found = 1, @@ -44,6 +44,7 @@ __pragma(push_macro("min")) failed_to_init_a_backup, unknown_member_value, }; + } namespace sqlite_orm { @@ -224,6 +225,7 @@ namespace sqlite_orm { // #include "static_magic.h" + #include // std::false_type, std::true_type, std::integral_constant namespace sqlite_orm { @@ -258,6 +260,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type @@ -544,8 +547,6 @@ namespace sqlite_orm { primary_key_t(decltype(columns) c) : columns(move(c)) {} - // using constraints_type = std::tuple<>; - primary_key_t asc() const { auto res = *this; res.asc_option = order_by::ascending; @@ -740,8 +741,6 @@ namespace sqlite_orm { return *this; } - // using constraints_type = std::tuple<>; - template void for_each_column(const L &) {} @@ -993,6 +992,7 @@ namespace sqlite_orm { // #include "serializator_context.h" + namespace sqlite_orm { namespace internal { @@ -1023,6 +1023,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -1264,6 +1265,7 @@ namespace sqlite_orm { // #include "getter_traits.h" + namespace sqlite_orm { namespace internal { @@ -1447,6 +1449,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1777,6 +1780,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -1809,6 +1813,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -3297,6 +3302,7 @@ namespace sqlite_orm { // #include "conditions.h" + namespace sqlite_orm { namespace internal { @@ -3416,6 +3422,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -3453,6 +3460,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace core_functions { @@ -4279,6 +4287,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -4635,6 +4644,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -4741,6 +4751,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -4768,6 +4779,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -4978,6 +4990,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::string #include // std::unique_ptr #include // std::array @@ -5038,6 +5051,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { /** @@ -5414,6 +5428,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { namespace internal { @@ -5662,6 +5677,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -5939,6 +5955,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -6238,10 +6255,12 @@ namespace sqlite_orm { // #include "field_value_holder.h" + #include // std::enable_if // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -6264,6 +6283,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -6768,6 +6788,7 @@ namespace sqlite_orm { // #include "view.h" + #include // std::shared_ptr #include // std::string #include // std::forward, std::move @@ -6783,6 +6804,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include // std::shared_ptr, std::unique_ptr, std::make_shared #include #include // std::decay @@ -6798,6 +6820,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -6926,6 +6949,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -6941,6 +6965,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::iterator_traits #include // std::string @@ -6949,12 +6974,14 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include // std::string #include // std::system_error // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -7029,6 +7056,7 @@ namespace sqlite_orm { // #include "select_constraints.h" + namespace sqlite_orm { namespace internal { @@ -7400,6 +7428,7 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } + namespace sqlite_orm { namespace internal { @@ -7857,6 +7886,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -7915,6 +7945,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include // std::function, std::bind #include #include // std::string @@ -7929,6 +7960,7 @@ namespace sqlite_orm { // #include "pragma.h" + #include // std::string #include #include // std::function @@ -7942,6 +7974,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -8062,6 +8095,7 @@ namespace sqlite_orm { // #include "limit_accesor.h" + #include #include // std::map #include // std::function @@ -8069,6 +8103,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -8202,10 +8237,12 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -8280,6 +8317,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::string #include @@ -8288,6 +8326,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -8353,6 +8392,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -8888,11 +8928,13 @@ namespace sqlite_orm { // #include "expression_object_type.h" + #include // std::decay #include // std::reference_wrapper // #include "prepared_statement.h" + namespace sqlite_orm { namespace internal { @@ -9012,6 +9054,7 @@ namespace sqlite_orm { // #include "statement_serializator.h" + #include // std::stringstream #include // std::string #include // std::is_arithmetic, std::enable_if @@ -9026,6 +9069,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -9313,6 +9357,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace conditions { @@ -12230,19 +12275,20 @@ __pragma(pop_macro("min")) #include // std::pair #include // std::reference_wrapper - // #include "conditions.h" +// #include "conditions.h" - // #include "operators.h" +// #include "operators.h" - // #include "select_constraints.h" +// #include "select_constraints.h" - // #include "prepared_statement.h" +// #include "prepared_statement.h" - // #include "optional_container.h" +// #include "optional_container.h" - // #include "core_functions.h" +// #include "core_functions.h" - namespace sqlite_orm { + +namespace sqlite_orm { namespace internal { @@ -12524,6 +12570,7 @@ __pragma(pop_macro("min")) // #include "expression_object_type.h" + namespace sqlite_orm { template From 9074ff70d9429efb0a93fc4e374fee5328be3912 Mon Sep 17 00:00:00 2001 From: fnc12 Date: Sun, 2 Feb 2020 13:46:57 +0300 Subject: [PATCH 3/3] code format --- include/sqlite_orm/sqlite_orm.h | 67 ++++----------------------------- 1 file changed, 8 insertions(+), 59 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 479ff9616..49294e3dd 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -27,7 +27,7 @@ __pragma(push_macro("min")) #include #include // std::ostringstream -namespace sqlite_orm { + namespace sqlite_orm { enum class orm_error_code { not_found = 1, @@ -44,7 +44,6 @@ namespace sqlite_orm { failed_to_init_a_backup, unknown_member_value, }; - } namespace sqlite_orm { @@ -225,7 +224,6 @@ namespace sqlite_orm { // #include "static_magic.h" - #include // std::false_type, std::true_type, std::integral_constant namespace sqlite_orm { @@ -260,7 +258,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type @@ -992,7 +989,6 @@ namespace sqlite_orm { // #include "serializator_context.h" - namespace sqlite_orm { namespace internal { @@ -1023,7 +1019,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -1265,7 +1260,6 @@ namespace sqlite_orm { // #include "getter_traits.h" - namespace sqlite_orm { namespace internal { @@ -1449,7 +1443,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1780,7 +1773,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -1813,7 +1805,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -3302,7 +3293,6 @@ namespace sqlite_orm { // #include "conditions.h" - namespace sqlite_orm { namespace internal { @@ -3422,7 +3412,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -3460,7 +3449,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace core_functions { @@ -4287,7 +4275,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -4644,7 +4631,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -4751,7 +4737,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -4779,7 +4764,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -4990,7 +4974,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::string #include // std::unique_ptr #include // std::array @@ -5051,7 +5034,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { /** @@ -5428,7 +5410,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { namespace internal { @@ -5677,7 +5658,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -5955,7 +5935,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -6255,12 +6234,10 @@ namespace sqlite_orm { // #include "field_value_holder.h" - #include // std::enable_if // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -6283,7 +6260,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -6788,7 +6764,6 @@ namespace sqlite_orm { // #include "view.h" - #include // std::shared_ptr #include // std::string #include // std::forward, std::move @@ -6804,7 +6779,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include // std::shared_ptr, std::unique_ptr, std::make_shared #include #include // std::decay @@ -6820,7 +6794,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -6949,7 +6922,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -6965,7 +6937,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::iterator_traits #include // std::string @@ -6974,14 +6945,12 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include // std::string #include // std::system_error // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -7056,7 +7025,6 @@ namespace sqlite_orm { // #include "select_constraints.h" - namespace sqlite_orm { namespace internal { @@ -7428,7 +7396,6 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } - namespace sqlite_orm { namespace internal { @@ -7886,7 +7853,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -7945,7 +7911,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include // std::function, std::bind #include #include // std::string @@ -7960,7 +7925,6 @@ namespace sqlite_orm { // #include "pragma.h" - #include // std::string #include #include // std::function @@ -7974,7 +7938,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -8095,7 +8058,6 @@ namespace sqlite_orm { // #include "limit_accesor.h" - #include #include // std::map #include // std::function @@ -8103,7 +8065,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -8237,12 +8198,10 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -8317,7 +8276,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::string #include @@ -8326,7 +8284,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -8392,7 +8349,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -8928,13 +8884,11 @@ namespace sqlite_orm { // #include "expression_object_type.h" - #include // std::decay #include // std::reference_wrapper // #include "prepared_statement.h" - namespace sqlite_orm { namespace internal { @@ -9054,7 +9008,6 @@ namespace sqlite_orm { // #include "statement_serializator.h" - #include // std::stringstream #include // std::string #include // std::is_arithmetic, std::enable_if @@ -9069,7 +9022,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -9357,7 +9309,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace conditions { @@ -12275,20 +12226,19 @@ __pragma(pop_macro("min")) #include // std::pair #include // std::reference_wrapper -// #include "conditions.h" - -// #include "operators.h" + // #include "conditions.h" -// #include "select_constraints.h" + // #include "operators.h" -// #include "prepared_statement.h" + // #include "select_constraints.h" -// #include "optional_container.h" + // #include "prepared_statement.h" -// #include "core_functions.h" + // #include "optional_container.h" + // #include "core_functions.h" -namespace sqlite_orm { + namespace sqlite_orm { namespace internal { @@ -12570,7 +12520,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template