From d617eb13894e36ac340727323b84e250f3f50198 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Sat, 21 Oct 2023 21:45:37 +0600 Subject: [PATCH 1/6] added assert_updatable_type --- dev/column_names_getter.h | 2 +- dev/constraints.h | 14 + dev/implementations/storage_definitions.h | 2 +- dev/schema/column.h | 7 +- dev/schema/table.h | 25 +- dev/storage.h | 18 +- dev/storage_impl.h | 2 +- include/sqlite_orm/sqlite_orm.h | 239 +++++++++++++++--- tests/CMakeLists.txt | 2 + .../flatten_primary_keys_columns.cpp | 52 ++++ tests/static_tests/table_static_tests.cpp | 91 +++++++ 11 files changed, 405 insertions(+), 49 deletions(-) create mode 100644 tests/static_tests/flatten_primary_keys_columns.cpp create mode 100644 tests/static_tests/table_static_tests.cpp diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index 63ea1082a..d82a800ee 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -30,7 +30,7 @@ namespace sqlite_orm { const Ctx& context) { if(definedOrder) { auto& table = pick_table>(context.db_objects); - collectedExpressions.reserve(collectedExpressions.size() + table.count_columns_amount()); + collectedExpressions.reserve(collectedExpressions.size() + table.columns_count); table.for_each_column([qualified = !context.skip_table_name, &tableName = table.name, &collectedExpressions](const column_identifier& column) { diff --git a/dev/constraints.h b/dev/constraints.h index 4d54c81ad..365d24db7 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -457,6 +457,20 @@ namespace sqlite_orm { static_assert(tuple_has>::value, "an unexpected type was passed"); }; + template + struct primary_key_colums_count_t; + + template + struct primary_key_colums_count_t>: std::integral_constant(sizeof...(Cs))> {}; + + template + struct flatten_primry_keys_columns { + using columns_tuple = typename conc_tuple::type; + }; + + template + struct flatten_primry_keys_columns>: flatten_primry_keys_columns {}; + template using is_constraint = mpl::instantiate, diff --git a/dev/implementations/storage_definitions.h b/dev/implementations/storage_definitions.h index 89e464ef2..5a842491a 100644 --- a/dev/implementations/storage_definitions.h +++ b/dev/implementations/storage_definitions.h @@ -120,7 +120,7 @@ namespace sqlite_orm { const Table& table, const std::vector& columnsToIgnore) const { // must ignore generated columns std::vector> columnNames; - columnNames.reserve(table.count_columns_amount()); + columnNames.reserve(table.columns_count); table.for_each_column([&columnNames, &columnsToIgnore](const column_identifier& column) { auto& columnName = column.name; #if __cpp_lib_ranges >= 201911L diff --git a/dev/schema/column.h b/dev/schema/column.h index b723a5205..79b8c2eaf 100644 --- a/dev/schema/column.h +++ b/dev/schema/column.h @@ -79,10 +79,12 @@ namespace sqlite_orm { * Checks whether contraints are of trait `Trait` */ template class Trait> - constexpr bool is() const { + constexpr static bool is() { return tuple_has::value; } + constexpr static bool is_primary_key = mpl::invoke_t, constraints_type>::value; + constexpr bool is_generated() const { #if SQLITE_VERSION_NUMBER >= 3031000 return is(); @@ -115,6 +117,9 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_column_v = polyfill::is_specialization_of_v; + template + using is_primary_key_column = polyfill::bool_constant; + template using is_column = polyfill::bool_constant>; diff --git a/dev/schema/table.h b/dev/schema/table.h index 6bc477f4c..3b788ed4f 100644 --- a/dev/schema/table.h +++ b/dev/schema/table.h @@ -41,8 +41,15 @@ namespace sqlite_orm { struct table_t : basic_table { using object_type = O; using elements_type = std::tuple; + using columns_tuple = filter_tuple_t; + using dedicated_primary_keys_tuple = filter_tuple_t; + using dedicated_primary_keys_columns_tuple = typename flatten_primry_keys_columns::columns_tuple; static constexpr bool is_without_rowid_v = WithoutRowId; + static constexpr int columns_count = static_cast(std::tuple_size::value); + static constexpr int primary_key_columns_count = count_tuple::value; + static constexpr int dedicated_primary_key_columns_count = static_cast(std::tuple_size::value); + using is_without_rowid = polyfill::bool_constant; elements_type elements; @@ -59,14 +66,12 @@ namespace sqlite_orm { /** * Returns foreign keys count in table definition */ - constexpr int foreign_keys_count() const { + static constexpr int foreign_keys_count = #if SQLITE_VERSION_NUMBER >= 3006019 - using fk_index_sequence = filter_tuple_sequence_t; - return int(fk_index_sequence::size()); + static_cast(filter_tuple_sequence_t::size()); #else - return 0; + 0; #endif - } /** * Function used to get field value from object by mapped member pointer/setter/getter. @@ -197,18 +202,10 @@ namespace sqlite_orm { col_index_sequence_excluding; return int(non_generated_col_index_sequence::size()); #else - return this->count_columns_amount(); + return this->columns_count; #endif } - /** - * Counts and returns amount of columns. Skips constraints. - */ - constexpr int count_columns_amount() const { - using col_index_sequence = filter_tuple_sequence_t; - return int(col_index_sequence::size()); - } - /** * Call passed lambda with all defined foreign keys. * @param lambda Lambda called for each column. Function signature: `void(auto& column)` diff --git a/dev/storage.h b/dev/storage.h index 854a8c385..85413f06c 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -171,6 +171,17 @@ namespace sqlite_orm { "type is not mapped to storage"); } + template + void assert_updatable_type() const { + using Table = storage_pick_table_t; + constexpr int primaryKeyColumnsCount = Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; + constexpr int nonPrimaryKeysColumnsCount = Table::columns_count - primaryKeyColumnsCount; + static_assert(primaryKeyColumnsCount > 0, + "Type with no primary keys can't be updated"); + static_assert(nonPrimaryKeysColumnsCount > 0, + "Type with primary keys only can't be updated. You need at least 1 non-primary key column"); + } + template, std::enable_if_t = true> @@ -1081,8 +1092,11 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - prepared_statement_t> prepare(update_t upd) { - return prepare_impl>(std::move(upd)); + prepared_statement_t> prepare(update_t statement) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + this->assert_updatable_type(); + return prepare_impl>(std::move(statement)); } template diff --git a/dev/storage_impl.h b/dev/storage_impl.h index eb0d8ea07..6fbbc6397 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -21,7 +21,7 @@ namespace sqlite_orm { int foreign_keys_count(const DBOs& dbObjects) { int res = 0; iterate_tuple(dbObjects, tables_index_sequence{}, [&res](const auto& table) { - res += table.foreign_keys_count(); + res += table.foreign_keys_count; }); return res; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 37eb7dec4..9e9ca10cf 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10,6 +10,7 @@ __pragma(push_macro("max")) // #include "cxx_universal.h" + /* * This header makes central C++ functionality on which sqlite_orm depends universally available: * - alternative operator representations @@ -28,6 +29,7 @@ using std::nullptr_t; // #include "cxx_core_features.h" + /* * This header detects core C++ language features on which sqlite_orm depends. * May be updated/overwritten by cxx_compiler_quirks.h @@ -108,6 +110,7 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" + /* * This header defines macros for circumventing compiler quirks on which sqlite_orm depends. * May amend cxx_core_features.h @@ -167,6 +170,8 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS #endif + + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -211,6 +216,7 @@ using std::nullptr_t; // #include "cxx_universal.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -352,6 +358,7 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } + namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -588,8 +595,10 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -598,6 +607,7 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif + // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -634,6 +644,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -732,6 +743,7 @@ namespace sqlite_orm { // #include "functional/mpl.h" + /* * Symbols for 'template metaprogramming' (compile-time template programming), * inspired by the MPL of Aleksey Gurtovoy and David Abrahams. @@ -760,6 +772,7 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { namespace mpl { @@ -1045,6 +1058,7 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" + namespace sqlite_orm { namespace internal { @@ -1074,6 +1088,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" + #include // std::is_same #include @@ -1081,6 +1096,7 @@ namespace sqlite_orm { // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { /* @@ -1129,6 +1145,7 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" + #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1136,10 +1153,12 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" + namespace sqlite_orm { namespace internal { /** @@ -1169,6 +1188,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1260,6 +1280,7 @@ namespace sqlite_orm { // #include "table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -1304,6 +1325,7 @@ namespace sqlite_orm { // #include "type_printer.h" + namespace sqlite_orm { namespace internal { @@ -1743,6 +1765,20 @@ namespace sqlite_orm { static_assert(tuple_has>::value, "an unexpected type was passed"); }; + template + struct primary_key_colums_count_t; + + template + struct primary_key_colums_count_t>: std::integral_constant(sizeof...(Cs))> {}; + + template + struct flatten_primry_keys_columns { + using columns_tuple = typename conc_tuple::type; + }; + + template + struct flatten_primry_keys_columns>: flatten_primry_keys_columns {}; + template using is_constraint = mpl::instantiate, @@ -1842,8 +1878,10 @@ namespace sqlite_orm { #include // std::shared_ptr, std::unique_ptr // #include "functional/cxx_optional.h" + // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { /** @@ -1883,6 +1921,7 @@ namespace sqlite_orm { // #include "tags.h" + // #include "functional/cxx_functional_polyfill.h" #include @@ -1897,12 +1936,14 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" + #include // std::enable_if, std::is_function, std::true_type, std::false_type // #include "../functional/cxx_universal.h" // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { // SFINAE friendly trait to get a member object pointer's field type @@ -1990,6 +2031,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -2061,6 +2103,7 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } + namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -2088,10 +2131,13 @@ namespace sqlite_orm { // #include "serialize_result_type.h" + // #include "functional/cxx_string_view.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -2116,6 +2162,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -2400,6 +2447,7 @@ namespace sqlite_orm { // #include "../constraints.h" + namespace sqlite_orm { namespace internal { @@ -2464,10 +2512,12 @@ namespace sqlite_orm { * Checks whether contraints are of trait `Trait` */ template class Trait> - constexpr bool is() const { + constexpr static bool is() { return tuple_has::value; } + constexpr static bool is_primary_key = mpl::invoke_t, constraints_type>::value; + constexpr bool is_generated() const { #if SQLITE_VERSION_NUMBER >= 3031000 return is(); @@ -2500,6 +2550,9 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_column_v = polyfill::is_specialization_of_v; + template + using is_primary_key_column = polyfill::bool_constant; + template using is_column = polyfill::bool_constant>; @@ -2587,12 +2640,14 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OMITS_CODECVT // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -2757,6 +2812,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -2802,6 +2858,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -2836,6 +2893,7 @@ namespace sqlite_orm { // #include "serializer_context.h" + namespace sqlite_orm { namespace internal { @@ -2877,6 +2935,7 @@ namespace sqlite_orm { // #include "alias_traits.h" + #include // std::remove_const, std::is_base_of, std::is_same #ifdef SQLITE_ORM_WITH_CPP20_ALIASES #include @@ -2888,6 +2947,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { /** @short Base class for a custom table alias, column alias or expression alias. @@ -2966,17 +3026,20 @@ namespace sqlite_orm { // #include "expression.h" + #include #include // std::enable_if #include // std::move, std::forward, std::declval // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" // #include "tags.h" + namespace sqlite_orm { namespace internal { @@ -3061,6 +3124,7 @@ namespace sqlite_orm { // #include "column_pointer.h" + #include // std::enable_if #include // std::move @@ -3068,6 +3132,7 @@ namespace sqlite_orm { // #include "tags.h" + namespace sqlite_orm { namespace internal { /** @@ -3110,6 +3175,7 @@ namespace sqlite_orm { // #include "literal.h" + namespace sqlite_orm { namespace internal { @@ -3126,6 +3192,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -4390,7 +4457,7 @@ namespace sqlite_orm { #include // std::copy_n // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -4399,6 +4466,7 @@ namespace sqlite_orm { // #include "tags.h" + namespace sqlite_orm { namespace internal { @@ -4734,8 +4802,10 @@ namespace sqlite_orm { // #include "ast/into.h" + // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -4754,6 +4824,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { using int64 = sqlite_int64; @@ -6854,6 +6925,7 @@ namespace sqlite_orm { #include // std::tuple, std::get, std::tuple_size // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" @@ -6866,6 +6938,7 @@ namespace sqlite_orm { // #include "ast/where.h" + #include // std::false_type, std::true_type #include // std::move @@ -6875,6 +6948,7 @@ namespace sqlite_orm { // #include "../serialize_result_type.h" + namespace sqlite_orm { namespace internal { @@ -6922,12 +6996,14 @@ namespace sqlite_orm { // #include "ast/group_by.h" + #include // std::tuple, std::make_tuple #include // std::true_type, std::false_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -6974,6 +7050,7 @@ namespace sqlite_orm { // #include "alias_traits.h" + namespace sqlite_orm { namespace internal { @@ -7397,6 +7474,7 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" + namespace sqlite_orm { struct table_info { @@ -7454,6 +7532,7 @@ namespace sqlite_orm { // #include "../optional_container.h" + // NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? // (Could be implemented with a normal trigger that insert or update an internal table and then retreive // the event in the C++ code, to call the C++ user callback, with update hooks: https://www.sqlite.org/c3ref/update_hook.html) @@ -7777,6 +7856,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" + #include // std::integral_constant #ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #include @@ -7786,6 +7866,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -8027,6 +8108,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { /** @@ -8223,6 +8305,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { /** @@ -8593,6 +8676,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8669,6 +8753,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -9099,6 +9184,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { /** @@ -9294,6 +9380,7 @@ namespace sqlite_orm { // #include "../indexed_column.h" + #include // std::string #include // std::move @@ -9301,6 +9388,7 @@ namespace sqlite_orm { // #include "ast/where.h" + namespace sqlite_orm { namespace internal { @@ -9366,6 +9454,7 @@ namespace sqlite_orm { // #include "../table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -9504,13 +9593,14 @@ namespace sqlite_orm { #include // std::forward, std::move // #include "../functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "../functional/cxx_type_traits_polyfill.h" // #include "../functional/cxx_functional_polyfill.h" // #include "../functional/static_magic.h" + #ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED #include // std::false_type, std::true_type, std::integral_constant #endif @@ -9595,16 +9685,18 @@ namespace sqlite_orm { // #include "../tuple_helper/tuple_iteration.h" + #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::remove_reference, std::index_sequence, std::make_index_sequence #include // std::forward, std::move // #include "../functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "../functional/cxx_type_traits_polyfill.h" // #include "../functional/cxx_functional_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -9743,6 +9835,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -9762,8 +9855,15 @@ namespace sqlite_orm { struct table_t : basic_table { using object_type = O; using elements_type = std::tuple; + using columns_tuple = filter_tuple_t; + using dedicated_primary_keys_tuple = filter_tuple_t; + using dedicated_primary_keys_columns_tuple = typename flatten_primry_keys_columns::columns_tuple; static constexpr bool is_without_rowid_v = WithoutRowId; + static constexpr int columns_count = static_cast(std::tuple_size::value); + static constexpr int primary_key_columns_count = count_tuple::value; + static constexpr int dedicated_primary_key_columns_count = static_cast(std::tuple_size::value); + using is_without_rowid = polyfill::bool_constant; elements_type elements; @@ -9780,14 +9880,12 @@ namespace sqlite_orm { /** * Returns foreign keys count in table definition */ - constexpr int foreign_keys_count() const { + static constexpr int foreign_keys_count = #if SQLITE_VERSION_NUMBER >= 3006019 - using fk_index_sequence = filter_tuple_sequence_t; - return int(fk_index_sequence::size()); + static_cast(filter_tuple_sequence_t::size()); #else - return 0; + 0; #endif - } /** * Function used to get field value from object by mapped member pointer/setter/getter. @@ -9918,18 +10016,10 @@ namespace sqlite_orm { col_index_sequence_excluding; return int(non_generated_col_index_sequence::size()); #else - return this->count_columns_amount(); + return this->columns_count; #endif } - /** - * Counts and returns amount of columns. Skips constraints. - */ - constexpr int count_columns_amount() const { - using col_index_sequence = filter_tuple_sequence_t; - return int(col_index_sequence::size()); - } - /** * Call passed lambda with all defined foreign keys. * @param lambda Lambda called for each column. Function signature: `void(auto& column)` @@ -10141,7 +10231,7 @@ namespace sqlite_orm { #include // std::string // #include "functional/cxx_universal.h" -// ::nullptr_t + // ::nullptr_t // #include "functional/static_magic.h" // #include "tuple_helper/tuple_filter.h" @@ -10154,6 +10244,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + #include // std::true_type, std::false_type, std::remove_const, std::enable_if, std::is_base_of, std::is_void #include #include // std::index_sequence, std::make_index_sequence @@ -10164,6 +10255,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { namespace internal { @@ -10296,6 +10388,7 @@ namespace sqlite_orm { } } + // interface functions namespace sqlite_orm { namespace internal { @@ -10307,7 +10400,7 @@ namespace sqlite_orm { int foreign_keys_count(const DBOs& dbObjects) { int res = 0; iterate_tuple(dbObjects, tables_index_sequence{}, [&res](const auto& table) { - res += table.foreign_keys_count(); + res += table.foreign_keys_count; }); return res; } @@ -10359,6 +10452,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10395,6 +10489,7 @@ namespace sqlite_orm { #include // std::for_each, std::ranges::for_each // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -10435,6 +10530,7 @@ namespace sqlite_orm { // #include "column_result.h" + #include // std::enable_if, std::is_same, std::decay, std::is_arithmetic, std::is_base_of #include // std::tuple #include // std::reference_wrapper @@ -10445,6 +10541,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_fy.h" + #include namespace sqlite_orm { @@ -10473,12 +10570,14 @@ namespace sqlite_orm { // #include "mapped_type_proxy.h" + #include // std::remove_const // #include "type_traits.h" // #include "alias_traits.h" + namespace sqlite_orm { namespace internal { @@ -10510,6 +10609,7 @@ namespace sqlite_orm { // #include "storage_traits.h" + #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -10518,10 +10618,12 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" + #include // std::tuple // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { @@ -10547,6 +10649,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10577,6 +10680,7 @@ namespace sqlite_orm { // #include "function.h" + #include #include #include // std::string @@ -10589,6 +10693,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { struct arg_values; @@ -10825,6 +10930,7 @@ namespace sqlite_orm { // #include "ast/special_keywords.h" + namespace sqlite_orm { namespace internal { struct current_time_t {}; @@ -11146,6 +11252,7 @@ namespace sqlite_orm { // #include "view.h" + #include #include // std::string #include // std::forward, std::move @@ -11157,6 +11264,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -11173,6 +11281,7 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" + #include #include // std::is_member_object_pointer @@ -11180,6 +11289,7 @@ namespace sqlite_orm { // #include "row_extractor.h" + namespace sqlite_orm { namespace internal { @@ -11225,6 +11335,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -11312,6 +11423,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -11331,6 +11443,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::unique_ptr #include // std::iterator_traits @@ -11348,12 +11461,14 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include #include // std::string // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -11426,6 +11541,7 @@ namespace sqlite_orm { // #include "values.h" + #include // std::vector #include // std::tuple #include // std::forward @@ -11434,6 +11550,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -11474,6 +11591,7 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" + #if SQLITE_VERSION_NUMBER >= 3024000 #include // std::tuple #include // std::forward, std::move @@ -11481,6 +11599,7 @@ namespace sqlite_orm { // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11543,6 +11662,7 @@ namespace sqlite_orm { // #include "ast/set.h" + #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11551,6 +11671,7 @@ namespace sqlite_orm { // #include "../table_name_collector.h" + #include // std::set #include // std::string #include // std::pair, std::move @@ -11569,6 +11690,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -11658,6 +11780,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -11757,6 +11880,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -12474,6 +12598,7 @@ namespace sqlite_orm { // #include "ast/excluded.h" + #include // std::move namespace sqlite_orm { @@ -12503,10 +12628,12 @@ namespace sqlite_orm { // #include "ast/exists.h" + #include // std::move // #include "../tags.h" + namespace sqlite_orm { namespace internal { @@ -12539,6 +12666,7 @@ namespace sqlite_orm { // #include "ast/match.h" + namespace sqlite_orm { namespace internal { @@ -12559,6 +12687,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -13248,6 +13377,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -13304,6 +13434,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include #include // std::function, std::bind #include // std::string @@ -13317,11 +13448,12 @@ namespace sqlite_orm { #include // std::find_if // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "tuple_helper/tuple_iteration.h" // #include "pragma.h" + #include #include // std::string #include // std::function @@ -13341,6 +13473,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + #include // std::index_sequence #include #include @@ -13349,7 +13482,7 @@ namespace sqlite_orm { #include // std::exchange, std::tuple_size // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_iteration.h" @@ -13362,6 +13495,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { template @@ -13737,6 +13871,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -13956,6 +14091,7 @@ namespace sqlite_orm { // #include "limit_accessor.h" + #include #include // std::map #include // std::function @@ -13963,6 +14099,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -14096,11 +14233,13 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function #include // std::move // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -14181,6 +14320,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::system_error #include // std::string @@ -14191,6 +14331,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -14258,6 +14399,7 @@ namespace sqlite_orm { // #include "values_to_tuple.h" + #include #include // std::index_sequence, std::make_index_sequence #include // std::tuple, std::tuple_size, std::get @@ -14268,10 +14410,12 @@ namespace sqlite_orm { // #include "arg_values.h" + #include // #include "row_extractor.h" + namespace sqlite_orm { /** @short Wrapper around a dynamically typed value object. @@ -14415,6 +14559,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { namespace internal { @@ -14459,6 +14604,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -15257,11 +15403,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 { @@ -15395,6 +15543,7 @@ namespace sqlite_orm { // #include "statement_serializer.h" + #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -15410,6 +15559,7 @@ namespace sqlite_orm { // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -15430,6 +15580,7 @@ namespace sqlite_orm { // #include "ast/rank.h" + namespace sqlite_orm { namespace internal { struct rank_t {}; @@ -15470,6 +15621,7 @@ namespace sqlite_orm { // #include "column_names_getter.h" + #include // std::is_base_of #include // std::string #include // std::vector @@ -15490,11 +15642,12 @@ namespace sqlite_orm { // #include "select_constraints.h" // #include "storage_lookup.h" -// pick_table + // pick_table // #include "serializer_context.h" // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -15508,7 +15661,7 @@ namespace sqlite_orm { const Ctx& context) { if(definedOrder) { auto& table = pick_table>(context.db_objects); - collectedExpressions.reserve(collectedExpressions.size() + table.count_columns_amount()); + collectedExpressions.reserve(collectedExpressions.size() + table.columns_count); table.for_each_column([qualified = !context.skip_table_name, &tableName = table.name, &collectedExpressions](const column_identifier& column) { @@ -15597,6 +15750,7 @@ namespace sqlite_orm { // #include "order_by_serializer.h" + #include // std::string #include // std::stringstream @@ -15690,6 +15844,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -17827,6 +17982,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -17945,6 +18101,17 @@ namespace sqlite_orm { "type is not mapped to storage"); } + template + void assert_updatable_type() const { + using Table = storage_pick_table_t; + constexpr int primaryKeyColumnsCount = Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; + constexpr int nonPrimaryKeysColumnsCount = Table::columns_count - primaryKeyColumnsCount; + static_assert(primaryKeyColumnsCount > 0, + "Type with no primary keys can't be updated"); + static_assert(nonPrimaryKeysColumnsCount > 0, + "Type with primary keys only can't be updated. You need at least 1 non-primary key column"); + } + template, std::enable_if_t = true> @@ -18855,8 +19022,11 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - prepared_statement_t> prepare(update_t upd) { - return prepare_impl>(std::move(upd)); + prepared_statement_t> prepare(update_t statement) { + using object_type = typename expression_object_type::type; + this->assert_mapped_type(); + this->assert_updatable_type(); + return prepare_impl>(std::move(statement)); } template @@ -19265,7 +19435,7 @@ namespace sqlite_orm { #include // std::get // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/static_magic.h" // #include "prepared_statement.h" @@ -19274,12 +19444,14 @@ namespace sqlite_orm { // #include "node_tuple.h" + #include // std::enable_if #include // std::tuple #include // std::pair #include // std::reference_wrapper // #include "functional/cxx_optional.h" + // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_filter.h" @@ -19310,6 +19482,7 @@ namespace sqlite_orm { // #include "ast/match.h" + namespace sqlite_orm { namespace internal { @@ -19620,6 +19793,7 @@ namespace sqlite_orm { // #include "expression_object_type.h" + namespace sqlite_orm { template @@ -19799,6 +19973,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19873,6 +20048,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { /** * SQLite's "schema table" that stores the schema for a database. @@ -19918,6 +20094,7 @@ namespace sqlite_orm { // #include "../schema/table.h" + namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19960,6 +20137,7 @@ namespace sqlite_orm { * this file is also used to provide definitions of interface methods 'hitting the database'. */ + #include // std::make_unique // #include "../functional/cxx_core_features.h" @@ -19976,6 +20154,7 @@ namespace sqlite_orm { // #include "../schema/column.h" + namespace sqlite_orm { namespace internal { @@ -20010,13 +20189,14 @@ namespace sqlite_orm { #include // std::find_if, std::ranges::find // #include "../functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "../type_printer.h" // #include "../schema/column.h" // #include "../schema/table.h" + namespace sqlite_orm { namespace internal { @@ -20081,6 +20261,7 @@ namespace sqlite_orm { // #include "../storage.h" + namespace sqlite_orm { namespace internal { @@ -20186,7 +20367,7 @@ namespace sqlite_orm { const Table& table, const std::vector& columnsToIgnore) const { // must ignore generated columns std::vector> columnNames; - columnNames.reserve(table.count_columns_amount()); + columnNames.reserve(table.columns_count); table.for_each_column([&columnNames, &columnsToIgnore](const column_identifier& column) { auto& columnName = column.name; #if __cpp_lib_ranges >= 201911L diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ff037642b..171497517 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,8 @@ add_executable(unit_tests static_tests/is_primary_key_insertable.cpp static_tests/is_column_with_insertable_primary_key.cpp static_tests/operators_adl.cpp + static_tests/flatten_primary_keys_columns.cpp + static_tests/table_static_tests.cpp tuple_iteration.cpp sync_schema_tests.cpp tests.cpp diff --git a/tests/static_tests/flatten_primary_keys_columns.cpp b/tests/static_tests/flatten_primary_keys_columns.cpp new file mode 100644 index 000000000..b46b6233a --- /dev/null +++ b/tests/static_tests/flatten_primary_keys_columns.cpp @@ -0,0 +1,52 @@ +#include +#include +#include // std::is_same + +using namespace sqlite_orm; + +TEST_CASE("flatten_primry_keys_columns") { + struct User { + int id = 0; + std::string name; + }; + { // id + name + auto pk1 = primary_key(&User::id); + auto pk2 = primary_key(&User::name); + + using Pk1 = decltype(pk1); + using Pk2 = decltype(pk2); + using Result = internal::flatten_primry_keys_columns::columns_tuple; + using Expected = std::tuple; + STATIC_REQUIRE(std::is_same::value); + } + { // (empty) + name + auto pk1 = primary_key(); + auto pk2 = primary_key(&User::name); + + using Pk1 = decltype(pk1); + using Pk2 = decltype(pk2); + using Result = internal::flatten_primry_keys_columns::columns_tuple; + using Expected = std::tuple; + STATIC_REQUIRE(std::is_same::value); + } + { // id + (empty) + auto pk1 = primary_key(&User::id); + auto pk2 = primary_key(); + + using Pk1 = decltype(pk1); + using Pk2 = decltype(pk2); + using Result = internal::flatten_primry_keys_columns::columns_tuple; + using Expected = std::tuple; + STATIC_REQUIRE(std::is_same::value); + } + { // (empty) + (empty) + auto pk1 = primary_key(); + auto pk2 = primary_key(); + + using Pk1 = decltype(pk1); + using Pk2 = decltype(pk2); + using Result = internal::flatten_primry_keys_columns::columns_tuple; + using Expected = std::tuple<>; + STATIC_REQUIRE(std::is_same::value); + } +} diff --git a/tests/static_tests/table_static_tests.cpp b/tests/static_tests/table_static_tests.cpp new file mode 100644 index 000000000..68819f09d --- /dev/null +++ b/tests/static_tests/table_static_tests.cpp @@ -0,0 +1,91 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("table static columns_count") { + struct User { + int id = 0; + std::string name; + }; + { // 1 column no pk + auto table = make_table("users", + make_column("id", &User::id)); + STATIC_REQUIRE(table.columns_count == 1); + STATIC_REQUIRE(table.primary_key_columns_count == 0); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + } + { // 1 column with 1 inline pk + auto table = make_table("users", + make_column("id", &User::id, primary_key())); + STATIC_REQUIRE(table.columns_count == 1); + STATIC_REQUIRE(table.primary_key_columns_count == 1); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + } + { // 1 column with 1 inline pk autoincrement + auto table = make_table("users", + make_column("id", &User::id, primary_key().autoincrement())); + STATIC_REQUIRE(table.columns_count == 1); + STATIC_REQUIRE(table.primary_key_columns_count == 1); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + } + { // 1 column with 1 dedicated pk + auto table = make_table("users", + make_column("id", &User::id), + primary_key(&User::id)); + STATIC_REQUIRE(table.columns_count == 1); + STATIC_REQUIRE(table.primary_key_columns_count == 0); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); + } + { // 2 columns no pk + auto table = make_table("users", + make_column("id", &User::id), + make_column("id", &User::name)); + STATIC_REQUIRE(table.columns_count == 2); + STATIC_REQUIRE(table.primary_key_columns_count == 0); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + } + { // 2 columns with 1 inline id pk + auto table = make_table("users", + make_column("id", &User::id, primary_key()), + make_column("id", &User::name)); + STATIC_REQUIRE(table.columns_count == 2); + STATIC_REQUIRE(table.primary_key_columns_count == 1); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + } + { // 2 columns with 1 inline name pk + auto table = make_table("users", + make_column("id", &User::id), + make_column("id", &User::name, primary_key())); + STATIC_REQUIRE(table.columns_count == 2); + STATIC_REQUIRE(table.primary_key_columns_count == 1); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + } + { // 2 columns with 1 dedicated id pk + auto table = make_table("users", + make_column("id", &User::id), + make_column("id", &User::name), + primary_key(&User::id)); + STATIC_REQUIRE(table.columns_count == 2); + STATIC_REQUIRE(table.primary_key_columns_count == 0); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); + } + { // 2 columns with 1 dedicated name pk + auto table = make_table("users", + make_column("id", &User::id), + make_column("id", &User::name), + primary_key(&User::name)); + STATIC_REQUIRE(table.columns_count == 2); + STATIC_REQUIRE(table.primary_key_columns_count == 0); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); + } + { // 2 columns with 2 dedicated pks + auto table = make_table("users", + make_column("id", &User::id), + make_column("id", &User::name), + primary_key(&User::id, &User::name)); + STATIC_REQUIRE(table.columns_count == 2); + STATIC_REQUIRE(table.primary_key_columns_count == 0); + STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 2); + } +} From db83d84c63681282ca5767c2ef5b17b77cda3357 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Sat, 21 Oct 2023 21:49:50 +0600 Subject: [PATCH 2/6] code format --- dev/constraints.h | 11 +- dev/schema/column.h | 3 +- dev/schema/table.h | 8 +- dev/storage.h | 9 +- include/sqlite_orm/sqlite_orm.h | 200 +++--------------- .../flatten_primary_keys_columns.cpp | 16 +- tests/static_tests/table_static_tests.cpp | 57 ++--- 7 files changed, 74 insertions(+), 230 deletions(-) diff --git a/dev/constraints.h b/dev/constraints.h index 365d24db7..6fd308edf 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -460,16 +460,17 @@ namespace sqlite_orm { template struct primary_key_colums_count_t; - template - struct primary_key_colums_count_t>: std::integral_constant(sizeof...(Cs))> {}; + template + struct primary_key_colums_count_t> + : std::integral_constant(sizeof...(Cs))> {}; - template + template struct flatten_primry_keys_columns { using columns_tuple = typename conc_tuple::type; }; - template - struct flatten_primry_keys_columns>: flatten_primry_keys_columns {}; + template + struct flatten_primry_keys_columns> : flatten_primry_keys_columns {}; template using is_constraint = diff --git a/dev/schema/column.h b/dev/schema/column.h index 79b8c2eaf..c3f81baf5 100644 --- a/dev/schema/column.h +++ b/dev/schema/column.h @@ -83,7 +83,8 @@ namespace sqlite_orm { return tuple_has::value; } - constexpr static bool is_primary_key = mpl::invoke_t, constraints_type>::value; + constexpr static bool is_primary_key = + mpl::invoke_t, constraints_type>::value; constexpr bool is_generated() const { #if SQLITE_VERSION_NUMBER >= 3031000 diff --git a/dev/schema/table.h b/dev/schema/table.h index 3b788ed4f..bc69e4d68 100644 --- a/dev/schema/table.h +++ b/dev/schema/table.h @@ -43,12 +43,14 @@ namespace sqlite_orm { using elements_type = std::tuple; using columns_tuple = filter_tuple_t; using dedicated_primary_keys_tuple = filter_tuple_t; - using dedicated_primary_keys_columns_tuple = typename flatten_primry_keys_columns::columns_tuple; + using dedicated_primary_keys_columns_tuple = + typename flatten_primry_keys_columns::columns_tuple; static constexpr bool is_without_rowid_v = WithoutRowId; static constexpr int columns_count = static_cast(std::tuple_size::value); static constexpr int primary_key_columns_count = count_tuple::value; - static constexpr int dedicated_primary_key_columns_count = static_cast(std::tuple_size::value); + static constexpr int dedicated_primary_key_columns_count = + static_cast(std::tuple_size::value); using is_without_rowid = polyfill::bool_constant; @@ -66,7 +68,7 @@ namespace sqlite_orm { /** * Returns foreign keys count in table definition */ - static constexpr int foreign_keys_count = + static constexpr int foreign_keys_count = #if SQLITE_VERSION_NUMBER >= 3006019 static_cast(filter_tuple_sequence_t::size()); #else diff --git a/dev/storage.h b/dev/storage.h index 85413f06c..012898438 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -174,11 +174,12 @@ namespace sqlite_orm { template void assert_updatable_type() const { using Table = storage_pick_table_t; - constexpr int primaryKeyColumnsCount = Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; + constexpr int primaryKeyColumnsCount = + Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; constexpr int nonPrimaryKeysColumnsCount = Table::columns_count - primaryKeyColumnsCount; - static_assert(primaryKeyColumnsCount > 0, - "Type with no primary keys can't be updated"); - static_assert(nonPrimaryKeysColumnsCount > 0, + static_assert(primaryKeyColumnsCount > 0, "Type with no primary keys can't be updated"); + static_assert( + nonPrimaryKeysColumnsCount > 0, "Type with primary keys only can't be updated. You need at least 1 non-primary key column"); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9e9ca10cf..d2428ce28 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10,7 +10,6 @@ __pragma(push_macro("max")) // #include "cxx_universal.h" - /* * This header makes central C++ functionality on which sqlite_orm depends universally available: * - alternative operator representations @@ -29,7 +28,6 @@ using std::nullptr_t; // #include "cxx_core_features.h" - /* * This header detects core C++ language features on which sqlite_orm depends. * May be updated/overwritten by cxx_compiler_quirks.h @@ -110,7 +108,6 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" - /* * This header defines macros for circumventing compiler quirks on which sqlite_orm depends. * May amend cxx_core_features.h @@ -170,8 +167,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS #endif - - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -216,7 +211,6 @@ using std::nullptr_t; // #include "cxx_universal.h" - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -358,7 +352,6 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } - namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -595,10 +588,8 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -607,7 +598,6 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif - // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -644,7 +634,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -743,7 +732,6 @@ namespace sqlite_orm { // #include "functional/mpl.h" - /* * Symbols for 'template metaprogramming' (compile-time template programming), * inspired by the MPL of Aleksey Gurtovoy and David Abrahams. @@ -772,7 +760,6 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { namespace mpl { @@ -1058,7 +1045,6 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" - namespace sqlite_orm { namespace internal { @@ -1088,7 +1074,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" - #include // std::is_same #include @@ -1096,7 +1081,6 @@ namespace sqlite_orm { // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { /* @@ -1145,7 +1129,6 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" - #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1153,12 +1136,10 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" - namespace sqlite_orm { namespace internal { /** @@ -1188,7 +1169,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1280,7 +1260,6 @@ namespace sqlite_orm { // #include "table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -1325,7 +1304,6 @@ namespace sqlite_orm { // #include "type_printer.h" - namespace sqlite_orm { namespace internal { @@ -1768,16 +1746,17 @@ namespace sqlite_orm { template struct primary_key_colums_count_t; - template - struct primary_key_colums_count_t>: std::integral_constant(sizeof...(Cs))> {}; + template + struct primary_key_colums_count_t> + : std::integral_constant(sizeof...(Cs))> {}; - template + template struct flatten_primry_keys_columns { using columns_tuple = typename conc_tuple::type; }; - template - struct flatten_primry_keys_columns>: flatten_primry_keys_columns {}; + template + struct flatten_primry_keys_columns> : flatten_primry_keys_columns {}; template using is_constraint = @@ -1878,10 +1857,8 @@ namespace sqlite_orm { #include // std::shared_ptr, std::unique_ptr // #include "functional/cxx_optional.h" - // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { /** @@ -1921,7 +1898,6 @@ namespace sqlite_orm { // #include "tags.h" - // #include "functional/cxx_functional_polyfill.h" #include @@ -1936,14 +1912,12 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" - #include // std::enable_if, std::is_function, std::true_type, std::false_type // #include "../functional/cxx_universal.h" // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { // SFINAE friendly trait to get a member object pointer's field type @@ -2031,7 +2005,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -2103,7 +2076,6 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } - namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -2131,13 +2103,10 @@ namespace sqlite_orm { // #include "serialize_result_type.h" - // #include "functional/cxx_string_view.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -2162,7 +2131,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -2447,7 +2415,6 @@ namespace sqlite_orm { // #include "../constraints.h" - namespace sqlite_orm { namespace internal { @@ -2516,7 +2483,8 @@ namespace sqlite_orm { return tuple_has::value; } - constexpr static bool is_primary_key = mpl::invoke_t, constraints_type>::value; + constexpr static bool is_primary_key = + mpl::invoke_t, constraints_type>::value; constexpr bool is_generated() const { #if SQLITE_VERSION_NUMBER >= 3031000 @@ -2640,14 +2608,12 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OMITS_CODECVT // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -2812,7 +2778,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -2858,7 +2823,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -2893,7 +2857,6 @@ namespace sqlite_orm { // #include "serializer_context.h" - namespace sqlite_orm { namespace internal { @@ -2935,7 +2898,6 @@ namespace sqlite_orm { // #include "alias_traits.h" - #include // std::remove_const, std::is_base_of, std::is_same #ifdef SQLITE_ORM_WITH_CPP20_ALIASES #include @@ -2947,7 +2909,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { /** @short Base class for a custom table alias, column alias or expression alias. @@ -3026,20 +2987,17 @@ namespace sqlite_orm { // #include "expression.h" - #include #include // std::enable_if #include // std::move, std::forward, std::declval // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" // #include "tags.h" - namespace sqlite_orm { namespace internal { @@ -3124,7 +3082,6 @@ namespace sqlite_orm { // #include "column_pointer.h" - #include // std::enable_if #include // std::move @@ -3132,7 +3089,6 @@ namespace sqlite_orm { // #include "tags.h" - namespace sqlite_orm { namespace internal { /** @@ -3175,7 +3131,6 @@ namespace sqlite_orm { // #include "literal.h" - namespace sqlite_orm { namespace internal { @@ -3192,7 +3147,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -4457,7 +4411,7 @@ namespace sqlite_orm { #include // std::copy_n // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -4466,7 +4420,6 @@ namespace sqlite_orm { // #include "tags.h" - namespace sqlite_orm { namespace internal { @@ -4802,10 +4755,8 @@ namespace sqlite_orm { // #include "ast/into.h" - // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -4824,7 +4775,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { using int64 = sqlite_int64; @@ -6925,7 +6875,6 @@ namespace sqlite_orm { #include // std::tuple, std::get, std::tuple_size // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" @@ -6938,7 +6887,6 @@ namespace sqlite_orm { // #include "ast/where.h" - #include // std::false_type, std::true_type #include // std::move @@ -6948,7 +6896,6 @@ namespace sqlite_orm { // #include "../serialize_result_type.h" - namespace sqlite_orm { namespace internal { @@ -6996,14 +6943,12 @@ namespace sqlite_orm { // #include "ast/group_by.h" - #include // std::tuple, std::make_tuple #include // std::true_type, std::false_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -7050,7 +6995,6 @@ namespace sqlite_orm { // #include "alias_traits.h" - namespace sqlite_orm { namespace internal { @@ -7474,7 +7418,6 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" - namespace sqlite_orm { struct table_info { @@ -7532,7 +7475,6 @@ namespace sqlite_orm { // #include "../optional_container.h" - // NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? // (Could be implemented with a normal trigger that insert or update an internal table and then retreive // the event in the C++ code, to call the C++ user callback, with update hooks: https://www.sqlite.org/c3ref/update_hook.html) @@ -7856,7 +7798,6 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" - #include // std::integral_constant #ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #include @@ -7866,7 +7807,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -8108,7 +8048,6 @@ namespace sqlite_orm { #endif } - namespace sqlite_orm { /** @@ -8305,7 +8244,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { /** @@ -8676,7 +8614,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8753,7 +8690,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -9184,7 +9120,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { /** @@ -9380,7 +9315,6 @@ namespace sqlite_orm { // #include "../indexed_column.h" - #include // std::string #include // std::move @@ -9388,7 +9322,6 @@ namespace sqlite_orm { // #include "ast/where.h" - namespace sqlite_orm { namespace internal { @@ -9454,7 +9387,6 @@ namespace sqlite_orm { // #include "../table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -9593,14 +9525,13 @@ namespace sqlite_orm { #include // std::forward, std::move // #include "../functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "../functional/cxx_type_traits_polyfill.h" // #include "../functional/cxx_functional_polyfill.h" // #include "../functional/static_magic.h" - #ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED #include // std::false_type, std::true_type, std::integral_constant #endif @@ -9685,18 +9616,16 @@ namespace sqlite_orm { // #include "../tuple_helper/tuple_iteration.h" - #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::remove_reference, std::index_sequence, std::make_index_sequence #include // std::forward, std::move // #include "../functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "../functional/cxx_type_traits_polyfill.h" // #include "../functional/cxx_functional_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -9835,7 +9764,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -9857,12 +9785,14 @@ namespace sqlite_orm { using elements_type = std::tuple; using columns_tuple = filter_tuple_t; using dedicated_primary_keys_tuple = filter_tuple_t; - using dedicated_primary_keys_columns_tuple = typename flatten_primry_keys_columns::columns_tuple; + using dedicated_primary_keys_columns_tuple = + typename flatten_primry_keys_columns::columns_tuple; static constexpr bool is_without_rowid_v = WithoutRowId; static constexpr int columns_count = static_cast(std::tuple_size::value); static constexpr int primary_key_columns_count = count_tuple::value; - static constexpr int dedicated_primary_key_columns_count = static_cast(std::tuple_size::value); + static constexpr int dedicated_primary_key_columns_count = + static_cast(std::tuple_size::value); using is_without_rowid = polyfill::bool_constant; @@ -9880,7 +9810,7 @@ namespace sqlite_orm { /** * Returns foreign keys count in table definition */ - static constexpr int foreign_keys_count = + static constexpr int foreign_keys_count = #if SQLITE_VERSION_NUMBER >= 3006019 static_cast(filter_tuple_sequence_t::size()); #else @@ -10231,7 +10161,7 @@ namespace sqlite_orm { #include // std::string // #include "functional/cxx_universal.h" - // ::nullptr_t +// ::nullptr_t // #include "functional/static_magic.h" // #include "tuple_helper/tuple_filter.h" @@ -10244,7 +10174,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - #include // std::true_type, std::false_type, std::remove_const, std::enable_if, std::is_base_of, std::is_void #include #include // std::index_sequence, std::make_index_sequence @@ -10255,7 +10184,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { namespace internal { @@ -10388,7 +10316,6 @@ namespace sqlite_orm { } } - // interface functions namespace sqlite_orm { namespace internal { @@ -10452,7 +10379,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10489,7 +10415,6 @@ namespace sqlite_orm { #include // std::for_each, std::ranges::for_each // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -10530,7 +10455,6 @@ namespace sqlite_orm { // #include "column_result.h" - #include // std::enable_if, std::is_same, std::decay, std::is_arithmetic, std::is_base_of #include // std::tuple #include // std::reference_wrapper @@ -10541,7 +10465,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_fy.h" - #include namespace sqlite_orm { @@ -10570,14 +10493,12 @@ namespace sqlite_orm { // #include "mapped_type_proxy.h" - #include // std::remove_const // #include "type_traits.h" // #include "alias_traits.h" - namespace sqlite_orm { namespace internal { @@ -10609,7 +10530,6 @@ namespace sqlite_orm { // #include "storage_traits.h" - #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -10618,12 +10538,10 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" - #include // std::tuple // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { @@ -10649,7 +10567,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10680,7 +10597,6 @@ namespace sqlite_orm { // #include "function.h" - #include #include #include // std::string @@ -10693,7 +10609,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { struct arg_values; @@ -10930,7 +10845,6 @@ namespace sqlite_orm { // #include "ast/special_keywords.h" - namespace sqlite_orm { namespace internal { struct current_time_t {}; @@ -11252,7 +11166,6 @@ namespace sqlite_orm { // #include "view.h" - #include #include // std::string #include // std::forward, std::move @@ -11264,7 +11177,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -11281,7 +11193,6 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" - #include #include // std::is_member_object_pointer @@ -11289,7 +11200,6 @@ namespace sqlite_orm { // #include "row_extractor.h" - namespace sqlite_orm { namespace internal { @@ -11335,7 +11245,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -11423,7 +11332,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -11443,7 +11351,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::unique_ptr #include // std::iterator_traits @@ -11461,14 +11368,12 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include #include // std::string // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -11541,7 +11446,6 @@ namespace sqlite_orm { // #include "values.h" - #include // std::vector #include // std::tuple #include // std::forward @@ -11550,7 +11454,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -11591,7 +11494,6 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" - #if SQLITE_VERSION_NUMBER >= 3024000 #include // std::tuple #include // std::forward, std::move @@ -11599,7 +11501,6 @@ namespace sqlite_orm { // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11662,7 +11563,6 @@ namespace sqlite_orm { // #include "ast/set.h" - #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11671,7 +11571,6 @@ namespace sqlite_orm { // #include "../table_name_collector.h" - #include // std::set #include // std::string #include // std::pair, std::move @@ -11690,7 +11589,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -11780,7 +11678,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -11880,7 +11777,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -12598,7 +12494,6 @@ namespace sqlite_orm { // #include "ast/excluded.h" - #include // std::move namespace sqlite_orm { @@ -12628,12 +12523,10 @@ namespace sqlite_orm { // #include "ast/exists.h" - #include // std::move // #include "../tags.h" - namespace sqlite_orm { namespace internal { @@ -12666,7 +12559,6 @@ namespace sqlite_orm { // #include "ast/match.h" - namespace sqlite_orm { namespace internal { @@ -12687,7 +12579,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -13377,7 +13268,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -13434,7 +13324,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include #include // std::function, std::bind #include // std::string @@ -13448,12 +13337,11 @@ namespace sqlite_orm { #include // std::find_if // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "tuple_helper/tuple_iteration.h" // #include "pragma.h" - #include #include // std::string #include // std::function @@ -13473,7 +13361,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - #include // std::index_sequence #include #include @@ -13482,7 +13369,7 @@ namespace sqlite_orm { #include // std::exchange, std::tuple_size // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_iteration.h" @@ -13495,7 +13382,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { template @@ -13871,7 +13757,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -14091,7 +13976,6 @@ namespace sqlite_orm { // #include "limit_accessor.h" - #include #include // std::map #include // std::function @@ -14099,7 +13983,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -14233,13 +14116,11 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function #include // std::move // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -14320,7 +14201,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::system_error #include // std::string @@ -14331,7 +14211,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -14399,7 +14278,6 @@ namespace sqlite_orm { // #include "values_to_tuple.h" - #include #include // std::index_sequence, std::make_index_sequence #include // std::tuple, std::tuple_size, std::get @@ -14410,12 +14288,10 @@ namespace sqlite_orm { // #include "arg_values.h" - #include // #include "row_extractor.h" - namespace sqlite_orm { /** @short Wrapper around a dynamically typed value object. @@ -14559,7 +14435,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { namespace internal { @@ -14604,7 +14479,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -15403,13 +15277,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 { @@ -15543,7 +15415,6 @@ namespace sqlite_orm { // #include "statement_serializer.h" - #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -15559,7 +15430,6 @@ namespace sqlite_orm { // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -15580,7 +15450,6 @@ namespace sqlite_orm { // #include "ast/rank.h" - namespace sqlite_orm { namespace internal { struct rank_t {}; @@ -15621,7 +15490,6 @@ namespace sqlite_orm { // #include "column_names_getter.h" - #include // std::is_base_of #include // std::string #include // std::vector @@ -15642,12 +15510,11 @@ namespace sqlite_orm { // #include "select_constraints.h" // #include "storage_lookup.h" - // pick_table +// pick_table // #include "serializer_context.h" // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -15750,7 +15617,6 @@ namespace sqlite_orm { // #include "order_by_serializer.h" - #include // std::string #include // std::stringstream @@ -15844,7 +15710,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -17982,7 +17847,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -18104,11 +17968,12 @@ namespace sqlite_orm { template void assert_updatable_type() const { using Table = storage_pick_table_t; - constexpr int primaryKeyColumnsCount = Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; + constexpr int primaryKeyColumnsCount = + Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; constexpr int nonPrimaryKeysColumnsCount = Table::columns_count - primaryKeyColumnsCount; - static_assert(primaryKeyColumnsCount > 0, - "Type with no primary keys can't be updated"); - static_assert(nonPrimaryKeysColumnsCount > 0, + static_assert(primaryKeyColumnsCount > 0, "Type with no primary keys can't be updated"); + static_assert( + nonPrimaryKeysColumnsCount > 0, "Type with primary keys only can't be updated. You need at least 1 non-primary key column"); } @@ -19435,7 +19300,7 @@ namespace sqlite_orm { #include // std::get // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/static_magic.h" // #include "prepared_statement.h" @@ -19444,14 +19309,12 @@ namespace sqlite_orm { // #include "node_tuple.h" - #include // std::enable_if #include // std::tuple #include // std::pair #include // std::reference_wrapper // #include "functional/cxx_optional.h" - // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_filter.h" @@ -19482,7 +19345,6 @@ namespace sqlite_orm { // #include "ast/match.h" - namespace sqlite_orm { namespace internal { @@ -19793,7 +19655,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template @@ -19973,7 +19834,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -20048,7 +19908,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { /** * SQLite's "schema table" that stores the schema for a database. @@ -20094,7 +19953,6 @@ namespace sqlite_orm { // #include "../schema/table.h" - namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -20137,7 +19995,6 @@ namespace sqlite_orm { * this file is also used to provide definitions of interface methods 'hitting the database'. */ - #include // std::make_unique // #include "../functional/cxx_core_features.h" @@ -20154,7 +20011,6 @@ namespace sqlite_orm { // #include "../schema/column.h" - namespace sqlite_orm { namespace internal { @@ -20189,14 +20045,13 @@ namespace sqlite_orm { #include // std::find_if, std::ranges::find // #include "../functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "../type_printer.h" // #include "../schema/column.h" // #include "../schema/table.h" - namespace sqlite_orm { namespace internal { @@ -20261,7 +20116,6 @@ namespace sqlite_orm { // #include "../storage.h" - namespace sqlite_orm { namespace internal { diff --git a/tests/static_tests/flatten_primary_keys_columns.cpp b/tests/static_tests/flatten_primary_keys_columns.cpp index b46b6233a..e9aa9c3b6 100644 --- a/tests/static_tests/flatten_primary_keys_columns.cpp +++ b/tests/static_tests/flatten_primary_keys_columns.cpp @@ -9,40 +9,40 @@ TEST_CASE("flatten_primry_keys_columns") { int id = 0; std::string name; }; - { // id + name + { // id + name auto pk1 = primary_key(&User::id); auto pk2 = primary_key(&User::name); - + using Pk1 = decltype(pk1); using Pk2 = decltype(pk2); using Result = internal::flatten_primry_keys_columns::columns_tuple; using Expected = std::tuple; STATIC_REQUIRE(std::is_same::value); } - { // (empty) + name + { // (empty) + name auto pk1 = primary_key(); auto pk2 = primary_key(&User::name); - + using Pk1 = decltype(pk1); using Pk2 = decltype(pk2); using Result = internal::flatten_primry_keys_columns::columns_tuple; using Expected = std::tuple; STATIC_REQUIRE(std::is_same::value); } - { // id + (empty) + { // id + (empty) auto pk1 = primary_key(&User::id); auto pk2 = primary_key(); - + using Pk1 = decltype(pk1); using Pk2 = decltype(pk2); using Result = internal::flatten_primry_keys_columns::columns_tuple; using Expected = std::tuple; STATIC_REQUIRE(std::is_same::value); } - { // (empty) + (empty) + { // (empty) + (empty) auto pk1 = primary_key(); auto pk2 = primary_key(); - + using Pk1 = decltype(pk1); using Pk2 = decltype(pk2); using Result = internal::flatten_primry_keys_columns::columns_tuple; diff --git a/tests/static_tests/table_static_tests.cpp b/tests/static_tests/table_static_tests.cpp index 68819f09d..5f3099665 100644 --- a/tests/static_tests/table_static_tests.cpp +++ b/tests/static_tests/table_static_tests.cpp @@ -8,78 +8,63 @@ TEST_CASE("table static columns_count") { int id = 0; std::string name; }; - { // 1 column no pk - auto table = make_table("users", - make_column("id", &User::id)); + { // 1 column no pk + auto table = make_table("users", make_column("id", &User::id)); STATIC_REQUIRE(table.columns_count == 1); STATIC_REQUIRE(table.primary_key_columns_count == 0); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); } - { // 1 column with 1 inline pk - auto table = make_table("users", - make_column("id", &User::id, primary_key())); + { // 1 column with 1 inline pk + auto table = make_table("users", make_column("id", &User::id, primary_key())); STATIC_REQUIRE(table.columns_count == 1); STATIC_REQUIRE(table.primary_key_columns_count == 1); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); } - { // 1 column with 1 inline pk autoincrement - auto table = make_table("users", - make_column("id", &User::id, primary_key().autoincrement())); + { // 1 column with 1 inline pk autoincrement + auto table = make_table("users", make_column("id", &User::id, primary_key().autoincrement())); STATIC_REQUIRE(table.columns_count == 1); STATIC_REQUIRE(table.primary_key_columns_count == 1); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); } - { // 1 column with 1 dedicated pk - auto table = make_table("users", - make_column("id", &User::id), - primary_key(&User::id)); + { // 1 column with 1 dedicated pk + auto table = make_table("users", make_column("id", &User::id), primary_key(&User::id)); STATIC_REQUIRE(table.columns_count == 1); STATIC_REQUIRE(table.primary_key_columns_count == 0); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); } - { // 2 columns no pk - auto table = make_table("users", - make_column("id", &User::id), - make_column("id", &User::name)); + { // 2 columns no pk + auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name)); STATIC_REQUIRE(table.columns_count == 2); STATIC_REQUIRE(table.primary_key_columns_count == 0); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); } - { // 2 columns with 1 inline id pk - auto table = make_table("users", - make_column("id", &User::id, primary_key()), - make_column("id", &User::name)); + { // 2 columns with 1 inline id pk + auto table = make_table("users", make_column("id", &User::id, primary_key()), make_column("id", &User::name)); STATIC_REQUIRE(table.columns_count == 2); STATIC_REQUIRE(table.primary_key_columns_count == 1); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); } - { // 2 columns with 1 inline name pk - auto table = make_table("users", - make_column("id", &User::id), - make_column("id", &User::name, primary_key())); + { // 2 columns with 1 inline name pk + auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name, primary_key())); STATIC_REQUIRE(table.columns_count == 2); STATIC_REQUIRE(table.primary_key_columns_count == 1); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); } - { // 2 columns with 1 dedicated id pk - auto table = make_table("users", - make_column("id", &User::id), - make_column("id", &User::name), - primary_key(&User::id)); + { // 2 columns with 1 dedicated id pk + auto table = + make_table("users", make_column("id", &User::id), make_column("id", &User::name), primary_key(&User::id)); STATIC_REQUIRE(table.columns_count == 2); STATIC_REQUIRE(table.primary_key_columns_count == 0); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); } - { // 2 columns with 1 dedicated name pk - auto table = make_table("users", - make_column("id", &User::id), - make_column("id", &User::name), - primary_key(&User::name)); + { // 2 columns with 1 dedicated name pk + auto table = + make_table("users", make_column("id", &User::id), make_column("id", &User::name), primary_key(&User::name)); STATIC_REQUIRE(table.columns_count == 2); STATIC_REQUIRE(table.primary_key_columns_count == 0); STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); } - { // 2 columns with 2 dedicated pks + { // 2 columns with 2 dedicated pks auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name), From a2f37cd03255ddb31b63e3595f0fedd01b6cdee5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 24 Oct 2023 15:33:08 +0200 Subject: [PATCH 3/6] Generalize the counting of columns --- dev/column_names_getter.h | 2 +- dev/constraints.h | 60 ++-- dev/functional/index_sequence_util.h | 2 +- dev/implementations/storage_definitions.h | 2 +- dev/implementations/table_definitions.h | 2 +- dev/schema/column.h | 16 +- dev/schema/table.h | 55 ++- dev/statement_serializer.h | 2 +- dev/storage.h | 20 +- dev/storage_impl.h | 2 +- dev/tuple_helper/tuple_filter.h | 2 +- dev/tuple_helper/tuple_iteration.h | 17 +- dev/tuple_helper/tuple_transformer.h | 88 ++++- dev/type_traits.h | 3 + include/sqlite_orm/sqlite_orm.h | 321 +++++++++++------- tests/CMakeLists.txt | 1 - tests/schema/column_tests.cpp | 11 +- .../flatten_primary_keys_columns.cpp | 52 --- tests/static_tests/table_static_tests.cpp | 102 ++++-- 19 files changed, 429 insertions(+), 331 deletions(-) delete mode 100644 tests/static_tests/flatten_primary_keys_columns.cpp diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index d82a800ee..05820ed83 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -30,7 +30,7 @@ namespace sqlite_orm { const Ctx& context) { if(definedOrder) { auto& table = pick_table>(context.db_objects); - collectedExpressions.reserve(collectedExpressions.size() + table.columns_count); + collectedExpressions.reserve(collectedExpressions.size() + table.template count_of()); table.for_each_column([qualified = !context.skip_table_name, &tableName = table.name, &collectedExpressions](const column_identifier& column) { diff --git a/dev/constraints.h b/dev/constraints.h index 6fd308edf..e59bb42a9 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -379,6 +379,7 @@ namespace sqlite_orm { expression_type expression; }; +#if SQLITE_VERSION_NUMBER >= 3031000 struct basic_generated_always { enum class storage_type { not_specified, @@ -411,6 +412,7 @@ namespace sqlite_orm { return {std::move(this->expression), this->full, storage_type::stored}; } }; +#endif struct null_t {}; @@ -420,7 +422,12 @@ namespace sqlite_orm { namespace internal { template - SQLITE_ORM_INLINE_VAR constexpr bool is_foreign_key_v = polyfill::is_specialization_of_v; + SQLITE_ORM_INLINE_VAR constexpr bool is_foreign_key_v = +#if SQLITE_VERSION_NUMBER >= 3006019 + polyfill::is_specialization_of_v; +#else + false; +#endif template using is_foreign_key = polyfill::bool_constant>; @@ -438,10 +445,15 @@ namespace sqlite_orm { SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = is_primary_key::value; template - using is_generated_always = polyfill::is_specialization_of; + SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = +#if SQLITE_VERSION_NUMBER >= 3031000 + polyfill::is_specialization_of_v; +#else + false; +#endif template - SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = is_generated_always::value; + using is_generated_always = polyfill::bool_constant>; /** * PRIMARY KEY INSERTABLE traits. @@ -458,37 +470,17 @@ namespace sqlite_orm { }; template - struct primary_key_colums_count_t; - - template - struct primary_key_colums_count_t> - : std::integral_constant(sizeof...(Cs))> {}; - - template - struct flatten_primry_keys_columns { - using columns_tuple = typename conc_tuple::type; - }; - - template - struct flatten_primry_keys_columns> : flatten_primry_keys_columns {}; - - template - using is_constraint = - mpl::instantiate, - check_if, - check_if_is_type, - check_if_is_type, - check_if_is_template, - check_if_is_template, - check_if_is_template, - check_if_is_template, - check_if_is_type, -#if SQLITE_VERSION_NUMBER >= 3031000 - check_if, -#endif - // dummy tail because of SQLITE_VERSION_NUMBER checks above - mpl::always>, - T>; + using is_constraint = mpl::instantiate, + check_if, + check_if_is_type, + check_if_is_type, + check_if_is_template, + check_if_is_template, + check_if_is_template, + check_if_is_template, + check_if_is_type, + check_if>, + T>; } #if SQLITE_VERSION_NUMBER >= 3031000 diff --git a/dev/functional/index_sequence_util.h b/dev/functional/index_sequence_util.h index b13343663..7d7a40d73 100644 --- a/dev/functional/index_sequence_util.h +++ b/dev/functional/index_sequence_util.h @@ -1,6 +1,6 @@ #pragma once -#include // std::index_sequence, std::make_index_sequence +#include // std::index_sequence #include "../functional/cxx_universal.h" diff --git a/dev/implementations/storage_definitions.h b/dev/implementations/storage_definitions.h index 5a842491a..30d498b13 100644 --- a/dev/implementations/storage_definitions.h +++ b/dev/implementations/storage_definitions.h @@ -120,7 +120,7 @@ namespace sqlite_orm { const Table& table, const std::vector& columnsToIgnore) const { // must ignore generated columns std::vector> columnNames; - columnNames.reserve(table.columns_count); + columnNames.reserve(table.template count_of()); table.for_each_column([&columnNames, &columnsToIgnore](const column_identifier& column) { auto& columnName = column.name; #if __cpp_lib_ranges >= 201911L diff --git a/dev/implementations/table_definitions.h b/dev/implementations/table_definitions.h index 8e3c24268..a869d2272 100644 --- a/dev/implementations/table_definitions.h +++ b/dev/implementations/table_definitions.h @@ -31,7 +31,7 @@ namespace sqlite_orm { column.is_not_null(), std::move(dft), column.template is(), - column.is_generated()); + column.template is()); }); auto compositeKeyColumnNames = this->composite_key_columns_names(); for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) { diff --git a/dev/schema/column.h b/dev/schema/column.h index c3f81baf5..f7654a1cf 100644 --- a/dev/schema/column.h +++ b/dev/schema/column.h @@ -76,24 +76,13 @@ namespace sqlite_orm { constraints_type constraints; /** - * Checks whether contraints are of trait `Trait` + * Checks whether contraints contain specified type. */ template class Trait> constexpr static bool is() { return tuple_has::value; } - constexpr static bool is_primary_key = - mpl::invoke_t, constraints_type>::value; - - constexpr bool is_generated() const { -#if SQLITE_VERSION_NUMBER >= 3031000 - return is(); -#else - return false; -#endif - } - /** * Simplified interface for `DEFAULT` constraint * @return string representation of default value if it exists otherwise nullptr @@ -118,9 +107,6 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_column_v = polyfill::is_specialization_of_v; - template - using is_primary_key_column = polyfill::bool_constant; - template using is_column = polyfill::bool_constant>; diff --git a/dev/schema/table.h b/dev/schema/table.h index bc69e4d68..67916e4a8 100644 --- a/dev/schema/table.h +++ b/dev/schema/table.h @@ -15,6 +15,7 @@ #include "../tuple_helper/tuple_filter.h" #include "../tuple_helper/tuple_traits.h" #include "../tuple_helper/tuple_iteration.h" +#include "../tuple_helper/tuple_transformer.h" #include "../member_traits/member_traits.h" #include "../typed_comparator.h" #include "../type_traits.h" @@ -41,16 +42,8 @@ namespace sqlite_orm { struct table_t : basic_table { using object_type = O; using elements_type = std::tuple; - using columns_tuple = filter_tuple_t; - using dedicated_primary_keys_tuple = filter_tuple_t; - using dedicated_primary_keys_columns_tuple = - typename flatten_primry_keys_columns::columns_tuple; static constexpr bool is_without_rowid_v = WithoutRowId; - static constexpr int columns_count = static_cast(std::tuple_size::value); - static constexpr int primary_key_columns_count = count_tuple::value; - static constexpr int dedicated_primary_key_columns_count = - static_cast(std::tuple_size::value); using is_without_rowid = polyfill::bool_constant; @@ -65,15 +58,32 @@ namespace sqlite_orm { return {this->name, this->elements}; } - /** - * Returns foreign keys count in table definition + /* + * Returns the number of elements of the specified type. */ - static constexpr int foreign_keys_count = -#if SQLITE_VERSION_NUMBER >= 3006019 - static_cast(filter_tuple_sequence_t::size()); -#else - 0; -#endif + template class Trait> + static constexpr int count_of() { + using sequence_of = filter_tuple_sequence_t; + return int(sequence_of::size()); + } + + /* + * Returns the number of columns having the specified constraint trait. + */ + template class Trait> + static constexpr int count_of_columns_with() { + using filtered_index_sequence = col_index_sequence_with; + return int(filtered_index_sequence::size()); + } + + /* + * Returns the number of columns having the specified constraint trait. + */ + template class Trait> + static constexpr int count_of_columns_excluding() { + using excluded_col_index_sequence = col_index_sequence_excluding; + return int(excluded_col_index_sequence::size()); + } /** * Function used to get field value from object by mapped member pointer/setter/getter. @@ -195,19 +205,6 @@ namespace sqlite_orm { return res; } - /** - * Counts and returns amount of columns without GENERATED ALWAYS constraints. Skips table constraints. - */ - constexpr int non_generated_columns_count() const { -#if SQLITE_VERSION_NUMBER >= 3031000 - using non_generated_col_index_sequence = - col_index_sequence_excluding; - return int(non_generated_col_index_sequence::size()); -#else - return this->columns_count; -#endif - } - /** * Call passed lambda with all defined foreign keys. * @param lambda Lambda called for each column. Function signature: `void(auto& column)` diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 2877647b0..1b6c896cd 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1430,7 +1430,7 @@ namespace sqlite_orm { ss << "REPLACE INTO " << streaming_identifier(table.name) << " (" << streaming_non_generated_column_names(table) << ")"; const auto valuesCount = std::distance(rep.range.first, rep.range.second); - const auto columnsCount = table.non_generated_columns_count(); + const auto columnsCount = table.template count_of_columns_excluding(); ss << " VALUES " << streaming_values_placeholders(columnsCount, valuesCount); return ss.str(); } diff --git a/dev/storage.h b/dev/storage.h index 012898438..729d9ccc0 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -20,6 +20,7 @@ #include "functional/mpl.h" #include "tuple_helper/tuple_traits.h" #include "tuple_helper/tuple_filter.h" +#include "tuple_helper/tuple_transformer.h" #include "tuple_helper/tuple_iteration.h" #include "type_traits.h" #include "alias.h" @@ -173,14 +174,23 @@ namespace sqlite_orm { template void assert_updatable_type() const { +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) using Table = storage_pick_table_t; - constexpr int primaryKeyColumnsCount = - Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; - constexpr int nonPrimaryKeysColumnsCount = Table::columns_count - primaryKeyColumnsCount; - static_assert(primaryKeyColumnsCount > 0, "Type with no primary keys can't be updated"); + using elements_type = elements_type_t; + using col_index_sequence = filter_tuple_sequence_t; + using pk_index_sequence = filter_tuple_sequence_t; + using pkcol_index_sequence = col_index_sequence_with; + constexpr size_t dedicatedPrimaryKeyColumnsCount = + nested_tuple_size_for_t::value; + + constexpr size_t primaryKeyColumnsCount = + dedicatedPrimaryKeyColumnsCount + pkcol_index_sequence::size(); + constexpr ptrdiff_t nonPrimaryKeysColumnsCount = col_index_sequence::size() - primaryKeyColumnsCount; + static_assert(primaryKeyColumnsCount > 0, "A table without primary keys cannot be updated"); static_assert( nonPrimaryKeysColumnsCount > 0, - "Type with primary keys only can't be updated. You need at least 1 non-primary key column"); + "A table with only primary keys cannot be updated. You need at least 1 non-primary key column"); +#endif } template(dbObjects, tables_index_sequence{}, [&res](const auto& table) { - res += table.foreign_keys_count; + res += table.template count_of(); }); return res; } diff --git a/dev/tuple_helper/tuple_filter.h b/dev/tuple_helper/tuple_filter.h index 2fea55d8e..0cd049d67 100644 --- a/dev/tuple_helper/tuple_filter.h +++ b/dev/tuple_helper/tuple_filter.h @@ -3,7 +3,7 @@ #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple -#include "../functional/cxx_universal.h" +#include "../functional/cxx_universal.h" // ::size_t #include "../functional/index_sequence_util.h" namespace sqlite_orm { diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index a0154a927..7c40910fe 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -1,12 +1,10 @@ #pragma once #include // std::tuple, std::get, std::tuple_element, std::tuple_size -#include // std::remove_reference, std::index_sequence, std::make_index_sequence +#include // std::remove_reference, std::index_sequence, std::make_index_sequence, std::forward, std::move #include // std::forward, std::move #include "../functional/cxx_universal.h" // ::size_t -#include "../functional/cxx_type_traits_polyfill.h" -#include "../functional/cxx_functional_polyfill.h" namespace sqlite_orm { namespace internal { @@ -92,19 +90,6 @@ namespace sqlite_orm { iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); } - template - R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { - return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; - } - - template - R create_from_tuple(Tpl&& tpl, Projection project = {}) { - return create_from_tuple( - std::forward(tpl), - std::make_index_sequence>::value>{}, - std::forward(project)); - } - template class Base, class L> struct lambda_as_template_base : L { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED diff --git a/dev/tuple_helper/tuple_transformer.h b/dev/tuple_helper/tuple_transformer.h index 9c7a73c43..72e3248bc 100644 --- a/dev/tuple_helper/tuple_transformer.h +++ b/dev/tuple_helper/tuple_transformer.h @@ -1,7 +1,11 @@ #pragma once -#include // std::tuple +#include // std::remove_reference, std::common_type, std::index_sequence, std::make_index_sequence, std::forward, std::move, std::integral_constant, std::declval +#include // std::tuple_size, std::get +#include "../functional/cxx_universal.h" // ::size_t +#include "../functional/cxx_type_traits_polyfill.h" +#include "../functional/cxx_functional_polyfill.h" #include "../functional/mpl.h" namespace sqlite_orm { @@ -10,9 +14,9 @@ namespace sqlite_orm { template class Op> struct tuple_transformer; - template class Op> - struct tuple_transformer, Op> { - using type = std::tuple...>; + template class Pack, class... Types, template class Op> + struct tuple_transformer, Op> { + using type = Pack...>; }; /* @@ -22,5 +26,81 @@ namespace sqlite_orm { */ template class Op> using transform_tuple_t = typename tuple_transformer::type; + +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + /* + * Apply a projection to a tuple's elements filtered by the specified indexes, and combine the results. + * + * @note It's a glorified version of `std::apply()` and a variant of `std::accumulate()`. + * It combines filtering the tuple (indexes), transforming the elements (projection) and finally applying the callable (combine). + */ + template + constexpr auto recombine_tuple(CombineOp combine, + const Tpl& tpl, + std::index_sequence, + Projector project, + Init initial) { + return combine(initial, polyfill::invoke(project, std::get(tpl))...); + } + + /* + * Apply a projection to a tuple's elements, and combine the results. + * + * @note It's a glorified version of `std::apply()` and a variant of `std::accumulate()`. + * It combines filtering the tuple (indexes), transforming the elements (projection) and finally applying the callable (combine). + */ + template + constexpr auto recombine_tuple(CombineOp combine, const Tpl& tpl, Projector project, Init initial) { + return recombine_tuple(std::move(combine), + std::forward(tpl), + std::make_index_sequence::value>{}, + std::move(project), + std::move(initial)); + } + + /* + * Function object that takes integral constants and returns the sum of their values as an integral constant. + * Because it's a "transparent" functor, it must be called with at least one argument, otherwise it cannot deduce the integral constant type. + */ + struct plus_reduce_integrals { + template + constexpr auto operator()(const Integrals&... integrals) const { + using integral_type = std::common_type_t; + return std::integral_constant{}; + } + }; + + /* + * Function object that takes a type, applies a projection on it, and returns the tuple size of the projected type (as an integral constant). + * The projection is applied on the argument type, not the argument value/object. + */ + template class NestedProject> + struct project_nested_tuple_size { + template + constexpr auto operator()(const T&) const { + return typename std::tuple_size>::type{}; + } + }; + + template class NestedProject, class Tpl, class IdxSeq> + using nested_tuple_size_for_t = decltype(recombine_tuple(plus_reduce_integrals{}, + std::declval(), + IdxSeq{}, + project_nested_tuple_size{}, + std::integral_constant{})); +#endif + + template + R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { + return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; + } + + template + R create_from_tuple(Tpl&& tpl, Projection project = {}) { + return create_from_tuple( + std::forward(tpl), + std::make_index_sequence>::value>{}, + std::forward(project)); + } } } diff --git a/dev/type_traits.h b/dev/type_traits.h index 64bf1ccdb..dac8df271 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -49,6 +49,9 @@ namespace sqlite_orm { template using constraints_type_t = typename T::constraints_type; + template + using columns_tuple_t = typename T::columns_tuple; + template using object_type_t = typename T::object_type; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d2428ce28..d7f16ed06 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -394,6 +394,9 @@ namespace sqlite_orm { template using constraints_type_t = typename T::constraints_type; + template + using columns_tuple_t = typename T::columns_tuple; + template using object_type_t = typename T::object_type; @@ -1133,10 +1136,10 @@ namespace sqlite_orm { #include // std::tuple // #include "../functional/cxx_universal.h" - +// ::size_t // #include "../functional/index_sequence_util.h" -#include // std::index_sequence, std::make_index_sequence +#include // std::index_sequence // #include "../functional/cxx_universal.h" @@ -1665,6 +1668,7 @@ namespace sqlite_orm { expression_type expression; }; +#if SQLITE_VERSION_NUMBER >= 3031000 struct basic_generated_always { enum class storage_type { not_specified, @@ -1697,6 +1701,7 @@ namespace sqlite_orm { return {std::move(this->expression), this->full, storage_type::stored}; } }; +#endif struct null_t {}; @@ -1706,7 +1711,12 @@ namespace sqlite_orm { namespace internal { template - SQLITE_ORM_INLINE_VAR constexpr bool is_foreign_key_v = polyfill::is_specialization_of_v; + SQLITE_ORM_INLINE_VAR constexpr bool is_foreign_key_v = +#if SQLITE_VERSION_NUMBER >= 3006019 + polyfill::is_specialization_of_v; +#else + false; +#endif template using is_foreign_key = polyfill::bool_constant>; @@ -1724,10 +1734,15 @@ namespace sqlite_orm { SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = is_primary_key::value; template - using is_generated_always = polyfill::is_specialization_of; + SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = +#if SQLITE_VERSION_NUMBER >= 3031000 + polyfill::is_specialization_of_v; +#else + false; +#endif template - SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = is_generated_always::value; + using is_generated_always = polyfill::bool_constant>; /** * PRIMARY KEY INSERTABLE traits. @@ -1744,37 +1759,17 @@ namespace sqlite_orm { }; template - struct primary_key_colums_count_t; - - template - struct primary_key_colums_count_t> - : std::integral_constant(sizeof...(Cs))> {}; - - template - struct flatten_primry_keys_columns { - using columns_tuple = typename conc_tuple::type; - }; - - template - struct flatten_primry_keys_columns> : flatten_primry_keys_columns {}; - - template - using is_constraint = - mpl::instantiate, - check_if, - check_if_is_type, - check_if_is_type, - check_if_is_template, - check_if_is_template, - check_if_is_template, - check_if_is_template, - check_if_is_type, -#if SQLITE_VERSION_NUMBER >= 3031000 - check_if, -#endif - // dummy tail because of SQLITE_VERSION_NUMBER checks above - mpl::always>, - T>; + using is_constraint = mpl::instantiate, + check_if, + check_if_is_type, + check_if_is_type, + check_if_is_template, + check_if_is_template, + check_if_is_template, + check_if_is_template, + check_if_is_type, + check_if>, + T>; } #if SQLITE_VERSION_NUMBER >= 3031000 @@ -2476,24 +2471,13 @@ namespace sqlite_orm { constraints_type constraints; /** - * Checks whether contraints are of trait `Trait` + * Checks whether contraints contain specified type. */ template class Trait> constexpr static bool is() { return tuple_has::value; } - constexpr static bool is_primary_key = - mpl::invoke_t, constraints_type>::value; - - constexpr bool is_generated() const { -#if SQLITE_VERSION_NUMBER >= 3031000 - return is(); -#else - return false; -#endif - } - /** * Simplified interface for `DEFAULT` constraint * @return string representation of default value if it exists otherwise nullptr @@ -2518,9 +2502,6 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_column_v = polyfill::is_specialization_of_v; - template - using is_primary_key_column = polyfill::bool_constant; - template using is_column = polyfill::bool_constant>; @@ -9617,14 +9598,11 @@ namespace sqlite_orm { // #include "../tuple_helper/tuple_iteration.h" #include // std::tuple, std::get, std::tuple_element, std::tuple_size -#include // std::remove_reference, std::index_sequence, std::make_index_sequence +#include // std::remove_reference, std::index_sequence, std::make_index_sequence, std::forward, std::move #include // std::forward, std::move // #include "../functional/cxx_universal.h" // ::size_t -// #include "../functional/cxx_type_traits_polyfill.h" - -// #include "../functional/cxx_functional_polyfill.h" namespace sqlite_orm { namespace internal { @@ -9710,19 +9688,6 @@ namespace sqlite_orm { iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); } - template - R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { - return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; - } - - template - R create_from_tuple(Tpl&& tpl, Projection project = {}) { - return create_from_tuple( - std::forward(tpl), - std::make_index_sequence>::value>{}, - std::forward(project)); - } - template class Base, class L> struct lambda_as_template_base : L { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED @@ -9752,6 +9717,116 @@ namespace sqlite_orm { } } +// #include "../tuple_helper/tuple_transformer.h" + +#include // std::remove_reference, std::common_type, std::index_sequence, std::make_index_sequence, std::forward, std::move, std::integral_constant, std::declval +#include // std::tuple_size, std::get + +// #include "../functional/cxx_universal.h" +// ::size_t +// #include "../functional/cxx_type_traits_polyfill.h" + +// #include "../functional/cxx_functional_polyfill.h" + +// #include "../functional/mpl.h" + +namespace sqlite_orm { + namespace internal { + + template class Op> + struct tuple_transformer; + + template class Pack, class... Types, template class Op> + struct tuple_transformer, Op> { + using type = Pack...>; + }; + + /* + * Transform specified tuple. + * + * `Op` is a metafunction operation. + */ + template class Op> + using transform_tuple_t = typename tuple_transformer::type; + +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + /* + * Apply a projection to a tuple's elements filtered by the specified indexes, and combine the results. + * + * @note It's a glorified version of `std::apply()` and a variant of `std::accumulate()`. + * It combines filtering the tuple (indexes), transforming the elements (projection) and finally applying the callable (combine). + */ + template + constexpr auto recombine_tuple(CombineOp combine, + const Tpl& tpl, + std::index_sequence, + Projector project, + Init initial) { + return combine(initial, polyfill::invoke(project, std::get(tpl))...); + } + + /* + * Apply a projection to a tuple's elements, and combine the results. + * + * @note It's a glorified version of `std::apply()` and a variant of `std::accumulate()`. + * It combines filtering the tuple (indexes), transforming the elements (projection) and finally applying the callable (combine). + */ + template + constexpr auto recombine_tuple(CombineOp combine, const Tpl& tpl, Projector project, Init initial) { + return recombine_tuple(std::move(combine), + std::forward(tpl), + std::make_index_sequence::value>{}, + std::move(project), + std::move(initial)); + } + + /* + * Function object that takes integral constants and returns the sum of their values as an integral constant. + * Because it's a "transparent" functor, it must be called with at least one argument, otherwise it cannot deduce the integral constant type. + */ + struct plus_reduce_integrals { + template + constexpr auto operator()(const Integrals&... integrals) const { + using integral_type = std::common_type_t; + return std::integral_constant{}; + } + }; + + /* + * Function object that takes a type, applies a projection on it, and returns the tuple size of the projected type (as an integral constant). + * The projection is applied on the argument type, not the argument value/object. + */ + template class NestedProject> + struct project_nested_tuple_size { + template + constexpr auto operator()(const T&) const { + return typename std::tuple_size>::type{}; + } + }; + + template class NestedProject, class Tpl, class IdxSeq> + using nested_tuple_size_for_t = decltype(recombine_tuple(plus_reduce_integrals{}, + std::declval(), + IdxSeq{}, + project_nested_tuple_size{}, + std::integral_constant{})); +#endif + + template + R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { + return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; + } + + template + R create_from_tuple(Tpl&& tpl, Projection project = {}) { + return create_from_tuple( + std::forward(tpl), + std::make_index_sequence>::value>{}, + std::forward(project)); + } + } +} + // #include "../member_traits/member_traits.h" // #include "../typed_comparator.h" @@ -9783,16 +9858,8 @@ namespace sqlite_orm { struct table_t : basic_table { using object_type = O; using elements_type = std::tuple; - using columns_tuple = filter_tuple_t; - using dedicated_primary_keys_tuple = filter_tuple_t; - using dedicated_primary_keys_columns_tuple = - typename flatten_primry_keys_columns::columns_tuple; static constexpr bool is_without_rowid_v = WithoutRowId; - static constexpr int columns_count = static_cast(std::tuple_size::value); - static constexpr int primary_key_columns_count = count_tuple::value; - static constexpr int dedicated_primary_key_columns_count = - static_cast(std::tuple_size::value); using is_without_rowid = polyfill::bool_constant; @@ -9807,15 +9874,32 @@ namespace sqlite_orm { return {this->name, this->elements}; } - /** - * Returns foreign keys count in table definition + /* + * Returns the number of elements of the specified type. */ - static constexpr int foreign_keys_count = -#if SQLITE_VERSION_NUMBER >= 3006019 - static_cast(filter_tuple_sequence_t::size()); -#else - 0; -#endif + template class Trait> + static constexpr int count_of() { + using sequence_of = filter_tuple_sequence_t; + return int(sequence_of::size()); + } + + /* + * Returns the number of columns having the specified constraint trait. + */ + template class Trait> + static constexpr int count_of_columns_with() { + using filtered_index_sequence = col_index_sequence_with; + return int(filtered_index_sequence::size()); + } + + /* + * Returns the number of columns having the specified constraint trait. + */ + template class Trait> + static constexpr int count_of_columns_excluding() { + using excluded_col_index_sequence = col_index_sequence_excluding; + return int(excluded_col_index_sequence::size()); + } /** * Function used to get field value from object by mapped member pointer/setter/getter. @@ -9937,19 +10021,6 @@ namespace sqlite_orm { return res; } - /** - * Counts and returns amount of columns without GENERATED ALWAYS constraints. Skips table constraints. - */ - constexpr int non_generated_columns_count() const { -#if SQLITE_VERSION_NUMBER >= 3031000 - using non_generated_col_index_sequence = - col_index_sequence_excluding; - return int(non_generated_col_index_sequence::size()); -#else - return this->columns_count; -#endif - } - /** * Call passed lambda with all defined foreign keys. * @param lambda Lambda called for each column. Function signature: `void(auto& column)` @@ -10327,7 +10398,7 @@ namespace sqlite_orm { int foreign_keys_count(const DBOs& dbObjects) { int res = 0; iterate_tuple(dbObjects, tables_index_sequence{}, [&res](const auto& table) { - res += table.foreign_keys_count; + res += table.template count_of(); }); return res; } @@ -10427,6 +10498,8 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_filter.h" +// #include "tuple_helper/tuple_transformer.h" + // #include "tuple_helper/tuple_iteration.h" // #include "type_traits.h" @@ -10538,31 +10611,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" -#include // std::tuple - -// #include "../functional/mpl.h" - -namespace sqlite_orm { - namespace internal { - - template class Op> - struct tuple_transformer; - - template class Op> - struct tuple_transformer, Op> { - using type = std::tuple...>; - }; - - /* - * Transform specified tuple. - * - * `Op` is a metafunction operation. - */ - template class Op> - using transform_tuple_t = typename tuple_transformer::type; - } -} - // #include "type_traits.h" // #include "storage_lookup.h" @@ -15528,7 +15576,7 @@ namespace sqlite_orm { const Ctx& context) { if(definedOrder) { auto& table = pick_table>(context.db_objects); - collectedExpressions.reserve(collectedExpressions.size() + table.columns_count); + collectedExpressions.reserve(collectedExpressions.size() + table.template count_of()); table.for_each_column([qualified = !context.skip_table_name, &tableName = table.name, &collectedExpressions](const column_identifier& column) { @@ -17091,7 +17139,7 @@ namespace sqlite_orm { ss << "REPLACE INTO " << streaming_identifier(table.name) << " (" << streaming_non_generated_column_names(table) << ")"; const auto valuesCount = std::distance(rep.range.first, rep.range.second); - const auto columnsCount = table.non_generated_columns_count(); + const auto columnsCount = table.template count_of_columns_excluding(); ss << " VALUES " << streaming_values_placeholders(columnsCount, valuesCount); return ss.str(); } @@ -17967,14 +18015,23 @@ namespace sqlite_orm { template void assert_updatable_type() const { +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) using Table = storage_pick_table_t; - constexpr int primaryKeyColumnsCount = - Table::primary_key_columns_count + Table::dedicated_primary_key_columns_count; - constexpr int nonPrimaryKeysColumnsCount = Table::columns_count - primaryKeyColumnsCount; - static_assert(primaryKeyColumnsCount > 0, "Type with no primary keys can't be updated"); + using elements_type = elements_type_t
; + using col_index_sequence = filter_tuple_sequence_t; + using pk_index_sequence = filter_tuple_sequence_t; + using pkcol_index_sequence = col_index_sequence_with; + constexpr size_t dedicatedPrimaryKeyColumnsCount = + nested_tuple_size_for_t::value; + + constexpr size_t primaryKeyColumnsCount = + dedicatedPrimaryKeyColumnsCount + pkcol_index_sequence::size(); + constexpr ptrdiff_t nonPrimaryKeysColumnsCount = col_index_sequence::size() - primaryKeyColumnsCount; + static_assert(primaryKeyColumnsCount > 0, "A table without primary keys cannot be updated"); static_assert( nonPrimaryKeysColumnsCount > 0, - "Type with primary keys only can't be updated. You need at least 1 non-primary key column"); + "A table with only primary keys cannot be updated. You need at least 1 non-primary key column"); +#endif } template(), - column.is_generated()); + column.template is()); }); auto compositeKeyColumnNames = this->composite_key_columns_names(); for(size_t i = 0; i < compositeKeyColumnNames.size(); ++i) { @@ -20221,7 +20278,7 @@ namespace sqlite_orm { const Table& table, const std::vector& columnsToIgnore) const { // must ignore generated columns std::vector> columnNames; - columnNames.reserve(table.columns_count); + columnNames.reserve(table.template count_of()); table.for_each_column([&columnNames, &columnsToIgnore](const column_identifier& column) { auto& columnName = column.name; #if __cpp_lib_ranges >= 201911L diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 171497517..b15a6baf6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,6 @@ add_executable(unit_tests static_tests/is_primary_key_insertable.cpp static_tests/is_column_with_insertable_primary_key.cpp static_tests/operators_adl.cpp - static_tests/flatten_primary_keys_columns.cpp static_tests/table_static_tests.cpp tuple_iteration.cpp sync_schema_tests.cpp diff --git a/tests/schema/column_tests.cpp b/tests/schema/column_tests.cpp index da245ad3e..ee661a7c7 100644 --- a/tests/schema/column_tests.cpp +++ b/tests/schema/column_tests.cpp @@ -2,32 +2,33 @@ #include using namespace sqlite_orm; +using internal::is_generated_always; -TEST_CASE("column tests is_generated") { +TEST_CASE("column tests is") { struct User { int id = 0; int age = 0; }; SECTION("no constraints") { auto column = make_column("id", &User::id); - REQUIRE_FALSE(column.is_generated()); + REQUIRE_FALSE(column.is()); } #if SQLITE_VERSION_NUMBER >= 3031000 SECTION("1 constraint: generated") { SECTION("full") { auto column = make_column("age", &User::age, generated_always_as(add(&User::id, 5))); - REQUIRE(column.is_generated()); + REQUIRE(column.is()); } SECTION("not full") { auto column = make_column("age", &User::age, as(add(&User::id, 5))); - REQUIRE(column.is_generated()); + REQUIRE(column.is()); } } #endif SECTION("1 constraint: primary key") { auto column = make_column("id", &User::id, primary_key()); - REQUIRE_FALSE(column.is_generated()); + REQUIRE_FALSE(column.is()); } } diff --git a/tests/static_tests/flatten_primary_keys_columns.cpp b/tests/static_tests/flatten_primary_keys_columns.cpp deleted file mode 100644 index e9aa9c3b6..000000000 --- a/tests/static_tests/flatten_primary_keys_columns.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include // std::is_same - -using namespace sqlite_orm; - -TEST_CASE("flatten_primry_keys_columns") { - struct User { - int id = 0; - std::string name; - }; - { // id + name - auto pk1 = primary_key(&User::id); - auto pk2 = primary_key(&User::name); - - using Pk1 = decltype(pk1); - using Pk2 = decltype(pk2); - using Result = internal::flatten_primry_keys_columns::columns_tuple; - using Expected = std::tuple; - STATIC_REQUIRE(std::is_same::value); - } - { // (empty) + name - auto pk1 = primary_key(); - auto pk2 = primary_key(&User::name); - - using Pk1 = decltype(pk1); - using Pk2 = decltype(pk2); - using Result = internal::flatten_primry_keys_columns::columns_tuple; - using Expected = std::tuple; - STATIC_REQUIRE(std::is_same::value); - } - { // id + (empty) - auto pk1 = primary_key(&User::id); - auto pk2 = primary_key(); - - using Pk1 = decltype(pk1); - using Pk2 = decltype(pk2); - using Result = internal::flatten_primry_keys_columns::columns_tuple; - using Expected = std::tuple; - STATIC_REQUIRE(std::is_same::value); - } - { // (empty) + (empty) - auto pk1 = primary_key(); - auto pk2 = primary_key(); - - using Pk1 = decltype(pk1); - using Pk2 = decltype(pk2); - using Result = internal::flatten_primry_keys_columns::columns_tuple; - using Expected = std::tuple<>; - STATIC_REQUIRE(std::is_same::value); - } -} diff --git a/tests/static_tests/table_static_tests.cpp b/tests/static_tests/table_static_tests.cpp index 5f3099665..e96895de0 100644 --- a/tests/static_tests/table_static_tests.cpp +++ b/tests/static_tests/table_static_tests.cpp @@ -2,75 +2,115 @@ #include using namespace sqlite_orm; +using internal::is_column; +using internal::is_primary_key; -TEST_CASE("table static columns_count") { +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) +template +using dedicated_pk_columns_count_t = + internal::nested_tuple_size_for_t>; +#endif + +TEST_CASE("table static count_of()") { struct User { int id = 0; std::string name; }; { // 1 column no pk auto table = make_table("users", make_column("id", &User::id)); - STATIC_REQUIRE(table.columns_count == 1); - STATIC_REQUIRE(table.primary_key_columns_count == 0); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of() == 0); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 0); +#endif } { // 1 column with 1 inline pk auto table = make_table("users", make_column("id", &User::id, primary_key())); - STATIC_REQUIRE(table.columns_count == 1); - STATIC_REQUIRE(table.primary_key_columns_count == 1); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of() == 0); + STATIC_REQUIRE(table.count_of_columns_with() == 1); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 0); +#endif } { // 1 column with 1 inline pk autoincrement auto table = make_table("users", make_column("id", &User::id, primary_key().autoincrement())); - STATIC_REQUIRE(table.columns_count == 1); - STATIC_REQUIRE(table.primary_key_columns_count == 1); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of() == 0); + STATIC_REQUIRE(table.count_of_columns_with() == 1); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 0); +#endif } { // 1 column with 1 dedicated pk auto table = make_table("users", make_column("id", &User::id), primary_key(&User::id)); - STATIC_REQUIRE(table.columns_count == 1); - STATIC_REQUIRE(table.primary_key_columns_count == 0); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 1); +#endif } { // 2 columns no pk auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name)); - STATIC_REQUIRE(table.columns_count == 2); - STATIC_REQUIRE(table.primary_key_columns_count == 0); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + STATIC_REQUIRE(table.count_of() == 2); + STATIC_REQUIRE(table.count_of() == 0); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 0); +#endif } { // 2 columns with 1 inline id pk auto table = make_table("users", make_column("id", &User::id, primary_key()), make_column("id", &User::name)); - STATIC_REQUIRE(table.columns_count == 2); - STATIC_REQUIRE(table.primary_key_columns_count == 1); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + STATIC_REQUIRE(table.count_of() == 2); + STATIC_REQUIRE(table.count_of() == 0); + STATIC_REQUIRE(table.count_of_columns_with() == 1); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 0); +#endif } { // 2 columns with 1 inline name pk auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name, primary_key())); - STATIC_REQUIRE(table.columns_count == 2); - STATIC_REQUIRE(table.primary_key_columns_count == 1); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 0); + STATIC_REQUIRE(table.count_of() == 2); + STATIC_REQUIRE(table.count_of() == 0); + STATIC_REQUIRE(table.count_of_columns_with() == 1); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 0); +#endif } { // 2 columns with 1 dedicated id pk auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name), primary_key(&User::id)); - STATIC_REQUIRE(table.columns_count == 2); - STATIC_REQUIRE(table.primary_key_columns_count == 0); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); + STATIC_REQUIRE(table.count_of() == 2); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 1); +#endif } { // 2 columns with 1 dedicated name pk auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name), primary_key(&User::name)); - STATIC_REQUIRE(table.columns_count == 2); - STATIC_REQUIRE(table.primary_key_columns_count == 0); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 1); + STATIC_REQUIRE(table.count_of() == 2); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 1); +#endif } { // 2 columns with 2 dedicated pks auto table = make_table("users", make_column("id", &User::id), make_column("id", &User::name), primary_key(&User::id, &User::name)); - STATIC_REQUIRE(table.columns_count == 2); - STATIC_REQUIRE(table.primary_key_columns_count == 0); - STATIC_REQUIRE(table.dedicated_primary_key_columns_count == 2); + STATIC_REQUIRE(table.count_of() == 2); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 2); +#endif } } From c05c6f89a84f206d8ed67c4142994a17677719e1 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 24 Oct 2023 16:34:33 +0200 Subject: [PATCH 4/6] Clang choked while accessing a variable that is actually constexpr --- dev/tuple_helper/tuple_transformer.h | 8 ++++---- include/sqlite_orm/sqlite_orm.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dev/tuple_helper/tuple_transformer.h b/dev/tuple_helper/tuple_transformer.h index 72e3248bc..2e3b723a5 100644 --- a/dev/tuple_helper/tuple_transformer.h +++ b/dev/tuple_helper/tuple_transformer.h @@ -62,11 +62,11 @@ namespace sqlite_orm { * Function object that takes integral constants and returns the sum of their values as an integral constant. * Because it's a "transparent" functor, it must be called with at least one argument, otherwise it cannot deduce the integral constant type. */ - struct plus_reduce_integrals { + struct plus_fold_integrals { template - constexpr auto operator()(const Integrals&... integrals) const { + constexpr auto operator()(const Integrals&...) const { using integral_type = std::common_type_t; - return std::integral_constant{}; + return std::integral_constant{}; } }; @@ -83,7 +83,7 @@ namespace sqlite_orm { }; template class NestedProject, class Tpl, class IdxSeq> - using nested_tuple_size_for_t = decltype(recombine_tuple(plus_reduce_integrals{}, + using nested_tuple_size_for_t = decltype(recombine_tuple(plus_fold_integrals{}, std::declval(), IdxSeq{}, project_nested_tuple_size{}, diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d7f16ed06..6e7c645e7 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9784,11 +9784,11 @@ namespace sqlite_orm { * Function object that takes integral constants and returns the sum of their values as an integral constant. * Because it's a "transparent" functor, it must be called with at least one argument, otherwise it cannot deduce the integral constant type. */ - struct plus_reduce_integrals { + struct plus_fold_integrals { template - constexpr auto operator()(const Integrals&... integrals) const { + constexpr auto operator()(const Integrals&...) const { using integral_type = std::common_type_t; - return std::integral_constant{}; + return std::integral_constant{}; } }; @@ -9805,7 +9805,7 @@ namespace sqlite_orm { }; template class NestedProject, class Tpl, class IdxSeq> - using nested_tuple_size_for_t = decltype(recombine_tuple(plus_reduce_integrals{}, + using nested_tuple_size_for_t = decltype(recombine_tuple(plus_fold_integrals{}, std::declval(), IdxSeq{}, project_nested_tuple_size{}, From e868539c9c3313d6fd678ba94a3f3fadf05ef931 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 24 Oct 2023 20:08:39 +0200 Subject: [PATCH 5/6] Update check now also works with auto-incrementable primary keys --- dev/constraints.h | 24 +++++++---------- dev/statement_serializer.h | 8 +++--- include/sqlite_orm/sqlite_orm.h | 32 ++++++++++------------- tests/static_tests/table_static_tests.cpp | 9 +++++++ 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/dev/constraints.h b/dev/constraints.h index e59bb42a9..211ac2751 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -44,12 +44,15 @@ namespace sqlite_orm { }; template - struct primary_key_with_autoincrement { + struct primary_key_with_autoincrement : T { using primary_key_type = T; - primary_key_type primary_key; - - primary_key_with_autoincrement(primary_key_type primary_key_) : primary_key(primary_key_) {} + const primary_key_type& as_base() const { + return *this; + } +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + primary_key_with_autoincrement(T primary_key) : T{primary_key} {} +#endif }; /** @@ -65,7 +68,7 @@ namespace sqlite_orm { columns_tuple columns; - primary_key_t(decltype(columns) columns) : columns(std::move(columns)) {} + primary_key_t(columns_tuple columns) : columns(std::move(columns)) {} self asc() const { auto res = *this; @@ -433,16 +436,10 @@ namespace sqlite_orm { using is_foreign_key = polyfill::bool_constant>; template - struct is_primary_key : std::false_type {}; - - template - struct is_primary_key> : std::true_type {}; - - template - struct is_primary_key> : std::true_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = std::is_base_of::value; template - SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = is_primary_key::value; + using is_primary_key = polyfill::bool_constant>; template SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = @@ -477,7 +474,6 @@ namespace sqlite_orm { check_if_is_template, check_if_is_template, check_if_is_template, - check_if_is_template, check_if_is_type, check_if>, T>; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 3dad4c474..ddaad6feb 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -907,13 +907,13 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = primary_key_with_autoincrement; + template + struct statement_serializer, void> { + using statement_type = primary_key_with_autoincrement; template std::string operator()(const statement_type& statement, const Ctx& context) const { - return serialize(statement.primary_key, context) + " AUTOINCREMENT"; + return serialize(statement.as_base(), context) + " AUTOINCREMENT"; } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 691d67cab..dc2ed46d0 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1351,12 +1351,15 @@ namespace sqlite_orm { }; template - struct primary_key_with_autoincrement { + struct primary_key_with_autoincrement : T { using primary_key_type = T; - primary_key_type primary_key; - - primary_key_with_autoincrement(primary_key_type primary_key_) : primary_key(primary_key_) {} + const primary_key_type& as_base() const { + return *this; + } +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + primary_key_with_autoincrement(T primary_key) : T{primary_key} {} +#endif }; /** @@ -1372,7 +1375,7 @@ namespace sqlite_orm { columns_tuple columns; - primary_key_t(decltype(columns) columns) : columns(std::move(columns)) {} + primary_key_t(columns_tuple columns) : columns(std::move(columns)) {} self asc() const { auto res = *this; @@ -1740,16 +1743,10 @@ namespace sqlite_orm { using is_foreign_key = polyfill::bool_constant>; template - struct is_primary_key : std::false_type {}; - - template - struct is_primary_key> : std::true_type {}; + SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = std::is_base_of::value; template - struct is_primary_key> : std::true_type {}; - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_primary_key_v = is_primary_key::value; + using is_primary_key = polyfill::bool_constant>; template SQLITE_ORM_INLINE_VAR constexpr bool is_generated_always_v = @@ -1784,7 +1781,6 @@ namespace sqlite_orm { check_if_is_template, check_if_is_template, check_if_is_template, - check_if_is_template, check_if_is_type, check_if>, T>; @@ -16692,13 +16688,13 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = primary_key_with_autoincrement; + template + struct statement_serializer, void> { + using statement_type = primary_key_with_autoincrement; template std::string operator()(const statement_type& statement, const Ctx& context) const { - return serialize(statement.primary_key, context) + " AUTOINCREMENT"; + return serialize(statement.as_base(), context) + " AUTOINCREMENT"; } }; diff --git a/tests/static_tests/table_static_tests.cpp b/tests/static_tests/table_static_tests.cpp index e96895de0..ff782f178 100644 --- a/tests/static_tests/table_static_tests.cpp +++ b/tests/static_tests/table_static_tests.cpp @@ -52,6 +52,15 @@ TEST_CASE("table static count_of()") { STATIC_REQUIRE(table.count_of_columns_with() == 0); #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 1); +#endif + } + { // 1 column with 1 dedicated pk autoincrement + auto table = make_table("users", make_column("id", &User::id), primary_key(&User::id).autoincrement()); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of() == 1); + STATIC_REQUIRE(table.count_of_columns_with() == 0); +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) + STATIC_REQUIRE(dedicated_pk_columns_count_t::value == 1); #endif } { // 2 columns no pk From 87cee49ad80b810db1950a11c993fafaba4f7df5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 24 Oct 2023 20:23:09 +0200 Subject: [PATCH 6/6] Reused alias template type in primary key constructor again --- dev/constraints.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/constraints.h b/dev/constraints.h index 211ac2751..67c36f32e 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -51,7 +51,7 @@ namespace sqlite_orm { return *this; } #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - primary_key_with_autoincrement(T primary_key) : T{primary_key} {} + primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {} #endif }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index dc2ed46d0..eb3f56d88 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1358,7 +1358,7 @@ namespace sqlite_orm { return *this; } #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - primary_key_with_autoincrement(T primary_key) : T{primary_key} {} + primary_key_with_autoincrement(primary_key_type primary_key) : primary_key_type{primary_key} {} #endif };