From 30a6324df905e3675e07a1b541d208720c2f78ad Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 13 Dec 2022 08:27:01 -0600 Subject: [PATCH 001/100] added explicit overload of make_index --- dev/index.h | 24 +- dev/statement_serializer.h | 10 +- dev/storage.h | 2 +- dev/table_type_of.h | 7 + dev/xdestroy_handling.h | 35 +- include/sqlite_orm/sqlite_orm.h | 377 ++++++++++-------- tests/index_tests.cpp | 12 + .../schema/index.cpp | 11 + 8 files changed, 277 insertions(+), 201 deletions(-) diff --git a/dev/index.h b/dev/index.h index 36e25815d..b0027bf95 100644 --- a/dev/index.h +++ b/dev/index.h @@ -1,12 +1,13 @@ #pragma once -#include // std::tuple, std::make_tuple, std::declval +#include // std::tuple, std::make_tuple, std::declval, std::tuple_element_t #include // std::string #include // std::forward #include "functional/cxx_universal.h" #include "tuple_helper/tuple_filter.h" #include "indexed_column.h" +#include "table_type_of.h" namespace sqlite_orm { @@ -21,10 +22,11 @@ namespace sqlite_orm { #endif }; - template + template struct index_t : index_base { using elements_type = std::tuple; using object_type = void; + using table_mapped_type = T; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED index_t(std::string name_, bool unique_, elements_type elements_) : @@ -35,9 +37,20 @@ namespace sqlite_orm { }; } + template + internal::index_t()))...> make_index(std::string name, + Cols... cols) { + using cols_tuple = std::tuple; + static_assert(internal::count_tuple::value <= 1, + "amount of where arguments can be 0 or 1"); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + } + template - internal::index_t()))...> make_index(std::string name, - Cols... cols) { + internal::index_t>>, + decltype(internal::make_indexed_column(std::declval()))...> + make_index(std::string name, Cols... cols) { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); @@ -46,7 +59,8 @@ namespace sqlite_orm { } template - internal::index_t()))...> + internal::index_t>>, + decltype(internal::make_indexed_column(std::declval()))...> make_unique_index(std::string name, Cols... cols) { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index cfe5dac2c..a44b3f2ca 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1536,9 +1536,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = index_t; + template + struct statement_serializer, void> { + using statement_type = index_t; template std::string operator()(const statement_type& statement, const Ctx& context) const { @@ -1547,9 +1547,7 @@ namespace sqlite_orm { if(statement.unique) { ss << "UNIQUE "; } - using elements_type = typename std::decay_t::elements_type; - using head_t = typename std::tuple_element_t<0, elements_type>::column_type; - using indexed_type = table_type_of_t; + using indexed_type = typename std::decay_t::table_mapped_type; ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " << streaming_identifier(lookup_table_name(context.db_objects)); std::vector columnNames; diff --git a/dev/storage.h b/dev/storage.h index 33f37cdb8..1d5a53563 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -586,7 +586,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto { + [](auto expression) -> auto{ expression.highest_level = true; return expression; }, diff --git a/dev/table_type_of.h b/dev/table_type_of.h index fa3e20b3a..842002e8e 100644 --- a/dev/table_type_of.h +++ b/dev/table_type_of.h @@ -1,5 +1,7 @@ #pragma once +#include "indexed_column.h" + namespace sqlite_orm { namespace internal { @@ -29,6 +31,11 @@ namespace sqlite_orm { using type = T; }; + template + struct table_type_of> { + using type = typename table_type_of::type; + }; + template using table_type_of_t = typename table_type_of::type; } diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index e9f986a03..25e172a32 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -29,20 +29,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - {+d}; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -57,7 +57,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value&& std::is_default_constructible::value; + std::is_empty::value && std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -118,7 +118,8 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -146,7 +147,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -181,7 +182,9 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -200,7 +203,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { return internal::xdestroy_proxy; } @@ -219,7 +224,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { return d; } #else diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 3ead3a346..47ae45570 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1206,6 +1206,158 @@ namespace sqlite_orm { // #include "table_type_of.h" +// #include "indexed_column.h" + +#include // std::string +#include // std::move + +// #include "functional/cxx_universal.h" + +// #include "ast/where.h" + +#include // std::false_type, std::true_type +#include // std::move + +// #include "../functional/cxx_universal.h" + +// #include "../functional/cxx_type_traits_polyfill.h" + +// #include "../serialize_result_type.h" + +// #include "functional/cxx_string_view.h" + +// #include "cxx_core_features.h" + +#if SQLITE_ORM_HAS_INCLUDE() +#include +#endif + +#if __cpp_lib_string_view >= 201606L +#define SQLITE_ORM_STRING_VIEW_SUPPORTED +#endif + +#ifndef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include // std::string +#endif + +namespace sqlite_orm { + namespace internal { +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + using serialize_result_type = std::string_view; +#else + using serialize_result_type = std::string; +#endif + } +} + +namespace sqlite_orm { + namespace internal { + + struct where_string { + serialize_result_type serialize() const { + return "WHERE"; + } + }; + + /** + * WHERE argument holder. + * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc + * Don't construct it manually. Call `where(...)` function instead. + */ + template + struct where_t : where_string { + using expression_type = C; + + expression_type expression; + + where_t(expression_type expression_) : expression(std::move(expression_)) {} + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_where_v = polyfill::is_specialization_of_v; + + template + using is_where = polyfill::bool_constant>; + } + + /** + * WHERE clause. Use it to add WHERE conditions wherever you like. + * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc + * @example + * // SELECT name + * // FROM letters + * // WHERE id > 3 + * auto rows = storage.select(&Letter::name, where(greater_than(&Letter::id, 3))); + */ + template + internal::where_t where(C expression) { + return {std::move(expression)}; + } +} + +namespace sqlite_orm { + + namespace internal { + + template + struct indexed_column_t { + using column_type = C; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + indexed_column_t(column_type _column_or_expression) : + column_or_expression(std::move(_column_or_expression)) {} +#endif + + column_type column_or_expression; + std::string _collation_name; + int _order = 0; // -1 = desc, 1 = asc, 0 = not specified + + indexed_column_t collate(std::string name) { + auto res = std::move(*this); + res._collation_name = move(name); + return res; + } + + indexed_column_t asc() { + auto res = std::move(*this); + res._order = 1; + return res; + } + + indexed_column_t desc() { + auto res = std::move(*this); + res._order = -1; + return res; + } + }; + + template + indexed_column_t make_indexed_column(C col) { + return {std::move(col)}; + } + + template + where_t make_indexed_column(where_t wher) { + return std::move(wher); + } + + template + indexed_column_t make_indexed_column(indexed_column_t col) { + return std::move(col); + } + } + + /** + * Use this function to specify indexed column inside `make_index` function call. + * Example: make_index("index_name", indexed_column(&User::id).asc()) + */ + template + internal::indexed_column_t indexed_column(C column_or_expression) { + return {std::move(column_or_expression)}; + } + +} + namespace sqlite_orm { namespace internal { @@ -1235,6 +1387,11 @@ namespace sqlite_orm { using type = T; }; + template + struct table_type_of> { + using type = typename table_type_of::type; + }; + template using table_type_of_t = typename table_type_of::type; } @@ -1828,32 +1985,6 @@ 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 - -#if __cpp_lib_string_view >= 201606L -#define SQLITE_ORM_STRING_VIEW_SUPPORTED -#endif - -#ifndef SQLITE_ORM_STRING_VIEW_SUPPORTED -#include // std::string -#endif - -namespace sqlite_orm { - namespace internal { -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - using serialize_result_type = std::string_view; -#else - using serialize_result_type = std::string; -#endif - } -} - namespace sqlite_orm { namespace internal { @@ -6473,60 +6604,6 @@ namespace sqlite_orm { // #include "ast/where.h" -#include // std::false_type, std::true_type -#include // std::move - -// #include "../functional/cxx_universal.h" - -// #include "../functional/cxx_type_traits_polyfill.h" - -// #include "../serialize_result_type.h" - -namespace sqlite_orm { - namespace internal { - - struct where_string { - serialize_result_type serialize() const { - return "WHERE"; - } - }; - - /** - * WHERE argument holder. - * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc - * Don't construct it manually. Call `where(...)` function instead. - */ - template - struct where_t : where_string { - using expression_type = C; - - expression_type expression; - - where_t(expression_type expression_) : expression(std::move(expression_)) {} - }; - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_where_v = polyfill::is_specialization_of_v; - - template - using is_where = polyfill::bool_constant>; - } - - /** - * WHERE clause. Use it to add WHERE conditions wherever you like. - * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc - * @example - * // SELECT name - * // FROM letters - * // WHERE id > 3 - * auto rows = storage.select(&Letter::name, where(greater_than(&Letter::id, 3))); - */ - template - internal::where_t where(C expression) { - return {std::move(expression)}; - } -} - // #include "ast/group_by.h" #include // std::tuple, std::make_tuple @@ -7488,20 +7565,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - {+d}; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -7516,7 +7593,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value&& std::is_default_constructible::value; + std::is_empty::value && std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -7577,7 +7654,8 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -7605,7 +7683,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -7640,7 +7718,9 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -7659,7 +7739,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { return internal::xdestroy_proxy; } @@ -7678,7 +7760,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { return d; } #else @@ -8923,7 +9007,7 @@ namespace sqlite_orm { } #pragma once -#include // std::tuple, std::make_tuple, std::declval +#include // std::tuple, std::make_tuple, std::declval, std::tuple_element_t #include // std::string #include // std::forward @@ -8933,75 +9017,7 @@ namespace sqlite_orm { // #include "indexed_column.h" -#include // std::string -#include // std::move - -// #include "functional/cxx_universal.h" - -// #include "ast/where.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct indexed_column_t { - using column_type = C; - -#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - indexed_column_t(column_type _column_or_expression) : - column_or_expression(std::move(_column_or_expression)) {} -#endif - - column_type column_or_expression; - std::string _collation_name; - int _order = 0; // -1 = desc, 1 = asc, 0 = not specified - - indexed_column_t collate(std::string name) { - auto res = std::move(*this); - res._collation_name = move(name); - return res; - } - - indexed_column_t asc() { - auto res = std::move(*this); - res._order = 1; - return res; - } - - indexed_column_t desc() { - auto res = std::move(*this); - res._order = -1; - return res; - } - }; - - template - indexed_column_t make_indexed_column(C col) { - return {std::move(col)}; - } - - template - where_t make_indexed_column(where_t wher) { - return std::move(wher); - } - - template - indexed_column_t make_indexed_column(indexed_column_t col) { - return std::move(col); - } - } - - /** - * Use this function to specify indexed column inside `make_index` function call. - * Example: make_index("index_name", indexed_column(&User::id).asc()) - */ - template - internal::indexed_column_t indexed_column(C column_or_expression) { - return {std::move(column_or_expression)}; - } - -} +// #include "table_type_of.h" namespace sqlite_orm { @@ -9016,10 +9032,11 @@ namespace sqlite_orm { #endif }; - template + template struct index_t : index_base { using elements_type = std::tuple; using object_type = void; + using table_mapped_type = T; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED index_t(std::string name_, bool unique_, elements_type elements_) : @@ -9030,9 +9047,20 @@ namespace sqlite_orm { }; } + template + internal::index_t()))...> make_index(std::string name, + Cols... cols) { + using cols_tuple = std::tuple; + static_assert(internal::count_tuple::value <= 1, + "amount of where arguments can be 0 or 1"); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + } + template - internal::index_t()))...> make_index(std::string name, - Cols... cols) { + internal::index_t>>, + decltype(internal::make_indexed_column(std::declval()))...> + make_index(std::string name, Cols... cols) { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); @@ -9041,7 +9069,8 @@ namespace sqlite_orm { } template - internal::index_t()))...> + internal::index_t>>, + decltype(internal::make_indexed_column(std::declval()))...> make_unique_index(std::string name, Cols... cols) { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, @@ -16513,9 +16542,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = index_t; + template + struct statement_serializer, void> { + using statement_type = index_t; template std::string operator()(const statement_type& statement, const Ctx& context) const { @@ -16524,9 +16553,7 @@ namespace sqlite_orm { if(statement.unique) { ss << "UNIQUE "; } - using elements_type = typename std::decay_t::elements_type; - using head_t = typename std::tuple_element_t<0, elements_type>::column_type; - using indexed_type = table_type_of_t; + using indexed_type = typename std::decay_t::table_mapped_type; ss << "INDEX IF NOT EXISTS " << streaming_identifier(statement.name) << " ON " << streaming_identifier(lookup_table_name(context.db_objects)); std::vector columnNames; @@ -17582,7 +17609,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto { + [](auto expression) -> auto{ expression.highest_level = true; return expression; }, diff --git a/tests/index_tests.cpp b/tests/index_tests.cpp index 98396a90e..435de9443 100644 --- a/tests/index_tests.cpp +++ b/tests/index_tests.cpp @@ -30,6 +30,18 @@ TEST_CASE("index") { auto storage = make_storage({}, make_index("name_index", indexed_column(&User::name)), table); REQUIRE_NOTHROW(storage.sync_schema()); } + SECTION("json implicit") { + auto storage = + make_storage({}, make_index("name_index", json_extract(&User::name, "$.field")), table); + REQUIRE_NOTHROW(storage.sync_schema()); + } + SECTION("json explicit") { + auto storage = + make_storage({}, + make_index("name_index", indexed_column(json_extract(&User::name, "$.field"))), + table); + REQUIRE_NOTHROW(storage.sync_schema()); + } SECTION("collate") { auto storage = make_storage({}, make_index("name_index", indexed_column(&User::name).collate("binary")), table); REQUIRE_NOTHROW(storage.sync_schema()); diff --git a/tests/statement_serializer_tests/schema/index.cpp b/tests/statement_serializer_tests/schema/index.cpp index b2a670112..8f438c6df 100644 --- a/tests/statement_serializer_tests/schema/index.cpp +++ b/tests/statement_serializer_tests/schema/index.cpp @@ -50,5 +50,16 @@ TEST_CASE("statement_serializer index") { value = internal::serialize(index, context); expected = R"(CREATE INDEX IF NOT EXISTS "idx" ON "users" ("id") WHERE ("id" IS NOT NULL))"; } + SECTION("json") { + SECTION("implicit") { + auto index = make_index("idx", json_extract(&User::name, "$.field")); + value = internal::serialize(index, context); + } + SECTION("explicit") { + auto index = make_index("idx", indexed_column(json_extract(&User::name, "$.field"))); + value = internal::serialize(index, context); + } + expected = "CREATE INDEX IF NOT EXISTS \"idx\" ON \"users\" (JSON_EXTRACT(\"name\", '$.field'))"; + } REQUIRE(value == expected); } From a9546658d2109f4daf2e235af8092c6f4d7bc733 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 13 Dec 2022 08:56:34 -0600 Subject: [PATCH 002/100] added ifdef for json --- tests/index_tests.cpp | 2 ++ tests/statement_serializer_tests/schema/index.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/index_tests.cpp b/tests/index_tests.cpp index 435de9443..e9321c800 100644 --- a/tests/index_tests.cpp +++ b/tests/index_tests.cpp @@ -30,6 +30,7 @@ TEST_CASE("index") { auto storage = make_storage({}, make_index("name_index", indexed_column(&User::name)), table); REQUIRE_NOTHROW(storage.sync_schema()); } +#ifdef SQLITE_ENABLE_JSON1 SECTION("json implicit") { auto storage = make_storage({}, make_index("name_index", json_extract(&User::name, "$.field")), table); @@ -42,6 +43,7 @@ TEST_CASE("index") { table); REQUIRE_NOTHROW(storage.sync_schema()); } +#endif // SQLITE_ENABLE_JSON1 SECTION("collate") { auto storage = make_storage({}, make_index("name_index", indexed_column(&User::name).collate("binary")), table); REQUIRE_NOTHROW(storage.sync_schema()); diff --git a/tests/statement_serializer_tests/schema/index.cpp b/tests/statement_serializer_tests/schema/index.cpp index 8f438c6df..ee0f8e78e 100644 --- a/tests/statement_serializer_tests/schema/index.cpp +++ b/tests/statement_serializer_tests/schema/index.cpp @@ -50,6 +50,7 @@ TEST_CASE("statement_serializer index") { value = internal::serialize(index, context); expected = R"(CREATE INDEX IF NOT EXISTS "idx" ON "users" ("id") WHERE ("id" IS NOT NULL))"; } +#ifdef SQLITE_ENABLE_JSON1 SECTION("json") { SECTION("implicit") { auto index = make_index("idx", json_extract(&User::name, "$.field")); @@ -61,5 +62,6 @@ TEST_CASE("statement_serializer index") { } expected = "CREATE INDEX IF NOT EXISTS \"idx\" ON \"users\" (JSON_EXTRACT(\"name\", '$.field'))"; } +#endif // SQLITE_ENABLE_JSON1 REQUIRE(value == expected); } From cfa725e1a452bc9a8abb51eaa9aebc476df0ec79 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 13 Dec 2022 18:47:26 -0600 Subject: [PATCH 003/100] reverted two files --- dev/storage.h | 2 +- dev/xdestroy_handling.h | 35 ++-- include/sqlite_orm/sqlite_orm.h | 356 ++++++++++++++++++++++---------- 3 files changed, 260 insertions(+), 133 deletions(-) diff --git a/dev/storage.h b/dev/storage.h index 1d5a53563..33f37cdb8 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -586,7 +586,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto{ + [](auto expression) -> auto { expression.highest_level = true; return expression; }, diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index 25e172a32..e9f986a03 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -29,20 +29,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - { +d }; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + {+d}; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -57,7 +57,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value && std::is_default_constructible::value; + std::is_empty::value&& std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -118,8 +118,7 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) - void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -147,7 +146,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -182,9 +181,7 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::is_unusable_for_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -203,9 +200,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::needs_xdestroy_proxy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; } @@ -224,9 +219,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept - requires(internal::yields_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { return d; } #else diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 47ae45570..ebbb25687 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,6 +16,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 @@ -34,6 +35,7 @@ using std::nullptr_t; // #include "cxx_core_features.h" + #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -107,6 +109,7 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" + #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -136,6 +139,8 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif + + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -277,6 +282,7 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } + namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -505,8 +511,10 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -515,6 +523,7 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif + // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -551,6 +560,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -649,6 +659,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. @@ -677,6 +688,7 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { namespace mpl { @@ -957,6 +969,7 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" + namespace sqlite_orm { namespace internal { @@ -986,6 +999,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" + #include // std::is_same #include @@ -993,6 +1007,7 @@ namespace sqlite_orm { // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { /* @@ -1040,6 +1055,7 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" + #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1047,6 +1063,7 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" @@ -1115,6 +1132,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1206,8 +1224,10 @@ namespace sqlite_orm { // #include "table_type_of.h" + // #include "indexed_column.h" + #include // std::string #include // std::move @@ -1215,6 +1235,7 @@ namespace sqlite_orm { // #include "ast/where.h" + #include // std::false_type, std::true_type #include // std::move @@ -1224,10 +1245,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 @@ -1250,6 +1274,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1295,6 +1320,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1358,6 +1384,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -1399,6 +1426,7 @@ namespace sqlite_orm { // #include "type_printer.h" + namespace sqlite_orm { namespace internal { @@ -1944,8 +1972,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 { /** @@ -1970,8 +2000,10 @@ namespace sqlite_orm { #include // std::move // #include "functional/cxx_optional.h" + // #include "tags.h" + namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1985,6 +2017,7 @@ namespace sqlite_orm { // #include "serialize_result_type.h" + namespace sqlite_orm { namespace internal { @@ -2273,12 +2306,14 @@ namespace sqlite_orm { // #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 @@ -2370,6 +2405,7 @@ namespace sqlite_orm { // #include "constraints.h" + namespace sqlite_orm { namespace internal { @@ -2548,12 +2584,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 { /** @@ -2717,6 +2755,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -2751,6 +2790,7 @@ namespace sqlite_orm { // #include "serializer_context.h" + namespace sqlite_orm { namespace internal { @@ -2792,14 +2832,17 @@ namespace sqlite_orm { // #include "expression.h" + #include #include // std::move, std::forward // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "operators.h" + namespace sqlite_orm { namespace internal { @@ -2878,6 +2921,7 @@ namespace sqlite_orm { // #include "literal.h" + namespace sqlite_orm { namespace internal { @@ -2894,6 +2938,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -4311,6 +4356,7 @@ namespace sqlite_orm { // #include "conditions.h" + namespace sqlite_orm { namespace internal { @@ -4424,6 +4470,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4469,8 +4516,10 @@ namespace sqlite_orm { // #include "ast/into.h" + // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -4489,6 +4538,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { using int64 = sqlite_int64; @@ -6592,6 +6642,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" @@ -6606,12 +6657,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 { @@ -6681,6 +6734,7 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { @@ -7157,6 +7211,7 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" + namespace sqlite_orm { struct table_info { @@ -7213,6 +7268,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) @@ -7245,7 +7301,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} - partial_trigger_t& end() { + partial_trigger_t &end() { return *this; } }; @@ -7314,7 +7370,7 @@ namespace sqlite_orm { trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - trigger_base_t& for_each_row() { + trigger_base_t &for_each_row() { this->do_for_each_row = true; return *this; } @@ -7475,7 +7531,7 @@ namespace sqlite_orm { } template - internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t &part) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); } @@ -7535,6 +7591,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" + #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7544,6 +7601,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7565,20 +7623,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - { +d }; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + {+d}; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -7593,7 +7651,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value && std::is_default_constructible::value; + std::is_empty::value&& std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -7654,8 +7712,7 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) - void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -7683,7 +7740,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -7718,9 +7775,7 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::is_unusable_for_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -7739,9 +7794,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::needs_xdestroy_proxy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; } @@ -7760,9 +7813,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept - requires(internal::yields_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { return d; } #else @@ -7785,6 +7836,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { /** @@ -7981,6 +8033,7 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8059,6 +8112,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { /** @@ -8422,6 +8476,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8498,6 +8553,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -8822,6 +8878,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { /** @@ -9019,6 +9076,7 @@ namespace sqlite_orm { // #include "table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -9085,6 +9143,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { namespace internal { @@ -9200,6 +9259,7 @@ namespace sqlite_orm { // #include "storage_traits.h" + #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -9208,10 +9268,12 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" + #include // std::tuple // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { @@ -9237,6 +9299,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + #include // std::true_type, std::false_type, std::remove_const, std::enable_if #include #include // std::index_sequence @@ -9247,6 +9310,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { namespace internal { @@ -9375,6 +9439,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -9405,6 +9470,7 @@ namespace sqlite_orm { // #include "function.h" + #include #include #include // std::string @@ -9417,6 +9483,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { struct arg_values; @@ -9430,13 +9497,13 @@ namespace sqlite_orm { struct user_defined_function_base { using func_call = std::function< - void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; - using final_call = std::function; + void(sqlite3_context *context, void *functionPointer, int argsCount, sqlite3_value **values)>; + using final_call = std::function; std::string name; int argumentsCount = 0; - std::function create; - void (*destroy)(int*) = nullptr; + std::function create; + void (*destroy)(int *) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_base(decltype(name) name_, @@ -9568,7 +9635,7 @@ namespace sqlite_orm { constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // using C++17 or higher - template + template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); @@ -9651,6 +9718,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -9937,6 +10005,7 @@ namespace sqlite_orm { // #include "functional/static_magic.h" + #include // std::false_type, std::true_type, std::integral_constant #include // std::forward @@ -10019,6 +10088,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" + #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -10031,6 +10101,7 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + namespace sqlite_orm { namespace internal { @@ -10160,6 +10231,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -10462,6 +10534,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + // interface functions namespace sqlite_orm { namespace internal { @@ -10546,6 +10619,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10582,6 +10656,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" @@ -10602,16 +10677,19 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" + // #include "functional/cxx_universal.h" // #include "row_extractor.h" // #include "mapped_row_extractor.h" + #include // #include "object_from_column_builder.h" + #include #include // std::is_member_object_pointer @@ -10619,6 +10697,7 @@ namespace sqlite_orm { // #include "row_extractor.h" + namespace sqlite_orm { namespace internal { @@ -10659,6 +10738,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -10689,6 +10769,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -10740,6 +10821,7 @@ namespace sqlite_orm { // #include "view.h" + #include #include // std::string #include // std::forward, std::move @@ -10751,6 +10833,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10771,6 +10854,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -10858,6 +10942,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -10873,6 +10958,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::unique_ptr #include // std::iterator_traits @@ -10890,12 +10976,14 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include #include // std::string // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -10968,6 +11056,7 @@ namespace sqlite_orm { // #include "values.h" + #include // std::vector #include // std::tuple #include // std::forward @@ -10976,6 +11065,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -11014,12 +11104,14 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" + #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11075,6 +11167,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { namespace internal { @@ -11816,6 +11909,7 @@ namespace sqlite_orm { // #include "ast/excluded.h" + #include // std::move namespace sqlite_orm { @@ -11845,10 +11939,12 @@ namespace sqlite_orm { // #include "ast/exists.h" + #include // std::move // #include "../tags.h" + namespace sqlite_orm { namespace internal { @@ -11877,6 +11973,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -12556,6 +12653,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -12612,6 +12710,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include #include // std::function, std::bind #include // std::string @@ -12632,6 +12731,7 @@ namespace sqlite_orm { // #include "pragma.h" + #include #include // std::string #include // std::function @@ -12651,6 +12751,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + #include // std::index_sequence #include #include @@ -12674,6 +12775,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { template @@ -12699,18 +12801,18 @@ namespace sqlite_orm { } } #else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; - } - os << c; + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; } + os << c; } } + } #endif inline void stream_identifier(std::ostream& ss, @@ -13075,6 +13177,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -13283,6 +13386,7 @@ namespace sqlite_orm { // #include "limit_accessor.h" + #include #include // std::map #include // std::function @@ -13290,6 +13394,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13423,11 +13528,13 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function #include // std::move // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13454,7 +13561,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} - transaction_guard_t(transaction_guard_t&& other) : + transaction_guard_t(transaction_guard_t &&other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), gotta_fire(other.gotta_fire) { @@ -13471,7 +13578,7 @@ namespace sqlite_orm { } } - transaction_guard_t& operator=(transaction_guard_t&&) = delete; + transaction_guard_t &operator=(transaction_guard_t &&) = delete; /** * Call `COMMIT` explicitly. After this call @@ -13508,6 +13615,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::system_error #include // std::string @@ -13518,6 +13626,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13585,6 +13694,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 @@ -13595,17 +13705,19 @@ namespace sqlite_orm { // #include "arg_values.h" + #include // #include "row_extractor.h" + namespace sqlite_orm { struct arg_value { arg_value() : arg_value(nullptr) {} - arg_value(sqlite3_value* value_) : value(value_) {} + arg_value(sqlite3_value *value_) : value(value_) {} template T get() const { @@ -13642,18 +13754,18 @@ namespace sqlite_orm { } private: - sqlite3_value* value = nullptr; + sqlite3_value *value = nullptr; }; struct arg_values { struct iterator { - iterator(const arg_values& container_, int index_) : + iterator(const arg_values &container_, int index_) : container(container_), index(index_), currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} - iterator& operator++() { + iterator &operator++() { ++this->index; if(this->index < int(this->container.size())) { this->currentValue = this->container[this->index]; @@ -13682,27 +13794,27 @@ namespace sqlite_orm { } } - arg_value* operator->() const { + arg_value *operator->() const { return &this->currentValue; } - bool operator==(const iterator& other) const { + bool operator==(const iterator &other) const { return &other.container == &this->container && other.index == this->index; } - bool operator!=(const iterator& other) const { + bool operator!=(const iterator &other) const { return !(*this == other); } private: - const arg_values& container; + const arg_values &container; int index = 0; mutable arg_value currentValue; }; arg_values() : arg_values(0, nullptr) {} - arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} + arg_values(int argsCount_, sqlite3_value **values_) : argsCount(argsCount_), values(values_) {} size_t size() const { return this->argsCount; @@ -13714,7 +13826,7 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - sqlite3_value* value = this->values[index]; + sqlite3_value *value = this->values[index]; return {value}; } else { throw std::system_error{orm_error_code::index_is_out_of_bounds}; @@ -13735,10 +13847,11 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value** values = nullptr; + sqlite3_value **values = nullptr; }; } + namespace sqlite_orm { namespace internal { @@ -13760,13 +13873,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -13782,6 +13895,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -14548,11 +14662,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 { @@ -14686,6 +14802,7 @@ namespace sqlite_orm { // #include "statement_serializer.h" + #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14698,6 +14815,7 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -14740,6 +14858,7 @@ namespace sqlite_orm { // #include "table_name_collector.h" + #include // std::set #include // std::string #include // std::function @@ -14755,13 +14874,14 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { struct table_name_collector { using table_name_set = std::set>; - using find_table_name_t = std::function; + using find_table_name_t = std::function; find_table_name_t find_table_name; mutable table_name_set table_names; @@ -14771,7 +14891,7 @@ namespace sqlite_orm { table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} template - table_name_set operator()(const T&) const { + table_name_set operator()(const T &) const { return {}; } @@ -14781,17 +14901,17 @@ namespace sqlite_orm { } template - void operator()(const column_pointer&) const { + void operator()(const column_pointer &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const alias_column_t& a) const { + void operator()(const alias_column_t &a) const { (*this)(a.column, alias_extractor::get()); } template - void operator()(const count_asterisk_t&) const { + void operator()(const count_asterisk_t &) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { table_names.emplace(move(tableName), ""); @@ -14799,12 +14919,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -14813,22 +14933,22 @@ namespace sqlite_orm { } template - void operator()(const object_t&) const { + void operator()(const object_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_rowid_t&) const { + void operator()(const table_rowid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_oid_t&) const { + void operator()(const table_oid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table__rowid_t&) const { + void operator()(const table__rowid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } }; @@ -14839,6 +14959,7 @@ namespace sqlite_orm { // #include "column_names_getter.h" + #include // std::system_error #include // std::string #include // std::vector @@ -14854,6 +14975,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -14958,6 +15080,7 @@ namespace sqlite_orm { // #include "order_by_serializer.h" + #include // std::string #include // std::stringstream @@ -15049,6 +15172,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -17077,6 +17201,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -17609,7 +17734,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto{ + [](auto expression) -> auto { expression.highest_level = true; return expression; }, @@ -17878,7 +18003,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18197,13 +18322,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18243,13 +18368,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18341,22 +18466,22 @@ namespace sqlite_orm { } return move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); - } + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); } + } #endif } @@ -18467,6 +18592,7 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" + // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18493,6 +18619,7 @@ namespace sqlite_orm { // #include "ast/group_by.h" + namespace sqlite_orm { namespace internal { @@ -18797,6 +18924,7 @@ namespace sqlite_orm { // #include "expression_object_type.h" + namespace sqlite_orm { template @@ -18976,6 +19104,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19048,6 +19177,7 @@ namespace sqlite_orm { // #include "table.h" + namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19090,6 +19220,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" @@ -19106,6 +19237,7 @@ namespace sqlite_orm { // #include "../column.h" + namespace sqlite_orm { namespace internal { @@ -19145,6 +19277,7 @@ namespace sqlite_orm { // #include "../table.h" + namespace sqlite_orm { namespace internal { @@ -19172,9 +19305,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19205,6 +19338,7 @@ namespace sqlite_orm { // #include "../storage.h" + namespace sqlite_orm { namespace internal { @@ -19247,9 +19381,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19313,11 +19447,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); From bc19b22410e4b13efd63f12eb1bc8d236549f5ca Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 27 Dec 2022 10:04:35 -0600 Subject: [PATCH 004/100] added dynamic_set --- dev/ast/set.h | 76 +++ dev/ast_iterator.h | 1 + dev/prepared_statement.h | 1 + dev/select_constraints.h | 20 - dev/statement_serializer.h | 20 + dev/storage.h | 2 +- dev/xdestroy_handling.h | 35 +- include/sqlite_orm/sqlite_orm.h | 471 ++++++++----------- tests/statement_serializer_tests/ast/set.cpp | 62 +++ 9 files changed, 390 insertions(+), 298 deletions(-) create mode 100644 dev/ast/set.h create mode 100644 tests/statement_serializer_tests/ast/set.cpp diff --git a/dev/ast/set.h b/dev/ast/set.h new file mode 100644 index 000000000..0b86ab273 --- /dev/null +++ b/dev/ast/set.h @@ -0,0 +1,76 @@ +#pragma once + +#include // std::tuple, std::tuple_size +#include // std::string +#include // std::vector +#include // std::stringstream + +namespace sqlite_orm { + + namespace internal { + + template + struct set_t { + using assigns_type = std::tuple; + + assigns_type assigns; + }; + + template + struct dynamic_set_t { + using context_t = C; + using entry_t = std::string; + using const_iterator = typename std::vector::const_iterator; + + dynamic_set_t(const context_t& context_) : context(context_) {} + + template + void push_back(assign_t assign) { + auto newContext = this->context; + newContext.skip_table_name = true; + std::stringstream ss; + ss << serialize(assign.lhs, newContext) << ' ' << assign.serialize() << ' ' + << serialize(assign.rhs, context); + entries.push_back(ss.str()); + } + + const_iterator begin() const { + return this->entries.begin(); + } + + const_iterator end() const { + return this->entries.end(); + } + + void clear() { + this->entries.clear(); + } + + protected: + context_t context; + std::vector entries; + }; + } + + /** + * SET keyword used in UPDATE ... SET queries. + * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) + */ + template + internal::set_t set(Args... args) { + using arg_tuple = std::tuple; + static_assert(std::tuple_size::value == + internal::count_tuple::value, + "set function accepts assign operators only"); + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * SET keyword used in UPDATE ... SET queries. It is dynamic version. It means use can add amount of arguments now known at compilation time but known at runtime. + */ + template + internal::dynamic_set_t> dynamic_set(const S& storage) { + internal::serializer_context_builder builder(storage); + return builder(); + } +} diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 460ec8507..598a86e9b 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -17,6 +17,7 @@ #include "ast/into.h" #include "ast/group_by.h" #include "ast/exists.h" +#include "ast/set.h" namespace sqlite_orm { diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index b4091f4ef..79b48a7ff 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -15,6 +15,7 @@ #include "select_constraints.h" #include "values.h" #include "ast/upsert_clause.h" +#include "ast/set.h" namespace sqlite_orm { diff --git a/dev/select_constraints.h b/dev/select_constraints.h index f16bcc98f..211e58a53 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -80,13 +80,6 @@ namespace sqlite_orm { template using is_columns = polyfill::bool_constant>; - template - struct set_t { - using assigns_type = std::tuple; - - assigns_type assigns; - }; - /** * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). * Is useful when mapped type is derived from other type and base class has members mapped to a storage. @@ -371,19 +364,6 @@ namespace sqlite_orm { return cols; } - /** - * SET keyword used in UPDATE ... SET queries. - * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) - */ - template - internal::set_t set(Args... args) { - using arg_tuple = std::tuple; - static_assert(std::tuple_size::value == - internal::count_tuple::value, - "set function accepts assign operators only"); - return {std::make_tuple(std::forward(args)...)}; - } - template internal::columns_t columns(Args... args) { return {std::make_tuple(std::forward(args)...)}; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index a44b3f2ca..c2298731c 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1070,6 +1070,26 @@ namespace sqlite_orm { } }; + template + struct statement_serializer, void> { + using statement_type = dynamic_set_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "SET "; + int index = 0; + for(const std::string& entry: statement) { + if(index > 0) { + ss << ", "; + } + ss << entry; + ++index; + } + return ss.str(); + } + }; + template struct statement_serializer, void> { using statement_type = set_t; diff --git a/dev/storage.h b/dev/storage.h index 33f37cdb8..1d5a53563 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -586,7 +586,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto { + [](auto expression) -> auto{ expression.highest_level = true; return expression; }, diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index e9f986a03..25e172a32 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -29,20 +29,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - {+d}; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -57,7 +57,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value&& std::is_default_constructible::value; + std::is_empty::value && std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -118,7 +118,8 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -146,7 +147,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -181,7 +182,9 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -200,7 +203,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { return internal::xdestroy_proxy; } @@ -219,7 +224,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { return d; } #else diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ebbb25687..0f7f1482f 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,7 +16,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 @@ -35,7 +34,6 @@ using std::nullptr_t; // #include "cxx_core_features.h" - #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -109,7 +107,6 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" - #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -139,8 +136,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif - - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -282,7 +277,6 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } - namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -511,10 +505,8 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -523,7 +515,6 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif - // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -560,7 +551,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -659,7 +649,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. @@ -688,7 +677,6 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { namespace mpl { @@ -969,7 +957,6 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" - namespace sqlite_orm { namespace internal { @@ -999,7 +986,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" - #include // std::is_same #include @@ -1007,7 +993,6 @@ namespace sqlite_orm { // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { /* @@ -1055,7 +1040,6 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" - #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1063,7 +1047,6 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" @@ -1132,7 +1115,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1224,10 +1206,8 @@ namespace sqlite_orm { // #include "table_type_of.h" - // #include "indexed_column.h" - #include // std::string #include // std::move @@ -1235,7 +1215,6 @@ namespace sqlite_orm { // #include "ast/where.h" - #include // std::false_type, std::true_type #include // std::move @@ -1245,13 +1224,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 @@ -1274,7 +1250,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1320,7 +1295,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1384,7 +1358,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -1426,7 +1399,6 @@ namespace sqlite_orm { // #include "type_printer.h" - namespace sqlite_orm { namespace internal { @@ -1972,10 +1944,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 { /** @@ -2000,10 +1970,8 @@ namespace sqlite_orm { #include // std::move // #include "functional/cxx_optional.h" - // #include "tags.h" - namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -2017,7 +1985,6 @@ namespace sqlite_orm { // #include "serialize_result_type.h" - namespace sqlite_orm { namespace internal { @@ -2306,14 +2273,12 @@ namespace sqlite_orm { // #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 @@ -2405,7 +2370,6 @@ namespace sqlite_orm { // #include "constraints.h" - namespace sqlite_orm { namespace internal { @@ -2584,14 +2548,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 { /** @@ -2755,7 +2717,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -2790,7 +2751,6 @@ namespace sqlite_orm { // #include "serializer_context.h" - namespace sqlite_orm { namespace internal { @@ -2832,17 +2792,14 @@ namespace sqlite_orm { // #include "expression.h" - #include #include // std::move, std::forward // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "operators.h" - namespace sqlite_orm { namespace internal { @@ -2921,7 +2878,6 @@ namespace sqlite_orm { // #include "literal.h" - namespace sqlite_orm { namespace internal { @@ -2938,7 +2894,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -4356,7 +4311,6 @@ namespace sqlite_orm { // #include "conditions.h" - namespace sqlite_orm { namespace internal { @@ -4470,7 +4424,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4516,10 +4469,8 @@ namespace sqlite_orm { // #include "ast/into.h" - // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -4538,7 +4489,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { using int64 = sqlite_int64; @@ -6642,7 +6592,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" @@ -6657,14 +6606,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 { @@ -6734,7 +6681,6 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { @@ -6801,13 +6747,6 @@ namespace sqlite_orm { template using is_columns = polyfill::bool_constant>; - template - struct set_t { - using assigns_type = std::tuple; - - assigns_type assigns; - }; - /** * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). * Is useful when mapped type is derived from other type and base class has members mapped to a storage. @@ -7092,19 +7031,6 @@ namespace sqlite_orm { return cols; } - /** - * SET keyword used in UPDATE ... SET queries. - * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) - */ - template - internal::set_t set(Args... args) { - using arg_tuple = std::tuple; - static_assert(std::tuple_size::value == - internal::count_tuple::value, - "set function accepts assign operators only"); - return {std::make_tuple(std::forward(args)...)}; - } - template internal::columns_t columns(Args... args) { return {std::make_tuple(std::forward(args)...)}; @@ -7211,7 +7137,6 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" - namespace sqlite_orm { struct table_info { @@ -7268,7 +7193,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) @@ -7301,7 +7225,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} - partial_trigger_t &end() { + partial_trigger_t& end() { return *this; } }; @@ -7370,7 +7294,7 @@ namespace sqlite_orm { trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - trigger_base_t &for_each_row() { + trigger_base_t& for_each_row() { this->do_for_each_row = true; return *this; } @@ -7531,7 +7455,7 @@ namespace sqlite_orm { } template - internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t &part) { + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); } @@ -7591,7 +7515,6 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" - #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7601,7 +7524,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7623,20 +7545,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - {+d}; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -7651,7 +7573,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value&& std::is_default_constructible::value; + std::is_empty::value && std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -7712,7 +7634,8 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -7740,7 +7663,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -7775,7 +7698,9 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -7794,7 +7719,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { return internal::xdestroy_proxy; } @@ -7813,7 +7740,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { return d; } #else @@ -7836,7 +7765,6 @@ namespace sqlite_orm { #endif } - namespace sqlite_orm { /** @@ -8033,7 +7961,6 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8112,7 +8039,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { /** @@ -8476,7 +8402,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8553,7 +8478,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -8878,7 +8802,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { /** @@ -9076,7 +8999,6 @@ namespace sqlite_orm { // #include "table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -9143,7 +9065,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { namespace internal { @@ -9259,7 +9180,6 @@ namespace sqlite_orm { // #include "storage_traits.h" - #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -9268,12 +9188,10 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" - #include // std::tuple // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { @@ -9299,7 +9217,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - #include // std::true_type, std::false_type, std::remove_const, std::enable_if #include #include // std::index_sequence @@ -9310,7 +9227,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { namespace internal { @@ -9439,7 +9355,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -9470,7 +9385,6 @@ namespace sqlite_orm { // #include "function.h" - #include #include #include // std::string @@ -9483,7 +9397,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { struct arg_values; @@ -9497,13 +9410,13 @@ namespace sqlite_orm { struct user_defined_function_base { using func_call = std::function< - void(sqlite3_context *context, void *functionPointer, int argsCount, sqlite3_value **values)>; - using final_call = std::function; + void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; + using final_call = std::function; std::string name; int argumentsCount = 0; - std::function create; - void (*destroy)(int *) = nullptr; + std::function create; + void (*destroy)(int*) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_base(decltype(name) name_, @@ -9635,7 +9548,7 @@ namespace sqlite_orm { constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // using C++17 or higher - template + template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); @@ -9718,7 +9631,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -10005,7 +9917,6 @@ namespace sqlite_orm { // #include "functional/static_magic.h" - #include // std::false_type, std::true_type, std::integral_constant #include // std::forward @@ -10088,7 +9999,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" - #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -10101,7 +10011,6 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - namespace sqlite_orm { namespace internal { @@ -10231,7 +10140,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -10534,7 +10442,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - // interface functions namespace sqlite_orm { namespace internal { @@ -10619,7 +10526,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10656,7 +10562,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" @@ -10677,19 +10582,16 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" - // #include "functional/cxx_universal.h" // #include "row_extractor.h" // #include "mapped_row_extractor.h" - #include // #include "object_from_column_builder.h" - #include #include // std::is_member_object_pointer @@ -10697,7 +10599,6 @@ namespace sqlite_orm { // #include "row_extractor.h" - namespace sqlite_orm { namespace internal { @@ -10738,7 +10639,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -10769,7 +10669,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -10821,7 +10720,6 @@ namespace sqlite_orm { // #include "view.h" - #include #include // std::string #include // std::forward, std::move @@ -10833,7 +10731,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10854,7 +10751,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -10942,7 +10838,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -10958,7 +10853,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::unique_ptr #include // std::iterator_traits @@ -10976,14 +10870,12 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include #include // std::string // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -11056,7 +10948,6 @@ namespace sqlite_orm { // #include "values.h" - #include // std::vector #include // std::tuple #include // std::forward @@ -11065,7 +10956,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -11104,14 +10994,12 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" - #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11167,6 +11055,82 @@ namespace sqlite_orm { #endif } +// #include "ast/set.h" + +#include // std::tuple, std::tuple_size +#include // std::string +#include // std::vector +#include // std::stringstream + +namespace sqlite_orm { + + namespace internal { + + template + struct set_t { + using assigns_type = std::tuple; + + assigns_type assigns; + }; + + template + struct dynamic_set_t { + using context_t = C; + using entry_t = std::string; + using const_iterator = typename std::vector::const_iterator; + + dynamic_set_t(const context_t& context_) : context(context_) {} + + template + void push_back(assign_t assign) { + auto newContext = this->context; + newContext.skip_table_name = true; + std::stringstream ss; + ss << serialize(assign.lhs, newContext) << ' ' << assign.serialize() << ' ' + << serialize(assign.rhs, context); + entries.push_back(ss.str()); + } + + const_iterator begin() const { + return this->entries.begin(); + } + + const_iterator end() const { + return this->entries.end(); + } + + void clear() { + this->entries.clear(); + } + + protected: + context_t context; + std::vector entries; + }; + } + + /** + * SET keyword used in UPDATE ... SET queries. + * Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5) + */ + template + internal::set_t set(Args... args) { + using arg_tuple = std::tuple; + static_assert(std::tuple_size::value == + internal::count_tuple::value, + "set function accepts assign operators only"); + return {std::make_tuple(std::forward(args)...)}; + } + + /** + * SET keyword used in UPDATE ... SET queries. It is dynamic version. It means use can add amount of arguments now known at compilation time but known at runtime. + */ + template + internal::dynamic_set_t> dynamic_set(const S& storage) { + internal::serializer_context_builder builder(storage); + return builder(); + } +} namespace sqlite_orm { @@ -11909,7 +11873,6 @@ namespace sqlite_orm { // #include "ast/excluded.h" - #include // std::move namespace sqlite_orm { @@ -11939,12 +11902,10 @@ namespace sqlite_orm { // #include "ast/exists.h" - #include // std::move // #include "../tags.h" - namespace sqlite_orm { namespace internal { @@ -11973,6 +11934,7 @@ namespace sqlite_orm { } } +// #include "ast/set.h" namespace sqlite_orm { @@ -12653,7 +12615,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -12710,7 +12671,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include #include // std::function, std::bind #include // std::string @@ -12731,7 +12691,6 @@ namespace sqlite_orm { // #include "pragma.h" - #include #include // std::string #include // std::function @@ -12751,7 +12710,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - #include // std::index_sequence #include #include @@ -12775,7 +12733,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { template @@ -12801,18 +12758,18 @@ namespace sqlite_orm { } } #else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; + } + os << c; } - os << c; } } - } #endif inline void stream_identifier(std::ostream& ss, @@ -13177,7 +13134,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -13386,7 +13342,6 @@ namespace sqlite_orm { // #include "limit_accessor.h" - #include #include // std::map #include // std::function @@ -13394,7 +13349,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13528,13 +13482,11 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function #include // std::move // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13561,7 +13513,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} - transaction_guard_t(transaction_guard_t &&other) : + transaction_guard_t(transaction_guard_t&& other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), gotta_fire(other.gotta_fire) { @@ -13578,7 +13530,7 @@ namespace sqlite_orm { } } - transaction_guard_t &operator=(transaction_guard_t &&) = delete; + transaction_guard_t& operator=(transaction_guard_t&&) = delete; /** * Call `COMMIT` explicitly. After this call @@ -13615,7 +13567,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::system_error #include // std::string @@ -13626,7 +13577,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13694,7 +13644,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 @@ -13705,19 +13654,17 @@ namespace sqlite_orm { // #include "arg_values.h" - #include // #include "row_extractor.h" - namespace sqlite_orm { struct arg_value { arg_value() : arg_value(nullptr) {} - arg_value(sqlite3_value *value_) : value(value_) {} + arg_value(sqlite3_value* value_) : value(value_) {} template T get() const { @@ -13754,18 +13701,18 @@ namespace sqlite_orm { } private: - sqlite3_value *value = nullptr; + sqlite3_value* value = nullptr; }; struct arg_values { struct iterator { - iterator(const arg_values &container_, int index_) : + iterator(const arg_values& container_, int index_) : container(container_), index(index_), currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} - iterator &operator++() { + iterator& operator++() { ++this->index; if(this->index < int(this->container.size())) { this->currentValue = this->container[this->index]; @@ -13794,27 +13741,27 @@ namespace sqlite_orm { } } - arg_value *operator->() const { + arg_value* operator->() const { return &this->currentValue; } - bool operator==(const iterator &other) const { + bool operator==(const iterator& other) const { return &other.container == &this->container && other.index == this->index; } - bool operator!=(const iterator &other) const { + bool operator!=(const iterator& other) const { return !(*this == other); } private: - const arg_values &container; + const arg_values& container; int index = 0; mutable arg_value currentValue; }; arg_values() : arg_values(0, nullptr) {} - arg_values(int argsCount_, sqlite3_value **values_) : argsCount(argsCount_), values(values_) {} + arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} size_t size() const { return this->argsCount; @@ -13826,7 +13773,7 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - sqlite3_value *value = this->values[index]; + sqlite3_value* value = this->values[index]; return {value}; } else { throw std::system_error{orm_error_code::index_is_out_of_bounds}; @@ -13847,11 +13794,10 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value **values = nullptr; + sqlite3_value** values = nullptr; }; } - namespace sqlite_orm { namespace internal { @@ -13873,13 +13819,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -13895,7 +13841,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -14662,13 +14607,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 { @@ -14802,7 +14745,6 @@ namespace sqlite_orm { // #include "statement_serializer.h" - #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14815,7 +14757,6 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -14858,7 +14799,6 @@ namespace sqlite_orm { // #include "table_name_collector.h" - #include // std::set #include // std::string #include // std::function @@ -14874,14 +14814,13 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { struct table_name_collector { using table_name_set = std::set>; - using find_table_name_t = std::function; + using find_table_name_t = std::function; find_table_name_t find_table_name; mutable table_name_set table_names; @@ -14891,7 +14830,7 @@ namespace sqlite_orm { table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} template - table_name_set operator()(const T &) const { + table_name_set operator()(const T&) const { return {}; } @@ -14901,17 +14840,17 @@ namespace sqlite_orm { } template - void operator()(const column_pointer &) const { + void operator()(const column_pointer&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const alias_column_t &a) const { + void operator()(const alias_column_t& a) const { (*this)(a.column, alias_extractor::get()); } template - void operator()(const count_asterisk_t &) const { + void operator()(const count_asterisk_t&) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { table_names.emplace(move(tableName), ""); @@ -14919,12 +14858,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t &) const { + void operator()(const asterisk_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template = true> - void operator()(const asterisk_t &) const { + void operator()(const asterisk_t&) const { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -14933,22 +14872,22 @@ namespace sqlite_orm { } template - void operator()(const object_t &) const { + void operator()(const object_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_rowid_t &) const { + void operator()(const table_rowid_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_oid_t &) const { + void operator()(const table_oid_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table__rowid_t &) const { + void operator()(const table__rowid_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } }; @@ -14959,7 +14898,6 @@ namespace sqlite_orm { // #include "column_names_getter.h" - #include // std::system_error #include // std::string #include // std::vector @@ -14975,7 +14913,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -15080,7 +15017,6 @@ namespace sqlite_orm { // #include "order_by_serializer.h" - #include // std::string #include // std::stringstream @@ -15172,7 +15108,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -16200,6 +16135,26 @@ namespace sqlite_orm { } }; + template + struct statement_serializer, void> { + using statement_type = dynamic_set_t; + + template + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::stringstream ss; + ss << "SET "; + int index = 0; + for(const std::string& entry: statement) { + if(index > 0) { + ss << ", "; + } + ss << entry; + ++index; + } + return ss.str(); + } + }; + template struct statement_serializer, void> { using statement_type = set_t; @@ -17201,7 +17156,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -17734,7 +17688,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto { + [](auto expression) -> auto{ expression.highest_level = true; return expression; }, @@ -18003,7 +17957,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18322,13 +18276,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18368,13 +18322,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18466,22 +18420,22 @@ namespace sqlite_orm { } return move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); + } } - } #endif } @@ -18592,7 +18546,6 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" - // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18619,7 +18572,6 @@ namespace sqlite_orm { // #include "ast/group_by.h" - namespace sqlite_orm { namespace internal { @@ -18924,7 +18876,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template @@ -19104,7 +19055,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19177,7 +19127,6 @@ namespace sqlite_orm { // #include "table.h" - namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19220,7 +19169,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" @@ -19237,7 +19185,6 @@ namespace sqlite_orm { // #include "../column.h" - namespace sqlite_orm { namespace internal { @@ -19277,7 +19224,6 @@ namespace sqlite_orm { // #include "../table.h" - namespace sqlite_orm { namespace internal { @@ -19305,9 +19251,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19338,7 +19284,6 @@ namespace sqlite_orm { // #include "../storage.h" - namespace sqlite_orm { namespace internal { @@ -19381,9 +19326,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19447,11 +19392,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); diff --git a/tests/statement_serializer_tests/ast/set.cpp b/tests/statement_serializer_tests/ast/set.cpp new file mode 100644 index 000000000..c3c94fa80 --- /dev/null +++ b/tests/statement_serializer_tests/ast/set.cpp @@ -0,0 +1,62 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("set") { + struct User { + int id = 0; + std::string name; + }; + auto table = make_table("users", make_column("id", &User::id, primary_key()), make_column("name", &User::name)); + using db_objects_t = internal::db_objects_tuple; + auto dbObjects = db_objects_t{table}; + using context_t = internal::serializer_context; + context_t context{dbObjects}; + + std::string value; + std::string expected; + SECTION("one item") { + SECTION("static") { + auto expression = set(assign(&User::id, 5)); + value = internal::serialize(expression, context); + } + SECTION("dynamic") { + auto storage = make_storage("", table); + auto expression = dynamic_set(storage); + expression.push_back(assign(&User::id, 5)); + SECTION("empty") { + //.. + } + SECTION("clear and push_back") { + expression.clear(); + expression.push_back(assign(&User::id, 5)); + } + value = internal::serialize(expression, context); + } + expected = "SET \"id\" = 5"; + } + SECTION("two items") { + SECTION("static") { + auto expression = set(assign(&User::id, 5), assign(&User::name, "ototo")); + value = internal::serialize(expression, context); + } + SECTION("dynamic") { + auto storage = make_storage("", table); + auto expression = dynamic_set(storage); + expression.push_back(assign(&User::id, 5)); + expression.push_back(assign(&User::name, "ototo")); + SECTION("empty") { + //.. + } + SECTION("clear and push_back") { + expression.clear(); + expression.push_back(assign(&User::id, 5)); + expression.push_back(assign(&User::name, "ototo")); + } + value = internal::serialize(expression, context); + } + expected = "SET \"id\" = 5, \"name\" = 'ototo'"; + } + REQUIRE(value == expected); +} From c3107fb8fafdc8d60f0c8767a5fbeb243357007c Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 27 Dec 2022 10:06:29 -0600 Subject: [PATCH 005/100] reverted formatting --- dev/storage.h | 2 +- dev/xdestroy_handling.h | 35 ++-- include/sqlite_orm/sqlite_orm.h | 357 ++++++++++++++++++++++---------- 3 files changed, 261 insertions(+), 133 deletions(-) diff --git a/dev/storage.h b/dev/storage.h index 1d5a53563..33f37cdb8 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -586,7 +586,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto{ + [](auto expression) -> auto { expression.highest_level = true; return expression; }, diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index 25e172a32..e9f986a03 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -29,20 +29,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - { +d }; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + {+d}; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -57,7 +57,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value && std::is_default_constructible::value; + std::is_empty::value&& std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -118,8 +118,7 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) - void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -147,7 +146,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -182,9 +181,7 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::is_unusable_for_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -203,9 +200,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::needs_xdestroy_proxy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; } @@ -224,9 +219,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept - requires(internal::yields_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { return d; } #else diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 0f7f1482f..0d7aeb2d4 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,6 +16,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 @@ -34,6 +35,7 @@ using std::nullptr_t; // #include "cxx_core_features.h" + #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -107,6 +109,7 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" + #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -136,6 +139,8 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif + + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -277,6 +282,7 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } + namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -505,8 +511,10 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -515,6 +523,7 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif + // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -551,6 +560,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -649,6 +659,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. @@ -677,6 +688,7 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { namespace mpl { @@ -957,6 +969,7 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" + namespace sqlite_orm { namespace internal { @@ -986,6 +999,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" + #include // std::is_same #include @@ -993,6 +1007,7 @@ namespace sqlite_orm { // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { /* @@ -1040,6 +1055,7 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" + #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1047,6 +1063,7 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" @@ -1115,6 +1132,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1206,8 +1224,10 @@ namespace sqlite_orm { // #include "table_type_of.h" + // #include "indexed_column.h" + #include // std::string #include // std::move @@ -1215,6 +1235,7 @@ namespace sqlite_orm { // #include "ast/where.h" + #include // std::false_type, std::true_type #include // std::move @@ -1224,10 +1245,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 @@ -1250,6 +1274,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1295,6 +1320,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1358,6 +1384,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -1399,6 +1426,7 @@ namespace sqlite_orm { // #include "type_printer.h" + namespace sqlite_orm { namespace internal { @@ -1944,8 +1972,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 { /** @@ -1970,8 +2000,10 @@ namespace sqlite_orm { #include // std::move // #include "functional/cxx_optional.h" + // #include "tags.h" + namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1985,6 +2017,7 @@ namespace sqlite_orm { // #include "serialize_result_type.h" + namespace sqlite_orm { namespace internal { @@ -2273,12 +2306,14 @@ namespace sqlite_orm { // #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 @@ -2370,6 +2405,7 @@ namespace sqlite_orm { // #include "constraints.h" + namespace sqlite_orm { namespace internal { @@ -2548,12 +2584,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 { /** @@ -2717,6 +2755,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -2751,6 +2790,7 @@ namespace sqlite_orm { // #include "serializer_context.h" + namespace sqlite_orm { namespace internal { @@ -2792,14 +2832,17 @@ namespace sqlite_orm { // #include "expression.h" + #include #include // std::move, std::forward // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "operators.h" + namespace sqlite_orm { namespace internal { @@ -2878,6 +2921,7 @@ namespace sqlite_orm { // #include "literal.h" + namespace sqlite_orm { namespace internal { @@ -2894,6 +2938,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -4311,6 +4356,7 @@ namespace sqlite_orm { // #include "conditions.h" + namespace sqlite_orm { namespace internal { @@ -4424,6 +4470,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4469,8 +4516,10 @@ namespace sqlite_orm { // #include "ast/into.h" + // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -4489,6 +4538,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { using int64 = sqlite_int64; @@ -6592,6 +6642,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" @@ -6606,12 +6657,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 { @@ -6681,6 +6734,7 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { @@ -7137,6 +7191,7 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" + namespace sqlite_orm { struct table_info { @@ -7193,6 +7248,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) @@ -7225,7 +7281,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} - partial_trigger_t& end() { + partial_trigger_t &end() { return *this; } }; @@ -7294,7 +7350,7 @@ namespace sqlite_orm { trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - trigger_base_t& for_each_row() { + trigger_base_t &for_each_row() { this->do_for_each_row = true; return *this; } @@ -7455,7 +7511,7 @@ namespace sqlite_orm { } template - internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t &part) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); } @@ -7515,6 +7571,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" + #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7524,6 +7581,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7545,20 +7603,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - { +d }; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + {+d}; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -7573,7 +7631,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value && std::is_default_constructible::value; + std::is_empty::value&& std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -7634,8 +7692,7 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) - void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -7663,7 +7720,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -7698,9 +7755,7 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::is_unusable_for_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -7719,9 +7774,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::needs_xdestroy_proxy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; } @@ -7740,9 +7793,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept - requires(internal::yields_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { return d; } #else @@ -7765,6 +7816,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { /** @@ -7961,6 +8013,7 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8039,6 +8092,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { /** @@ -8402,6 +8456,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8478,6 +8533,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -8802,6 +8858,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { /** @@ -8999,6 +9056,7 @@ namespace sqlite_orm { // #include "table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -9065,6 +9123,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { namespace internal { @@ -9180,6 +9239,7 @@ namespace sqlite_orm { // #include "storage_traits.h" + #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -9188,10 +9248,12 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" + #include // std::tuple // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { @@ -9217,6 +9279,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + #include // std::true_type, std::false_type, std::remove_const, std::enable_if #include #include // std::index_sequence @@ -9227,6 +9290,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { namespace internal { @@ -9355,6 +9419,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -9385,6 +9450,7 @@ namespace sqlite_orm { // #include "function.h" + #include #include #include // std::string @@ -9397,6 +9463,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { struct arg_values; @@ -9410,13 +9477,13 @@ namespace sqlite_orm { struct user_defined_function_base { using func_call = std::function< - void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; - using final_call = std::function; + void(sqlite3_context *context, void *functionPointer, int argsCount, sqlite3_value **values)>; + using final_call = std::function; std::string name; int argumentsCount = 0; - std::function create; - void (*destroy)(int*) = nullptr; + std::function create; + void (*destroy)(int *) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_base(decltype(name) name_, @@ -9548,7 +9615,7 @@ namespace sqlite_orm { constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // using C++17 or higher - template + template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); @@ -9631,6 +9698,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -9917,6 +9985,7 @@ namespace sqlite_orm { // #include "functional/static_magic.h" + #include // std::false_type, std::true_type, std::integral_constant #include // std::forward @@ -9999,6 +10068,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" + #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -10011,6 +10081,7 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + namespace sqlite_orm { namespace internal { @@ -10140,6 +10211,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -10442,6 +10514,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + // interface functions namespace sqlite_orm { namespace internal { @@ -10526,6 +10599,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10562,6 +10636,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" @@ -10582,16 +10657,19 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" + // #include "functional/cxx_universal.h" // #include "row_extractor.h" // #include "mapped_row_extractor.h" + #include // #include "object_from_column_builder.h" + #include #include // std::is_member_object_pointer @@ -10599,6 +10677,7 @@ namespace sqlite_orm { // #include "row_extractor.h" + namespace sqlite_orm { namespace internal { @@ -10639,6 +10718,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -10669,6 +10749,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -10720,6 +10801,7 @@ namespace sqlite_orm { // #include "view.h" + #include #include // std::string #include // std::forward, std::move @@ -10731,6 +10813,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10751,6 +10834,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -10838,6 +10922,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -10853,6 +10938,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::unique_ptr #include // std::iterator_traits @@ -10870,12 +10956,14 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include #include // std::string // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -10948,6 +11036,7 @@ namespace sqlite_orm { // #include "values.h" + #include // std::vector #include // std::tuple #include // std::forward @@ -10956,6 +11045,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -10994,12 +11084,14 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" + #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11057,6 +11149,7 @@ namespace sqlite_orm { // #include "ast/set.h" + #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11132,6 +11225,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -11873,6 +11967,7 @@ namespace sqlite_orm { // #include "ast/excluded.h" + #include // std::move namespace sqlite_orm { @@ -11902,10 +11997,12 @@ namespace sqlite_orm { // #include "ast/exists.h" + #include // std::move // #include "../tags.h" + namespace sqlite_orm { namespace internal { @@ -11936,6 +12033,7 @@ namespace sqlite_orm { // #include "ast/set.h" + namespace sqlite_orm { namespace internal { @@ -12615,6 +12713,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -12671,6 +12770,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include #include // std::function, std::bind #include // std::string @@ -12691,6 +12791,7 @@ namespace sqlite_orm { // #include "pragma.h" + #include #include // std::string #include // std::function @@ -12710,6 +12811,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + #include // std::index_sequence #include #include @@ -12733,6 +12835,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { template @@ -12758,18 +12861,18 @@ namespace sqlite_orm { } } #else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; - } - os << c; + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; } + os << c; } } + } #endif inline void stream_identifier(std::ostream& ss, @@ -13134,6 +13237,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -13342,6 +13446,7 @@ namespace sqlite_orm { // #include "limit_accessor.h" + #include #include // std::map #include // std::function @@ -13349,6 +13454,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13482,11 +13588,13 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function #include // std::move // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13513,7 +13621,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} - transaction_guard_t(transaction_guard_t&& other) : + transaction_guard_t(transaction_guard_t &&other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), gotta_fire(other.gotta_fire) { @@ -13530,7 +13638,7 @@ namespace sqlite_orm { } } - transaction_guard_t& operator=(transaction_guard_t&&) = delete; + transaction_guard_t &operator=(transaction_guard_t &&) = delete; /** * Call `COMMIT` explicitly. After this call @@ -13567,6 +13675,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::system_error #include // std::string @@ -13577,6 +13686,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13644,6 +13754,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 @@ -13654,17 +13765,19 @@ namespace sqlite_orm { // #include "arg_values.h" + #include // #include "row_extractor.h" + namespace sqlite_orm { struct arg_value { arg_value() : arg_value(nullptr) {} - arg_value(sqlite3_value* value_) : value(value_) {} + arg_value(sqlite3_value *value_) : value(value_) {} template T get() const { @@ -13701,18 +13814,18 @@ namespace sqlite_orm { } private: - sqlite3_value* value = nullptr; + sqlite3_value *value = nullptr; }; struct arg_values { struct iterator { - iterator(const arg_values& container_, int index_) : + iterator(const arg_values &container_, int index_) : container(container_), index(index_), currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} - iterator& operator++() { + iterator &operator++() { ++this->index; if(this->index < int(this->container.size())) { this->currentValue = this->container[this->index]; @@ -13741,27 +13854,27 @@ namespace sqlite_orm { } } - arg_value* operator->() const { + arg_value *operator->() const { return &this->currentValue; } - bool operator==(const iterator& other) const { + bool operator==(const iterator &other) const { return &other.container == &this->container && other.index == this->index; } - bool operator!=(const iterator& other) const { + bool operator!=(const iterator &other) const { return !(*this == other); } private: - const arg_values& container; + const arg_values &container; int index = 0; mutable arg_value currentValue; }; arg_values() : arg_values(0, nullptr) {} - arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} + arg_values(int argsCount_, sqlite3_value **values_) : argsCount(argsCount_), values(values_) {} size_t size() const { return this->argsCount; @@ -13773,7 +13886,7 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - sqlite3_value* value = this->values[index]; + sqlite3_value *value = this->values[index]; return {value}; } else { throw std::system_error{orm_error_code::index_is_out_of_bounds}; @@ -13794,10 +13907,11 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value** values = nullptr; + sqlite3_value **values = nullptr; }; } + namespace sqlite_orm { namespace internal { @@ -13819,13 +13933,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -13841,6 +13955,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -14607,11 +14722,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 { @@ -14745,6 +14862,7 @@ namespace sqlite_orm { // #include "statement_serializer.h" + #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14757,6 +14875,7 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -14799,6 +14918,7 @@ namespace sqlite_orm { // #include "table_name_collector.h" + #include // std::set #include // std::string #include // std::function @@ -14814,13 +14934,14 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { struct table_name_collector { using table_name_set = std::set>; - using find_table_name_t = std::function; + using find_table_name_t = std::function; find_table_name_t find_table_name; mutable table_name_set table_names; @@ -14830,7 +14951,7 @@ namespace sqlite_orm { table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} template - table_name_set operator()(const T&) const { + table_name_set operator()(const T &) const { return {}; } @@ -14840,17 +14961,17 @@ namespace sqlite_orm { } template - void operator()(const column_pointer&) const { + void operator()(const column_pointer &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const alias_column_t& a) const { + void operator()(const alias_column_t &a) const { (*this)(a.column, alias_extractor::get()); } template - void operator()(const count_asterisk_t&) const { + void operator()(const count_asterisk_t &) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { table_names.emplace(move(tableName), ""); @@ -14858,12 +14979,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -14872,22 +14993,22 @@ namespace sqlite_orm { } template - void operator()(const object_t&) const { + void operator()(const object_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_rowid_t&) const { + void operator()(const table_rowid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_oid_t&) const { + void operator()(const table_oid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table__rowid_t&) const { + void operator()(const table__rowid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } }; @@ -14898,6 +15019,7 @@ namespace sqlite_orm { // #include "column_names_getter.h" + #include // std::system_error #include // std::string #include // std::vector @@ -14913,6 +15035,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -15017,6 +15140,7 @@ namespace sqlite_orm { // #include "order_by_serializer.h" + #include // std::string #include // std::stringstream @@ -15108,6 +15232,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -17156,6 +17281,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -17688,7 +17814,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto{ + [](auto expression) -> auto { expression.highest_level = true; return expression; }, @@ -17957,7 +18083,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18276,13 +18402,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18322,13 +18448,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18420,22 +18546,22 @@ namespace sqlite_orm { } return move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); - } + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); } + } #endif } @@ -18546,6 +18672,7 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" + // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18572,6 +18699,7 @@ namespace sqlite_orm { // #include "ast/group_by.h" + namespace sqlite_orm { namespace internal { @@ -18876,6 +19004,7 @@ namespace sqlite_orm { // #include "expression_object_type.h" + namespace sqlite_orm { template @@ -19055,6 +19184,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19127,6 +19257,7 @@ namespace sqlite_orm { // #include "table.h" + namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19169,6 +19300,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" @@ -19185,6 +19317,7 @@ namespace sqlite_orm { // #include "../column.h" + namespace sqlite_orm { namespace internal { @@ -19224,6 +19357,7 @@ namespace sqlite_orm { // #include "../table.h" + namespace sqlite_orm { namespace internal { @@ -19251,9 +19385,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19284,6 +19418,7 @@ namespace sqlite_orm { // #include "../storage.h" + namespace sqlite_orm { namespace internal { @@ -19326,9 +19461,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19392,11 +19527,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); From 85f14d9324686afc4a1e43beebb2a866a903eb54 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Thu, 29 Dec 2022 16:29:34 -0600 Subject: [PATCH 006/100] fixed compilation --- dev/ast/set.h | 75 +- dev/ast_iterator.h | 20 +- dev/conditions.h | 2 +- dev/prepared_statement.h | 16 +- dev/statement_serializer.h | 92 ++- dev/storage.h | 2 +- dev/table_name_collector.h | 4 +- dev/xdestroy_handling.h | 35 +- include/sqlite_orm/sqlite_orm.h | 734 +++++++++--------- tests/CMakeLists.txt | 1 + .../statements/update.cpp | 23 +- 11 files changed, 559 insertions(+), 445 deletions(-) diff --git a/dev/ast/set.h b/dev/ast/set.h index 0b86ab273..a5ea93a0c 100644 --- a/dev/ast/set.h +++ b/dev/ast/set.h @@ -4,11 +4,18 @@ #include // std::string #include // std::vector #include // std::stringstream +#include // std::false_type, std::true_type +#include // std::function + +#include "table_name_collector.h" namespace sqlite_orm { namespace internal { + template + void iterate_ast(const T& t, L&& lambda); + template struct set_t { using assigns_type = std::tuple; @@ -16,22 +23,70 @@ namespace sqlite_orm { assigns_type assigns; }; + template + struct is_set : std::false_type {}; + + template + struct is_set> : std::true_type {}; + + struct dynamic_set_entry { + std::string serialized_value; + // std::function + }; + template struct dynamic_set_t { using context_t = C; - using entry_t = std::string; + using entry_t = dynamic_set_entry; using const_iterator = typename std::vector::const_iterator; - dynamic_set_t(const context_t& context_) : context(context_) {} + dynamic_set_t(const context_t& context_) : + context(context_), collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }) {} + + dynamic_set_t(const dynamic_set_t& other) : + entries(other.entries), context(other.context), collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }) { + collector.table_names = other.collector.table_names; + } + + dynamic_set_t(dynamic_set_t&& other) : + entries(move(other.entries)), context(std::move(other.context)), + collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }) { + collector.table_names = move(other.collector.table_names); + } + + dynamic_set_t& operator=(const dynamic_set_t& other) { + this->entries = other.entries; + this->context = other.context; + this->collector = table_name_collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }); + this->collector.table_names = other.collector.table_names; + } + + dynamic_set_t& operator=(dynamic_set_t&& other) { + this->entries = move(other.entries); + this->context = std::move(other.context); + this->collector = table_name_collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }); + this->collector.table_names = move(other.collector.table_names); + } template void push_back(assign_t assign) { auto newContext = this->context; newContext.skip_table_name = true; + iterate_ast(assign, this->collector); std::stringstream ss; ss << serialize(assign.lhs, newContext) << ' ' << assign.serialize() << ' ' << serialize(assign.rhs, context); - entries.push_back(ss.str()); + this->entries.push_back({ss.str()}); } const_iterator begin() const { @@ -44,12 +99,22 @@ namespace sqlite_orm { void clear() { this->entries.clear(); + this->collector.table_names.clear(); } - protected: - context_t context; std::vector entries; + context_t context; + table_name_collector collector; }; + + template + struct is_set> : std::true_type {}; + + template + struct is_dynamic_set : std::false_type {}; + + template + struct is_dynamic_set> : std::true_type {}; } /** diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 598a86e9b..23d2698e0 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -276,9 +276,9 @@ namespace sqlite_orm { }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct ast_iterator, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; + template + struct ast_iterator, void> { + using node_type = update_all_t; template void operator()(const node_type& u, L& lambda) const { @@ -302,8 +302,18 @@ namespace sqlite_orm { using node_type = set_t; template - void operator()(const node_type& s, L& lambda) const { - iterate_ast(s.assigns, lambda); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.assigns, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = dynamic_set_t; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.entries, lambda); } }; diff --git a/dev/conditions.h b/dev/conditions.h index 873776481..185013f03 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -527,7 +527,7 @@ namespace sqlite_orm { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); - entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); + this->entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); } const_iterator begin() const { diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index 79b48a7ff..aa4e4e8da 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -129,14 +129,13 @@ namespace sqlite_orm { }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct update_all_t; - - template - struct update_all_t, Wargs...> { - using set_type = set_t; + template + struct update_all_t { + using set_type = S; using conditions_type = std::tuple; + static_assert(is_set::value, "update_all_t must have set or dynamic set as the first argument"); + set_type set; conditions_type conditions; }; @@ -688,8 +687,9 @@ namespace sqlite_orm { * Create an update all statement. * Usage: storage.update_all(set(...), ...); */ - template - internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { + template + internal::update_all_t update_all(S set, Wargs... wh) { + static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index c2298731c..7f5f973a7 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1079,11 +1079,11 @@ namespace sqlite_orm { std::stringstream ss; ss << "SET "; int index = 0; - for(const std::string& entry: statement) { + for(const dynamic_set_entry& entry: statement) { if(index > 0) { ss << ", "; } - ss << entry; + ss << entry.serialized_value; ++index; } return ss.str(); @@ -1109,38 +1109,78 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, Wargs...>, void> { - using statement_type = update_all_t, Wargs...>; + template + struct table_name_collector_holder; + + template + struct table_name_collector_holder> { + + table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) : + collector(move(find_table_name)) {} + + table_name_collector collector; + }; + + template + struct table_name_collector_holder> { + + table_name_collector_holder(const table_name_collector& collector) : collector(collector) {} + + const table_name_collector& collector; + }; + + template + table_name_collector_holder> make_table_name_collector_holder(const set_t& set, + const Ctx& context) { + table_name_collector_holder> holder([&context](const std::type_index& ti) { + return find_table_name(context.db_objects, ti); + }); + iterate_ast(set, holder.collector); + return holder; + } + + template + table_name_collector_holder> make_table_name_collector_holder(const dynamic_set_t& set, + const Ctx&) { + return {set.collector}; + } + + template + struct statement_serializer, void> { + using statement_type = update_all_t; template - std::string operator()(const statement_type& upd, const Ctx& context) const { - table_name_collector collector([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); - iterate_ast(upd.set.assigns, collector); + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::string tableName; + auto collectorHolder = make_table_name_collector_holder(statement.set, context); + const table_name_collector& collector = collectorHolder.collector; if(collector.table_names.empty()) { throw std::system_error{orm_error_code::no_tables_specified}; } + tableName = collector.table_names.begin()->first; - std::stringstream ss; - ss << "UPDATE " << streaming_identifier(collector.table_names.begin()->first) << " SET "; - { - std::vector setPairs; - setPairs.reserve(std::tuple_size::assigns_type>::value); - auto leftContext = context; - leftContext.skip_table_name = true; - iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto& asgn) { - std::stringstream sss; - sss << serialize(asgn.lhs, leftContext); - sss << ' ' << asgn.serialize() << ' '; - sss << serialize(asgn.rhs, context); - setPairs.push_back(sss.str()); + /*static_if::value>([&tableName, &context] (const statement_type& statement) { + table_name_collector collector([&context](const std::type_index& ti) { + return find_table_name(context.db_objects, ti); }); - ss << streaming_serialized(setPairs) << streaming_conditions_tuple(upd.conditions, context); - return ss.str(); - } + iterate_ast(statement.set, collector); + if(collector.table_names.empty()) { + throw std::system_error{orm_error_code::no_tables_specified}; + } + tableName = collector.table_names.begin()->first; + }, [&tableName] (const statement_type& statement) { + if (statement.set.collector.table_names.empty()) { + throw std::system_error{orm_error_code::no_tables_specified}; + } + tableName = statement.set.collector.table_names.begin()->first; + })(statement);*/ + + std::stringstream ss; + ss << "UPDATE " << streaming_identifier(tableName); + ss << ' ' << serialize(statement.set, context); + ss << streaming_conditions_tuple(statement.conditions, context); + return ss.str(); } }; diff --git a/dev/storage.h b/dev/storage.h index 33f37cdb8..1d5a53563 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -586,7 +586,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto { + [](auto expression) -> auto{ expression.highest_level = true; return expression; }, diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index 6e9ed8426..9afc140f4 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -27,8 +27,8 @@ namespace sqlite_orm { table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} template - table_name_set operator()(const T &) const { - return {}; + void operator()(const T &) const { + //.. } template diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index e9f986a03..25e172a32 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -29,20 +29,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - {+d}; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -57,7 +57,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value&& std::is_default_constructible::value; + std::is_empty::value && std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -118,7 +118,8 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -146,7 +147,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -181,7 +182,9 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -200,7 +203,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { return internal::xdestroy_proxy; } @@ -219,7 +224,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { return d; } #else diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 0d7aeb2d4..b75e79b21 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,7 +16,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 @@ -35,7 +34,6 @@ using std::nullptr_t; // #include "cxx_core_features.h" - #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -109,7 +107,6 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" - #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -139,8 +136,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif - - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -282,7 +277,6 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } - namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -511,10 +505,8 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -523,7 +515,6 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif - // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -560,7 +551,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -659,7 +649,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. @@ -688,7 +677,6 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { namespace mpl { @@ -969,7 +957,6 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" - namespace sqlite_orm { namespace internal { @@ -999,7 +986,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" - #include // std::is_same #include @@ -1007,7 +993,6 @@ namespace sqlite_orm { // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { /* @@ -1055,7 +1040,6 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" - #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1063,7 +1047,6 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" @@ -1132,7 +1115,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1224,10 +1206,8 @@ namespace sqlite_orm { // #include "table_type_of.h" - // #include "indexed_column.h" - #include // std::string #include // std::move @@ -1235,7 +1215,6 @@ namespace sqlite_orm { // #include "ast/where.h" - #include // std::false_type, std::true_type #include // std::move @@ -1245,13 +1224,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 @@ -1274,7 +1250,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1320,7 +1295,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1384,7 +1358,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -1426,7 +1399,6 @@ namespace sqlite_orm { // #include "type_printer.h" - namespace sqlite_orm { namespace internal { @@ -1972,10 +1944,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 { /** @@ -2000,10 +1970,8 @@ namespace sqlite_orm { #include // std::move // #include "functional/cxx_optional.h" - // #include "tags.h" - namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -2017,7 +1985,6 @@ namespace sqlite_orm { // #include "serialize_result_type.h" - namespace sqlite_orm { namespace internal { @@ -2306,14 +2273,12 @@ namespace sqlite_orm { // #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 @@ -2405,7 +2370,6 @@ namespace sqlite_orm { // #include "constraints.h" - namespace sqlite_orm { namespace internal { @@ -2584,14 +2548,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 { /** @@ -2755,7 +2717,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -2790,7 +2751,6 @@ namespace sqlite_orm { // #include "serializer_context.h" - namespace sqlite_orm { namespace internal { @@ -2832,17 +2792,14 @@ namespace sqlite_orm { // #include "expression.h" - #include #include // std::move, std::forward // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "operators.h" - namespace sqlite_orm { namespace internal { @@ -2921,7 +2878,6 @@ namespace sqlite_orm { // #include "literal.h" - namespace sqlite_orm { namespace internal { @@ -2938,7 +2894,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -3448,7 +3403,7 @@ namespace sqlite_orm { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); - entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); + this->entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); } const_iterator begin() const { @@ -4356,7 +4311,6 @@ namespace sqlite_orm { // #include "conditions.h" - namespace sqlite_orm { namespace internal { @@ -4470,7 +4424,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4516,10 +4469,8 @@ namespace sqlite_orm { // #include "ast/into.h" - // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -4538,7 +4489,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { using int64 = sqlite_int64; @@ -6642,7 +6592,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" @@ -6657,14 +6606,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 { @@ -6734,7 +6681,6 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { @@ -7191,7 +7137,6 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" - namespace sqlite_orm { struct table_info { @@ -7248,7 +7193,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) @@ -7281,7 +7225,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} - partial_trigger_t &end() { + partial_trigger_t& end() { return *this; } }; @@ -7350,7 +7294,7 @@ namespace sqlite_orm { trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - trigger_base_t &for_each_row() { + trigger_base_t& for_each_row() { this->do_for_each_row = true; return *this; } @@ -7511,7 +7455,7 @@ namespace sqlite_orm { } template - internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t &part) { + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); } @@ -7571,7 +7515,6 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" - #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7581,7 +7524,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7603,20 +7545,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - {+d}; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + { +d }; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -7631,7 +7573,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value&& std::is_default_constructible::value; + std::is_empty::value && std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -7692,7 +7634,8 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) + void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -7720,7 +7663,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -7755,7 +7698,9 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::is_unusable_for_xdestroy) + { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -7774,7 +7719,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + requires(internal::needs_xdestroy_proxy) + { return internal::xdestroy_proxy; } @@ -7793,7 +7740,9 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + requires(internal::yields_xdestroy) + { return d; } #else @@ -7816,7 +7765,6 @@ namespace sqlite_orm { #endif } - namespace sqlite_orm { /** @@ -8013,7 +7961,6 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8092,7 +8039,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { /** @@ -8456,7 +8402,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8533,7 +8478,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -8858,7 +8802,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { /** @@ -9056,7 +8999,6 @@ namespace sqlite_orm { // #include "table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -9123,7 +9065,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { namespace internal { @@ -9239,7 +9180,6 @@ namespace sqlite_orm { // #include "storage_traits.h" - #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -9248,12 +9188,10 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" - #include // std::tuple // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { @@ -9279,7 +9217,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - #include // std::true_type, std::false_type, std::remove_const, std::enable_if #include #include // std::index_sequence @@ -9290,7 +9227,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { namespace internal { @@ -9419,7 +9355,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -9450,7 +9385,6 @@ namespace sqlite_orm { // #include "function.h" - #include #include #include // std::string @@ -9463,7 +9397,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { struct arg_values; @@ -9477,13 +9410,13 @@ namespace sqlite_orm { struct user_defined_function_base { using func_call = std::function< - void(sqlite3_context *context, void *functionPointer, int argsCount, sqlite3_value **values)>; - using final_call = std::function; + void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; + using final_call = std::function; std::string name; int argumentsCount = 0; - std::function create; - void (*destroy)(int *) = nullptr; + std::function create; + void (*destroy)(int*) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_base(decltype(name) name_, @@ -9615,7 +9548,7 @@ namespace sqlite_orm { constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // using C++17 or higher - template + template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); @@ -9698,7 +9631,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -9985,7 +9917,6 @@ namespace sqlite_orm { // #include "functional/static_magic.h" - #include // std::false_type, std::true_type, std::integral_constant #include // std::forward @@ -10068,7 +9999,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" - #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -10081,7 +10011,6 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - namespace sqlite_orm { namespace internal { @@ -10211,7 +10140,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -10514,7 +10442,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - // interface functions namespace sqlite_orm { namespace internal { @@ -10599,7 +10526,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10636,7 +10562,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" @@ -10657,19 +10582,16 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" - // #include "functional/cxx_universal.h" // #include "row_extractor.h" // #include "mapped_row_extractor.h" - #include // #include "object_from_column_builder.h" - #include #include // std::is_member_object_pointer @@ -10677,7 +10599,6 @@ namespace sqlite_orm { // #include "row_extractor.h" - namespace sqlite_orm { namespace internal { @@ -10718,7 +10639,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -10749,7 +10669,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -10801,7 +10720,6 @@ namespace sqlite_orm { // #include "view.h" - #include #include // std::string #include // std::forward, std::move @@ -10813,7 +10731,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10834,7 +10751,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -10922,7 +10838,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -10938,7 +10853,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::unique_ptr #include // std::iterator_traits @@ -10956,14 +10870,12 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include #include // std::string // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -11036,7 +10948,6 @@ namespace sqlite_orm { // #include "values.h" - #include // std::vector #include // std::tuple #include // std::forward @@ -11045,7 +10956,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -11084,14 +10994,12 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" - #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11149,16 +11057,119 @@ namespace sqlite_orm { // #include "ast/set.h" - #include // std::tuple, std::tuple_size #include // std::string #include // std::vector #include // std::stringstream +#include // std::false_type, std::true_type +#include // std::function + +// #include "table_name_collector.h" + +#include // std::set +#include // std::string +#include // std::function +#include // std::type_index + +// #include "functional/cxx_type_traits_polyfill.h" + +// #include "type_traits.h" + +// #include "select_constraints.h" + +// #include "alias.h" + +// #include "core_functions.h" namespace sqlite_orm { namespace internal { + struct table_name_collector { + using table_name_set = std::set>; + using find_table_name_t = std::function; + + find_table_name_t find_table_name; + mutable table_name_set table_names; + + table_name_collector() = default; + + table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} + + template + void operator()(const T&) const { + //.. + } + + template + void operator()(F O::*, std::string alias = {}) const { + table_names.emplace(this->find_table_name(typeid(O)), move(alias)); + } + + template + void operator()(const column_pointer&) const { + table_names.emplace(this->find_table_name(typeid(T)), ""); + } + + template + void operator()(const alias_column_t& a) const { + (*this)(a.column, alias_extractor::get()); + } + + template + void operator()(const count_asterisk_t&) const { + auto tableName = this->find_table_name(typeid(T)); + if(!tableName.empty()) { + table_names.emplace(move(tableName), ""); + } + } + + template = true> + void operator()(const asterisk_t&) const { + table_names.emplace(this->find_table_name(typeid(T)), ""); + } + + template = true> + void operator()(const asterisk_t&) const { + // note: not all alias classes have a nested A::type + static_assert(polyfill::is_detected_v, + "alias must have a nested alias::type typename"); + auto tableName = this->find_table_name(typeid(type_t)); + table_names.emplace(move(tableName), alias_extractor::get()); + } + + template + void operator()(const object_t&) const { + table_names.emplace(this->find_table_name(typeid(T)), ""); + } + + template + void operator()(const table_rowid_t&) const { + table_names.emplace(this->find_table_name(typeid(T)), ""); + } + + template + void operator()(const table_oid_t&) const { + table_names.emplace(this->find_table_name(typeid(T)), ""); + } + + template + void operator()(const table__rowid_t&) const { + table_names.emplace(this->find_table_name(typeid(T)), ""); + } + }; + + } + +} + +namespace sqlite_orm { + + namespace internal { + + template + void iterate_ast(const T& t, L&& lambda); + template struct set_t { using assigns_type = std::tuple; @@ -11166,22 +11177,70 @@ namespace sqlite_orm { assigns_type assigns; }; + template + struct is_set : std::false_type {}; + + template + struct is_set> : std::true_type {}; + + struct dynamic_set_entry { + std::string serialized_value; + // std::function + }; + template struct dynamic_set_t { using context_t = C; - using entry_t = std::string; + using entry_t = dynamic_set_entry; using const_iterator = typename std::vector::const_iterator; - dynamic_set_t(const context_t& context_) : context(context_) {} + dynamic_set_t(const context_t& context_) : + context(context_), collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }) {} + + dynamic_set_t(const dynamic_set_t& other) : + entries(other.entries), context(other.context), collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }) { + collector.table_names = other.collector.table_names; + } + + dynamic_set_t(dynamic_set_t&& other) : + entries(move(other.entries)), context(std::move(other.context)), + collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }) { + collector.table_names = move(other.collector.table_names); + } + + dynamic_set_t& operator=(const dynamic_set_t& other) { + this->entries = other.entries; + this->context = other.context; + this->collector = table_name_collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }); + this->collector.table_names = other.collector.table_names; + } + + dynamic_set_t& operator=(dynamic_set_t&& other) { + this->entries = move(other.entries); + this->context = std::move(other.context); + this->collector = table_name_collector([this](const std::type_index& ti) { + return find_table_name(this->context.db_objects, ti); + }); + this->collector.table_names = move(other.collector.table_names); + } template void push_back(assign_t assign) { auto newContext = this->context; newContext.skip_table_name = true; + iterate_ast(assign, this->collector); std::stringstream ss; ss << serialize(assign.lhs, newContext) << ' ' << assign.serialize() << ' ' << serialize(assign.rhs, context); - entries.push_back(ss.str()); + this->entries.push_back({ss.str()}); } const_iterator begin() const { @@ -11194,12 +11253,22 @@ namespace sqlite_orm { void clear() { this->entries.clear(); + this->collector.table_names.clear(); } - protected: - context_t context; std::vector entries; + context_t context; + table_name_collector collector; }; + + template + struct is_set> : std::true_type {}; + + template + struct is_dynamic_set : std::false_type {}; + + template + struct is_dynamic_set> : std::true_type {}; } /** @@ -11225,7 +11294,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -11338,14 +11406,13 @@ namespace sqlite_orm { }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct update_all_t; - - template - struct update_all_t, Wargs...> { - using set_type = set_t; + template + struct update_all_t { + using set_type = S; using conditions_type = std::tuple; + static_assert(is_set::value, "update_all_t must have set or dynamic set as the first argument"); + set_type set; conditions_type conditions; }; @@ -11897,8 +11964,9 @@ namespace sqlite_orm { * Create an update all statement. * Usage: storage.update_all(set(...), ...); */ - template - internal::update_all_t, Wargs...> update_all(internal::set_t set, Wargs... wh) { + template + internal::update_all_t update_all(S set, Wargs... wh) { + static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; @@ -11967,7 +12035,6 @@ namespace sqlite_orm { // #include "ast/excluded.h" - #include // std::move namespace sqlite_orm { @@ -11997,12 +12064,10 @@ namespace sqlite_orm { // #include "ast/exists.h" - #include // std::move // #include "../tags.h" - namespace sqlite_orm { namespace internal { @@ -12033,7 +12098,6 @@ namespace sqlite_orm { // #include "ast/set.h" - namespace sqlite_orm { namespace internal { @@ -12291,9 +12355,9 @@ namespace sqlite_orm { }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct ast_iterator, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; + template + struct ast_iterator, void> { + using node_type = update_all_t; template void operator()(const node_type& u, L& lambda) const { @@ -12317,8 +12381,18 @@ namespace sqlite_orm { using node_type = set_t; template - void operator()(const node_type& s, L& lambda) const { - iterate_ast(s.assigns, lambda); + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.assigns, lambda); + } + }; + + template + struct ast_iterator, void> { + using node_type = dynamic_set_t; + + template + void operator()(const node_type& node, L& lambda) const { + iterate_ast(node.entries, lambda); } }; @@ -12713,7 +12787,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -12770,7 +12843,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include #include // std::function, std::bind #include // std::string @@ -12791,7 +12863,6 @@ namespace sqlite_orm { // #include "pragma.h" - #include #include // std::string #include // std::function @@ -12811,7 +12882,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - #include // std::index_sequence #include #include @@ -12835,7 +12905,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { template @@ -12861,18 +12930,18 @@ namespace sqlite_orm { } } #else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; + } + os << c; } - os << c; } } - } #endif inline void stream_identifier(std::ostream& ss, @@ -13237,7 +13306,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -13446,7 +13514,6 @@ namespace sqlite_orm { // #include "limit_accessor.h" - #include #include // std::map #include // std::function @@ -13454,7 +13521,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13588,13 +13654,11 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function #include // std::move // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13621,7 +13685,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} - transaction_guard_t(transaction_guard_t &&other) : + transaction_guard_t(transaction_guard_t&& other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), gotta_fire(other.gotta_fire) { @@ -13638,7 +13702,7 @@ namespace sqlite_orm { } } - transaction_guard_t &operator=(transaction_guard_t &&) = delete; + transaction_guard_t& operator=(transaction_guard_t&&) = delete; /** * Call `COMMIT` explicitly. After this call @@ -13675,7 +13739,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::system_error #include // std::string @@ -13686,7 +13749,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13754,7 +13816,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 @@ -13765,19 +13826,17 @@ namespace sqlite_orm { // #include "arg_values.h" - #include // #include "row_extractor.h" - namespace sqlite_orm { struct arg_value { arg_value() : arg_value(nullptr) {} - arg_value(sqlite3_value *value_) : value(value_) {} + arg_value(sqlite3_value* value_) : value(value_) {} template T get() const { @@ -13814,18 +13873,18 @@ namespace sqlite_orm { } private: - sqlite3_value *value = nullptr; + sqlite3_value* value = nullptr; }; struct arg_values { struct iterator { - iterator(const arg_values &container_, int index_) : + iterator(const arg_values& container_, int index_) : container(container_), index(index_), currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} - iterator &operator++() { + iterator& operator++() { ++this->index; if(this->index < int(this->container.size())) { this->currentValue = this->container[this->index]; @@ -13854,27 +13913,27 @@ namespace sqlite_orm { } } - arg_value *operator->() const { + arg_value* operator->() const { return &this->currentValue; } - bool operator==(const iterator &other) const { + bool operator==(const iterator& other) const { return &other.container == &this->container && other.index == this->index; } - bool operator!=(const iterator &other) const { + bool operator!=(const iterator& other) const { return !(*this == other); } private: - const arg_values &container; + const arg_values& container; int index = 0; mutable arg_value currentValue; }; arg_values() : arg_values(0, nullptr) {} - arg_values(int argsCount_, sqlite3_value **values_) : argsCount(argsCount_), values(values_) {} + arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} size_t size() const { return this->argsCount; @@ -13886,7 +13945,7 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - sqlite3_value *value = this->values[index]; + sqlite3_value* value = this->values[index]; return {value}; } else { throw std::system_error{orm_error_code::index_is_out_of_bounds}; @@ -13907,11 +13966,10 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value **values = nullptr; + sqlite3_value** values = nullptr; }; } - namespace sqlite_orm { namespace internal { @@ -13933,13 +13991,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -13955,7 +14013,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -14722,13 +14779,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 { @@ -14862,7 +14917,6 @@ namespace sqlite_orm { // #include "statement_serializer.h" - #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14875,7 +14929,6 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -14918,108 +14971,8 @@ namespace sqlite_orm { // #include "table_name_collector.h" - -#include // std::set -#include // std::string -#include // std::function -#include // std::type_index - -// #include "functional/cxx_type_traits_polyfill.h" - -// #include "type_traits.h" - -// #include "select_constraints.h" - -// #include "alias.h" - -// #include "core_functions.h" - - -namespace sqlite_orm { - - namespace internal { - - struct table_name_collector { - using table_name_set = std::set>; - using find_table_name_t = std::function; - - find_table_name_t find_table_name; - mutable table_name_set table_names; - - table_name_collector() = default; - - table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} - - template - table_name_set operator()(const T &) const { - return {}; - } - - template - void operator()(F O::*, std::string alias = {}) const { - table_names.emplace(this->find_table_name(typeid(O)), move(alias)); - } - - template - void operator()(const column_pointer &) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); - } - - template - void operator()(const alias_column_t &a) const { - (*this)(a.column, alias_extractor::get()); - } - - template - void operator()(const count_asterisk_t &) const { - auto tableName = this->find_table_name(typeid(T)); - if(!tableName.empty()) { - table_names.emplace(move(tableName), ""); - } - } - - template = true> - void operator()(const asterisk_t &) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); - } - - template = true> - void operator()(const asterisk_t &) const { - // note: not all alias classes have a nested A::type - static_assert(polyfill::is_detected_v, - "alias must have a nested alias::type typename"); - auto tableName = this->find_table_name(typeid(type_t)); - table_names.emplace(move(tableName), alias_extractor::get()); - } - - template - void operator()(const object_t &) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); - } - - template - void operator()(const table_rowid_t &) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); - } - - template - void operator()(const table_oid_t &) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); - } - - template - void operator()(const table__rowid_t &) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); - } - }; - - } - -} - // #include "column_names_getter.h" - #include // std::system_error #include // std::string #include // std::vector @@ -15035,7 +14988,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -15140,7 +15092,6 @@ namespace sqlite_orm { // #include "order_by_serializer.h" - #include // std::string #include // std::stringstream @@ -15232,7 +15183,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -16269,11 +16219,11 @@ namespace sqlite_orm { std::stringstream ss; ss << "SET "; int index = 0; - for(const std::string& entry: statement) { + for(const dynamic_set_entry& entry: statement) { if(index > 0) { ss << ", "; } - ss << entry; + ss << entry.serialized_value; ++index; } return ss.str(); @@ -16299,38 +16249,78 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, Wargs...>, void> { - using statement_type = update_all_t, Wargs...>; + template + struct table_name_collector_holder; + + template + struct table_name_collector_holder> { + + table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) : + collector(move(find_table_name)) {} + + table_name_collector collector; + }; + + template + struct table_name_collector_holder> { + + table_name_collector_holder(const table_name_collector& collector) : collector(collector) {} + + const table_name_collector& collector; + }; + + template + table_name_collector_holder> make_table_name_collector_holder(const set_t& set, + const Ctx& context) { + table_name_collector_holder> holder([&context](const std::type_index& ti) { + return find_table_name(context.db_objects, ti); + }); + iterate_ast(set, holder.collector); + return holder; + } + + template + table_name_collector_holder> make_table_name_collector_holder(const dynamic_set_t& set, + const Ctx&) { + return {set.collector}; + } + + template + struct statement_serializer, void> { + using statement_type = update_all_t; template - std::string operator()(const statement_type& upd, const Ctx& context) const { - table_name_collector collector([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); - iterate_ast(upd.set.assigns, collector); + std::string operator()(const statement_type& statement, const Ctx& context) const { + std::string tableName; + auto collectorHolder = make_table_name_collector_holder(statement.set, context); + const table_name_collector& collector = collectorHolder.collector; if(collector.table_names.empty()) { throw std::system_error{orm_error_code::no_tables_specified}; } + tableName = collector.table_names.begin()->first; - std::stringstream ss; - ss << "UPDATE " << streaming_identifier(collector.table_names.begin()->first) << " SET "; - { - std::vector setPairs; - setPairs.reserve(std::tuple_size::assigns_type>::value); - auto leftContext = context; - leftContext.skip_table_name = true; - iterate_tuple(upd.set.assigns, [&context, &leftContext, &setPairs](auto& asgn) { - std::stringstream sss; - sss << serialize(asgn.lhs, leftContext); - sss << ' ' << asgn.serialize() << ' '; - sss << serialize(asgn.rhs, context); - setPairs.push_back(sss.str()); + /*static_if::value>([&tableName, &context] (const statement_type& statement) { + table_name_collector collector([&context](const std::type_index& ti) { + return find_table_name(context.db_objects, ti); }); - ss << streaming_serialized(setPairs) << streaming_conditions_tuple(upd.conditions, context); - return ss.str(); - } + iterate_ast(statement.set, collector); + if(collector.table_names.empty()) { + throw std::system_error{orm_error_code::no_tables_specified}; + } + tableName = collector.table_names.begin()->first; + }, [&tableName] (const statement_type& statement) { + if (statement.set.collector.table_names.empty()) { + throw std::system_error{orm_error_code::no_tables_specified}; + } + tableName = statement.set.collector.table_names.begin()->first; + })(statement);*/ + + std::stringstream ss; + ss << "UPDATE " << streaming_identifier(tableName); + ss << ' ' << serialize(statement.set, context); + ss << streaming_conditions_tuple(statement.conditions, context); + return ss.str(); } }; @@ -17281,7 +17271,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -17814,7 +17803,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto { + [](auto expression) -> auto{ expression.highest_level = true; return expression; }, @@ -18083,7 +18072,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18402,13 +18391,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18448,13 +18437,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18546,22 +18535,22 @@ namespace sqlite_orm { } return move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); + } } - } #endif } @@ -18672,7 +18661,6 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" - // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18699,7 +18687,6 @@ namespace sqlite_orm { // #include "ast/group_by.h" - namespace sqlite_orm { namespace internal { @@ -19004,7 +18991,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template @@ -19184,7 +19170,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19257,7 +19242,6 @@ namespace sqlite_orm { // #include "table.h" - namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19300,7 +19284,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" @@ -19317,7 +19300,6 @@ namespace sqlite_orm { // #include "../column.h" - namespace sqlite_orm { namespace internal { @@ -19357,7 +19339,6 @@ namespace sqlite_orm { // #include "../table.h" - namespace sqlite_orm { namespace internal { @@ -19385,9 +19366,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19418,7 +19399,6 @@ namespace sqlite_orm { // #include "../storage.h" - namespace sqlite_orm { namespace internal { @@ -19461,9 +19441,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19527,11 +19507,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f1095b369..253d94d75 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -84,6 +84,7 @@ add_executable(unit_tests statement_serializer_tests/bindables.cpp statement_serializer_tests/ast/upsert_clause.cpp statement_serializer_tests/ast/excluded.cpp + statement_serializer_tests/ast/set.cpp statement_serializer_tests/arithmetic_operators.cpp statement_serializer_tests/base_types.cpp statement_serializer_tests/collate.cpp diff --git a/tests/statement_serializer_tests/statements/update.cpp b/tests/statement_serializer_tests/statements/update.cpp index 3cf3105dd..7d9979272 100644 --- a/tests/statement_serializer_tests/statements/update.cpp +++ b/tests/statement_serializer_tests/statements/update.cpp @@ -44,16 +44,27 @@ TEST_CASE("statement_serializer update") { value = serialize(expression, context); } SECTION("update_all") { - auto expression = update_all(set(assign(&A::value, 5)), where(is_equal(&A::address, 1))); - SECTION("with question marks") { - context.replace_bindable_with_question = true; - expected = R"(UPDATE "table" SET "value" = ? WHERE (("address" = ?)))"; + SECTION("static set") { + auto expression = update_all(set(assign(&A::value, 5)), where(is_equal(&A::address, 1))); + SECTION("with question marks") { + context.replace_bindable_with_question = true; + expected = R"(UPDATE "table" SET "value" = ? WHERE (("address" = ?)))"; + } + SECTION("without question marks") { + context.replace_bindable_with_question = false; + expected = R"(UPDATE "table" SET "value" = 5 WHERE (("address" = 1)))"; + } + value = serialize(expression, context); } - SECTION("without question marks") { + SECTION("dynamic set") { + auto storage = make_storage({}, table); + auto dynamicSet = dynamic_set(storage); + dynamicSet.push_back(assign(&A::value, 5)); + auto expression = update_all(dynamicSet, where(is_equal(&A::address, 1))); context.replace_bindable_with_question = false; expected = R"(UPDATE "table" SET "value" = 5 WHERE (("address" = 1)))"; + value = serialize(expression, context); } - value = serialize(expression, context); } } SECTION("table") { From 32eabd2ada86afd7aa50c0694e83e17a5ae916ea Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Thu, 29 Dec 2022 16:35:21 -0600 Subject: [PATCH 007/100] removed comments and fixed formatting --- dev/ast/set.h | 2 -- dev/statement_serializer.h | 16 --------------- dev/storage.h | 2 +- dev/xdestroy_handling.h | 35 +++++++++++++-------------------- include/sqlite_orm/sqlite_orm.h | 18 ----------------- 5 files changed, 15 insertions(+), 58 deletions(-) diff --git a/dev/ast/set.h b/dev/ast/set.h index a5ea93a0c..77a631ac9 100644 --- a/dev/ast/set.h +++ b/dev/ast/set.h @@ -5,7 +5,6 @@ #include // std::vector #include // std::stringstream #include // std::false_type, std::true_type -#include // std::function #include "table_name_collector.h" @@ -31,7 +30,6 @@ namespace sqlite_orm { struct dynamic_set_entry { std::string serialized_value; - // std::function }; template diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 7f5f973a7..d0e6b50eb 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1160,22 +1160,6 @@ namespace sqlite_orm { } tableName = collector.table_names.begin()->first; - /*static_if::value>([&tableName, &context] (const statement_type& statement) { - table_name_collector collector([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); - iterate_ast(statement.set, collector); - if(collector.table_names.empty()) { - throw std::system_error{orm_error_code::no_tables_specified}; - } - tableName = collector.table_names.begin()->first; - }, [&tableName] (const statement_type& statement) { - if (statement.set.collector.table_names.empty()) { - throw std::system_error{orm_error_code::no_tables_specified}; - } - tableName = statement.set.collector.table_names.begin()->first; - })(statement);*/ - std::stringstream ss; ss << "UPDATE " << streaming_identifier(tableName); ss << ' ' << serialize(statement.set, context); diff --git a/dev/storage.h b/dev/storage.h index 1d5a53563..33f37cdb8 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -586,7 +586,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto{ + [](auto expression) -> auto { expression.highest_level = true; return expression; }, diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index 25e172a32..e9f986a03 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -29,20 +29,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - { +d }; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + {+d}; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -57,7 +57,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value && std::is_default_constructible::value; + std::is_empty::value&& std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -118,8 +118,7 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) - void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -147,7 +146,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -182,9 +181,7 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::is_unusable_for_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -203,9 +200,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::needs_xdestroy_proxy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; } @@ -224,9 +219,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept - requires(internal::yields_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { return d; } #else diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index b75e79b21..e040a3fff 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -11062,7 +11062,6 @@ namespace sqlite_orm { #include // std::vector #include // std::stringstream #include // std::false_type, std::true_type -#include // std::function // #include "table_name_collector.h" @@ -11185,7 +11184,6 @@ namespace sqlite_orm { struct dynamic_set_entry { std::string serialized_value; - // std::function }; template @@ -16300,22 +16298,6 @@ namespace sqlite_orm { } tableName = collector.table_names.begin()->first; - /*static_if::value>([&tableName, &context] (const statement_type& statement) { - table_name_collector collector([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); - iterate_ast(statement.set, collector); - if(collector.table_names.empty()) { - throw std::system_error{orm_error_code::no_tables_specified}; - } - tableName = collector.table_names.begin()->first; - }, [&tableName] (const statement_type& statement) { - if (statement.set.collector.table_names.empty()) { - throw std::system_error{orm_error_code::no_tables_specified}; - } - tableName = statement.set.collector.table_names.begin()->first; - })(statement);*/ - std::stringstream ss; ss << "UPDATE " << streaming_identifier(tableName); ss << ' ' << serialize(statement.set, context); From 995761eba8bf3a7b29e574665ec951191a10ce2f Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Mon, 9 Jan 2023 17:07:45 -0600 Subject: [PATCH 008/100] fixed update_all with dynamic_set compilation --- dev/storage.h | 21 +- include/sqlite_orm/sqlite_orm.h | 379 +++++++++++++++++++++---------- tests/storage_non_crud_tests.cpp | 16 ++ 3 files changed, 283 insertions(+), 133 deletions(-) diff --git a/dev/storage.h b/dev/storage.h index 33f37cdb8..ee0da99f5 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -260,8 +260,9 @@ namespace sqlite_orm { this->execute(statement); } - template - void update_all(internal::set_t set, Wargs... wh) { + template + void update_all(S set, Wargs... wh) { + static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); this->execute(statement); } @@ -1041,10 +1042,10 @@ namespace sqlite_orm { } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - prepared_statement_t, Wargs...>> - prepare(update_all_t, Wargs...> upd) { - return prepare_impl, Wargs...>>(std::move(upd)); + template + prepared_statement_t> + prepare(update_all_t upd) { + return prepare_impl>(std::move(upd)); } template @@ -1344,13 +1345,11 @@ namespace sqlite_orm { perform_step(stmt); } - template - void execute(const prepared_statement_t, Wargs...>>& statement) { + template + void execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); conditional_binder bind_node{stmt}; - iterate_tuple(statement.expression.set.assigns, [&bind_node](auto& setArg) { - iterate_ast(setArg, bind_node); - }); + iterate_ast(statement.expression.set, bind_node); iterate_ast(statement.expression.conditions, bind_node); perform_step(stmt); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index e040a3fff..f908d22d4 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,6 +16,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 @@ -34,6 +35,7 @@ using std::nullptr_t; // #include "cxx_core_features.h" + #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -107,6 +109,7 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" + #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -136,6 +139,8 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif + + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -277,6 +282,7 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } + namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -505,8 +511,10 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -515,6 +523,7 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif + // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -551,6 +560,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -649,6 +659,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. @@ -677,6 +688,7 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { namespace mpl { @@ -957,6 +969,7 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" + namespace sqlite_orm { namespace internal { @@ -986,6 +999,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" + #include // std::is_same #include @@ -993,6 +1007,7 @@ namespace sqlite_orm { // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { /* @@ -1040,6 +1055,7 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" + #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1047,6 +1063,7 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" @@ -1115,6 +1132,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1206,8 +1224,10 @@ namespace sqlite_orm { // #include "table_type_of.h" + // #include "indexed_column.h" + #include // std::string #include // std::move @@ -1215,6 +1235,7 @@ namespace sqlite_orm { // #include "ast/where.h" + #include // std::false_type, std::true_type #include // std::move @@ -1224,10 +1245,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 @@ -1250,6 +1274,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1295,6 +1320,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1358,6 +1384,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -1399,6 +1426,7 @@ namespace sqlite_orm { // #include "type_printer.h" + namespace sqlite_orm { namespace internal { @@ -1944,8 +1972,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 { /** @@ -1970,8 +2000,10 @@ namespace sqlite_orm { #include // std::move // #include "functional/cxx_optional.h" + // #include "tags.h" + namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1985,6 +2017,7 @@ namespace sqlite_orm { // #include "serialize_result_type.h" + namespace sqlite_orm { namespace internal { @@ -2273,12 +2306,14 @@ namespace sqlite_orm { // #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 @@ -2370,6 +2405,7 @@ namespace sqlite_orm { // #include "constraints.h" + namespace sqlite_orm { namespace internal { @@ -2548,12 +2584,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 { /** @@ -2717,6 +2755,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -2751,6 +2790,7 @@ namespace sqlite_orm { // #include "serializer_context.h" + namespace sqlite_orm { namespace internal { @@ -2792,14 +2832,17 @@ namespace sqlite_orm { // #include "expression.h" + #include #include // std::move, std::forward // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "operators.h" + namespace sqlite_orm { namespace internal { @@ -2878,6 +2921,7 @@ namespace sqlite_orm { // #include "literal.h" + namespace sqlite_orm { namespace internal { @@ -2894,6 +2938,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -4311,6 +4356,7 @@ namespace sqlite_orm { // #include "conditions.h" + namespace sqlite_orm { namespace internal { @@ -4424,6 +4470,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4469,8 +4516,10 @@ namespace sqlite_orm { // #include "ast/into.h" + // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -4489,6 +4538,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { using int64 = sqlite_int64; @@ -6592,6 +6642,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" @@ -6606,12 +6657,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 { @@ -6681,6 +6734,7 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { @@ -7137,6 +7191,7 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" + namespace sqlite_orm { struct table_info { @@ -7193,6 +7248,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) @@ -7225,7 +7281,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} - partial_trigger_t& end() { + partial_trigger_t &end() { return *this; } }; @@ -7294,7 +7350,7 @@ namespace sqlite_orm { trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - trigger_base_t& for_each_row() { + trigger_base_t &for_each_row() { this->do_for_each_row = true; return *this; } @@ -7455,7 +7511,7 @@ namespace sqlite_orm { } template - internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t &part) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); } @@ -7515,6 +7571,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" + #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7524,6 +7581,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7545,20 +7603,20 @@ namespace sqlite_orm { */ template concept integral_fp_c = requires { - typename D::value_type; - D::value; - requires std::is_function_v>; - }; + typename D::value_type; + D::value; + requires std::is_function_v>; + }; /** * Constraints a deleter to be or to yield a function pointer. */ template concept yields_fp = requires(D d) { - // yielding function pointer by using the plus trick - { +d }; - requires std::is_function_v>; - }; + // yielding function pointer by using the plus trick + {+d}; + requires std::is_function_v>; + }; #endif #if __cpp_lib_concepts >= 201907L @@ -7573,7 +7631,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool is_stateless_deleter_v = - std::is_empty::value && std::is_default_constructible::value; + std::is_empty::value&& std::is_default_constructible::value; template struct is_integral_fp_c : std::false_type {}; @@ -7634,8 +7692,7 @@ namespace sqlite_orm { * it doesn't check so explicitly, but a compiler error will occur. */ template - requires(!integral_fp_c) - void xdestroy_proxy(void* p) noexcept { + requires(!integral_fp_c) void xdestroy_proxy(void* p) noexcept { // C-casting `void* -> P*` like statement_binder> auto o = (P*)p; // ignoring return code @@ -7663,7 +7720,7 @@ namespace sqlite_orm { template SQLITE_ORM_INLINE_VAR constexpr bool can_yield_xdestroy_v = - can_yield_fp_v && std::is_convertible, xdestroy_fn_t>::value; + can_yield_fp_v&& std::is_convertible, xdestroy_fn_t>::value; template SQLITE_ORM_INLINE_VAR constexpr bool needs_xdestroy_proxy_v = @@ -7698,9 +7755,7 @@ namespace sqlite_orm { * Explicitly declared for better error messages. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::is_unusable_for_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; @@ -7719,9 +7774,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept - requires(internal::needs_xdestroy_proxy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; } @@ -7740,9 +7793,7 @@ namespace sqlite_orm { * is invocable with the non-q-qualified pointer value. */ template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept - requires(internal::yields_xdestroy) - { + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept requires(internal::yields_xdestroy) { return d; } #else @@ -7765,6 +7816,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { /** @@ -7961,6 +8013,7 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8039,6 +8092,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { /** @@ -8402,6 +8456,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8478,6 +8533,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -8802,6 +8858,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { /** @@ -8999,6 +9056,7 @@ namespace sqlite_orm { // #include "table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -9065,6 +9123,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { namespace internal { @@ -9180,6 +9239,7 @@ namespace sqlite_orm { // #include "storage_traits.h" + #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -9188,10 +9248,12 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" + #include // std::tuple // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { @@ -9217,6 +9279,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + #include // std::true_type, std::false_type, std::remove_const, std::enable_if #include #include // std::index_sequence @@ -9227,6 +9290,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { namespace internal { @@ -9355,6 +9419,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -9385,6 +9450,7 @@ namespace sqlite_orm { // #include "function.h" + #include #include #include // std::string @@ -9397,6 +9463,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { struct arg_values; @@ -9410,13 +9477,13 @@ namespace sqlite_orm { struct user_defined_function_base { using func_call = std::function< - void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; - using final_call = std::function; + void(sqlite3_context *context, void *functionPointer, int argsCount, sqlite3_value **values)>; + using final_call = std::function; std::string name; int argumentsCount = 0; - std::function create; - void (*destroy)(int*) = nullptr; + std::function create; + void (*destroy)(int *) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_base(decltype(name) name_, @@ -9548,7 +9615,7 @@ namespace sqlite_orm { constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // using C++17 or higher - template + template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); @@ -9631,6 +9698,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -9917,6 +9985,7 @@ namespace sqlite_orm { // #include "functional/static_magic.h" + #include // std::false_type, std::true_type, std::integral_constant #include // std::forward @@ -9999,6 +10068,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" + #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -10011,6 +10081,7 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + namespace sqlite_orm { namespace internal { @@ -10140,6 +10211,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -10442,6 +10514,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + // interface functions namespace sqlite_orm { namespace internal { @@ -10526,6 +10599,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10562,6 +10636,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" @@ -10582,16 +10657,19 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" + // #include "functional/cxx_universal.h" // #include "row_extractor.h" // #include "mapped_row_extractor.h" + #include // #include "object_from_column_builder.h" + #include #include // std::is_member_object_pointer @@ -10599,6 +10677,7 @@ namespace sqlite_orm { // #include "row_extractor.h" + namespace sqlite_orm { namespace internal { @@ -10639,6 +10718,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -10669,6 +10749,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -10720,6 +10801,7 @@ namespace sqlite_orm { // #include "view.h" + #include #include // std::string #include // std::forward, std::move @@ -10731,6 +10813,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10751,6 +10834,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -10838,6 +10922,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -10853,6 +10938,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::unique_ptr #include // std::iterator_traits @@ -10870,12 +10956,14 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include #include // std::string // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -10948,6 +11036,7 @@ namespace sqlite_orm { // #include "values.h" + #include // std::vector #include // std::tuple #include // std::forward @@ -10956,6 +11045,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -10994,12 +11084,14 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" + #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11057,6 +11149,7 @@ namespace sqlite_orm { // #include "ast/set.h" + #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11065,6 +11158,7 @@ namespace sqlite_orm { // #include "table_name_collector.h" + #include // std::set #include // std::string #include // std::function @@ -11080,13 +11174,14 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { struct table_name_collector { using table_name_set = std::set>; - using find_table_name_t = std::function; + using find_table_name_t = std::function; find_table_name_t find_table_name; mutable table_name_set table_names; @@ -11096,7 +11191,7 @@ namespace sqlite_orm { table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} template - void operator()(const T&) const { + void operator()(const T &) const { //.. } @@ -11106,17 +11201,17 @@ namespace sqlite_orm { } template - void operator()(const column_pointer&) const { + void operator()(const column_pointer &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const alias_column_t& a) const { + void operator()(const alias_column_t &a) const { (*this)(a.column, alias_extractor::get()); } template - void operator()(const count_asterisk_t&) const { + void operator()(const count_asterisk_t &) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { table_names.emplace(move(tableName), ""); @@ -11124,12 +11219,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -11138,22 +11233,22 @@ namespace sqlite_orm { } template - void operator()(const object_t&) const { + void operator()(const object_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_rowid_t&) const { + void operator()(const table_rowid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_oid_t&) const { + void operator()(const table_oid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table__rowid_t&) const { + void operator()(const table__rowid_t &) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } }; @@ -11162,6 +11257,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -11292,6 +11388,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -12033,6 +12130,7 @@ namespace sqlite_orm { // #include "ast/excluded.h" + #include // std::move namespace sqlite_orm { @@ -12062,10 +12160,12 @@ namespace sqlite_orm { // #include "ast/exists.h" + #include // std::move // #include "../tags.h" + namespace sqlite_orm { namespace internal { @@ -12096,6 +12196,7 @@ namespace sqlite_orm { // #include "ast/set.h" + namespace sqlite_orm { namespace internal { @@ -12785,6 +12886,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -12841,6 +12943,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include #include // std::function, std::bind #include // std::string @@ -12861,6 +12964,7 @@ namespace sqlite_orm { // #include "pragma.h" + #include #include // std::string #include // std::function @@ -12880,6 +12984,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + #include // std::index_sequence #include #include @@ -12903,6 +13008,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { template @@ -12928,18 +13034,18 @@ namespace sqlite_orm { } } #else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; - } - os << c; + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; } + os << c; } } + } #endif inline void stream_identifier(std::ostream& ss, @@ -13304,6 +13410,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -13512,6 +13619,7 @@ namespace sqlite_orm { // #include "limit_accessor.h" + #include #include // std::map #include // std::function @@ -13519,6 +13627,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13652,11 +13761,13 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function #include // std::move // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13683,7 +13794,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} - transaction_guard_t(transaction_guard_t&& other) : + transaction_guard_t(transaction_guard_t &&other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), gotta_fire(other.gotta_fire) { @@ -13700,7 +13811,7 @@ namespace sqlite_orm { } } - transaction_guard_t& operator=(transaction_guard_t&&) = delete; + transaction_guard_t &operator=(transaction_guard_t &&) = delete; /** * Call `COMMIT` explicitly. After this call @@ -13737,6 +13848,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::system_error #include // std::string @@ -13747,6 +13859,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13814,6 +13927,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 @@ -13824,17 +13938,19 @@ namespace sqlite_orm { // #include "arg_values.h" + #include // #include "row_extractor.h" + namespace sqlite_orm { struct arg_value { arg_value() : arg_value(nullptr) {} - arg_value(sqlite3_value* value_) : value(value_) {} + arg_value(sqlite3_value *value_) : value(value_) {} template T get() const { @@ -13871,18 +13987,18 @@ namespace sqlite_orm { } private: - sqlite3_value* value = nullptr; + sqlite3_value *value = nullptr; }; struct arg_values { struct iterator { - iterator(const arg_values& container_, int index_) : + iterator(const arg_values &container_, int index_) : container(container_), index(index_), currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} - iterator& operator++() { + iterator &operator++() { ++this->index; if(this->index < int(this->container.size())) { this->currentValue = this->container[this->index]; @@ -13911,27 +14027,27 @@ namespace sqlite_orm { } } - arg_value* operator->() const { + arg_value *operator->() const { return &this->currentValue; } - bool operator==(const iterator& other) const { + bool operator==(const iterator &other) const { return &other.container == &this->container && other.index == this->index; } - bool operator!=(const iterator& other) const { + bool operator!=(const iterator &other) const { return !(*this == other); } private: - const arg_values& container; + const arg_values &container; int index = 0; mutable arg_value currentValue; }; arg_values() : arg_values(0, nullptr) {} - arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} + arg_values(int argsCount_, sqlite3_value **values_) : argsCount(argsCount_), values(values_) {} size_t size() const { return this->argsCount; @@ -13943,7 +14059,7 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - sqlite3_value* value = this->values[index]; + sqlite3_value *value = this->values[index]; return {value}; } else { throw std::system_error{orm_error_code::index_is_out_of_bounds}; @@ -13964,10 +14080,11 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value** values = nullptr; + sqlite3_value **values = nullptr; }; } + namespace sqlite_orm { namespace internal { @@ -13989,13 +14106,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -14011,6 +14128,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -14777,11 +14895,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 { @@ -14915,6 +15035,7 @@ namespace sqlite_orm { // #include "statement_serializer.h" + #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14927,6 +15048,7 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -14971,6 +15093,7 @@ namespace sqlite_orm { // #include "column_names_getter.h" + #include // std::system_error #include // std::string #include // std::vector @@ -14986,6 +15109,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -15090,6 +15214,7 @@ namespace sqlite_orm { // #include "order_by_serializer.h" + #include // std::string #include // std::stringstream @@ -15181,6 +15306,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -17253,6 +17379,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -17459,8 +17586,9 @@ namespace sqlite_orm { this->execute(statement); } - template - void update_all(internal::set_t set, Wargs... wh) { + template + void update_all(S set, Wargs... wh) { + static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); this->execute(statement); } @@ -17785,7 +17913,7 @@ namespace sqlite_orm { static_assert(is_preparable_v, "Expression must be a high-level statement"); decltype(auto) e2 = static_if>( - [](auto expression) -> auto{ + [](auto expression) -> auto { expression.highest_level = true; return expression; }, @@ -18054,7 +18182,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18240,10 +18368,10 @@ namespace sqlite_orm { } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - template - prepared_statement_t, Wargs...>> - prepare(update_all_t, Wargs...> upd) { - return prepare_impl, Wargs...>>(std::move(upd)); + template + prepared_statement_t> + prepare(update_all_t upd) { + return prepare_impl>(std::move(upd)); } template @@ -18373,13 +18501,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18419,13 +18547,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18517,22 +18645,22 @@ namespace sqlite_orm { } return move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); - } + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); } + } #endif } @@ -18543,13 +18671,11 @@ namespace sqlite_orm { perform_step(stmt); } - template - void execute(const prepared_statement_t, Wargs...>>& statement) { + template + void execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); conditional_binder bind_node{stmt}; - iterate_tuple(statement.expression.set.assigns, [&bind_node](auto& setArg) { - iterate_ast(setArg, bind_node); - }); + iterate_ast(statement.expression.set, bind_node); iterate_ast(statement.expression.conditions, bind_node); perform_step(stmt); } @@ -18643,6 +18769,7 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" + // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18669,6 +18796,7 @@ namespace sqlite_orm { // #include "ast/group_by.h" + namespace sqlite_orm { namespace internal { @@ -18973,6 +19101,7 @@ namespace sqlite_orm { // #include "expression_object_type.h" + namespace sqlite_orm { template @@ -19152,6 +19281,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19224,6 +19354,7 @@ namespace sqlite_orm { // #include "table.h" + namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19266,6 +19397,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" @@ -19282,6 +19414,7 @@ namespace sqlite_orm { // #include "../column.h" + namespace sqlite_orm { namespace internal { @@ -19321,6 +19454,7 @@ namespace sqlite_orm { // #include "../table.h" + namespace sqlite_orm { namespace internal { @@ -19348,9 +19482,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19381,6 +19515,7 @@ namespace sqlite_orm { // #include "../storage.h" + namespace sqlite_orm { namespace internal { @@ -19423,9 +19558,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19489,11 +19624,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); diff --git a/tests/storage_non_crud_tests.cpp b/tests/storage_non_crud_tests.cpp index 30b412fae..408abda85 100644 --- a/tests/storage_non_crud_tests.cpp +++ b/tests/storage_non_crud_tests.cpp @@ -58,6 +58,22 @@ TEST_CASE("explicit from") { REQUIRE(expected == rows); } +TEST_CASE("update_all") { + struct Record { + int id = 0; + std::string name; + }; + auto storage = make_storage({}, + make_table("records", + make_column("id", &Record::id, primary_key()), + make_column("name", &Record::name))); + storage.sync_schema(); + auto vars = dynamic_set( storage ); + vars.push_back(assign(&Record::name, "Bob")); + storage.update_all(vars, where(is_equal(&Record::id, 10))); + +} + TEST_CASE("update set null") { struct User { From b6ce0c2181ef378a1e82ae4756b6fe0eb7d995ee Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sat, 28 Jan 2023 11:16:12 +0200 Subject: [PATCH 009/100] Ability to daisy-chain the concatenation operator --- dev/conditions.h | 10 ++++++++++ include/sqlite_orm/sqlite_orm.h | 10 ++++++++++ tests/operators/arithmetic_operators.cpp | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/dev/conditions.h b/dev/conditions.h index 873776481..a251d8458 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -896,6 +896,16 @@ namespace sqlite_orm { return {std::move(l.value), std::move(r.value)}; } + template = true> + internal::conc_t operator||(E expr, R r) { + return {std::move(expr), std::move(r)}; + } + + template = true> + internal::conc_t operator||(L l, E expr) { + return {std::move(l), std::move(expr)}; + } + template internal::add_t operator+(internal::expression_t expr, R r) { return {std::move(expr.value), std::move(r)}; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ddf40f57c..976160358 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3657,6 +3657,16 @@ namespace sqlite_orm { return {std::move(l.value), std::move(r.value)}; } + template = true> + internal::conc_t operator||(E expr, R r) { + return {std::move(expr), std::move(r)}; + } + + template = true> + internal::conc_t operator||(L l, E expr) { + return {std::move(l), std::move(expr)}; + } + template internal::add_t operator+(internal::expression_t expr, R r) { return {std::move(expr.value), std::move(r)}; diff --git a/tests/operators/arithmetic_operators.cpp b/tests/operators/arithmetic_operators.cpp index d0d92083d..c54e4a64b 100644 --- a/tests/operators/arithmetic_operators.cpp +++ b/tests/operators/arithmetic_operators.cpp @@ -51,6 +51,24 @@ TEST_CASE("Arithmetic operators") { REQUIRE(row == name + suffix); } } + { // daisy-chaining ||, left + std::string suffix = "ototo"; + auto rows = storage.select(c(&Object::name) || suffix || "."); + for(size_t i = 0; i < rows.size(); ++i) { + auto& row = rows[i]; + auto& name = names[i]; + REQUIRE(row == name + suffix + "."); + } + } + { // daisy-chaining ||, right + std::string prefix = "ototo"; + auto rows = storage.select(prefix || (c(&Object::name) || ".")); + for(size_t i = 0; i < rows.size(); ++i) { + auto& row = rows[i]; + auto& name = names[i]; + REQUIRE(row == prefix + name + "."); + } + } { // || std::string suffix = "ototo"; auto rows = storage.select(columns(conc(&Object::name, suffix))); From d653ce74158d2cf5e3d23045b61fc6d6636ea6d8 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sat, 28 Jan 2023 20:57:04 +0200 Subject: [PATCH 010/100] Updated example that daisy-chains the concatenation operator --- examples/self_join.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/self_join.cpp b/examples/self_join.cpp index 56a154aa6..224c4b73e 100644 --- a/examples/self_join.cpp +++ b/examples/self_join.cpp @@ -201,8 +201,8 @@ int main() { // ON m.ReportsTo = employees.EmployeeId using als = alias_m; auto firstNames = storage.select( - columns(c(alias_column(&Employee::firstName)) || " " || c(alias_column(&Employee::lastName)), - c(&Employee::firstName) || " " || c(&Employee::lastName)), + columns(alias_column(&Employee::firstName) || c(" ") || alias_column(&Employee::lastName), + &Employee::firstName || c(" ") || &Employee::lastName), inner_join(on(alias_column(&Employee::reportsTo) == c(&Employee::employeeId)))); cout << "firstNames count = " << firstNames.size() << endl; for(auto& row: firstNames) { @@ -221,8 +221,8 @@ int main() { // ON emp.ReportsTo = employees.EmployeeId using als = custom_alias; auto firstNames = storage.select( - columns(c(alias_column(&Employee::firstName)) || " " || c(alias_column(&Employee::lastName)), - c(&Employee::firstName) || " " || c(&Employee::lastName)), + columns(alias_column(&Employee::firstName) || c(" ") || alias_column(&Employee::lastName), + &Employee::firstName || c(" ") || &Employee::lastName), inner_join(on(alias_column(&Employee::reportsTo) == c(&Employee::employeeId)))); cout << "firstNames count = " << firstNames.size() << endl; for(auto& row: firstNames) { From 7eba3986cd99fa33ca04d2d2775b8e89bce91f95 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 30 Jan 2023 17:43:16 +0200 Subject: [PATCH 011/100] EXISTS must use parentheses --- dev/statement_serializer.h | 5 +++-- include/sqlite_orm/sqlite_orm.h | 5 +++-- tests/statement_serializer_tests/select_constraints.cpp | 7 +++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 28ae2b8f4..a24ece00f 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -767,8 +767,9 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << "EXISTS "; - ss << serialize(statement.expression, context); + auto newContext = context; + newContext.use_parentheses = true; + ss << "EXISTS " << serialize(statement.expression, newContext); return ss.str(); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 976160358..ed4736ba2 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -15777,8 +15777,9 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << "EXISTS "; - ss << serialize(statement.expression, context); + auto newContext = context; + newContext.use_parentheses = true; + ss << "EXISTS " << serialize(statement.expression, newContext); return ss.str(); } }; diff --git a/tests/statement_serializer_tests/select_constraints.cpp b/tests/statement_serializer_tests/select_constraints.cpp index 29861b4d6..939a99068 100644 --- a/tests/statement_serializer_tests/select_constraints.cpp +++ b/tests/statement_serializer_tests/select_constraints.cpp @@ -86,5 +86,12 @@ TEST_CASE("statement_serializer select constraints") { value = serialize(expression, context); expected = R"(EVEN("id"))"; } + SECTION("exists") { + // EXISTS must use parentheses in a new context + context.use_parentheses = false; + auto expression = exists(select(1)); + value = serialize(expression, context); + expected = "EXISTS (SELECT 1)"; + } REQUIRE(value == expected); } From 95c3e9428e02c1df53b9fc97e18abb2fbd4b83d2 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 31 Jan 2023 20:13:44 -0600 Subject: [PATCH 012/100] fixed catch include path --- tests/statement_serializer_tests/ast/set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/statement_serializer_tests/ast/set.cpp b/tests/statement_serializer_tests/ast/set.cpp index c3c94fa80..cf7dc3667 100644 --- a/tests/statement_serializer_tests/ast/set.cpp +++ b/tests/statement_serializer_tests/ast/set.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace sqlite_orm; From 81e28bc811cb105c6307e73091ed39f9ecbcde6f Mon Sep 17 00:00:00 2001 From: liushuai <770722922@qq.com> Date: Tue, 31 Jan 2023 16:45:35 +0800 Subject: [PATCH 013/100] Fix warning of std::move --- dev/ast/group_by.h | 2 +- dev/ast/upsert_clause.h | 4 ++-- dev/backup.h | 4 ++-- dev/column.h | 10 +++++----- dev/column_names_getter.h | 2 +- dev/conditions.h | 6 +++--- dev/connection_holder.h | 2 +- dev/constraints.h | 6 +++--- dev/function.h | 12 ++++++------ dev/implementations/table_definitions.h | 2 +- dev/index.h | 8 ++++---- dev/indexed_column.h | 2 +- dev/iterator.h | 2 +- dev/pragma.h | 8 ++++---- dev/prepared_statement.h | 24 ++++++++++++------------ dev/select_constraints.h | 4 ++-- dev/statement_serializer.h | 4 ++-- dev/storage.h | 22 +++++++++++----------- dev/storage_base.h | 16 ++++++++-------- dev/table.h | 6 +++--- dev/table_info.h | 4 ++-- dev/table_name_collector.h | 8 ++++---- dev/transaction_guard.h | 4 ++-- dev/triggers.h | 12 ++++++------ dev/tuple_helper/tuple_iteration.h | 6 +++--- dev/util.h | 6 +++--- dev/values.h | 2 +- dev/view.h | 2 +- 28 files changed, 95 insertions(+), 95 deletions(-) diff --git a/dev/ast/group_by.h b/dev/ast/group_by.h index e8f10c763..0ad6bd31a 100644 --- a/dev/ast/group_by.h +++ b/dev/ast/group_by.h @@ -29,7 +29,7 @@ namespace sqlite_orm { template group_by_with_having having(T expression) { - return {move(this->args), std::move(expression)}; + return {std::move(this->args), std::move(expression)}; } }; diff --git a/dev/ast/upsert_clause.h b/dev/ast/upsert_clause.h index f46a293b6..d1a6d5714 100644 --- a/dev/ast/upsert_clause.h +++ b/dev/ast/upsert_clause.h @@ -19,12 +19,12 @@ namespace sqlite_orm { args_tuple args; upsert_clause> do_nothing() { - return {move(this->args), {}}; + return {std::move(this->args), {}}; } template upsert_clause> do_update(ActionsArgs... actions) { - return {move(this->args), {std::make_tuple(std::forward(actions)...)}}; + return {std::move(this->args), {std::make_tuple(std::forward(actions)...)}}; } }; diff --git a/dev/backup.h b/dev/backup.h index 1bc1af70e..73b62250e 100644 --- a/dev/backup.h +++ b/dev/backup.h @@ -26,14 +26,14 @@ namespace sqlite_orm { const std::string& zSourceName, std::unique_ptr holder_) : handle(sqlite3_backup_init(to_.get(), zDestName.c_str(), from_.get(), zSourceName.c_str())), - holder(move(holder_)), to(to_), from(from_) { + holder(std::move(holder_)), to(to_), from(from_) { if(!this->handle) { throw std::system_error{orm_error_code::failed_to_init_a_backup}; } } backup_t(backup_t&& other) : - handle(std::exchange(other.handle, nullptr)), holder(move(other.holder)), to(other.to), + handle(std::exchange(other.handle, nullptr)), holder(std::move(other.holder)), to(other.to), from(other.from) {} ~backup_t() { diff --git a/dev/column.h b/dev/column.h index abdfe1069..458f87182 100644 --- a/dev/column.h +++ b/dev/column.h @@ -106,8 +106,8 @@ namespace sqlite_orm { struct column_t : column_identifier, column_field, column_constraints { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED column_t(std::string name, G memberPointer, S setter, std::tuple op) : - column_identifier{move(name)}, column_field{memberPointer, setter}, column_constraints{ - move(op)} {} + column_identifier{std::move(name)}, column_field{memberPointer, setter}, column_constraints{ + std::move(op)} {} #endif }; @@ -144,7 +144,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, M m, Op... constraints) { static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), m, {}, std::make_tuple(constraints...)}); } /** @@ -160,7 +160,7 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), getter, setter, std::make_tuple(constraints...)}); } /** @@ -177,6 +177,6 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), getter, setter, std::make_tuple(constraints...)}); } } diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index ce1881991..31868e249 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -28,7 +28,7 @@ namespace sqlite_orm { newContext.skip_table_name = false; auto columnName = serialize(t, newContext); if(!columnName.empty()) { - return {move(columnName)}; + return {std::move(columnName)}; } else { throw std::system_error{orm_error_code::column_not_found}; } diff --git a/dev/conditions.h b/dev/conditions.h index f59f75c6c..2707d6bb6 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -426,7 +426,7 @@ namespace sqlite_orm { order_by_base() = default; order_by_base(decltype(asc_desc) asc_desc_, decltype(_collate_argument) _collate_argument_) : - asc_desc(asc_desc_), _collate_argument(move(_collate_argument_)) {} + asc_desc(asc_desc_), _collate_argument(std::move(_collate_argument_)) {} #endif }; @@ -508,7 +508,7 @@ namespace sqlite_orm { std::string name; dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) : - order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {} + order_by_base{asc_desc_, std::move(collate_argument_)}, name(std::move(name_)) {} }; /** @@ -527,7 +527,7 @@ namespace sqlite_orm { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); - this->entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); + this->entries.emplace_back(std::move(columnName), order_by.asc_desc, std::move(order_by._collate_argument)); } const_iterator begin() const { diff --git a/dev/connection_holder.h b/dev/connection_holder.h index b0f61c1f6..0631adf81 100644 --- a/dev/connection_holder.h +++ b/dev/connection_holder.h @@ -12,7 +12,7 @@ namespace sqlite_orm { struct connection_holder { - connection_holder(std::string filename_) : filename(move(filename_)) {} + connection_holder(std::string filename_) : filename(std::move(filename_)) {} void retain() { if(1 == ++this->_retain_count) { diff --git a/dev/constraints.h b/dev/constraints.h index 5e7570e76..37ef84039 100644 --- a/dev/constraints.h +++ b/dev/constraints.h @@ -70,7 +70,7 @@ namespace sqlite_orm { columns_tuple columns; - primary_key_t(decltype(columns) columns) : columns(move(columns)) {} + primary_key_t(decltype(columns) columns) : columns(std::move(columns)) {} self asc() const { auto res = *this; @@ -139,7 +139,7 @@ namespace sqlite_orm { columns_tuple columns; - unique_t(columns_tuple columns_) : columns(move(columns_)) {} + unique_t(columns_tuple columns_) : columns(std::move(columns_)) {} }; /** @@ -314,7 +314,7 @@ namespace sqlite_orm { static_assert(!std::is_same::value, "All references must have the same type"); foreign_key_t(columns_type columns_, references_type references_) : - columns(move(columns_)), references(move(references_)), + columns(std::move(columns_)), references(std::move(references_)), on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {} foreign_key_t(const self& other) : diff --git a/dev/function.h b/dev/function.h index 0462c22b3..ca851f203 100644 --- a/dev/function.h +++ b/dev/function.h @@ -37,8 +37,8 @@ namespace sqlite_orm { decltype(argumentsCount) argumentsCount_, decltype(create) create_, decltype(destroy) destroy_) : - name(move(name_)), - argumentsCount(argumentsCount_), create(move(create_)), destroy(destroy_) {} + name(std::move(name_)), + argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} #endif }; @@ -50,8 +50,8 @@ namespace sqlite_orm { decltype(create) create_, decltype(run) run_, decltype(destroy) destroy_) : - user_defined_function_base{move(name_), argumentsCount_, move(create_), destroy_}, - run(move(run_)) {} + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + run(std::move(run_)) {} }; struct user_defined_aggregate_function_t : user_defined_function_base { @@ -64,8 +64,8 @@ namespace sqlite_orm { decltype(step) step_, decltype(finalCall) finalCall_, decltype(destroy) destroy_) : - user_defined_function_base{move(name_), argumentsCount_, move(create_), destroy_}, - step(move(step_)), finalCall(move(finalCall_)) {} + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + step(std::move(step_)), finalCall(std::move(finalCall_)) {} }; template diff --git a/dev/implementations/table_definitions.h b/dev/implementations/table_definitions.h index 30a2dcabc..9b0b2e996 100644 --- a/dev/implementations/table_definitions.h +++ b/dev/implementations/table_definitions.h @@ -22,7 +22,7 @@ namespace sqlite_orm { using field_type = field_type_t>; std::string dft; if(auto d = column.default_value()) { - dft = move(*d); + dft = std::move(*d); } res.emplace_back(-1, column.name, diff --git a/dev/index.h b/dev/index.h index b0027bf95..39b6c2eb8 100644 --- a/dev/index.h +++ b/dev/index.h @@ -18,7 +18,7 @@ namespace sqlite_orm { bool unique = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - index_base(std::string name, bool unique) : name{move(name)}, unique{unique} {} + index_base(std::string name, bool unique) : name{std::move(name)}, unique{unique} {} #endif }; @@ -30,7 +30,7 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED index_t(std::string name_, bool unique_, elements_type elements_) : - index_base{move(name_), unique_}, elements(move(elements_)) {} + index_base{std::move(name_), unique_}, elements(std::move(elements_)) {} #endif elements_type elements; @@ -44,7 +44,7 @@ namespace sqlite_orm { static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template @@ -66,6 +66,6 @@ namespace sqlite_orm { static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } } diff --git a/dev/indexed_column.h b/dev/indexed_column.h index 53a908956..e8bd3f1d4 100644 --- a/dev/indexed_column.h +++ b/dev/indexed_column.h @@ -25,7 +25,7 @@ namespace sqlite_orm { indexed_column_t collate(std::string name) { auto res = std::move(*this); - res._collation_name = move(name); + res._collation_name = std::move(name); return res; } diff --git a/dev/iterator.h b/dev/iterator.h index 4376f82d0..932087eae 100644 --- a/dev/iterator.h +++ b/dev/iterator.h @@ -65,7 +65,7 @@ namespace sqlite_orm { iterator_t(){}; - iterator_t(statement_finalizer stmt_, view_type& view_) : stmt{move(stmt_)}, view{&view_} { + iterator_t(statement_finalizer stmt_, view_type& view_) : stmt{std::move(stmt_)}, view{&view_} { next(); } diff --git a/dev/pragma.h b/dev/pragma.h index 4c1ab05a7..2b957b6db 100644 --- a/dev/pragma.h +++ b/dev/pragma.h @@ -30,7 +30,7 @@ namespace sqlite_orm { res.reserve(argc); for(decltype(argc) i = 0; i < argc; ++i) { auto rowString = row_extractor().extract(argv[i]); - res.push_back(move(rowString)); + res.push_back(std::move(rowString)); } return 0; } @@ -38,7 +38,7 @@ namespace sqlite_orm { struct pragma_t { using get_connection_t = std::function; - pragma_t(get_connection_t get_connection_) : get_connection(move(get_connection_)) {} + pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} void busy_timeout(int value) { this->set_pragma("busy_timeout", value); @@ -139,7 +139,7 @@ namespace sqlite_orm { ++index; auto pk = std::atoi(argv[index++]); auto hidden = std::atoi(argv[index++]); - res.emplace_back(cid, move(name), move(type), notnull, move(dflt_value), pk, hidden); + res.emplace_back(cid, std::move(name), std::move(type), notnull, std::move(dflt_value), pk, hidden); } return 0; }, @@ -169,7 +169,7 @@ namespace sqlite_orm { std::string dflt_value = argv[index] ? argv[index] : ""; ++index; auto pk = std::atoi(argv[index++]); - res.emplace_back(cid, move(name), move(type), notnull, move(dflt_value), pk); + res.emplace_back(cid, std::move(name), std::move(type), notnull, std::move(dflt_value), pk); } return 0; }, diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index aa4e4e8da..b73853fef 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -593,7 +593,7 @@ namespace sqlite_orm { template internal::remove_t remove(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } /** @@ -616,7 +616,7 @@ namespace sqlite_orm { template internal::get_t get(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } /** @@ -627,7 +627,7 @@ namespace sqlite_orm { template internal::get_pointer_t get_pointer(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -639,7 +639,7 @@ namespace sqlite_orm { template internal::get_optional_t get_optional(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED @@ -653,7 +653,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -666,7 +666,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -680,7 +680,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -693,7 +693,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; - return {std::move(set), move(conditions)}; + return {std::move(set), std::move(conditions)}; } /** @@ -706,7 +706,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** * Create a get all pointer statement. @@ -719,7 +719,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -733,7 +733,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -747,7 +747,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 211e58a53..ce89f5d37 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -70,7 +70,7 @@ namespace sqlite_orm { static constexpr int count = std::tuple_size::value; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - columns_t(columns_type columns) : columns{move(columns)} {} + columns_t(columns_type columns) : columns{std::move(columns)} {} #endif }; @@ -136,7 +136,7 @@ namespace sqlite_orm { bool highest_level = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - select_t(return_type col, conditions_type conditions) : col{std::move(col)}, conditions{move(conditions)} {} + select_t(return_type col, conditions_type conditions) : col{std::move(col)}, conditions{std::move(conditions)} {} #endif }; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 2c68eb539..875b0fd46 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1603,10 +1603,10 @@ namespace sqlite_orm { auto newContext = context; newContext.use_parentheses = false; auto whereString = serialize(value, newContext); - columnNames.push_back(move(whereString)); + columnNames.push_back(std::move(whereString)); } else { auto columnName = serialize(value, context); - whereString = move(columnName); + whereString = std::move(columnName); } }); ss << " (" << streaming_serialized(columnNames) << ")"; diff --git a/dev/storage.h b/dev/storage.h index 8026e2a91..f67ecf04b 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -79,7 +79,7 @@ namespace sqlite_orm { * @param dbObjects db_objects_tuple */ storage_t(std::string filename, db_objects_type dbObjects) : - storage_base{move(filename), foreign_keys_count(dbObjects)}, db_objects{std::move(dbObjects)} {} + storage_base{std::move(filename), foreign_keys_count(dbObjects)}, db_objects{std::move(dbObjects)} {} private: db_objects_type db_objects; @@ -156,7 +156,7 @@ namespace sqlite_orm { ss << suffix << std::flush; auto anotherBackupTableName = backupTableName + ss.str(); if(!this->table_exists(db, anotherBackupTableName)) { - backupTableName = move(anotherBackupTableName); + backupTableName = std::move(anotherBackupTableName); break; } ++suffix; @@ -273,12 +273,12 @@ namespace sqlite_orm { this->assert_mapped_type(); std::vector rows; if(y) { - rows = this->select(sqlite_orm::group_concat(m, move(*y)), std::forward(args)...); + rows = this->select(sqlite_orm::group_concat(m, std::move(*y)), std::forward(args)...); } else { rows = this->select(sqlite_orm::group_concat(m), std::forward(args)...); } if(!rows.empty()) { - return move(rows.front()); + return std::move(rows.front()); } else { return {}; } @@ -476,7 +476,7 @@ namespace sqlite_orm { template std::string group_concat(F O::*m, std::string y, Args&&... args) { return this->group_concat_internal(m, - std::make_unique(move(y)), + std::make_unique(std::move(y)), std::forward(args)...); } @@ -488,7 +488,7 @@ namespace sqlite_orm { } else { str = std::make_unique(); } - return this->group_concat_internal(m, move(str), std::forward(args)...); + return this->group_concat_internal(m, std::move(str), std::forward(args)...); } /** @@ -789,7 +789,7 @@ namespace sqlite_orm { void rename_table(std::string name) { this->assert_mapped_type(); auto& table = this->get_table(); - table.name = move(name); + table.name = std::move(name); } using storage_base::rename_table; @@ -1317,7 +1317,7 @@ namespace sqlite_orm { if(!res.has_value()) { throw std::system_error{orm_error_code::not_found}; } - return move(res).value(); + return std::move(res).value(); #else auto& table = this->get_table(); auto stepRes = sqlite3_step(stmt); @@ -1396,7 +1396,7 @@ namespace sqlite_orm { auto obj = std::make_unique(); object_from_column_builder builder{*obj, stmt}; table.for_each_column(builder); - res.push_back(move(obj)); + res.push_back(std::move(obj)); }); return res; } @@ -1413,7 +1413,7 @@ namespace sqlite_orm { auto obj = std::make_optional(); object_from_column_builder builder{*obj, stmt}; table.for_each_column(builder); - res.push_back(move(obj)); + res.push_back(std::move(obj)); }); return res; } @@ -1426,7 +1426,7 @@ namespace sqlite_orm { */ template internal::storage_t make_storage(std::string filename, DBO... dbObjects) { - return {move(filename), internal::db_objects_tuple{std::forward(dbObjects)...}}; + return {std::move(filename), internal::db_objects_tuple{std::forward(dbObjects)...}}; } /** diff --git a/dev/storage_base.h b/dev/storage_base.h index 6ccd7d7a3..6d43e1047 100644 --- a/dev/storage_base.h +++ b/dev/storage_base.h @@ -243,7 +243,7 @@ namespace sqlite_orm { ? -1 : int(std::tuple_size::value); this->scalarFunctions.emplace_back(new user_defined_scalar_function_t{ - move(name), + std::move(name), argsCount, []() -> int* { return (int*)(new F()); @@ -304,7 +304,7 @@ namespace sqlite_orm { ? -1 : int(std::tuple_size::value); this->aggregateFunctions.emplace_back(new user_defined_aggregate_function_t{ - move(name), + std::move(name), argsCount, /* create = */ []() -> int* { @@ -315,7 +315,7 @@ namespace sqlite_orm { auto& function = *static_cast(functionVoidPointer); args_tuple argsTuple; values_to_tuple{}(values, argsTuple, argsCount); - call(function, &F::step, move(argsTuple)); + call(function, &F::step, std::move(argsTuple)); }, /* finalCall = */ [](sqlite3_context* context, void* functionVoidPointer) { @@ -364,7 +364,7 @@ namespace sqlite_orm { }; std::stringstream ss; ss << C::name() << std::flush; - this->create_collation(ss.str(), move(func)); + this->create_collation(ss.str(), std::move(func)); } void create_collation(const std::string& name, collating_function f) { @@ -454,7 +454,7 @@ namespace sqlite_orm { backup_t make_backup_to(const std::string& filename) { auto holder = std::make_unique(filename); connection_ref conRef{*holder}; - return {conRef, "main", this->get_connection(), "main", move(holder)}; + return {conRef, "main", this->get_connection(), "main", std::move(holder)}; } backup_t make_backup_to(storage_base& other) { @@ -464,7 +464,7 @@ namespace sqlite_orm { backup_t make_backup_from(const std::string& filename) { auto holder = std::make_unique(filename); connection_ref conRef{*holder}; - return {this->get_connection(), "main", conRef, "main", move(holder)}; + return {this->get_connection(), "main", conRef, "main", std::move(holder)}; } backup_t make_backup_from(storage_base& other) { @@ -493,7 +493,7 @@ namespace sqlite_orm { } int busy_handler(std::function handler) { - _busy_handler = move(handler); + _busy_handler = std::move(handler); if(this->is_opened()) { if(_busy_handler) { return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); @@ -510,7 +510,7 @@ namespace sqlite_orm { pragma(std::bind(&storage_base::get_connection, this)), limit(std::bind(&storage_base::get_connection, this)), inMemory(filename.empty() || filename == ":memory:"), - connection(std::make_unique(move(filename))), + connection(std::make_unique(std::move(filename))), cachedForeignKeysCount(foreignKeysCount) { if(this->inMemory) { this->connection->retain(); diff --git a/dev/table.h b/dev/table.h index bc5fee824..e19fa235c 100644 --- a/dev/table.h +++ b/dev/table.h @@ -48,7 +48,7 @@ namespace sqlite_orm { elements_type elements; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - table_t(std::string name_, elements_type elements_) : basic_table{move(name_)}, elements{move(elements_)} {} + table_t(std::string name_, elements_type elements_) : basic_table{std::move(name_)}, elements{std::move(elements_)} {} #endif table_t without_rowid() const { @@ -291,7 +291,7 @@ namespace sqlite_orm { template>::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {std::move(name), std::make_tuple(std::forward(args)...)}); } /** @@ -302,6 +302,6 @@ namespace sqlite_orm { template internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {std::move(name), std::make_tuple(std::forward(args)...)}); } } diff --git a/dev/table_info.h b/dev/table_info.h index 5abeb7bef..4fa8bdfe3 100644 --- a/dev/table_info.h +++ b/dev/table_info.h @@ -22,7 +22,7 @@ namespace sqlite_orm { decltype(dflt_value) dflt_value_, decltype(pk) pk_) : cid(cid_), - name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), pk(pk_) {} + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), pk(pk_) {} #endif }; @@ -44,7 +44,7 @@ namespace sqlite_orm { decltype(pk) pk_, decltype(hidden) hidden_) : cid(cid_), - name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), pk(pk_), hidden{hidden_} {} #endif }; diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index 628f5faa0..a5e6334ad 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -24,7 +24,7 @@ namespace sqlite_orm { table_name_collector() = default; - table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} + table_name_collector(find_table_name_t find_table_name) : find_table_name{std::move(find_table_name)} {} template table_name_set operator()(const T&) const { @@ -33,7 +33,7 @@ namespace sqlite_orm { template void operator()(F O::*, std::string alias = {}) const { - table_names.emplace(this->find_table_name(typeid(O)), move(alias)); + table_names.emplace(this->find_table_name(typeid(O)), std::move(alias)); } template @@ -50,7 +50,7 @@ namespace sqlite_orm { void operator()(const count_asterisk_t&) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { - table_names.emplace(move(tableName), ""); + table_names.emplace(std::move(tableName), ""); } } @@ -65,7 +65,7 @@ namespace sqlite_orm { static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); auto tableName = this->find_table_name(typeid(type_t)); - table_names.emplace(move(tableName), alias_extractor::get()); + table_names.emplace(std::move(tableName), alias_extractor::get()); } template diff --git a/dev/transaction_guard.h b/dev/transaction_guard.h index b6cd33274..3ad6d7785 100644 --- a/dev/transaction_guard.h +++ b/dev/transaction_guard.h @@ -29,11 +29,11 @@ namespace sqlite_orm { std::function commit_func_, std::function rollback_func_) : connection(std::move(connection_)), - commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} + commit_func(std::move(commit_func_)), rollback_func(std::move(rollback_func_)) {} transaction_guard_t(transaction_guard_t&& other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), - commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), + commit_func(std::move(other.commit_func)), rollback_func(std::move(other.rollback_func)), gotta_fire(other.gotta_fire) { other.gotta_fire = false; } diff --git a/dev/triggers.h b/dev/triggers.h index f7b95da08..95f4c63ed 100644 --- a/dev/triggers.h +++ b/dev/triggers.h @@ -74,7 +74,7 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED trigger_t(std::string name, T trigger_base, elements_type statements) : - base_trigger{move(name)}, base(std::move(trigger_base)), elements(move(statements)) {} + base_trigger{std::move(name)}, base(std::move(trigger_base)), elements(std::move(statements)) {} #endif }; @@ -206,7 +206,7 @@ namespace sqlite_orm { std::string message; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - raise_t(type_t type, std::string message) : type{type}, message{move(message)} {} + raise_t(type_t type, std::string message) : type{type}, message{std::move(message)} {} #endif }; @@ -252,26 +252,26 @@ namespace sqlite_orm { * RAISE(ROLLBACK, %message%) expression used within TRIGGER expressions */ inline internal::raise_t raise_rollback(std::string message) { - return {internal::raise_t::type_t::rollback, move(message)}; + return {internal::raise_t::type_t::rollback, std::move(message)}; } /** * RAISE(ABORT, %message%) expression used within TRIGGER expressions */ inline internal::raise_t raise_abort(std::string message) { - return {internal::raise_t::type_t::abort, move(message)}; + return {internal::raise_t::type_t::abort, std::move(message)}; } /** * RAISE(FAIL, %message%) expression used within TRIGGER expressions */ inline internal::raise_t raise_fail(std::string message) { - return {internal::raise_t::type_t::fail, move(message)}; + return {internal::raise_t::type_t::fail, std::move(message)}; } template internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(part.base), std::move(part.statements)}); } inline internal::trigger_timing_t before() { diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index 7b4a23ea5..cb37f7cbe 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -15,18 +15,18 @@ namespace sqlite_orm { // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer template auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { - return (f.*functionPointer)(std::get(move(t))...); + return (f.*functionPointer)(std::get(std::move(t))...); } template auto call(Function& f, FunctionPointer functionPointer, Tuple t) { constexpr size_t size = std::tuple_size::value; - return call_impl(f, functionPointer, move(t), std::make_index_sequence{}); + return call_impl(f, functionPointer, std::move(t), std::make_index_sequence{}); } template auto call(Function& f, Tuple t) { - return call(f, &Function::operator(), move(t)); + return call(f, &Function::operator(), std::move(t)); } #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) diff --git a/dev/util.h b/dev/util.h index d8e034dfb..f162eeda9 100644 --- a/dev/util.h +++ b/dev/util.h @@ -27,7 +27,7 @@ namespace sqlite_orm { */ inline std::string quote_string_literal(std::string v) { constexpr char quoteChar = '\''; - return quoteChar + sql_escape(move(v), quoteChar) + quoteChar; + return quoteChar + sql_escape(std::move(v), quoteChar) + quoteChar; } /** @@ -36,7 +36,7 @@ namespace sqlite_orm { */ inline std::string quote_blob_literal(std::string v) { constexpr char quoteChar = '\''; - return std::string{char('x'), quoteChar} + move(v) + quoteChar; + return std::string{char('x'), quoteChar} + std::move(v) + quoteChar; } /** @@ -45,7 +45,7 @@ namespace sqlite_orm { */ inline std::string quote_identifier(std::string identifier) { constexpr char quoteChar = '"'; - return quoteChar + sql_escape(move(identifier), quoteChar) + quoteChar; + return quoteChar + sql_escape(std::move(identifier), quoteChar) + quoteChar; } namespace internal { diff --git a/dev/values.h b/dev/values.h index a42b52e68..42229dc65 100644 --- a/dev/values.h +++ b/dev/values.h @@ -38,7 +38,7 @@ namespace sqlite_orm { template internal::dynamic_values_t values(std::vector vector) { - return {{move(vector)}}; + return {{std::move(vector)}}; } } diff --git a/dev/view.h b/dev/view.h index f96d6ff23..7a7d7f4f5 100644 --- a/dev/view.h +++ b/dev/view.h @@ -55,7 +55,7 @@ namespace sqlite_orm { statement_finalizer stmt{prepare_stmt(this->connection.get(), serialize(this->args, context))}; iterate_ast(this->args.conditions, conditional_binder{stmt.get()}); - return {move(stmt), *this}; + return {std::move(stmt), *this}; } iterator_t end() { From 5e6ccf72d000eb772d04d4d231952a250cbeada8 Mon Sep 17 00:00:00 2001 From: liushuai <770722922@qq.com> Date: Tue, 31 Jan 2023 22:23:41 +0800 Subject: [PATCH 014/100] Format code with clang-format --- dev/column.h | 10 ++++++---- dev/conditions.h | 4 +++- dev/pragma.h | 8 +++++++- dev/select_constraints.h | 3 ++- dev/storage.h | 6 +++--- dev/table.h | 3 ++- dev/table_info.h | 3 ++- dev/triggers.h | 3 ++- 8 files changed, 27 insertions(+), 13 deletions(-) diff --git a/dev/column.h b/dev/column.h index 458f87182..61f744800 100644 --- a/dev/column.h +++ b/dev/column.h @@ -106,8 +106,8 @@ namespace sqlite_orm { struct column_t : column_identifier, column_field, column_constraints { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED column_t(std::string name, G memberPointer, S setter, std::tuple op) : - column_identifier{std::move(name)}, column_field{memberPointer, setter}, column_constraints{ - std::move(op)} {} + column_identifier{std::move(name)}, column_field{memberPointer, setter}, + column_constraints{std::move(op)} {} #endif }; @@ -160,7 +160,8 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), getter, setter, std::make_tuple(constraints...)}); } /** @@ -177,6 +178,7 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), getter, setter, std::make_tuple(constraints...)}); } } diff --git a/dev/conditions.h b/dev/conditions.h index 2707d6bb6..a97792bcb 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -527,7 +527,9 @@ namespace sqlite_orm { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); - this->entries.emplace_back(std::move(columnName), order_by.asc_desc, std::move(order_by._collate_argument)); + this->entries.emplace_back(std::move(columnName), + order_by.asc_desc, + std::move(order_by._collate_argument)); } const_iterator begin() const { diff --git a/dev/pragma.h b/dev/pragma.h index 2b957b6db..ba1b03e88 100644 --- a/dev/pragma.h +++ b/dev/pragma.h @@ -139,7 +139,13 @@ namespace sqlite_orm { ++index; auto pk = std::atoi(argv[index++]); auto hidden = std::atoi(argv[index++]); - res.emplace_back(cid, std::move(name), std::move(type), notnull, std::move(dflt_value), pk, hidden); + res.emplace_back(cid, + std::move(name), + std::move(type), + notnull, + std::move(dflt_value), + pk, + hidden); } return 0; }, diff --git a/dev/select_constraints.h b/dev/select_constraints.h index ce89f5d37..9d18ce778 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -136,7 +136,8 @@ namespace sqlite_orm { bool highest_level = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - select_t(return_type col, conditions_type conditions) : col{std::move(col)}, conditions{std::move(conditions)} {} + select_t(return_type col, conditions_type conditions) : + col{std::move(col)}, conditions{std::move(conditions)} {} #endif }; diff --git a/dev/storage.h b/dev/storage.h index f67ecf04b..9e37b6752 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -262,7 +262,8 @@ namespace sqlite_orm { template void update_all(S set, Wargs... wh) { - static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); + static_assert(internal::is_set::value, + "first argument in update_all can be either set or dynamic_set"); auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); this->execute(statement); } @@ -1043,8 +1044,7 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - prepared_statement_t> - prepare(update_all_t upd) { + prepared_statement_t> prepare(update_all_t upd) { return prepare_impl>(std::move(upd)); } diff --git a/dev/table.h b/dev/table.h index e19fa235c..3d1b6cdbb 100644 --- a/dev/table.h +++ b/dev/table.h @@ -48,7 +48,8 @@ namespace sqlite_orm { elements_type elements; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - table_t(std::string name_, elements_type elements_) : basic_table{std::move(name_)}, elements{std::move(elements_)} {} + table_t(std::string name_, elements_type elements_) : + basic_table{std::move(name_)}, elements{std::move(elements_)} {} #endif table_t without_rowid() const { diff --git a/dev/table_info.h b/dev/table_info.h index 4fa8bdfe3..087a3c6f2 100644 --- a/dev/table_info.h +++ b/dev/table_info.h @@ -22,7 +22,8 @@ namespace sqlite_orm { decltype(dflt_value) dflt_value_, decltype(pk) pk_) : cid(cid_), - name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), pk(pk_) {} + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), + pk(pk_) {} #endif }; diff --git a/dev/triggers.h b/dev/triggers.h index 95f4c63ed..c85e65a13 100644 --- a/dev/triggers.h +++ b/dev/triggers.h @@ -271,7 +271,8 @@ namespace sqlite_orm { template internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(part.base), std::move(part.statements)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::move(part.base), std::move(part.statements)}); } inline internal::trigger_timing_t before() { From a443cbf9d9d581d57cdba029d36a5feeb3b765d4 Mon Sep 17 00:00:00 2001 From: liushuai <770722922@qq.com> Date: Wed, 1 Feb 2023 23:18:02 +0800 Subject: [PATCH 015/100] Format other code --- include/sqlite_orm/sqlite_orm.h | 327 +++++++++---------------------- tests/storage_non_crud_tests.cpp | 10 +- 2 files changed, 96 insertions(+), 241 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index c5fda57b6..978bc38e3 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,7 +16,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 @@ -35,7 +34,6 @@ using std::nullptr_t; // #include "cxx_core_features.h" - #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -109,7 +107,6 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" - #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -139,8 +136,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif - - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -282,7 +277,6 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } - namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -511,10 +505,8 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -523,7 +515,6 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif - // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -560,7 +551,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -659,7 +649,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. @@ -688,7 +677,6 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { namespace mpl { @@ -969,7 +957,6 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" - namespace sqlite_orm { namespace internal { @@ -999,7 +986,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" - #include // std::is_same #include @@ -1007,7 +993,6 @@ namespace sqlite_orm { // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { /* @@ -1055,7 +1040,6 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" - #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1063,7 +1047,6 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" @@ -1132,7 +1115,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1224,10 +1206,8 @@ namespace sqlite_orm { // #include "table_type_of.h" - // #include "indexed_column.h" - #include // std::string #include // std::move @@ -1235,7 +1215,6 @@ namespace sqlite_orm { // #include "ast/where.h" - #include // std::false_type, std::true_type #include // std::move @@ -1245,13 +1224,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 @@ -1274,7 +1250,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1320,7 +1295,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1384,7 +1358,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -1426,7 +1399,6 @@ namespace sqlite_orm { // #include "type_printer.h" - namespace sqlite_orm { namespace internal { @@ -1973,10 +1945,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 { /** @@ -2016,10 +1986,8 @@ namespace sqlite_orm { #include // std::move // #include "functional/cxx_optional.h" - // #include "tags.h" - namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -2033,7 +2001,6 @@ namespace sqlite_orm { // #include "serialize_result_type.h" - namespace sqlite_orm { namespace internal { @@ -2322,14 +2289,12 @@ namespace sqlite_orm { // #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 @@ -2421,7 +2386,6 @@ namespace sqlite_orm { // #include "constraints.h" - namespace sqlite_orm { namespace internal { @@ -2600,14 +2564,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 { /** @@ -2771,7 +2733,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -2806,7 +2767,6 @@ namespace sqlite_orm { // #include "serializer_context.h" - namespace sqlite_orm { namespace internal { @@ -2848,17 +2808,14 @@ namespace sqlite_orm { // #include "expression.h" - #include #include // std::move, std::forward // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "operators.h" - namespace sqlite_orm { namespace internal { @@ -2937,7 +2894,6 @@ namespace sqlite_orm { // #include "literal.h" - namespace sqlite_orm { namespace internal { @@ -2954,7 +2910,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -4382,7 +4337,6 @@ namespace sqlite_orm { // #include "conditions.h" - namespace sqlite_orm { namespace internal { @@ -4496,7 +4450,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4542,10 +4495,8 @@ namespace sqlite_orm { // #include "ast/into.h" - // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -4564,7 +4515,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { using int64 = sqlite_int64; @@ -6668,7 +6618,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" @@ -6683,14 +6632,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 { @@ -6760,7 +6707,6 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { @@ -7217,7 +7163,6 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" - namespace sqlite_orm { struct table_info { @@ -7274,7 +7219,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) @@ -7307,7 +7251,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : base{std::move(trigger_base)}, statements{std::make_tuple(std::forward(statements)...)} {} - partial_trigger_t &end() { + partial_trigger_t& end() { return *this; } }; @@ -7376,7 +7320,7 @@ namespace sqlite_orm { trigger_base_t(trigger_type_base type_base_) : type_base(std::move(type_base_)) {} - trigger_base_t &for_each_row() { + trigger_base_t& for_each_row() { this->do_for_each_row = true; return *this; } @@ -7537,7 +7481,7 @@ namespace sqlite_orm { } template - internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t &part) { + internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); } @@ -7597,7 +7541,6 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" - #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7607,7 +7550,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7849,7 +7791,6 @@ namespace sqlite_orm { #endif } - namespace sqlite_orm { /** @@ -8046,7 +7987,6 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8125,7 +8065,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { /** @@ -8489,7 +8428,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8566,7 +8504,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -8891,7 +8828,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { /** @@ -9089,7 +9025,6 @@ namespace sqlite_orm { // #include "table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -9156,7 +9091,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { namespace internal { @@ -9272,7 +9206,6 @@ namespace sqlite_orm { // #include "storage_traits.h" - #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -9281,12 +9214,10 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" - #include // std::tuple // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { @@ -9312,7 +9243,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - #include // std::true_type, std::false_type, std::remove_const, std::enable_if #include #include // std::index_sequence @@ -9323,7 +9253,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { namespace internal { @@ -9452,7 +9381,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -9483,7 +9411,6 @@ namespace sqlite_orm { // #include "function.h" - #include #include #include // std::string @@ -9496,7 +9423,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { struct arg_values; @@ -9510,13 +9436,13 @@ namespace sqlite_orm { struct user_defined_function_base { using func_call = std::function< - void(sqlite3_context *context, void *functionPointer, int argsCount, sqlite3_value **values)>; - using final_call = std::function; + void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; + using final_call = std::function; std::string name; int argumentsCount = 0; - std::function create; - void (*destroy)(int *) = nullptr; + std::function create; + void (*destroy)(int*) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_base(decltype(name) name_, @@ -9648,7 +9574,7 @@ namespace sqlite_orm { constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // using C++17 or higher - template + template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); @@ -9731,7 +9657,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -10018,7 +9943,6 @@ namespace sqlite_orm { // #include "functional/static_magic.h" - #include // std::false_type, std::true_type, std::integral_constant #include // std::forward @@ -10101,7 +10025,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" - #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::index_sequence, std::make_index_sequence #include // std::forward, std::move @@ -10114,7 +10037,6 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - namespace sqlite_orm { namespace internal { @@ -10244,7 +10166,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -10547,7 +10468,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - // interface functions namespace sqlite_orm { namespace internal { @@ -10632,7 +10552,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10669,7 +10588,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" @@ -10690,19 +10608,16 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" - // #include "functional/cxx_universal.h" // #include "row_extractor.h" // #include "mapped_row_extractor.h" - #include // #include "object_from_column_builder.h" - #include #include // std::is_member_object_pointer @@ -10710,7 +10625,6 @@ namespace sqlite_orm { // #include "row_extractor.h" - namespace sqlite_orm { namespace internal { @@ -10751,7 +10665,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -10782,7 +10695,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -10834,7 +10746,6 @@ namespace sqlite_orm { // #include "view.h" - #include #include // std::string #include // std::forward, std::move @@ -10846,7 +10757,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10867,7 +10777,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -10955,7 +10864,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -10971,7 +10879,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::unique_ptr #include // std::iterator_traits @@ -10989,14 +10896,12 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include #include // std::string // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -11069,7 +10974,6 @@ namespace sqlite_orm { // #include "values.h" - #include // std::vector #include // std::tuple #include // std::forward @@ -11078,7 +10982,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -11117,14 +11020,12 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" - #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11182,7 +11083,6 @@ namespace sqlite_orm { // #include "ast/set.h" - #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11191,7 +11091,6 @@ namespace sqlite_orm { // #include "table_name_collector.h" - #include // std::set #include // std::string #include // std::function @@ -11207,14 +11106,13 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { struct table_name_collector { using table_name_set = std::set>; - using find_table_name_t = std::function; + using find_table_name_t = std::function; find_table_name_t find_table_name; mutable table_name_set table_names; @@ -11224,7 +11122,7 @@ namespace sqlite_orm { table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} template - void operator()(const T &) const { + void operator()(const T&) const { //.. } @@ -11234,17 +11132,17 @@ namespace sqlite_orm { } template - void operator()(const column_pointer &) const { + void operator()(const column_pointer&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const alias_column_t &a) const { + void operator()(const alias_column_t& a) const { (*this)(a.column, alias_extractor::get()); } template - void operator()(const count_asterisk_t &) const { + void operator()(const count_asterisk_t&) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { table_names.emplace(move(tableName), ""); @@ -11252,12 +11150,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t &) const { + void operator()(const asterisk_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template = true> - void operator()(const asterisk_t &) const { + void operator()(const asterisk_t&) const { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -11266,22 +11164,22 @@ namespace sqlite_orm { } template - void operator()(const object_t &) const { + void operator()(const object_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_rowid_t &) const { + void operator()(const table_rowid_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table_oid_t &) const { + void operator()(const table_oid_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } template - void operator()(const table__rowid_t &) const { + void operator()(const table__rowid_t&) const { table_names.emplace(this->find_table_name(typeid(T)), ""); } }; @@ -11290,7 +11188,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -11421,7 +11318,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -12163,7 +12059,6 @@ namespace sqlite_orm { // #include "ast/excluded.h" - #include // std::move namespace sqlite_orm { @@ -12193,12 +12088,10 @@ namespace sqlite_orm { // #include "ast/exists.h" - #include // std::move // #include "../tags.h" - namespace sqlite_orm { namespace internal { @@ -12229,7 +12122,6 @@ namespace sqlite_orm { // #include "ast/set.h" - namespace sqlite_orm { namespace internal { @@ -12919,7 +12811,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -12976,7 +12867,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include #include // std::function, std::bind #include // std::string @@ -12997,7 +12887,6 @@ namespace sqlite_orm { // #include "pragma.h" - #include #include // std::string #include // std::function @@ -13017,7 +12906,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - #include // std::index_sequence #include #include @@ -13041,7 +12929,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { template @@ -13067,18 +12954,18 @@ namespace sqlite_orm { } } #else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; + } + os << c; } - os << c; } } - } #endif inline void stream_identifier(std::ostream& ss, @@ -13443,7 +13330,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -13652,7 +13538,6 @@ namespace sqlite_orm { // #include "limit_accessor.h" - #include #include // std::map #include // std::function @@ -13660,7 +13545,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13794,13 +13678,11 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function #include // std::move // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13827,7 +13709,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} - transaction_guard_t(transaction_guard_t &&other) : + transaction_guard_t(transaction_guard_t&& other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), gotta_fire(other.gotta_fire) { @@ -13844,7 +13726,7 @@ namespace sqlite_orm { } } - transaction_guard_t &operator=(transaction_guard_t &&) = delete; + transaction_guard_t& operator=(transaction_guard_t&&) = delete; /** * Call `COMMIT` explicitly. After this call @@ -13881,7 +13763,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::system_error #include // std::string @@ -13892,7 +13773,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13960,7 +13840,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 @@ -13971,19 +13850,17 @@ namespace sqlite_orm { // #include "arg_values.h" - #include // #include "row_extractor.h" - namespace sqlite_orm { struct arg_value { arg_value() : arg_value(nullptr) {} - arg_value(sqlite3_value *value_) : value(value_) {} + arg_value(sqlite3_value* value_) : value(value_) {} template T get() const { @@ -14020,18 +13897,18 @@ namespace sqlite_orm { } private: - sqlite3_value *value = nullptr; + sqlite3_value* value = nullptr; }; struct arg_values { struct iterator { - iterator(const arg_values &container_, int index_) : + iterator(const arg_values& container_, int index_) : container(container_), index(index_), currentValue(index_ < int(container_.size()) ? container_[index_] : arg_value()) {} - iterator &operator++() { + iterator& operator++() { ++this->index; if(this->index < int(this->container.size())) { this->currentValue = this->container[this->index]; @@ -14060,27 +13937,27 @@ namespace sqlite_orm { } } - arg_value *operator->() const { + arg_value* operator->() const { return &this->currentValue; } - bool operator==(const iterator &other) const { + bool operator==(const iterator& other) const { return &other.container == &this->container && other.index == this->index; } - bool operator!=(const iterator &other) const { + bool operator!=(const iterator& other) const { return !(*this == other); } private: - const arg_values &container; + const arg_values& container; int index = 0; mutable arg_value currentValue; }; arg_values() : arg_values(0, nullptr) {} - arg_values(int argsCount_, sqlite3_value **values_) : argsCount(argsCount_), values(values_) {} + arg_values(int argsCount_, sqlite3_value** values_) : argsCount(argsCount_), values(values_) {} size_t size() const { return this->argsCount; @@ -14092,7 +13969,7 @@ namespace sqlite_orm { arg_value operator[](int index) const { if(index < this->argsCount && index >= 0) { - sqlite3_value *value = this->values[index]; + sqlite3_value* value = this->values[index]; return {value}; } else { throw std::system_error{orm_error_code::index_is_out_of_bounds}; @@ -14113,11 +13990,10 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value **values = nullptr; + sqlite3_value** values = nullptr; }; } - namespace sqlite_orm { namespace internal { @@ -14139,13 +14015,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -14161,7 +14037,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -14928,13 +14803,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 { @@ -15068,7 +14941,6 @@ namespace sqlite_orm { // #include "statement_serializer.h" - #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -15081,7 +14953,6 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -15126,7 +14997,6 @@ namespace sqlite_orm { // #include "column_names_getter.h" - #include // std::system_error #include // std::string #include // std::vector @@ -15142,7 +15012,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -15247,7 +15116,6 @@ namespace sqlite_orm { // #include "order_by_serializer.h" - #include // std::string #include // std::stringstream @@ -15339,7 +15207,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -17413,7 +17280,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -17622,7 +17488,8 @@ namespace sqlite_orm { template void update_all(S set, Wargs... wh) { - static_assert(internal::is_set::value, "first argument in update_all can be either set or dynamic_set"); + static_assert(internal::is_set::value, + "first argument in update_all can be either set or dynamic_set"); auto statement = this->prepare(sqlite_orm::update_all(std::move(set), std::forward(wh)...)); this->execute(statement); } @@ -18216,7 +18083,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18403,8 +18270,7 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - prepared_statement_t> - prepare(update_all_t upd) { + prepared_statement_t> prepare(update_all_t upd) { return prepare_impl>(std::move(upd)); } @@ -18535,13 +18401,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18581,13 +18447,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18679,22 +18545,22 @@ namespace sqlite_orm { } return move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); + } } - } #endif } @@ -18803,7 +18669,6 @@ namespace sqlite_orm { #include // std::reference_wrapper // #include "functional/cxx_optional.h" - // #include "tuple_helper/tuple_filter.h" // #include "conditions.h" @@ -18830,7 +18695,6 @@ namespace sqlite_orm { // #include "ast/group_by.h" - namespace sqlite_orm { namespace internal { @@ -19135,7 +18999,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template @@ -19315,7 +19178,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19388,7 +19250,6 @@ namespace sqlite_orm { // #include "table.h" - namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19431,7 +19292,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" @@ -19448,7 +19308,6 @@ namespace sqlite_orm { // #include "../column.h" - namespace sqlite_orm { namespace internal { @@ -19488,7 +19347,6 @@ namespace sqlite_orm { // #include "../table.h" - namespace sqlite_orm { namespace internal { @@ -19516,9 +19374,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19549,7 +19407,6 @@ namespace sqlite_orm { // #include "../storage.h" - namespace sqlite_orm { namespace internal { @@ -19592,9 +19449,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19658,11 +19515,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); diff --git a/tests/storage_non_crud_tests.cpp b/tests/storage_non_crud_tests.cpp index 5c5877555..e65856f10 100644 --- a/tests/storage_non_crud_tests.cpp +++ b/tests/storage_non_crud_tests.cpp @@ -63,15 +63,13 @@ TEST_CASE("update_all") { int id = 0; std::string name; }; - auto storage = make_storage({}, - make_table("records", - make_column("id", &Record::id, primary_key()), - make_column("name", &Record::name))); + auto storage = make_storage( + {}, + make_table("records", make_column("id", &Record::id, primary_key()), make_column("name", &Record::name))); storage.sync_schema(); - auto vars = dynamic_set( storage ); + auto vars = dynamic_set(storage); vars.push_back(assign(&Record::name, "Bob")); storage.update_all(vars, where(is_equal(&Record::id, 10))); - } TEST_CASE("update set null") { From ae34cd57d113b0b0afce00d763f92e2e0dc0c22a Mon Sep 17 00:00:00 2001 From: liushuai <770722922@qq.com> Date: Thu, 2 Feb 2023 18:29:00 +0800 Subject: [PATCH 016/100] Auto generate sqlite_orm.h --- include/sqlite_orm/sqlite_orm.h | 208 +++++++++++++++++--------------- 1 file changed, 111 insertions(+), 97 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 978bc38e3..22356cfc0 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1314,7 +1314,7 @@ namespace sqlite_orm { indexed_column_t collate(std::string name) { auto res = std::move(*this); - res._collation_name = move(name); + res._collation_name = std::move(name); return res; } @@ -1451,7 +1451,7 @@ namespace sqlite_orm { columns_tuple columns; - primary_key_t(decltype(columns) columns) : columns(move(columns)) {} + primary_key_t(decltype(columns) columns) : columns(std::move(columns)) {} self asc() const { auto res = *this; @@ -1520,7 +1520,7 @@ namespace sqlite_orm { columns_tuple columns; - unique_t(columns_tuple columns_) : columns(move(columns_)) {} + unique_t(columns_tuple columns_) : columns(std::move(columns_)) {} }; /** @@ -1695,7 +1695,7 @@ namespace sqlite_orm { static_assert(!std::is_same::value, "All references must have the same type"); foreign_key_t(columns_type columns_, references_type references_) : - columns(move(columns_)), references(move(references_)), + columns(std::move(columns_)), references(std::move(references_)), on_update(*this, true, foreign_key_action::none), on_delete(*this, false, foreign_key_action::none) {} foreign_key_t(const self& other) : @@ -2478,8 +2478,8 @@ namespace sqlite_orm { struct column_t : column_identifier, column_field, column_constraints { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED column_t(std::string name, G memberPointer, S setter, std::tuple op) : - column_identifier{move(name)}, column_field{memberPointer, setter}, column_constraints{ - move(op)} {} + column_identifier{std::move(name)}, column_field{memberPointer, setter}, + column_constraints{std::move(op)} {} #endif }; @@ -2516,7 +2516,7 @@ namespace sqlite_orm { internal::column_t make_column(std::string name, M m, Op... constraints) { static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), m, {}, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), m, {}, std::make_tuple(constraints...)}); } /** @@ -2532,7 +2532,8 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), getter, setter, std::make_tuple(constraints...)}); } /** @@ -2549,7 +2550,8 @@ namespace sqlite_orm { "Getter and setter must get and set same data type"); static_assert(polyfill::conjunction_v...>, "Incorrect constraints pack"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), getter, setter, std::make_tuple(constraints...)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), getter, setter, std::make_tuple(constraints...)}); } } #pragma once @@ -3318,7 +3320,7 @@ namespace sqlite_orm { order_by_base() = default; order_by_base(decltype(asc_desc) asc_desc_, decltype(_collate_argument) _collate_argument_) : - asc_desc(asc_desc_), _collate_argument(move(_collate_argument_)) {} + asc_desc(asc_desc_), _collate_argument(std::move(_collate_argument_)) {} #endif }; @@ -3400,7 +3402,7 @@ namespace sqlite_orm { std::string name; dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) : - order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {} + order_by_base{asc_desc_, std::move(collate_argument_)}, name(std::move(name_)) {} }; /** @@ -3419,7 +3421,9 @@ namespace sqlite_orm { auto newContext = this->context; newContext.skip_table_name = true; auto columnName = serialize(order_by.expression, newContext); - this->entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument)); + this->entries.emplace_back(std::move(columnName), + order_by.asc_desc, + std::move(order_by._collate_argument)); } const_iterator begin() const { @@ -6661,7 +6665,7 @@ namespace sqlite_orm { template group_by_with_having having(T expression) { - return {move(this->args), std::move(expression)}; + return {std::move(this->args), std::move(expression)}; } }; @@ -6763,7 +6767,7 @@ namespace sqlite_orm { static constexpr int count = std::tuple_size::value; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - columns_t(columns_type columns) : columns{move(columns)} {} + columns_t(columns_type columns) : columns{std::move(columns)} {} #endif }; @@ -6829,7 +6833,8 @@ namespace sqlite_orm { bool highest_level = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - select_t(return_type col, conditions_type conditions) : col{std::move(col)}, conditions{move(conditions)} {} + select_t(return_type col, conditions_type conditions) : + col{std::move(col)}, conditions{std::move(conditions)} {} #endif }; @@ -7181,7 +7186,8 @@ namespace sqlite_orm { decltype(dflt_value) dflt_value_, decltype(pk) pk_) : cid(cid_), - name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), pk(pk_) {} + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), + pk(pk_) {} #endif }; @@ -7203,7 +7209,7 @@ namespace sqlite_orm { decltype(pk) pk_, decltype(hidden) hidden_) : cid(cid_), - name(move(name_)), type(move(type_)), notnull(notnull_), dflt_value(move(dflt_value_)), + name(std::move(name_)), type(std::move(type_)), notnull(notnull_), dflt_value(std::move(dflt_value_)), pk(pk_), hidden{hidden_} {} #endif }; @@ -7285,7 +7291,7 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED trigger_t(std::string name, T trigger_base, elements_type statements) : - base_trigger{move(name)}, base(std::move(trigger_base)), elements(move(statements)) {} + base_trigger{std::move(name)}, base(std::move(trigger_base)), elements(std::move(statements)) {} #endif }; @@ -7417,7 +7423,7 @@ namespace sqlite_orm { std::string message; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - raise_t(type_t type, std::string message) : type{type}, message{move(message)} {} + raise_t(type_t type, std::string message) : type{type}, message{std::move(message)} {} #endif }; @@ -7463,26 +7469,27 @@ namespace sqlite_orm { * RAISE(ROLLBACK, %message%) expression used within TRIGGER expressions */ inline internal::raise_t raise_rollback(std::string message) { - return {internal::raise_t::type_t::rollback, move(message)}; + return {internal::raise_t::type_t::rollback, std::move(message)}; } /** * RAISE(ABORT, %message%) expression used within TRIGGER expressions */ inline internal::raise_t raise_abort(std::string message) { - return {internal::raise_t::type_t::abort, move(message)}; + return {internal::raise_t::type_t::abort, std::move(message)}; } /** * RAISE(FAIL, %message%) expression used within TRIGGER expressions */ inline internal::raise_t raise_fail(std::string message) { - return {internal::raise_t::type_t::fail, move(message)}; + return {internal::raise_t::type_t::fail, std::move(message)}; } template internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {move(name), std::move(part.base), std::move(part.statements)}); + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::move(part.base), std::move(part.statements)}); } inline internal::trigger_timing_t before() { @@ -8849,7 +8856,7 @@ namespace sqlite_orm { */ inline std::string quote_string_literal(std::string v) { constexpr char quoteChar = '\''; - return quoteChar + sql_escape(move(v), quoteChar) + quoteChar; + return quoteChar + sql_escape(std::move(v), quoteChar) + quoteChar; } /** @@ -8858,7 +8865,7 @@ namespace sqlite_orm { */ inline std::string quote_blob_literal(std::string v) { constexpr char quoteChar = '\''; - return std::string{char('x'), quoteChar} + move(v) + quoteChar; + return std::string{char('x'), quoteChar} + std::move(v) + quoteChar; } /** @@ -8867,7 +8874,7 @@ namespace sqlite_orm { */ inline std::string quote_identifier(std::string identifier) { constexpr char quoteChar = '"'; - return quoteChar + sql_escape(move(identifier), quoteChar) + quoteChar; + return quoteChar + sql_escape(std::move(identifier), quoteChar) + quoteChar; } namespace internal { @@ -9034,7 +9041,7 @@ namespace sqlite_orm { bool unique = false; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - index_base(std::string name, bool unique) : name{move(name)}, unique{unique} {} + index_base(std::string name, bool unique) : name{std::move(name)}, unique{unique} {} #endif }; @@ -9046,7 +9053,7 @@ namespace sqlite_orm { #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED index_t(std::string name_, bool unique_, elements_type elements_) : - index_base{move(name_), unique_}, elements(move(elements_)) {} + index_base{std::move(name_), unique_}, elements(std::move(elements_)) {} #endif elements_type elements; @@ -9060,7 +9067,7 @@ namespace sqlite_orm { static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template @@ -9082,7 +9089,7 @@ namespace sqlite_orm { static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } } #pragma once @@ -9449,8 +9456,8 @@ namespace sqlite_orm { decltype(argumentsCount) argumentsCount_, decltype(create) create_, decltype(destroy) destroy_) : - name(move(name_)), - argumentsCount(argumentsCount_), create(move(create_)), destroy(destroy_) {} + name(std::move(name_)), + argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} #endif }; @@ -9462,8 +9469,8 @@ namespace sqlite_orm { decltype(create) create_, decltype(run) run_, decltype(destroy) destroy_) : - user_defined_function_base{move(name_), argumentsCount_, move(create_), destroy_}, - run(move(run_)) {} + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + run(std::move(run_)) {} }; struct user_defined_aggregate_function_t : user_defined_function_base { @@ -9476,8 +9483,8 @@ namespace sqlite_orm { decltype(step) step_, decltype(finalCall) finalCall_, decltype(destroy) destroy_) : - user_defined_function_base{move(name_), argumentsCount_, move(create_), destroy_}, - step(move(step_)), finalCall(move(finalCall_)) {} + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + step(std::move(step_)), finalCall(std::move(finalCall_)) {} }; template @@ -10043,18 +10050,18 @@ namespace sqlite_orm { // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer template auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { - return (f.*functionPointer)(std::get(move(t))...); + return (f.*functionPointer)(std::get(std::move(t))...); } template auto call(Function& f, FunctionPointer functionPointer, Tuple t) { constexpr size_t size = std::tuple_size::value; - return call_impl(f, functionPointer, move(t), std::make_index_sequence{}); + return call_impl(f, functionPointer, std::move(t), std::make_index_sequence{}); } template auto call(Function& f, Tuple t) { - return call(f, &Function::operator(), move(t)); + return call(f, &Function::operator(), std::move(t)); } #if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) @@ -10192,7 +10199,8 @@ namespace sqlite_orm { elements_type elements; #ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - table_t(std::string name_, elements_type elements_) : basic_table{move(name_)}, elements{move(elements_)} {} + table_t(std::string name_, elements_type elements_) : + basic_table{std::move(name_)}, elements{std::move(elements_)} {} #endif table_t without_rowid() const { @@ -10435,7 +10443,7 @@ namespace sqlite_orm { template>::object_type> internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {std::move(name), std::make_tuple(std::forward(args)...)}); } /** @@ -10446,7 +10454,7 @@ namespace sqlite_orm { template internal::table_t make_table(std::string name, Cs... args) { SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), std::make_tuple(std::forward(args)...)}); + return {std::move(name), std::make_tuple(std::forward(args)...)}); } } #pragma once @@ -10827,7 +10835,7 @@ namespace sqlite_orm { iterator_t(){}; - iterator_t(statement_finalizer stmt_, view_type& view_) : stmt{move(stmt_)}, view{&view_} { + iterator_t(statement_finalizer stmt_, view_type& view_) : stmt{std::move(stmt_)}, view{&view_} { next(); } @@ -10908,7 +10916,7 @@ namespace sqlite_orm { struct connection_holder { - connection_holder(std::string filename_) : filename(move(filename_)) {} + connection_holder(std::string filename_) : filename(std::move(filename_)) {} void retain() { if(1 == ++this->_retain_count) { @@ -11013,7 +11021,7 @@ namespace sqlite_orm { template internal::dynamic_values_t values(std::vector vector) { - return {{move(vector)}}; + return {{std::move(vector)}}; } } @@ -11039,12 +11047,12 @@ namespace sqlite_orm { args_tuple args; upsert_clause> do_nothing() { - return {move(this->args), {}}; + return {std::move(this->args), {}}; } template upsert_clause> do_update(ActionsArgs... actions) { - return {move(this->args), {std::make_tuple(std::forward(actions)...)}}; + return {std::move(this->args), {std::make_tuple(std::forward(actions)...)}}; } }; @@ -11119,16 +11127,16 @@ namespace sqlite_orm { table_name_collector() = default; - table_name_collector(find_table_name_t find_table_name) : find_table_name{move(find_table_name)} {} + table_name_collector(find_table_name_t find_table_name) : find_table_name{std::move(find_table_name)} {} template - void operator()(const T&) const { - //.. + table_name_set operator()(const T&) const { + return {}; } template void operator()(F O::*, std::string alias = {}) const { - table_names.emplace(this->find_table_name(typeid(O)), move(alias)); + table_names.emplace(this->find_table_name(typeid(O)), std::move(alias)); } template @@ -11145,7 +11153,7 @@ namespace sqlite_orm { void operator()(const count_asterisk_t&) const { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { - table_names.emplace(move(tableName), ""); + table_names.emplace(std::move(tableName), ""); } } @@ -11160,7 +11168,7 @@ namespace sqlite_orm { static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); auto tableName = this->find_table_name(typeid(type_t)); - table_names.emplace(move(tableName), alias_extractor::get()); + table_names.emplace(std::move(tableName), alias_extractor::get()); } template @@ -11894,7 +11902,7 @@ namespace sqlite_orm { template internal::remove_t remove(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } /** @@ -11917,7 +11925,7 @@ namespace sqlite_orm { template internal::get_t get(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } /** @@ -11928,7 +11936,7 @@ namespace sqlite_orm { template internal::get_pointer_t get_pointer(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -11940,7 +11948,7 @@ namespace sqlite_orm { template internal::get_optional_t get_optional(Ids... ids) { std::tuple idsTuple{std::forward(ids)...}; - return {move(idsTuple)}; + return {std::move(idsTuple)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED @@ -11954,7 +11962,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -11967,7 +11975,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -11981,7 +11989,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -11994,7 +12002,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(wh)...}; - return {std::move(set), move(conditions)}; + return {std::move(set), std::move(conditions)}; } /** @@ -12007,7 +12015,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** * Create a get all pointer statement. @@ -12020,7 +12028,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED @@ -12034,7 +12042,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } /** @@ -12048,7 +12056,7 @@ namespace sqlite_orm { using args_tuple = std::tuple; internal::validate_conditions(); args_tuple conditions{std::forward(args)...}; - return {move(conditions)}; + return {std::move(conditions)}; } #endif // SQLITE_ORM_OPTIONAL_SUPPORTED } @@ -12853,7 +12861,7 @@ namespace sqlite_orm { statement_finalizer stmt{prepare_stmt(this->connection.get(), serialize(this->args, context))}; iterate_ast(this->args.conditions, conditional_binder{stmt.get()}); - return {move(stmt), *this}; + return {std::move(stmt), *this}; } iterator_t end() { @@ -13346,7 +13354,7 @@ namespace sqlite_orm { res.reserve(argc); for(decltype(argc) i = 0; i < argc; ++i) { auto rowString = row_extractor().extract(argv[i]); - res.push_back(move(rowString)); + res.push_back(std::move(rowString)); } return 0; } @@ -13354,7 +13362,7 @@ namespace sqlite_orm { struct pragma_t { using get_connection_t = std::function; - pragma_t(get_connection_t get_connection_) : get_connection(move(get_connection_)) {} + pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} void busy_timeout(int value) { this->set_pragma("busy_timeout", value); @@ -13455,7 +13463,13 @@ namespace sqlite_orm { ++index; auto pk = std::atoi(argv[index++]); auto hidden = std::atoi(argv[index++]); - res.emplace_back(cid, move(name), move(type), notnull, move(dflt_value), pk, hidden); + res.emplace_back(cid, + std::move(name), + std::move(type), + notnull, + std::move(dflt_value), + pk, + hidden); } return 0; }, @@ -13485,7 +13499,7 @@ namespace sqlite_orm { std::string dflt_value = argv[index] ? argv[index] : ""; ++index; auto pk = std::atoi(argv[index++]); - res.emplace_back(cid, move(name), move(type), notnull, move(dflt_value), pk); + res.emplace_back(cid, std::move(name), std::move(type), notnull, std::move(dflt_value), pk); } return 0; }, @@ -13707,11 +13721,11 @@ namespace sqlite_orm { std::function commit_func_, std::function rollback_func_) : connection(std::move(connection_)), - commit_func(move(commit_func_)), rollback_func(move(rollback_func_)) {} + commit_func(std::move(commit_func_)), rollback_func(std::move(rollback_func_)) {} transaction_guard_t(transaction_guard_t&& other) : commit_on_destroy(other.commit_on_destroy), connection(std::move(other.connection)), - commit_func(move(other.commit_func)), rollback_func(move(other.rollback_func)), + commit_func(std::move(other.commit_func)), rollback_func(std::move(other.rollback_func)), gotta_fire(other.gotta_fire) { other.gotta_fire = false; } @@ -13790,14 +13804,14 @@ namespace sqlite_orm { const std::string& zSourceName, std::unique_ptr holder_) : handle(sqlite3_backup_init(to_.get(), zDestName.c_str(), from_.get(), zSourceName.c_str())), - holder(move(holder_)), to(to_), from(from_) { + holder(std::move(holder_)), to(to_), from(from_) { if(!this->handle) { throw std::system_error{orm_error_code::failed_to_init_a_backup}; } } backup_t(backup_t&& other) : - handle(std::exchange(other.handle, nullptr)), holder(move(other.holder)), to(other.to), + handle(std::exchange(other.handle, nullptr)), holder(std::move(other.holder)), to(other.to), from(other.from) {} ~backup_t() { @@ -14253,7 +14267,7 @@ namespace sqlite_orm { ? -1 : int(std::tuple_size::value); this->scalarFunctions.emplace_back(new user_defined_scalar_function_t{ - move(name), + std::move(name), argsCount, []() -> int* { return (int*)(new F()); @@ -14314,7 +14328,7 @@ namespace sqlite_orm { ? -1 : int(std::tuple_size::value); this->aggregateFunctions.emplace_back(new user_defined_aggregate_function_t{ - move(name), + std::move(name), argsCount, /* create = */ []() -> int* { @@ -14325,7 +14339,7 @@ namespace sqlite_orm { auto& function = *static_cast(functionVoidPointer); args_tuple argsTuple; values_to_tuple{}(values, argsTuple, argsCount); - call(function, &F::step, move(argsTuple)); + call(function, &F::step, std::move(argsTuple)); }, /* finalCall = */ [](sqlite3_context* context, void* functionVoidPointer) { @@ -14374,7 +14388,7 @@ namespace sqlite_orm { }; std::stringstream ss; ss << C::name() << std::flush; - this->create_collation(ss.str(), move(func)); + this->create_collation(ss.str(), std::move(func)); } void create_collation(const std::string& name, collating_function f) { @@ -14464,7 +14478,7 @@ namespace sqlite_orm { backup_t make_backup_to(const std::string& filename) { auto holder = std::make_unique(filename); connection_ref conRef{*holder}; - return {conRef, "main", this->get_connection(), "main", move(holder)}; + return {conRef, "main", this->get_connection(), "main", std::move(holder)}; } backup_t make_backup_to(storage_base& other) { @@ -14474,7 +14488,7 @@ namespace sqlite_orm { backup_t make_backup_from(const std::string& filename) { auto holder = std::make_unique(filename); connection_ref conRef{*holder}; - return {this->get_connection(), "main", conRef, "main", move(holder)}; + return {this->get_connection(), "main", conRef, "main", std::move(holder)}; } backup_t make_backup_from(storage_base& other) { @@ -14503,7 +14517,7 @@ namespace sqlite_orm { } int busy_handler(std::function handler) { - _busy_handler = move(handler); + _busy_handler = std::move(handler); if(this->is_opened()) { if(_busy_handler) { return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); @@ -14520,7 +14534,7 @@ namespace sqlite_orm { pragma(std::bind(&storage_base::get_connection, this)), limit(std::bind(&storage_base::get_connection, this)), inMemory(filename.empty() || filename == ":memory:"), - connection(std::make_unique(move(filename))), + connection(std::make_unique(std::move(filename))), cachedForeignKeysCount(foreignKeysCount) { if(this->inMemory) { this->connection->retain(); @@ -15029,7 +15043,7 @@ namespace sqlite_orm { newContext.skip_table_name = false; auto columnName = serialize(t, newContext); if(!columnName.empty()) { - return {move(columnName)}; + return {std::move(columnName)}; } else { throw std::system_error{orm_error_code::column_not_found}; } @@ -16767,10 +16781,10 @@ namespace sqlite_orm { auto newContext = context; newContext.use_parentheses = false; auto whereString = serialize(value, newContext); - columnNames.push_back(move(whereString)); + columnNames.push_back(std::move(whereString)); } else { auto columnName = serialize(value, context); - whereString = move(columnName); + whereString = std::move(columnName); } }); ss << " (" << streaming_serialized(columnNames) << ")"; @@ -17305,7 +17319,7 @@ namespace sqlite_orm { * @param dbObjects db_objects_tuple */ storage_t(std::string filename, db_objects_type dbObjects) : - storage_base{move(filename), foreign_keys_count(dbObjects)}, db_objects{std::move(dbObjects)} {} + storage_base{std::move(filename), foreign_keys_count(dbObjects)}, db_objects{std::move(dbObjects)} {} private: db_objects_type db_objects; @@ -17382,7 +17396,7 @@ namespace sqlite_orm { ss << suffix << std::flush; auto anotherBackupTableName = backupTableName + ss.str(); if(!this->table_exists(db, anotherBackupTableName)) { - backupTableName = move(anotherBackupTableName); + backupTableName = std::move(anotherBackupTableName); break; } ++suffix; @@ -17500,12 +17514,12 @@ namespace sqlite_orm { this->assert_mapped_type(); std::vector rows; if(y) { - rows = this->select(sqlite_orm::group_concat(m, move(*y)), std::forward(args)...); + rows = this->select(sqlite_orm::group_concat(m, std::move(*y)), std::forward(args)...); } else { rows = this->select(sqlite_orm::group_concat(m), std::forward(args)...); } if(!rows.empty()) { - return move(rows.front()); + return std::move(rows.front()); } else { return {}; } @@ -17703,7 +17717,7 @@ namespace sqlite_orm { template std::string group_concat(F O::*m, std::string y, Args&&... args) { return this->group_concat_internal(m, - std::make_unique(move(y)), + std::make_unique(std::move(y)), std::forward(args)...); } @@ -17715,7 +17729,7 @@ namespace sqlite_orm { } else { str = std::make_unique(); } - return this->group_concat_internal(m, move(str), std::forward(args)...); + return this->group_concat_internal(m, std::move(str), std::forward(args)...); } /** @@ -18016,7 +18030,7 @@ namespace sqlite_orm { void rename_table(std::string name) { this->assert_mapped_type(); auto& table = this->get_table(); - table.name = move(name); + table.name = std::move(name); } using storage_base::rename_table; @@ -18543,7 +18557,7 @@ namespace sqlite_orm { if(!res.has_value()) { throw std::system_error{orm_error_code::not_found}; } - return move(res).value(); + return std::move(res).value(); #else auto& table = this->get_table(); auto stepRes = sqlite3_step(stmt); @@ -18622,7 +18636,7 @@ namespace sqlite_orm { auto obj = std::make_unique(); object_from_column_builder builder{*obj, stmt}; table.for_each_column(builder); - res.push_back(move(obj)); + res.push_back(std::move(obj)); }); return res; } @@ -18639,7 +18653,7 @@ namespace sqlite_orm { auto obj = std::make_optional(); object_from_column_builder builder{*obj, stmt}; table.for_each_column(builder); - res.push_back(move(obj)); + res.push_back(std::move(obj)); }); return res; } @@ -18652,7 +18666,7 @@ namespace sqlite_orm { */ template internal::storage_t make_storage(std::string filename, DBO... dbObjects) { - return {move(filename), internal::db_objects_tuple{std::forward(dbObjects)...}}; + return {std::move(filename), internal::db_objects_tuple{std::forward(dbObjects)...}}; } /** @@ -19358,7 +19372,7 @@ namespace sqlite_orm { using field_type = field_type_t>; std::string dft; if(auto d = column.default_value()) { - dft = move(*d); + dft = std::move(*d); } res.emplace_back(-1, column.name, From 46469ac559c9b37dcbb9355ebdbed49b4d9368aa Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 2 Feb 2023 16:54:35 +0200 Subject: [PATCH 017/100] Qualified remaining calls to `std::move()` --- dev/ast/set.h | 8 ++++---- dev/index.h | 2 +- dev/statement_serializer.h | 2 +- examples/case.cpp | 2 +- examples/check.cpp | 5 +++-- examples/column_aliases.cpp | 2 +- examples/core_functions.cpp | 11 ++++++----- examples/custom_aliases.cpp | 4 ++-- examples/except_intersection.cpp | 4 ++-- examples/generated_column.cpp | 2 +- examples/prepared_statement.cpp | 6 +++--- examples/triggers.cpp | 3 ++- include/sqlite_orm/sqlite_orm.h | 14 +++++++------- tests/backup_tests.cpp | 2 +- .../core_functions_tests.cpp | 15 ++++++++------- tests/constraints/unique.cpp | 6 +++--- tests/get_all_custom_containers.cpp | 2 +- tests/index_tests.cpp | 2 +- tests/json.cpp | 2 +- tests/operators/glob.cpp | 2 +- tests/operators/is_null.cpp | 2 +- tests/operators/like.cpp | 2 +- tests/pointer_passing_interface.cpp | 4 ++-- tests/prepared_statement_tests/insert.cpp | 2 +- tests/prepared_statement_tests/prepared_common.h | 4 ++-- tests/private_getters_tests.cpp | 2 +- tests/select_constraints_tests.cpp | 13 +++++++------ tests/statement_serializer_tests/column_names.cpp | 2 +- tests/statement_serializer_tests/foreign_key.cpp | 2 +- .../statements/insert_replace.cpp | 4 ++-- tests/static_tests/column_result_t.cpp | 2 +- tests/static_tests/function_static_tests.cpp | 2 +- tests/storage_non_crud_tests.cpp | 14 +++++++------- tests/sync_schema_tests.cpp | 4 ++-- tests/table_tests.cpp | 6 +++--- tests/tests2.cpp | 2 +- tests/tests4.cpp | 4 ++-- tests/transaction_tests.cpp | 4 ++-- tests/trigger_tests.cpp | 6 +++--- tests/unique_cases/get_all_with_two_tables.cpp | 4 ++-- tests/unique_cases/prepare_get_all_with_case.cpp | 2 +- 41 files changed, 94 insertions(+), 89 deletions(-) diff --git a/dev/ast/set.h b/dev/ast/set.h index 77a631ac9..c17615132 100644 --- a/dev/ast/set.h +++ b/dev/ast/set.h @@ -51,11 +51,11 @@ namespace sqlite_orm { } dynamic_set_t(dynamic_set_t&& other) : - entries(move(other.entries)), context(std::move(other.context)), + entries(std::move(other.entries)), context(std::move(other.context)), collector([this](const std::type_index& ti) { return find_table_name(this->context.db_objects, ti); }) { - collector.table_names = move(other.collector.table_names); + collector.table_names = std::move(other.collector.table_names); } dynamic_set_t& operator=(const dynamic_set_t& other) { @@ -68,12 +68,12 @@ namespace sqlite_orm { } dynamic_set_t& operator=(dynamic_set_t&& other) { - this->entries = move(other.entries); + this->entries = std::move(other.entries); this->context = std::move(other.context); this->collector = table_name_collector([this](const std::type_index& ti) { return find_table_name(this->context.db_objects, ti); }); - this->collector.table_names = move(other.collector.table_names); + this->collector.table_names = std::move(other.collector.table_names); } template diff --git a/dev/index.h b/dev/index.h index 39b6c2eb8..efa5a9ff5 100644 --- a/dev/index.h +++ b/dev/index.h @@ -55,7 +55,7 @@ namespace sqlite_orm { static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 875b0fd46..80c7f49c8 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1117,7 +1117,7 @@ namespace sqlite_orm { struct table_name_collector_holder> { table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) : - collector(move(find_table_name)) {} + collector(std::move(find_table_name)) {} table_name_collector collector; }; diff --git a/examples/case.cpp b/examples/case.cpp index ef0dbd6cd..8d288e82a 100644 --- a/examples/case.cpp +++ b/examples/case.cpp @@ -19,7 +19,7 @@ int main() { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Student() {} Student(int id, std::string name, std::string email, float marks) : - id{id}, name{move(name)}, email{move(email)}, marks{marks} {} + id{id}, name{std::move(name)}, email{std::move(email)}, marks{marks} {} #endif }; diff --git a/examples/check.cpp b/examples/check.cpp index e6e74fc72..c19456db2 100644 --- a/examples/check.cpp +++ b/examples/check.cpp @@ -17,7 +17,8 @@ int main() { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Contact() {} Contact(int id, std::string firstName, std::string lastName, std::string email, std::string phone) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, email{move(email)}, phone{move(phone)} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, email{std::move(email)}, + phone{std::move(phone)} {} #endif }; @@ -30,7 +31,7 @@ int main() { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Product() {} Product(int id, std::string name, float listPrice, float discount) : - id{id}, name{move(name)}, listPrice{listPrice}, discount{discount} {} + id{id}, name{std::move(name)}, listPrice{listPrice}, discount{discount} {} #endif }; diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index 7a9cad26f..163d8cd2a 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -17,7 +17,7 @@ void marvel_hero_ordered_by_o_pos() { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED MarvelHero() {} MarvelHero(int id, std::string name, std::string abilities, short points) : - id{id}, name{move(name)}, abilities{move(abilities)}, points{points} {} + id{id}, name{std::move(name)}, abilities{std::move(abilities)}, points{points} {} #endif }; diff --git a/examples/core_functions.cpp b/examples/core_functions.cpp index 9a6520223..4f783db21 100644 --- a/examples/core_functions.cpp +++ b/examples/core_functions.cpp @@ -14,7 +14,7 @@ struct MarvelHero { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED MarvelHero() {} MarvelHero(int id, std::string name, std::string abilities, short points) : - id{id}, name{move(name)}, abilities{move(abilities)}, points{points} {} + id{id}, name{std::move(name)}, abilities{std::move(abilities)}, points{points} {} #endif }; @@ -27,7 +27,7 @@ struct Contact { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Contact() {} Contact(int id, std::string firstName, std::string lastName, std::string phone) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, phone{move(phone)} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, phone{std::move(phone)} {} #endif }; @@ -62,9 +62,10 @@ struct Customer { std::string email, int supportRepId) : id{id}, - firstName{move(firstName)}, lastName{move(lastName)}, company{move(company)}, address{move(address)}, - city{move(city)}, state{move(state)}, country{move(country)}, postalCode{move(postalCode)}, phone{move(phone)}, - fax{move(fax)}, email{move(email)}, supportRepId{supportRepId} {} + firstName{std::move(firstName)}, lastName{std::move(lastName)}, company{std::move(company)}, + address{std::move(address)}, city{std::move(city)}, state{std::move(state)}, country{std::move(country)}, + postalCode{std::move(postalCode)}, phone{std::move(phone)}, fax{std::move(fax)}, email{std::move(email)}, + supportRepId{supportRepId} {} #endif }; diff --git a/examples/custom_aliases.cpp b/examples/custom_aliases.cpp index 47daf1553..0d6ffa7ca 100644 --- a/examples/custom_aliases.cpp +++ b/examples/custom_aliases.cpp @@ -21,7 +21,7 @@ struct Employee { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Employee() {} Employee(int id, std::string name, int age, std::string address, float salary) : - id{id}, name{move(name)}, age{age}, address{move(address)}, salary{salary} {} + id{id}, name{std::move(name)}, age{age}, address{std::move(address)}, salary{salary} {} #endif }; @@ -32,7 +32,7 @@ struct Department { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Department() {} - Department(int id, std::string dept, int empId) : id{id}, dept{move(dept)}, empId{empId} {} + Department(int id, std::string dept, int empId) : id{id}, dept{std::move(dept)}, empId{empId} {} #endif }; diff --git a/examples/except_intersection.cpp b/examples/except_intersection.cpp index 03a36d151..97a7629ed 100644 --- a/examples/except_intersection.cpp +++ b/examples/except_intersection.cpp @@ -14,7 +14,7 @@ struct DeptMaster { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED DeptMaster() = default; - DeptMaster(int deptId, std::string deptName) : deptId{deptId}, deptName{move(deptName)} {} + DeptMaster(int deptId, std::string deptName) : deptId{deptId}, deptName{std::move(deptName)} {} #endif }; @@ -33,7 +33,7 @@ struct EmpMaster { long salary, decltype(DeptMaster::deptId) deptId) : empId{empId}, - firstName{move(firstName)}, lastName{move(lastName)}, salary{salary}, deptId{deptId} {} + firstName{std::move(firstName)}, lastName{std::move(lastName)}, salary{salary}, deptId{deptId} {} #endif }; diff --git a/examples/generated_column.cpp b/examples/generated_column.cpp index e8e8cfb95..699cf3963 100644 --- a/examples/generated_column.cpp +++ b/examples/generated_column.cpp @@ -22,7 +22,7 @@ int main() { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Product() {} Product(int id, std::string name, int quantity, float price, float totalValue = 0.f) : - id{id}, name{move(name)}, quantity{quantity}, price{price}, totalValue{totalValue} {} + id{id}, name{std::move(name)}, quantity{quantity}, price{price}, totalValue{totalValue} {} #endif }; auto storage = make_storage({}, diff --git a/examples/prepared_statement.cpp b/examples/prepared_statement.cpp index 6a43a883f..e637e72bd 100644 --- a/examples/prepared_statement.cpp +++ b/examples/prepared_statement.cpp @@ -22,7 +22,7 @@ struct Doctor { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Doctor() = default; Doctor(int doctor_id, std::string doctor_name, std::string degree) : - doctor_id{doctor_id}, doctor_name{move(doctor_name)}, degree{move(degree)} {} + doctor_id{doctor_id}, doctor_name{std::move(doctor_name)}, degree{std::move(degree)} {} #endif }; @@ -34,7 +34,7 @@ struct Speciality { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Speciality() = default; Speciality(int spl_id, std::string spl_descrip, int doctor_id) : - spl_id{spl_id}, spl_descrip{move(spl_descrip)}, doctor_id{doctor_id} {} + spl_id{spl_id}, spl_descrip{std::move(spl_descrip)}, doctor_id{doctor_id} {} #endif }; @@ -46,7 +46,7 @@ struct Visit { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Visit() = default; Visit(int doctor_id, std::string patient_name, std::string vdate) : - doctor_id{doctor_id}, patient_name{move(patient_name)}, vdate{move(vdate)} {} + doctor_id{doctor_id}, patient_name{std::move(patient_name)}, vdate{std::move(vdate)} {} #endif }; diff --git a/examples/triggers.cpp b/examples/triggers.cpp index 0a8dc6726..d2a2c2ca1 100644 --- a/examples/triggers.cpp +++ b/examples/triggers.cpp @@ -20,7 +20,8 @@ struct Lead { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Lead() = default; Lead(int id, std::string firstName, std::string lastName, std::string email, std::string phone) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, email{move(email)}, phone{move(phone)} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, email{std::move(email)}, + phone{std::move(phone)} {} #endif }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 22356cfc0..0eca7e0c3 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9078,7 +9078,7 @@ namespace sqlite_orm { static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); } template @@ -11239,11 +11239,11 @@ namespace sqlite_orm { } dynamic_set_t(dynamic_set_t&& other) : - entries(move(other.entries)), context(std::move(other.context)), + entries(std::move(other.entries)), context(std::move(other.context)), collector([this](const std::type_index& ti) { return find_table_name(this->context.db_objects, ti); }) { - collector.table_names = move(other.collector.table_names); + collector.table_names = std::move(other.collector.table_names); } dynamic_set_t& operator=(const dynamic_set_t& other) { @@ -11256,12 +11256,12 @@ namespace sqlite_orm { } dynamic_set_t& operator=(dynamic_set_t&& other) { - this->entries = move(other.entries); + this->entries = std::move(other.entries); this->context = std::move(other.context); this->collector = table_name_collector([this](const std::type_index& ti) { return find_table_name(this->context.db_objects, ti); }); - this->collector.table_names = move(other.collector.table_names); + this->collector.table_names = std::move(other.collector.table_names); } template @@ -16295,7 +16295,7 @@ namespace sqlite_orm { struct table_name_collector_holder> { table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) : - collector(move(find_table_name)) {} + collector(std::move(find_table_name)) {} table_name_collector collector; }; @@ -19229,7 +19229,7 @@ namespace sqlite_orm { /** * Generalized form of the 'remember' SQL function that is a pass-through for values - * (it returns its argument unchanged using move semantics) but also saves the + * (it returns its argument unchanged using std::move semantics) but also saves the * value that is passed through into a bound variable. */ template diff --git a/tests/backup_tests.cpp b/tests/backup_tests.cpp index 0f127cd0d..3d4df0835 100644 --- a/tests/backup_tests.cpp +++ b/tests/backup_tests.cpp @@ -11,7 +11,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; diff --git a/tests/built_in_functions_tests/core_functions_tests.cpp b/tests/built_in_functions_tests/core_functions_tests.cpp index 312cbc85d..3faf6623f 100644 --- a/tests/built_in_functions_tests/core_functions_tests.cpp +++ b/tests/built_in_functions_tests/core_functions_tests.cpp @@ -11,7 +11,7 @@ TEST_CASE("substr") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Test() = default; - Test(std::string text, int x, int y) : text{move(text)}, x{x}, y{y} {} + Test(std::string text, int x, int y) : text{std::move(text)}, x{x}, y{y} {} #endif }; auto storage = make_storage( @@ -184,7 +184,7 @@ TEST_CASE("quote") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Department() = default; Department(int id, std::string name, int managerId, int locationId) : - id{id}, name{move(name)}, managerId{managerId}, locationId{locationId} {} + id{id}, name{std::move(name)}, managerId{managerId}, locationId{locationId} {} #endif }; auto storage = make_storage({}, @@ -268,7 +268,7 @@ TEST_CASE("instr") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Employee() = default; Employee(int id, std::string firstName, std::string lastName, std::string address) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, address{move(address)} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, address{std::move(address)} {} #endif }; @@ -340,7 +340,7 @@ namespace replace_func_local { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Contact() = default; Contact(int id, std::string firstName, std::string lastName, std::string phone) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, phone{move(phone)} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, phone{std::move(phone)} {} #endif }; @@ -541,9 +541,10 @@ TEST_CASE("ifnull") { std::string email, int supportRepId) : id{id}, - firstName{move(firstName)}, lastName{move(lastName)}, company{move(company)}, address{move(address)}, - city{move(city)}, state{move(state)}, country{move(country)}, postalCode{move(postalCode)}, - phone{move(phone)}, fax{move(fax)}, email{move(email)}, supportRepId{supportRepId} {} + firstName{std::move(firstName)}, lastName{std::move(lastName)}, company{std::move(company)}, + address{std::move(address)}, city{std::move(city)}, state{std::move(state)}, country{std::move(country)}, + postalCode{std::move(postalCode)}, phone{std::move(phone)}, fax{std::move(fax)}, email{std::move(email)}, + supportRepId{supportRepId} {} #endif }; auto storage = make_storage({}, diff --git a/tests/constraints/unique.cpp b/tests/constraints/unique.cpp index 300570a60..dd7a81be9 100644 --- a/tests/constraints/unique.cpp +++ b/tests/constraints/unique.cpp @@ -15,7 +15,7 @@ TEST_CASE("Unique") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Contact() = default; Contact(int id, std::string firstName, std::string lastName, std::string email) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, email{move(email)} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, email{std::move(email)} {} #endif }; struct Shape { @@ -26,7 +26,7 @@ TEST_CASE("Unique") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Shape() = default; Shape(int id, std::string backgroundColor, std::string foregroundColor) : - id{id}, backgroundColor{move(backgroundColor)}, foregroundColor{move(foregroundColor)} {} + id{id}, backgroundColor{std::move(backgroundColor)}, foregroundColor{std::move(foregroundColor)} {} #endif }; struct List { @@ -35,7 +35,7 @@ TEST_CASE("Unique") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED List() = default; - List(int id, decltype(email) email) : id{id}, email{move(email)} {} + List(int id, decltype(email) email) : id{id}, email{std::move(email)} {} #endif }; diff --git a/tests/get_all_custom_containers.cpp b/tests/get_all_custom_containers.cpp index 00eaf931d..99d05bc0a 100644 --- a/tests/get_all_custom_containers.cpp +++ b/tests/get_all_custom_containers.cpp @@ -13,7 +13,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; diff --git a/tests/index_tests.cpp b/tests/index_tests.cpp index b3ca02827..080967656 100644 --- a/tests/index_tests.cpp +++ b/tests/index_tests.cpp @@ -105,7 +105,7 @@ TEST_CASE("Compound index") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; auto table = make_table("users", make_column("id", &User::id), make_column("name", &User::name)); diff --git a/tests/json.cpp b/tests/json.cpp index 88534489d..ebc223892 100644 --- a/tests/json.cpp +++ b/tests/json.cpp @@ -97,7 +97,7 @@ TEST_CASE("json_array_length nullable") { rows = storage.select(json_array_length("{\"one\":[1,2,3]}", "$.two")); expected = nullptr; } - value = move(rows[0]); + value = std::move(rows[0]); REQUIRE(rows.size() == 1); REQUIRE(bool(expected) == bool(value)); if(expected) { diff --git a/tests/operators/glob.cpp b/tests/operators/glob.cpp index d44c92ab1..43ebf5113 100644 --- a/tests/operators/glob.cpp +++ b/tests/operators/glob.cpp @@ -19,7 +19,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Employee() = default; Employee(int id, std::string firstName, std::string lastName, float salary, int deptId) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, salary{salary}, deptId{deptId} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, salary{salary}, deptId{deptId} {} #endif }; } diff --git a/tests/operators/is_null.cpp b/tests/operators/is_null.cpp index c358ab3f0..473559e99 100644 --- a/tests/operators/is_null.cpp +++ b/tests/operators/is_null.cpp @@ -10,7 +10,7 @@ TEST_CASE("Is null") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, decltype(name) name = nullptr) : id{id}, name{move(name)} {} + User(int id, decltype(name) name = nullptr) : id{id}, name{std::move(name)} {} #endif }; auto storage = make_storage( diff --git a/tests/operators/like.cpp b/tests/operators/like.cpp index 18a701cf6..65b68ae73 100644 --- a/tests/operators/like.cpp +++ b/tests/operators/like.cpp @@ -10,7 +10,7 @@ TEST_CASE("Like operator") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; struct Pattern { diff --git a/tests/pointer_passing_interface.cpp b/tests/pointer_passing_interface.cpp index 5a13c80c6..8a6a4a030 100644 --- a/tests/pointer_passing_interface.cpp +++ b/tests/pointer_passing_interface.cpp @@ -112,7 +112,7 @@ TEST_CASE("pointer-passing") { SECTION("unbound is deleted") { try { unique_ptr x{new int64(42)}; - auto ast = select(func(bindable_pointer(move(x)))); + auto ast = select(func(bindable_pointer(std::move(x)))); auto stmt = storage.prepare(std::move(ast)); throw std::system_error{0, std::system_category()}; } catch(const std::system_error&) { @@ -124,7 +124,7 @@ TEST_CASE("pointer-passing") { SECTION("deleted with prepared statement") { { unique_ptr x{new int64(42)}; - auto ast = select(func(bindable_pointer(move(x)))); + auto ast = select(func(bindable_pointer(std::move(x)))); auto stmt = storage.prepare(std::move(ast)); storage.execute(stmt); diff --git a/tests/prepared_statement_tests/insert.cpp b/tests/prepared_statement_tests/insert.cpp index 8a5d88835..e5e00814b 100644 --- a/tests/prepared_statement_tests/insert.cpp +++ b/tests/prepared_statement_tests/insert.cpp @@ -15,7 +15,7 @@ TEST_CASE("Prepared insert") { Artist() = default; - Artist(decltype(id) id_, decltype(name) name_) : id(id_), name(move(name_)) {} + Artist(decltype(id) id_, decltype(name) name_) : id(id_), name(std::move(name_)) {} Artist(const Artist& other) : id(other.id), name(other.name ? std::make_unique(*other.name) : nullptr) {} diff --git a/tests/prepared_statement_tests/prepared_common.h b/tests/prepared_statement_tests/prepared_common.h index bc18a96f1..f45d30287 100644 --- a/tests/prepared_statement_tests/prepared_common.h +++ b/tests/prepared_statement_tests/prepared_common.h @@ -12,7 +12,7 @@ namespace PreparedStatementTests { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; @@ -38,7 +38,7 @@ namespace PreparedStatementTests { decltype(UserAndVisit::visitId) visitId, std::string description) : userId{userId}, - visitId{visitId}, description{move(description)} {} + visitId{visitId}, description{std::move(description)} {} #endif }; diff --git a/tests/private_getters_tests.cpp b/tests/private_getters_tests.cpp index 21e72400c..b5a138cff 100644 --- a/tests/private_getters_tests.cpp +++ b/tests/private_getters_tests.cpp @@ -9,7 +9,7 @@ TEST_CASE("Issue 343") { public: A() = default; - A(int id_, std::string name_) : name(move(name_)), id(id_) {} + A(int id_, std::string name_) : name(std::move(name_)), id(id_) {} int getId() const { return this->id; diff --git a/tests/select_constraints_tests.cpp b/tests/select_constraints_tests.cpp index bf085276c..c1d4d7d08 100644 --- a/tests/select_constraints_tests.cpp +++ b/tests/select_constraints_tests.cpp @@ -219,7 +219,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User1() = default; - User1(int id, std::string name) : id{id}, name{move(name)} {} + User1(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; @@ -270,7 +270,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User2() = default; User2(int id, std::string firstName, std::string lastName, std::string country) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, country{country} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, country{country} {} #endif }; @@ -281,7 +281,8 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Track2() = default; - Track2(int id, std::string name, long milliseconds) : id{id}, name{move(name)}, milliseconds{milliseconds} {} + Track2(int id, std::string name, long milliseconds) : + id{id}, name{std::move(name)}, milliseconds{milliseconds} {} #endif }; @@ -377,7 +378,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User3() = default; - User3(int id, int age, std::string name) : id{id}, age{age}, name{move(name)} {} + User3(int id, int age, std::string name) : id{id}, age{age}, name{std::move(name)} {} #endif }; @@ -420,7 +421,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User4() = default; - User4(int id, std::string firstName) : id{id}, firstName{move(firstName)} {} + User4(int id, std::string firstName) : id{id}, firstName{std::move(firstName)} {} #endif bool operator==(const User4& user) const { @@ -457,7 +458,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User5() = default; User5(int id, std::string firstName, std::string lastName, long registerTime) : - id{id}, firstName{move(firstName)}, lastName{move(lastName)}, registerTime{registerTime} {} + id{id}, firstName{std::move(firstName)}, lastName{std::move(lastName)}, registerTime{registerTime} {} #endif }; diff --git a/tests/statement_serializer_tests/column_names.cpp b/tests/statement_serializer_tests/column_names.cpp index 1cc7dc48f..5b6ae2537 100644 --- a/tests/statement_serializer_tests/column_names.cpp +++ b/tests/statement_serializer_tests/column_names.cpp @@ -48,7 +48,7 @@ TEST_CASE("statement_serializer column names") { } void setName(std::string value) { - this->name = move(value); + this->name = std::move(value); } private: diff --git a/tests/statement_serializer_tests/foreign_key.cpp b/tests/statement_serializer_tests/foreign_key.cpp index 4a938fe99..1a79ca061 100644 --- a/tests/statement_serializer_tests/foreign_key.cpp +++ b/tests/statement_serializer_tests/foreign_key.cpp @@ -297,7 +297,7 @@ TEST_CASE("statement_serializer foreign key") { struct User : Object { std::string name; - User(decltype(id) id_, decltype(name) name_) : Object{id_}, name(move(name_)) {} + User(decltype(id) id_, decltype(name) name_) : Object{id_}, name(std::move(name_)) {} }; struct Token : Object { diff --git a/tests/statement_serializer_tests/statements/insert_replace.cpp b/tests/statement_serializer_tests/statements/insert_replace.cpp index b13e7e08a..e30be740a 100644 --- a/tests/statement_serializer_tests/statements/insert_replace.cpp +++ b/tests/statement_serializer_tests/statements/insert_replace.cpp @@ -16,7 +16,7 @@ TEST_CASE("statement_serializer insert/replace") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; struct UserBackup { @@ -25,7 +25,7 @@ TEST_CASE("statement_serializer insert/replace") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED UserBackup() = default; - UserBackup(int id, std::string name) : id{id}, name{move(name)} {} + UserBackup(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; auto table = make_table("users", make_column("id", &User::id), make_column("name", &User::name)); diff --git a/tests/static_tests/column_result_t.cpp b/tests/static_tests/column_result_t.cpp index a40d32df2..bab71581e 100644 --- a/tests/static_tests/column_result_t.cpp +++ b/tests/static_tests/column_result_t.cpp @@ -26,7 +26,7 @@ TEST_CASE("column_result_t") { } void setComment(std::string comment) { - this->comment = move(comment); + this->comment = std::move(comment); } const std::string& getComment() const { diff --git a/tests/static_tests/function_static_tests.cpp b/tests/static_tests/function_static_tests.cpp index 00a3d5aa2..9217d3a89 100644 --- a/tests/static_tests/function_static_tests.cpp +++ b/tests/static_tests/function_static_tests.cpp @@ -201,7 +201,7 @@ TEST_CASE("function static") { } std::string fin() { - return move(result); + return std::move(result); } }; diff --git a/tests/storage_non_crud_tests.cpp b/tests/storage_non_crud_tests.cpp index e65856f10..100bffdd6 100644 --- a/tests/storage_non_crud_tests.cpp +++ b/tests/storage_non_crud_tests.cpp @@ -10,7 +10,7 @@ TEST_CASE("explicit from") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; auto storage = make_storage( @@ -80,7 +80,7 @@ TEST_CASE("update set null") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, decltype(name) name) : id{id}, name{move(name)} {} + User(int id, decltype(name) name) : id{id}, name{std::move(name)} {} #endif }; @@ -127,7 +127,7 @@ TEST_CASE("InsertRange") { #ifndef SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED Object() = default; - Object(int id, std::string name) : id{id}, name{move(name)} {} + Object(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; @@ -137,7 +137,7 @@ TEST_CASE("InsertRange") { #ifndef SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED ObjectWithoutRowid() = default; - ObjectWithoutRowid(int id, std::string name) : id{id}, name{move(name)} {} + ObjectWithoutRowid(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; @@ -391,13 +391,13 @@ TEST_CASE("Replace query") { #ifndef SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED Object() = default; - Object(int id, std::string name) : id{id}, name{move(name)} {} + Object(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; struct User { - User(int id_, std::string name_) : id(id_), name(move(name_)) {} + User(int id_, std::string name_) : id(id_), name(std::move(name_)) {} int getId() const { return this->id; @@ -412,7 +412,7 @@ TEST_CASE("Replace query") { } void setName(std::string name_) { - this->name = move(name_); + this->name = std::move(name_); } private: diff --git a/tests/sync_schema_tests.cpp b/tests/sync_schema_tests.cpp index 7ec68d229..a7e1d21c3 100644 --- a/tests/sync_schema_tests.cpp +++ b/tests/sync_schema_tests.cpp @@ -145,7 +145,7 @@ TEST_CASE("issue521") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED MockDatabasePoco() = default; MockDatabasePoco(int id, std::string name, uint32_t alpha, float beta) : - id{id}, name{move(name)}, alpha{alpha}, beta{beta} {} + id{id}, name{std::move(name)}, alpha{alpha}, beta{beta} {} #endif }; std::vector pocosToInsert; @@ -291,7 +291,7 @@ TEST_CASE("sync_schema") { User(int id_) : id(id_) {} - User(int id_, std::string name_) : id(id_), name(move(name_)) {} + User(int id_, std::string name_) : id(id_), name(std::move(name_)) {} User(int id_, int age_) : id(id_), age(age_) {} diff --git a/tests/table_tests.cpp b/tests/table_tests.cpp index d36e5e8dc..0b5618b0d 100644 --- a/tests/table_tests.cpp +++ b/tests/table_tests.cpp @@ -57,7 +57,7 @@ TEST_CASE("table::find_column_name") { } void setFirstName(std::string value) { - this->_firstName = move(value); + this->_firstName = std::move(value); } const std::string& lastName() const { @@ -65,7 +65,7 @@ TEST_CASE("table::find_column_name") { } void setLastName(std::string value) { - this->_lastName = move(value); + this->_lastName = std::move(value); } int countryCode() const { @@ -81,7 +81,7 @@ TEST_CASE("table::find_column_name") { } void setPhoneNumber(std::string value) { - this->_phoneNumber = move(value); + this->_phoneNumber = std::move(value); } int visitsCount() const { diff --git a/tests/tests2.cpp b/tests/tests2.cpp index e69ddfd02..871b9c3b5 100644 --- a/tests/tests2.cpp +++ b/tests/tests2.cpp @@ -79,7 +79,7 @@ TEST_CASE("insert with generated column") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Product() = default; Product(std::string name, double price, double discount, double tax, double netPrice) : - name{move(name)}, price{price}, discount{discount}, tax{tax}, netPrice{netPrice} {} + name{std::move(name)}, price{price}, discount{discount}, tax{tax}, netPrice{netPrice} {} #endif bool operator==(const Product& other) const { diff --git a/tests/tests4.cpp b/tests/tests4.cpp index 9a72a9f7e..3a690df26 100644 --- a/tests/tests4.cpp +++ b/tests/tests4.cpp @@ -29,7 +29,7 @@ TEST_CASE("Unique ptr in update") { } { std::unique_ptr ptr; - storage.update_all(set(assign(&User::name, move(ptr)))); + storage.update_all(set(assign(&User::name, std::move(ptr)))); REQUIRE(storage.count(where(is_not_null(&User::name))) == 0); } } @@ -77,7 +77,7 @@ TEST_CASE("join") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED User() = default; - User(int id, std::string name) : id{id}, name{move(name)} {} + User(int id, std::string name) : id{id}, name{std::move(name)} {} #endif }; diff --git a/tests/transaction_tests.cpp b/tests/transaction_tests.cpp index adf9792f8..6df82d22e 100644 --- a/tests/transaction_tests.cpp +++ b/tests/transaction_tests.cpp @@ -10,7 +10,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Object() = default; - Object(int id, std::string name) : id{id}, name{move(name)} {} + Object(int id, std::string name) : id{id}, name{std::move(name)} {} #endif bool operator==(const Object& other) const { @@ -175,7 +175,7 @@ TEST_CASE("Transaction guard") { auto countNow = storage.count(); REQUIRE(countNow == countBefore + 1); } - SECTION("move ctor") { + SECTION("std::move ctor") { std::vector guards; auto countBefore = storage.count(); { diff --git a/tests/trigger_tests.cpp b/tests/trigger_tests.cpp index 36d6a7de3..a5946ac80 100644 --- a/tests/trigger_tests.cpp +++ b/tests/trigger_tests.cpp @@ -12,7 +12,7 @@ TEST_CASE("triggers_basics") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED TestInsert() = default; - TestInsert(int id, std::string text, int x, int y) : id{id}, text{move(text)}, x{x}, y{y} {} + TestInsert(int id, std::string text, int x, int y) : id{id}, text{std::move(text)}, x{x}, y{y} {} #endif }; struct TestUpdate { @@ -23,7 +23,7 @@ TEST_CASE("triggers_basics") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED TestUpdate() = default; - TestUpdate(int id, std::string text, int x, int y) : id{id}, text{move(text)}, x{x}, y{y} {} + TestUpdate(int id, std::string text, int x, int y) : id{id}, text{std::move(text)}, x{x}, y{y} {} #endif }; struct TestDelete { @@ -34,7 +34,7 @@ TEST_CASE("triggers_basics") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED TestDelete() = default; - TestDelete(int id, std::string text, int x, int y) : id{id}, text{move(text)}, x{x}, y{y} {} + TestDelete(int id, std::string text, int x, int y) : id{id}, text{std::move(text)}, x{x}, y{y} {} #endif }; diff --git a/tests/unique_cases/get_all_with_two_tables.cpp b/tests/unique_cases/get_all_with_two_tables.cpp index f0eb715f3..91d17acde 100644 --- a/tests/unique_cases/get_all_with_two_tables.cpp +++ b/tests/unique_cases/get_all_with_two_tables.cpp @@ -9,7 +9,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_PAREN_INIT_SUPPORTED Pattern() = default; - Pattern(std::string value) : value{move(value)} {} + Pattern(std::string value) : value{std::move(value)} {} #endif }; struct Item { @@ -18,7 +18,7 @@ namespace { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED Item() = default; - Item(int id, std::string attributes) : id{id}, attributes{move(attributes)} {} + Item(int id, std::string attributes) : id{id}, attributes{std::move(attributes)} {} #endif }; diff --git a/tests/unique_cases/prepare_get_all_with_case.cpp b/tests/unique_cases/prepare_get_all_with_case.cpp index 1633a0f5d..60d21dcb4 100644 --- a/tests/unique_cases/prepare_get_all_with_case.cpp +++ b/tests/unique_cases/prepare_get_all_with_case.cpp @@ -10,7 +10,7 @@ TEST_CASE("Prepare with case") { #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED UserProfile() = default; - UserProfile(int id, std::string firstName) : id{id}, firstName{move(firstName)} {} + UserProfile(int id, std::string firstName) : id{id}, firstName{std::move(firstName)} {} #endif }; From 25217163e7568a8945f772a4455e8c5ead287fed Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 5 Feb 2023 21:06:43 +0200 Subject: [PATCH 018/100] Added a few unit tests for `table_name_collector` * Also made `aliased_column()` work with column pointers --- dev/alias.h | 11 +- dev/statement_serializer.h | 3 +- dev/table_name_collector.h | 9 +- dev/table_type_of.h | 5 +- include/sqlite_orm/sqlite_orm.h | 331 ++++++++++++++++---------------- tests/CMakeLists.txt | 1 + tests/table_name_collector.cpp | 49 +++++ 7 files changed, 238 insertions(+), 171 deletions(-) create mode 100644 tests/table_name_collector.cpp diff --git a/dev/alias.h b/dev/alias.h index bbc839fc4..69338910c 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -4,6 +4,8 @@ #include // std::stringstream #include // std::string +#include "type_traits.h" + namespace sqlite_orm { /** @@ -86,10 +88,11 @@ namespace sqlite_orm { * @return column with table alias attached. Place it instead of a column statement in case you need to specify a * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example */ - template - internal::alias_column_t alias_column(C c) { - static_assert(std::is_member_pointer::value, - "alias_column argument must be a member pointer mapped to a storage"); + template + internal::alias_column_t alias_column(C c) { + using table_type = internal::type_t; + static_assert(std::is_same, table_type>::value, + "Column must be from aliased table"); return {c}; } diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 80c7f49c8..ba4c68c39 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -11,6 +11,7 @@ #include #include #include "functional/cxx_string_view.h" +#include "functional/cxx_optional.h" #include "functional/cxx_universal.h" #include "functional/cxx_functional_polyfill.h" @@ -1076,7 +1077,7 @@ namespace sqlite_orm { using statement_type = dynamic_set_t; template - std::string operator()(const statement_type& statement, const Ctx& context) const { + std::string operator()(const statement_type& statement, const Ctx&) const { std::stringstream ss; ss << "SET "; int index = 0; diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index a5e6334ad..abe128c3b 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -4,6 +4,7 @@ #include // std::string #include // std::function #include // std::type_index +#include // std::move #include "functional/cxx_type_traits_polyfill.h" #include "type_traits.h" @@ -41,9 +42,11 @@ namespace sqlite_orm { table_names.emplace(this->find_table_name(typeid(T)), ""); } - template - void operator()(const alias_column_t& a) const { - (*this)(a.column, alias_extractor::get()); + template + void operator()(const alias_column_t&) const { + // note: instead of accessing the column, we are interested in the type the column is aliased into + auto tableName = this->find_table_name(typeid(mapped_type_proxy_t)); + table_names.emplace(std::move(tableName), alias_extractor::get()); } template diff --git a/dev/table_type_of.h b/dev/table_type_of.h index 842002e8e..47c9d9d88 100644 --- a/dev/table_type_of.h +++ b/dev/table_type_of.h @@ -1,7 +1,5 @@ #pragma once -#include "indexed_column.h" - namespace sqlite_orm { namespace internal { @@ -9,6 +7,9 @@ namespace sqlite_orm { template struct column_pointer; + template + struct indexed_column_t; + /** * Trait class used to define table mapped type by setter/getter/member * T - member pointer diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 0eca7e0c3..ab4406510 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1206,158 +1206,6 @@ namespace sqlite_orm { // #include "table_type_of.h" -// #include "indexed_column.h" - -#include // std::string -#include // std::move - -// #include "functional/cxx_universal.h" - -// #include "ast/where.h" - -#include // std::false_type, std::true_type -#include // std::move - -// #include "../functional/cxx_universal.h" - -// #include "../functional/cxx_type_traits_polyfill.h" - -// #include "../serialize_result_type.h" - -// #include "functional/cxx_string_view.h" - -// #include "cxx_core_features.h" - -#if SQLITE_ORM_HAS_INCLUDE() -#include -#endif - -#if __cpp_lib_string_view >= 201606L -#define SQLITE_ORM_STRING_VIEW_SUPPORTED -#endif - -#ifndef SQLITE_ORM_STRING_VIEW_SUPPORTED -#include // std::string -#endif - -namespace sqlite_orm { - namespace internal { -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - using serialize_result_type = std::string_view; -#else - using serialize_result_type = std::string; -#endif - } -} - -namespace sqlite_orm { - namespace internal { - - struct where_string { - serialize_result_type serialize() const { - return "WHERE"; - } - }; - - /** - * WHERE argument holder. - * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc - * Don't construct it manually. Call `where(...)` function instead. - */ - template - struct where_t : where_string { - using expression_type = C; - - expression_type expression; - - where_t(expression_type expression_) : expression(std::move(expression_)) {} - }; - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_where_v = polyfill::is_specialization_of_v; - - template - using is_where = polyfill::bool_constant>; - } - - /** - * WHERE clause. Use it to add WHERE conditions wherever you like. - * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc - * @example - * // SELECT name - * // FROM letters - * // WHERE id > 3 - * auto rows = storage.select(&Letter::name, where(greater_than(&Letter::id, 3))); - */ - template - internal::where_t where(C expression) { - return {std::move(expression)}; - } -} - -namespace sqlite_orm { - - namespace internal { - - template - struct indexed_column_t { - using column_type = C; - -#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - indexed_column_t(column_type _column_or_expression) : - column_or_expression(std::move(_column_or_expression)) {} -#endif - - column_type column_or_expression; - std::string _collation_name; - int _order = 0; // -1 = desc, 1 = asc, 0 = not specified - - indexed_column_t collate(std::string name) { - auto res = std::move(*this); - res._collation_name = std::move(name); - return res; - } - - indexed_column_t asc() { - auto res = std::move(*this); - res._order = 1; - return res; - } - - indexed_column_t desc() { - auto res = std::move(*this); - res._order = -1; - return res; - } - }; - - template - indexed_column_t make_indexed_column(C col) { - return {std::move(col)}; - } - - template - where_t make_indexed_column(where_t wher) { - return std::move(wher); - } - - template - indexed_column_t make_indexed_column(indexed_column_t col) { - return std::move(col); - } - } - - /** - * Use this function to specify indexed column inside `make_index` function call. - * Example: make_index("index_name", indexed_column(&User::id).asc()) - */ - template - internal::indexed_column_t indexed_column(C column_or_expression) { - return {std::move(column_or_expression)}; - } - -} - namespace sqlite_orm { namespace internal { @@ -1365,6 +1213,9 @@ namespace sqlite_orm { template struct column_pointer; + template + struct indexed_column_t; + /** * Trait class used to define table mapped type by setter/getter/member * T - member pointer @@ -2001,6 +1852,32 @@ 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 + +#if __cpp_lib_string_view >= 201606L +#define SQLITE_ORM_STRING_VIEW_SUPPORTED +#endif + +#ifndef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include // std::string +#endif + +namespace sqlite_orm { + namespace internal { +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + using serialize_result_type = std::string_view; +#else + using serialize_result_type = std::string; +#endif + } +} + namespace sqlite_orm { namespace internal { @@ -4175,6 +4052,8 @@ namespace sqlite_orm { #include // std::stringstream #include // std::string +// #include "type_traits.h" + namespace sqlite_orm { /** @@ -4257,10 +4136,11 @@ namespace sqlite_orm { * @return column with table alias attached. Place it instead of a column statement in case you need to specify a * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example */ - template - internal::alias_column_t alias_column(C c) { - static_assert(std::is_member_pointer::value, - "alias_column argument must be a member pointer mapped to a storage"); + template + internal::alias_column_t alias_column(C c) { + using table_type = internal::type_t; + static_assert(std::is_same, table_type>::value, + "Column must be from aliased table"); return {c}; } @@ -6634,6 +6514,60 @@ namespace sqlite_orm { // #include "ast/where.h" +#include // std::false_type, std::true_type +#include // std::move + +// #include "../functional/cxx_universal.h" + +// #include "../functional/cxx_type_traits_polyfill.h" + +// #include "../serialize_result_type.h" + +namespace sqlite_orm { + namespace internal { + + struct where_string { + serialize_result_type serialize() const { + return "WHERE"; + } + }; + + /** + * WHERE argument holder. + * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc + * Don't construct it manually. Call `where(...)` function instead. + */ + template + struct where_t : where_string { + using expression_type = C; + + expression_type expression; + + where_t(expression_type expression_) : expression(std::move(expression_)) {} + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_where_v = polyfill::is_specialization_of_v; + + template + using is_where = polyfill::bool_constant>; + } + + /** + * WHERE clause. Use it to add WHERE conditions wherever you like. + * C is expression type. Can be any expression like: is_equal_t, is_null_t, exists_t etc + * @example + * // SELECT name + * // FROM letters + * // WHERE id > 3 + * auto rows = storage.select(&Letter::name, where(greater_than(&Letter::id, 3))); + */ + template + internal::where_t where(C expression) { + return {std::move(expression)}; + } +} + // #include "ast/group_by.h" #include // std::tuple, std::make_tuple @@ -9030,6 +8964,76 @@ namespace sqlite_orm { // #include "indexed_column.h" +#include // std::string +#include // std::move + +// #include "functional/cxx_universal.h" + +// #include "ast/where.h" + +namespace sqlite_orm { + + namespace internal { + + template + struct indexed_column_t { + using column_type = C; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + indexed_column_t(column_type _column_or_expression) : + column_or_expression(std::move(_column_or_expression)) {} +#endif + + column_type column_or_expression; + std::string _collation_name; + int _order = 0; // -1 = desc, 1 = asc, 0 = not specified + + indexed_column_t collate(std::string name) { + auto res = std::move(*this); + res._collation_name = std::move(name); + return res; + } + + indexed_column_t asc() { + auto res = std::move(*this); + res._order = 1; + return res; + } + + indexed_column_t desc() { + auto res = std::move(*this); + res._order = -1; + return res; + } + }; + + template + indexed_column_t make_indexed_column(C col) { + return {std::move(col)}; + } + + template + where_t make_indexed_column(where_t wher) { + return std::move(wher); + } + + template + indexed_column_t make_indexed_column(indexed_column_t col) { + return std::move(col); + } + } + + /** + * Use this function to specify indexed column inside `make_index` function call. + * Example: make_index("index_name", indexed_column(&User::id).asc()) + */ + template + internal::indexed_column_t indexed_column(C column_or_expression) { + return {std::move(column_or_expression)}; + } + +} + // #include "table_type_of.h" namespace sqlite_orm { @@ -11103,6 +11107,7 @@ namespace sqlite_orm { #include // std::string #include // std::function #include // std::type_index +#include // std::move // #include "functional/cxx_type_traits_polyfill.h" @@ -11144,9 +11149,11 @@ namespace sqlite_orm { table_names.emplace(this->find_table_name(typeid(T)), ""); } - template - void operator()(const alias_column_t& a) const { - (*this)(a.column, alias_extractor::get()); + template + void operator()(const alias_column_t&) const { + // note: instead of accessing the column, we are interested in the type the column is aliased into + auto tableName = this->find_table_name(typeid(mapped_type_proxy_t)); + table_names.emplace(std::move(tableName), alias_extractor::get()); } template @@ -14967,6 +14974,8 @@ namespace sqlite_orm { #include // #include "functional/cxx_string_view.h" +// #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -16254,7 +16263,7 @@ namespace sqlite_orm { using statement_type = dynamic_set_t; template - std::string operator()(const statement_type& statement, const Ctx& context) const { + std::string operator()(const statement_type& statement, const Ctx&) const { std::stringstream ss; ss << "SET "; int index = 0; @@ -19229,7 +19238,7 @@ namespace sqlite_orm { /** * Generalized form of the 'remember' SQL function that is a pass-through for values - * (it returns its argument unchanged using std::move semantics) but also saves the + * (it returns its argument unchanged using move semantics) but also saves the * value that is passed through into a bound variable. */ template diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7670da3a9..2b1e4b093 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -129,6 +129,7 @@ add_executable(unit_tests row_id.cpp trigger_tests.cpp ast_iterator_tests.cpp + table_name_collector.cpp pointer_passing_interface.cpp ) diff --git a/tests/table_name_collector.cpp b/tests/table_name_collector.cpp new file mode 100644 index 000000000..8d5a795e8 --- /dev/null +++ b/tests/table_name_collector.cpp @@ -0,0 +1,49 @@ +#include +#include + +using namespace sqlite_orm; +using internal::alias_extractor; + +TEST_CASE("table name collector") { + struct User { + int id = 0; + std::string name; + }; + + auto table = make_table("users", make_column("id", &User::id), make_column("name", &User::name)); + using db_objects_t = internal::db_objects_tuple; + auto dbObjects = db_objects_t{table}; + internal::table_name_collector::table_name_set expected; + + SECTION("from table") { + internal::serializer_context context{dbObjects}; + internal::table_name_collector collector([&context](const std::type_index& ti) { + return internal::find_table_name(context.db_objects, ti); + }); + + SECTION("regular column") { + using als = alias_z; + auto expression = &User::id; + expected.emplace(table.name, ""); + iterate_ast(expression, collector); + } + SECTION("regular column pointer") { + auto expression = column(&User::id); + expected.emplace(table.name, ""); + iterate_ast(expression, collector); + } + SECTION("aliased regular column") { + using als = alias_z; + auto expression = alias_column(&User::id); + expected.emplace(table.name, "z"); + iterate_ast(expression, collector); + } + SECTION("aliased regular column pointer") { + using als = alias_z; + auto expression = alias_column(column(&User::id)); + expected.emplace(table.name, "z"); + iterate_ast(expression, collector); + } + REQUIRE(collector.table_names == expected); + } +} From acd4e79942543bdebb19f265f21c093037d254e1 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 6 Feb 2023 00:28:46 +0200 Subject: [PATCH 019/100] Collect table names w/o using RTTI --- dev/ast/set.h | 23 ++--- dev/statement_serializer.h | 59 ++++--------- dev/storage_impl.h | 12 --- dev/table_name_collector.h | 52 +++++++----- include/sqlite_orm/sqlite_orm.h | 146 +++++++++++--------------------- tests/table_name_collector.cpp | 6 +- 6 files changed, 102 insertions(+), 196 deletions(-) diff --git a/dev/ast/set.h b/dev/ast/set.h index c17615132..b22e0e40b 100644 --- a/dev/ast/set.h +++ b/dev/ast/set.h @@ -38,41 +38,30 @@ namespace sqlite_orm { using entry_t = dynamic_set_entry; using const_iterator = typename std::vector::const_iterator; - dynamic_set_t(const context_t& context_) : - context(context_), collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }) {} + dynamic_set_t(const context_t& context_) : context(context_), collector(this->context.db_objects) {} dynamic_set_t(const dynamic_set_t& other) : - entries(other.entries), context(other.context), collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }) { + entries(other.entries), context(other.context), collector(this->context.db_objects) { collector.table_names = other.collector.table_names; } dynamic_set_t(dynamic_set_t&& other) : entries(std::move(other.entries)), context(std::move(other.context)), - collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }) { + collector(this->context.db_objects) { collector.table_names = std::move(other.collector.table_names); } dynamic_set_t& operator=(const dynamic_set_t& other) { this->entries = other.entries; this->context = other.context; - this->collector = table_name_collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }); + this->collector = table_name_collector(this->context.db_objects); this->collector.table_names = other.collector.table_names; } dynamic_set_t& operator=(dynamic_set_t&& other) { this->entries = std::move(other.entries); this->context = std::move(other.context); - this->collector = table_name_collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }); + this->collector = table_name_collector(this->context.db_objects); this->collector.table_names = std::move(other.collector.table_names); } @@ -102,7 +91,7 @@ namespace sqlite_orm { std::vector entries; context_t context; - table_name_collector collector; + table_name_collector collector; }; template diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index ba4c68c39..b7e29c093 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1111,40 +1111,17 @@ namespace sqlite_orm { } }; - template - struct table_name_collector_holder; - - template - struct table_name_collector_holder> { - - table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) : - collector(std::move(find_table_name)) {} - - table_name_collector collector; - }; - - template - struct table_name_collector_holder> { - - table_name_collector_holder(const table_name_collector& collector) : collector(collector) {} - - const table_name_collector& collector; - }; - template - table_name_collector_holder> make_table_name_collector_holder(const set_t& set, - const Ctx& context) { - table_name_collector_holder> holder([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); - iterate_ast(set, holder.collector); - return holder; + std::set> collect_table_names(const set_t& set, const Ctx& ctx) { + auto collector = make_table_name_collector(ctx.db_objects); + iterate_ast(set, collector); + return std::move(collector.table_names); } - template - table_name_collector_holder> make_table_name_collector_holder(const dynamic_set_t& set, - const Ctx&) { - return {set.collector}; + template + const std::set>& collect_table_names(const dynamic_set_t& set, + const Ctx&) { + return set.collector.table_names; } template @@ -1153,19 +1130,15 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { - std::string tableName; - - auto collectorHolder = make_table_name_collector_holder(statement.set, context); - const table_name_collector& collector = collectorHolder.collector; - if(collector.table_names.empty()) { + const auto& tableNames = collect_table_names(statement.set, context); + if(tableNames.empty()) { throw std::system_error{orm_error_code::no_tables_specified}; } - tableName = collector.table_names.begin()->first; + const std::string& tableName = tableNames.begin()->first; std::stringstream ss; - ss << "UPDATE " << streaming_identifier(tableName); - ss << ' ' << serialize(statement.set, context); - ss << streaming_conditions_tuple(statement.conditions, context); + ss << "UPDATE " << streaming_identifier(tableName) << ' ' << serialize(statement.set, context) + << streaming_conditions_tuple(statement.conditions, context); return ss.str(); } }; @@ -1376,7 +1349,7 @@ namespace sqlite_orm { std::string serialize_get_all_impl(const T& get, const Ctx& context) { using primary_type = type_t; - table_name_collector collector; + auto collector = make_table_name_collector(context.db_objects); collector.table_names.emplace(lookup_table_name(context.db_objects), ""); // note: not collecting table names from get.conditions; @@ -1525,9 +1498,7 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - table_name_collector collector([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); + auto collector = make_table_name_collector(context.db_objects); constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; if(!explicitFromItemsCount) { iterate_ast(sel.col, collector); diff --git a/dev/storage_impl.h b/dev/storage_impl.h index 701ffa43c..bc300fa31 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -37,18 +37,6 @@ namespace sqlite_orm { empty_callable())(dbObjects); } - template = true> - std::string find_table_name(const DBOs& dbObjects, const std::type_index& ti) { - std::string res; - iterate_tuple(dbObjects, tables_index_sequence{}, [&ti, &res](const auto& table) { - using table_type = std::decay_t; - if(ti == typeid(object_type_t)) { - res = table.name; - } - }); - return res; - } - template = true> std::string lookup_table_name(const DBOs& dbObjects) { return static_if>( diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index abe128c3b..26879f9c3 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -2,9 +2,7 @@ #include // std::set #include // std::string -#include // std::function -#include // std::type_index -#include // std::move +#include // std::pair, std::move #include "functional/cxx_type_traits_polyfill.h" #include "type_traits.h" @@ -16,50 +14,53 @@ namespace sqlite_orm { namespace internal { - struct table_name_collector { + struct table_name_collector_base { using table_name_set = std::set>; - using find_table_name_t = std::function; - find_table_name_t find_table_name; mutable table_name_set table_names; + }; + + template + struct table_name_collector : table_name_collector_base { + using db_objects_type = DBOs; + + const db_objects_type& db_objects; table_name_collector() = default; - table_name_collector(find_table_name_t find_table_name) : find_table_name{std::move(find_table_name)} {} + table_name_collector(const db_objects_type& dbObjects) : db_objects{dbObjects} {} template - table_name_set operator()(const T&) const { - return {}; - } + void operator()(const T&) const {} template void operator()(F O::*, std::string alias = {}) const { - table_names.emplace(this->find_table_name(typeid(O)), std::move(alias)); + this->table_names.emplace(lookup_table_name(this->db_objects), std::move(alias)); } template void operator()(const column_pointer&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const alias_column_t&) const { // note: instead of accessing the column, we are interested in the type the column is aliased into - auto tableName = this->find_table_name(typeid(mapped_type_proxy_t)); - table_names.emplace(std::move(tableName), alias_extractor::get()); + auto tableName = lookup_table_name>(this->db_objects); + this->table_names.emplace(std::move(tableName), alias_extractor::get()); } template void operator()(const count_asterisk_t&) const { - auto tableName = this->find_table_name(typeid(T)); + auto tableName = lookup_table_name(this->db_objects); if(!tableName.empty()) { - table_names.emplace(std::move(tableName), ""); + this->table_names.emplace(std::move(tableName), ""); } } template = true> void operator()(const asterisk_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(db_objects), ""); } template = true> @@ -67,31 +68,36 @@ namespace sqlite_orm { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); - auto tableName = this->find_table_name(typeid(type_t)); - table_names.emplace(std::move(tableName), alias_extractor::get()); + auto tableName = lookup_table_name>(this->db_objects); + this->table_names.emplace(std::move(tableName), alias_extractor::get()); } template void operator()(const object_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const table_rowid_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const table_oid_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const table__rowid_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } }; + template + table_name_collector make_table_name_collector(const DBOs& dbObjects) { + return {dbObjects}; + } + } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ab4406510..ac6ee59d8 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10505,18 +10505,6 @@ namespace sqlite_orm { empty_callable())(dbObjects); } - template = true> - std::string find_table_name(const DBOs& dbObjects, const std::type_index& ti) { - std::string res; - iterate_tuple(dbObjects, tables_index_sequence{}, [&ti, &res](const auto& table) { - using table_type = std::decay_t; - if(ti == typeid(object_type_t)) { - res = table.name; - } - }); - return res; - } - template = true> std::string lookup_table_name(const DBOs& dbObjects) { return static_if>( @@ -11105,9 +11093,7 @@ namespace sqlite_orm { #include // std::set #include // std::string -#include // std::function -#include // std::type_index -#include // std::move +#include // std::pair, std::move // #include "functional/cxx_type_traits_polyfill.h" @@ -11123,50 +11109,53 @@ namespace sqlite_orm { namespace internal { - struct table_name_collector { + struct table_name_collector_base { using table_name_set = std::set>; - using find_table_name_t = std::function; - find_table_name_t find_table_name; mutable table_name_set table_names; + }; + + template + struct table_name_collector : table_name_collector_base { + using db_objects_type = DBOs; + + const db_objects_type& db_objects; table_name_collector() = default; - table_name_collector(find_table_name_t find_table_name) : find_table_name{std::move(find_table_name)} {} + table_name_collector(const db_objects_type& dbObjects) : db_objects{dbObjects} {} template - table_name_set operator()(const T&) const { - return {}; - } + void operator()(const T&) const {} template void operator()(F O::*, std::string alias = {}) const { - table_names.emplace(this->find_table_name(typeid(O)), std::move(alias)); + this->table_names.emplace(lookup_table_name(this->db_objects), std::move(alias)); } template void operator()(const column_pointer&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const alias_column_t&) const { // note: instead of accessing the column, we are interested in the type the column is aliased into - auto tableName = this->find_table_name(typeid(mapped_type_proxy_t)); - table_names.emplace(std::move(tableName), alias_extractor::get()); + auto tableName = lookup_table_name>(this->db_objects); + this->table_names.emplace(std::move(tableName), alias_extractor::get()); } template void operator()(const count_asterisk_t&) const { - auto tableName = this->find_table_name(typeid(T)); + auto tableName = lookup_table_name(this->db_objects); if(!tableName.empty()) { - table_names.emplace(std::move(tableName), ""); + this->table_names.emplace(std::move(tableName), ""); } } template = true> void operator()(const asterisk_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(db_objects), ""); } template = true> @@ -11174,31 +11163,36 @@ namespace sqlite_orm { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); - auto tableName = this->find_table_name(typeid(type_t)); - table_names.emplace(std::move(tableName), alias_extractor::get()); + auto tableName = lookup_table_name>(this->db_objects); + this->table_names.emplace(std::move(tableName), alias_extractor::get()); } template void operator()(const object_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const table_rowid_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const table_oid_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template void operator()(const table__rowid_t&) const { - table_names.emplace(this->find_table_name(typeid(T)), ""); + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } }; + template + table_name_collector make_table_name_collector(const DBOs& dbObjects) { + return {dbObjects}; + } + } } @@ -11233,41 +11227,30 @@ namespace sqlite_orm { using entry_t = dynamic_set_entry; using const_iterator = typename std::vector::const_iterator; - dynamic_set_t(const context_t& context_) : - context(context_), collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }) {} + dynamic_set_t(const context_t& context_) : context(context_), collector(this->context.db_objects) {} dynamic_set_t(const dynamic_set_t& other) : - entries(other.entries), context(other.context), collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }) { + entries(other.entries), context(other.context), collector(this->context.db_objects) { collector.table_names = other.collector.table_names; } dynamic_set_t(dynamic_set_t&& other) : entries(std::move(other.entries)), context(std::move(other.context)), - collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }) { + collector(this->context.db_objects) { collector.table_names = std::move(other.collector.table_names); } dynamic_set_t& operator=(const dynamic_set_t& other) { this->entries = other.entries; this->context = other.context; - this->collector = table_name_collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }); + this->collector = table_name_collector(this->context.db_objects); this->collector.table_names = other.collector.table_names; } dynamic_set_t& operator=(dynamic_set_t&& other) { this->entries = std::move(other.entries); this->context = std::move(other.context); - this->collector = table_name_collector([this](const std::type_index& ti) { - return find_table_name(this->context.db_objects, ti); - }); + this->collector = table_name_collector(this->context.db_objects); this->collector.table_names = std::move(other.collector.table_names); } @@ -11297,7 +11280,7 @@ namespace sqlite_orm { std::vector entries; context_t context; - table_name_collector collector; + table_name_collector collector; }; template @@ -16297,40 +16280,17 @@ namespace sqlite_orm { } }; - template - struct table_name_collector_holder; - - template - struct table_name_collector_holder> { - - table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) : - collector(std::move(find_table_name)) {} - - table_name_collector collector; - }; - - template - struct table_name_collector_holder> { - - table_name_collector_holder(const table_name_collector& collector) : collector(collector) {} - - const table_name_collector& collector; - }; - template - table_name_collector_holder> make_table_name_collector_holder(const set_t& set, - const Ctx& context) { - table_name_collector_holder> holder([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); - iterate_ast(set, holder.collector); - return holder; + std::set> collect_table_names(const set_t& set, const Ctx& ctx) { + auto collector = make_table_name_collector(ctx.db_objects); + iterate_ast(set, collector); + return std::move(collector.table_names); } - template - table_name_collector_holder> make_table_name_collector_holder(const dynamic_set_t& set, - const Ctx&) { - return {set.collector}; + template + const std::set>& collect_table_names(const dynamic_set_t& set, + const Ctx&) { + return set.collector.table_names; } template @@ -16339,19 +16299,15 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { - std::string tableName; - - auto collectorHolder = make_table_name_collector_holder(statement.set, context); - const table_name_collector& collector = collectorHolder.collector; - if(collector.table_names.empty()) { + const auto& tableNames = collect_table_names(statement.set, context); + if(tableNames.empty()) { throw std::system_error{orm_error_code::no_tables_specified}; } - tableName = collector.table_names.begin()->first; + const std::string& tableName = tableNames.begin()->first; std::stringstream ss; - ss << "UPDATE " << streaming_identifier(tableName); - ss << ' ' << serialize(statement.set, context); - ss << streaming_conditions_tuple(statement.conditions, context); + ss << "UPDATE " << streaming_identifier(tableName) << ' ' << serialize(statement.set, context) + << streaming_conditions_tuple(statement.conditions, context); return ss.str(); } }; @@ -16562,7 +16518,7 @@ namespace sqlite_orm { std::string serialize_get_all_impl(const T& get, const Ctx& context) { using primary_type = type_t; - table_name_collector collector; + auto collector = make_table_name_collector(context.db_objects); collector.table_names.emplace(lookup_table_name(context.db_objects), ""); // note: not collecting table names from get.conditions; @@ -16711,9 +16667,7 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - table_name_collector collector([&context](const std::type_index& ti) { - return find_table_name(context.db_objects, ti); - }); + auto collector = make_table_name_collector(context.db_objects); constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; if(!explicitFromItemsCount) { iterate_ast(sel.col, collector); diff --git a/tests/table_name_collector.cpp b/tests/table_name_collector.cpp index 8d5a795e8..3a5b813ed 100644 --- a/tests/table_name_collector.cpp +++ b/tests/table_name_collector.cpp @@ -13,13 +13,11 @@ TEST_CASE("table name collector") { auto table = make_table("users", make_column("id", &User::id), make_column("name", &User::name)); using db_objects_t = internal::db_objects_tuple; auto dbObjects = db_objects_t{table}; - internal::table_name_collector::table_name_set expected; + internal::table_name_collector_base::table_name_set expected; SECTION("from table") { internal::serializer_context context{dbObjects}; - internal::table_name_collector collector([&context](const std::type_index& ti) { - return internal::find_table_name(context.db_objects, ti); - }); + auto collector = internal::make_table_name_collector(context.db_objects); SECTION("regular column") { using als = alias_z; From c05904ae26e12d32da0e98a62d940a11693e2d1f Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 6 Feb 2023 09:07:16 +0200 Subject: [PATCH 020/100] Simplified `dynamic_set_t` --- dev/ast/set.h | 30 +++++------------------------ dev/table_name_collector.h | 3 ++- include/sqlite_orm/sqlite_orm.h | 34 ++++++++------------------------- 3 files changed, 15 insertions(+), 52 deletions(-) diff --git a/dev/ast/set.h b/dev/ast/set.h index b22e0e40b..0146acbc4 100644 --- a/dev/ast/set.h +++ b/dev/ast/set.h @@ -6,7 +6,7 @@ #include // std::stringstream #include // std::false_type, std::true_type -#include "table_name_collector.h" +#include "../table_name_collector.h" namespace sqlite_orm { @@ -40,30 +40,10 @@ namespace sqlite_orm { dynamic_set_t(const context_t& context_) : context(context_), collector(this->context.db_objects) {} - dynamic_set_t(const dynamic_set_t& other) : - entries(other.entries), context(other.context), collector(this->context.db_objects) { - collector.table_names = other.collector.table_names; - } - - dynamic_set_t(dynamic_set_t&& other) : - entries(std::move(other.entries)), context(std::move(other.context)), - collector(this->context.db_objects) { - collector.table_names = std::move(other.collector.table_names); - } - - dynamic_set_t& operator=(const dynamic_set_t& other) { - this->entries = other.entries; - this->context = other.context; - this->collector = table_name_collector(this->context.db_objects); - this->collector.table_names = other.collector.table_names; - } - - dynamic_set_t& operator=(dynamic_set_t&& other) { - this->entries = std::move(other.entries); - this->context = std::move(other.context); - this->collector = table_name_collector(this->context.db_objects); - this->collector.table_names = std::move(other.collector.table_names); - } + dynamic_set_t(const dynamic_set_t& other) = default; + dynamic_set_t(dynamic_set_t&& other) = default; + dynamic_set_t& operator=(const dynamic_set_t& other) = default; + dynamic_set_t& operator=(dynamic_set_t&& other) = default; template void push_back(assign_t assign) { diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index 26879f9c3..b2df4c51b 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -9,6 +9,7 @@ #include "select_constraints.h" #include "alias.h" #include "core_functions.h" +#include "storage_lookup.h" namespace sqlite_orm { @@ -93,7 +94,7 @@ namespace sqlite_orm { } }; - template + template = true> table_name_collector make_table_name_collector(const DBOs& dbObjects) { return {dbObjects}; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ac6ee59d8..b74e0564f 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -11089,7 +11089,7 @@ namespace sqlite_orm { #include // std::stringstream #include // std::false_type, std::true_type -// #include "table_name_collector.h" +// #include "../table_name_collector.h" #include // std::set #include // std::string @@ -11105,6 +11105,8 @@ namespace sqlite_orm { // #include "core_functions.h" +// #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -11188,7 +11190,7 @@ namespace sqlite_orm { } }; - template + template = true> table_name_collector make_table_name_collector(const DBOs& dbObjects) { return {dbObjects}; } @@ -11229,30 +11231,10 @@ namespace sqlite_orm { dynamic_set_t(const context_t& context_) : context(context_), collector(this->context.db_objects) {} - dynamic_set_t(const dynamic_set_t& other) : - entries(other.entries), context(other.context), collector(this->context.db_objects) { - collector.table_names = other.collector.table_names; - } - - dynamic_set_t(dynamic_set_t&& other) : - entries(std::move(other.entries)), context(std::move(other.context)), - collector(this->context.db_objects) { - collector.table_names = std::move(other.collector.table_names); - } - - dynamic_set_t& operator=(const dynamic_set_t& other) { - this->entries = other.entries; - this->context = other.context; - this->collector = table_name_collector(this->context.db_objects); - this->collector.table_names = other.collector.table_names; - } - - dynamic_set_t& operator=(dynamic_set_t&& other) { - this->entries = std::move(other.entries); - this->context = std::move(other.context); - this->collector = table_name_collector(this->context.db_objects); - this->collector.table_names = std::move(other.collector.table_names); - } + dynamic_set_t(const dynamic_set_t& other) = default; + dynamic_set_t(dynamic_set_t&& other) = default; + dynamic_set_t& operator=(const dynamic_set_t& other) = default; + dynamic_set_t& operator=(dynamic_set_t&& other) = default; template void push_back(assign_t assign) { From 088b094d2e14d87bfaee54593696b3af50370928 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 6 Feb 2023 09:40:40 +0200 Subject: [PATCH 021/100] Used `collect_table_names()` in more places --- dev/statement_serializer.h | 20 +++++++++++++------- include/sqlite_orm/sqlite_orm.h | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index b7e29c093..2a25bb0a8 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1124,6 +1124,14 @@ namespace sqlite_orm { return set.collector.table_names; } + template = true> + std::set> collect_table_names(const T& sel, const Ctx& ctx) { + auto collector = make_table_name_collector(ctx.db_objects); + iterate_ast(sel.col, collector); + iterate_ast(sel.conditions, collector); + return std::move(collector.table_names); + } + template struct statement_serializer, void> { using statement_type = update_all_t; @@ -1498,22 +1506,20 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - auto collector = make_table_name_collector(context.db_objects); constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; if(!explicitFromItemsCount) { - iterate_ast(sel.col, collector); - iterate_ast(sel.conditions, collector); - join_iterator()([&collector, &context](const auto& c) { + auto tableNames = collect_table_names(sel, context); + join_iterator()([&tableNames, &context](const auto& c) { using original_join_type = typename std::decay_t::join_type::type; using cross_join_type = mapped_type_proxy_t; auto crossJoinedTableName = lookup_table_name(context.db_objects); auto tableAliasString = alias_extractor::get(); std::pair tableNameWithAlias{std::move(crossJoinedTableName), std::move(tableAliasString)}; - collector.table_names.erase(tableNameWithAlias); + tableNames.erase(tableNameWithAlias); }); - if(!collector.table_names.empty() && !isCompoundOperator) { - ss << " FROM " << streaming_identifiers(collector.table_names); + if(!tableNames.empty() && !isCompoundOperator) { + ss << " FROM " << streaming_identifiers(tableNames); } } ss << streaming_conditions_tuple(sel.conditions, context); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index b74e0564f..914a2c16b 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16275,6 +16275,14 @@ namespace sqlite_orm { return set.collector.table_names; } + template = true> + std::set> collect_table_names(const T& sel, const Ctx& ctx) { + auto collector = make_table_name_collector(ctx.db_objects); + iterate_ast(sel.col, collector); + iterate_ast(sel.conditions, collector); + return std::move(collector.table_names); + } + template struct statement_serializer, void> { using statement_type = update_all_t; @@ -16649,22 +16657,20 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - auto collector = make_table_name_collector(context.db_objects); constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; if(!explicitFromItemsCount) { - iterate_ast(sel.col, collector); - iterate_ast(sel.conditions, collector); - join_iterator()([&collector, &context](const auto& c) { + auto tableNames = collect_table_names(sel, context); + join_iterator()([&tableNames, &context](const auto& c) { using original_join_type = typename std::decay_t::join_type::type; using cross_join_type = mapped_type_proxy_t; auto crossJoinedTableName = lookup_table_name(context.db_objects); auto tableAliasString = alias_extractor::get(); std::pair tableNameWithAlias{std::move(crossJoinedTableName), std::move(tableAliasString)}; - collector.table_names.erase(tableNameWithAlias); + tableNames.erase(tableNameWithAlias); }); - if(!collector.table_names.empty() && !isCompoundOperator) { - ss << " FROM " << streaming_identifiers(collector.table_names); + if(!tableNames.empty() && !isCompoundOperator) { + ss << " FROM " << streaming_identifiers(tableNames); } } ss << streaming_conditions_tuple(sel.conditions, context); From 0337cc654dadbbf2a4722e1223cda6d7e18ea3a7 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 6 Feb 2023 20:19:43 +0200 Subject: [PATCH 022/100] Streamlined code when rounding off the collection of table names --- dev/ast_iterator.h | 13 ++++-- dev/functional/static_magic.h | 2 + dev/statement_binder.h | 4 +- dev/statement_serializer.h | 20 ++++----- dev/storage_impl.h | 6 +-- dev/storage_lookup.h | 7 +++ dev/table_name_collector.h | 26 +++++------ include/sqlite_orm/sqlite_orm.h | 79 ++++++++++++++++++++------------- tests/ast_iterator_tests.cpp | 2 + 9 files changed, 95 insertions(+), 64 deletions(-) diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 23d2698e0..795ce22dd 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -28,9 +28,16 @@ namespace sqlite_orm { * which will be called for any node of provided expression. * E.g. if we pass `where(is_equal(5, max(&User::id, 10))` then * callable object will be called with 5, &User::id and 10. - * ast_iterator is used mostly in finding literals to be bound to - * a statement. To use it just call `iterate_ast(object, callable);` - * T is an ast element. E.g. where_t + * ast_iterator is used in finding literals to be bound to + * a statement, and to collect table names. + * + * Note that not all leaves of the expression tree are always visited: + * Column expressions can be more complex, but are passed as a whole to the callable. + * Examples are `column_pointer<>` and `alias_column_t<>`. + * + * To use `ast_iterator` call `iterate_ast(object, callable);` + * + * `T` is an ast element, e.g. where_t */ template struct ast_iterator { diff --git a/dev/functional/static_magic.h b/dev/functional/static_magic.h index 6304272b4..980107270 100644 --- a/dev/functional/static_magic.h +++ b/dev/functional/static_magic.h @@ -1,6 +1,8 @@ #pragma once +#ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED #include // std::false_type, std::true_type, std::integral_constant +#endif #include // std::forward namespace sqlite_orm { diff --git a/dev/statement_binder.h b/dev/statement_binder.h index 4a9e6abd8..0f38a2022 100644 --- a/dev/statement_binder.h +++ b/dev/statement_binder.h @@ -240,7 +240,7 @@ namespace sqlite_orm { template<> struct statement_binder, void> { int bind(sqlite3_stmt* stmt, int index, const std::vector& value) const { - if(value.size()) { + if(!value.empty()) { return sqlite3_bind_blob(stmt, index, (const void*)&value.front(), int(value.size()), SQLITE_TRANSIENT); } else { return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT); @@ -248,7 +248,7 @@ namespace sqlite_orm { } void result(sqlite3_context* context, const std::vector& value) const { - if(value.size()) { + if(!value.empty()) { sqlite3_result_blob(context, (const void*)&value.front(), int(value.size()), nullptr); } else { sqlite3_result_blob(context, "", 0, nullptr); diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 2a25bb0a8..1f5e37366 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -136,7 +136,7 @@ namespace sqlite_orm { * Serializer for literal values. */ template - struct statement_serializer> { + struct statement_serializer> { using statement_type = T; template @@ -1132,6 +1132,11 @@ namespace sqlite_orm { return std::move(collector.table_names); } + template = true> + std::set> collect_table_names(const T& table, const Ctx&) { + return {{table.name, ""}}; + } + template struct statement_serializer, void> { using statement_type = update_all_t; @@ -1357,17 +1362,12 @@ namespace sqlite_orm { std::string serialize_get_all_impl(const T& get, const Ctx& context) { using primary_type = type_t; - auto collector = make_table_name_collector(context.db_objects); - collector.table_names.emplace(lookup_table_name(context.db_objects), ""); - // note: not collecting table names from get.conditions; - auto& table = pick_table(context.db_objects); + auto tableNames = collect_table_names(table, context); + std::stringstream ss; - ss << "SELECT " << streaming_table_column_names(table, true); - if(!collector.table_names.empty()) { - ss << " FROM " << streaming_identifiers(collector.table_names); - } - ss << streaming_conditions_tuple(get.conditions, context); + ss << "SELECT " << streaming_table_column_names(table, true) << " FROM " + << streaming_identifiers(tableNames) << streaming_conditions_tuple(get.conditions, context); return ss.str(); } diff --git a/dev/storage_impl.h b/dev/storage_impl.h index bc300fa31..a539f9f76 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -1,12 +1,10 @@ #pragma once -#include // std::tuple_size -#include // std::type_index #include // std::string -#include // std::is_same, std::decay, std::make_index_sequence, std::index_sequence -#include "functional/cxx_universal.h" +#include "functional/cxx_universal.h" // ::nullptr_t #include "functional/static_magic.h" +#include "tuple_helper/tuple_filter.h" #include "tuple_helper/tuple_iteration.h" #include "type_traits.h" #include "select_constraints.h" diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index d5355241c..b796ab6cc 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -133,5 +133,12 @@ namespace sqlite_orm { using table_type = storage_pick_table_t; return std::get(dbObjects); } + + template> + auto lookup_table(const DBOs& dbObjects); + + template> + std::string lookup_table_name(const DBOs& dbObjects); + } } diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index b2df4c51b..0c5e80d64 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -18,7 +18,7 @@ namespace sqlite_orm { struct table_name_collector_base { using table_name_set = std::set>; - mutable table_name_set table_names; + table_name_set table_names; }; template @@ -35,24 +35,24 @@ namespace sqlite_orm { void operator()(const T&) const {} template - void operator()(F O::*, std::string alias = {}) const { - this->table_names.emplace(lookup_table_name(this->db_objects), std::move(alias)); + void operator()(F O::*) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const column_pointer&) const { + void operator()(const column_pointer&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const alias_column_t&) const { + void operator()(const alias_column_t&) { // note: instead of accessing the column, we are interested in the type the column is aliased into auto tableName = lookup_table_name>(this->db_objects); this->table_names.emplace(std::move(tableName), alias_extractor::get()); } template - void operator()(const count_asterisk_t&) const { + void operator()(const count_asterisk_t&) { auto tableName = lookup_table_name(this->db_objects); if(!tableName.empty()) { this->table_names.emplace(std::move(tableName), ""); @@ -60,12 +60,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { - this->table_names.emplace(lookup_table_name(db_objects), ""); + void operator()(const asterisk_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t&) { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -74,22 +74,22 @@ namespace sqlite_orm { } template - void operator()(const object_t&) const { + void operator()(const object_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const table_rowid_t&) const { + void operator()(const table_rowid_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const table_oid_t&) const { + void operator()(const table_oid_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const table__rowid_t&) const { + void operator()(const table__rowid_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 914a2c16b..0ee85e803 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8225,7 +8225,7 @@ namespace sqlite_orm { template<> struct statement_binder, void> { int bind(sqlite3_stmt* stmt, int index, const std::vector& value) const { - if(value.size()) { + if(!value.empty()) { return sqlite3_bind_blob(stmt, index, (const void*)&value.front(), int(value.size()), SQLITE_TRANSIENT); } else { return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT); @@ -8233,7 +8233,7 @@ namespace sqlite_orm { } void result(sqlite3_context* context, const std::vector& value) const { - if(value.size()) { + if(!value.empty()) { sqlite3_result_blob(context, (const void*)&value.front(), int(value.size()), nullptr); } else { sqlite3_result_blob(context, "", 0, nullptr); @@ -9389,6 +9389,13 @@ namespace sqlite_orm { using table_type = storage_pick_table_t; return std::get(dbObjects); } + + template> + auto lookup_table(const DBOs& dbObjects); + + template> + std::string lookup_table_name(const DBOs& dbObjects); + } } @@ -9954,7 +9961,9 @@ namespace sqlite_orm { // #include "functional/static_magic.h" +#ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED #include // std::false_type, std::true_type, std::integral_constant +#endif #include // std::forward namespace sqlite_orm { @@ -10463,15 +10472,14 @@ namespace sqlite_orm { } #pragma once -#include // std::tuple_size -#include // std::type_index #include // std::string -#include // std::is_same, std::decay, std::make_index_sequence, std::index_sequence // #include "functional/cxx_universal.h" - +// ::nullptr_t // #include "functional/static_magic.h" +// #include "tuple_helper/tuple_filter.h" + // #include "tuple_helper/tuple_iteration.h" // #include "type_traits.h" @@ -11114,7 +11122,7 @@ namespace sqlite_orm { struct table_name_collector_base { using table_name_set = std::set>; - mutable table_name_set table_names; + table_name_set table_names; }; template @@ -11131,24 +11139,24 @@ namespace sqlite_orm { void operator()(const T&) const {} template - void operator()(F O::*, std::string alias = {}) const { - this->table_names.emplace(lookup_table_name(this->db_objects), std::move(alias)); + void operator()(F O::*) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const column_pointer&) const { + void operator()(const column_pointer&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const alias_column_t&) const { + void operator()(const alias_column_t&) { // note: instead of accessing the column, we are interested in the type the column is aliased into auto tableName = lookup_table_name>(this->db_objects); this->table_names.emplace(std::move(tableName), alias_extractor::get()); } template - void operator()(const count_asterisk_t&) const { + void operator()(const count_asterisk_t&) { auto tableName = lookup_table_name(this->db_objects); if(!tableName.empty()) { this->table_names.emplace(std::move(tableName), ""); @@ -11156,12 +11164,12 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { - this->table_names.emplace(lookup_table_name(db_objects), ""); + void operator()(const asterisk_t&) { + this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t&) { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, "alias must have a nested alias::type typename"); @@ -11170,22 +11178,22 @@ namespace sqlite_orm { } template - void operator()(const object_t&) const { + void operator()(const object_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const table_rowid_t&) const { + void operator()(const table_rowid_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const table_oid_t&) const { + void operator()(const table_oid_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } template - void operator()(const table__rowid_t&) const { + void operator()(const table__rowid_t&) { this->table_names.emplace(lookup_table_name(this->db_objects), ""); } }; @@ -12111,9 +12119,16 @@ namespace sqlite_orm { * which will be called for any node of provided expression. * E.g. if we pass `where(is_equal(5, max(&User::id, 10))` then * callable object will be called with 5, &User::id and 10. - * ast_iterator is used mostly in finding literals to be bound to - * a statement. To use it just call `iterate_ast(object, callable);` - * T is an ast element. E.g. where_t + * ast_iterator is used in finding literals to be bound to + * a statement, and to collect table names. + * + * Note that not all leaves of the expression tree are always visited: + * Column expressions can be more complex, but are passed as a whole to the callable. + * Examples are `column_pointer<>` and `alias_column_t<>`. + * + * To use `ast_iterator` call `iterate_ast(object, callable);` + * + * `T` is an ast element, e.g. where_t */ template struct ast_iterator { @@ -15287,7 +15302,7 @@ namespace sqlite_orm { * Serializer for literal values. */ template - struct statement_serializer> { + struct statement_serializer> { using statement_type = T; template @@ -16283,6 +16298,11 @@ namespace sqlite_orm { return std::move(collector.table_names); } + template = true> + std::set> collect_table_names(const T& table, const Ctx&) { + return {{table.name, ""}}; + } + template struct statement_serializer, void> { using statement_type = update_all_t; @@ -16508,17 +16528,12 @@ namespace sqlite_orm { std::string serialize_get_all_impl(const T& get, const Ctx& context) { using primary_type = type_t; - auto collector = make_table_name_collector(context.db_objects); - collector.table_names.emplace(lookup_table_name(context.db_objects), ""); - // note: not collecting table names from get.conditions; - auto& table = pick_table(context.db_objects); + auto tableNames = collect_table_names(table, context); + std::stringstream ss; - ss << "SELECT " << streaming_table_column_names(table, true); - if(!collector.table_names.empty()) { - ss << " FROM " << streaming_identifiers(collector.table_names); - } - ss << streaming_conditions_tuple(get.conditions, context); + ss << "SELECT " << streaming_table_column_names(table, true) << " FROM " + << streaming_identifiers(tableNames) << streaming_conditions_tuple(get.conditions, context); return ss.str(); } diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 9f04b377b..a58aac769 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -1,6 +1,8 @@ #include #include +#include // std::type_index + using namespace sqlite_orm; TEST_CASE("ast_iterator") { From 35db7c8780f080a4ad0ea32577d8b784ddd220df Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 6 Feb 2023 20:54:12 +0200 Subject: [PATCH 023/100] Fixed forward-declaration of storage lookup functions --- dev/storage_impl.h | 4 ++-- dev/storage_lookup.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dev/storage_impl.h b/dev/storage_impl.h index a539f9f76..b7b96fefa 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -26,7 +26,7 @@ namespace sqlite_orm { return res; } - template = true> + template> auto lookup_table(const DBOs& dbObjects) { return static_if>( [](const auto& dbObjects) { @@ -35,7 +35,7 @@ namespace sqlite_orm { empty_callable())(dbObjects); } - template = true> + template> std::string lookup_table_name(const DBOs& dbObjects) { return static_if>( [](const auto& dbObjects) { diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index b796ab6cc..36e84d3f7 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -134,10 +134,10 @@ namespace sqlite_orm { return std::get(dbObjects); } - template> + template = true> auto lookup_table(const DBOs& dbObjects); - template> + template = true> std::string lookup_table_name(const DBOs& dbObjects); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 0ee85e803..36e80e860 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9390,10 +9390,10 @@ namespace sqlite_orm { return std::get(dbObjects); } - template> + template = true> auto lookup_table(const DBOs& dbObjects); - template> + template = true> std::string lookup_table_name(const DBOs& dbObjects); } @@ -10504,7 +10504,7 @@ namespace sqlite_orm { return res; } - template = true> + template> auto lookup_table(const DBOs& dbObjects) { return static_if>( [](const auto& dbObjects) { @@ -10513,7 +10513,7 @@ namespace sqlite_orm { empty_callable())(dbObjects); } - template = true> + template> std::string lookup_table_name(const DBOs& dbObjects) { return static_if>( [](const auto& dbObjects) { From f7f55c1f7a6a6cf681f99fa91fdf9be80b372ff9 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 7 Feb 2023 18:43:22 +0200 Subject: [PATCH 024/100] `lookup_table_name()` can return a reference to the table name --- dev/storage_impl.h | 4 ++-- dev/storage_lookup.h | 2 +- include/sqlite_orm/sqlite_orm.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/storage_impl.h b/dev/storage_impl.h index b7b96fefa..0abbffa54 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -36,9 +36,9 @@ namespace sqlite_orm { } template> - std::string lookup_table_name(const DBOs& dbObjects) { + decltype(auto) lookup_table_name(const DBOs& dbObjects) { return static_if>( - [](const auto& dbObjects) { + [](const auto& dbObjects) -> const std::string& { return pick_table(dbObjects).name; }, empty_callable())(dbObjects); diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index 36e84d3f7..6cbc47820 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -138,7 +138,7 @@ namespace sqlite_orm { auto lookup_table(const DBOs& dbObjects); template = true> - std::string lookup_table_name(const DBOs& dbObjects); + decltype(auto) lookup_table_name(const DBOs& dbObjects); } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 36e80e860..65b5a6ad8 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9394,7 +9394,7 @@ namespace sqlite_orm { auto lookup_table(const DBOs& dbObjects); template = true> - std::string lookup_table_name(const DBOs& dbObjects); + decltype(auto) lookup_table_name(const DBOs& dbObjects); } } @@ -10514,9 +10514,9 @@ namespace sqlite_orm { } template> - std::string lookup_table_name(const DBOs& dbObjects) { + decltype(auto) lookup_table_name(const DBOs& dbObjects) { return static_if>( - [](const auto& dbObjects) { + [](const auto& dbObjects) -> const std::string& { return pick_table(dbObjects).name; }, empty_callable())(dbObjects); From a30e8b8245724c85ab6423fd2c500025a00138dd Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 8 Feb 2023 17:58:32 +0200 Subject: [PATCH 025/100] Corrected detection of missing `std::identity` --- dev/functional/cxx_functional_polyfill.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/functional/cxx_functional_polyfill.h b/dev/functional/cxx_functional_polyfill.h index da59dfe0c..412459ea0 100644 --- a/dev/functional/cxx_functional_polyfill.h +++ b/dev/functional/cxx_functional_polyfill.h @@ -14,9 +14,9 @@ namespace sqlite_orm { namespace internal { namespace polyfill { // C++20 or later (unfortunately there's no feature test macro). - // Stupidly, clang < 11 says C++20, but comes w/o std::identity. + // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13. // Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges -#if(__cplusplus >= 202002L) && (!__clang_major__ || __clang_major__ >= 11) +#if(__cplusplus >= 202002L) && (!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13) using std::identity; #else struct identity { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 65b5a6ad8..9fc8c2729 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -7932,9 +7932,9 @@ namespace sqlite_orm { namespace internal { namespace polyfill { // C++20 or later (unfortunately there's no feature test macro). - // Stupidly, clang < 11 says C++20, but comes w/o std::identity. + // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13. // Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges -#if(__cplusplus >= 202002L) && (!__clang_major__ || __clang_major__ >= 11) +#if(__cplusplus >= 202002L) && (!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13) using std::identity; #else struct identity { From d9e206ec9777b5e94bc8e347e54217fb3d18eddf Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 8 Feb 2023 20:24:54 +0200 Subject: [PATCH 026/100] Corrected again detection of missing `std::identity` --- dev/functional/cxx_functional_polyfill.h | 9 +++++++-- include/sqlite_orm/sqlite_orm.h | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/dev/functional/cxx_functional_polyfill.h b/dev/functional/cxx_functional_polyfill.h index 412459ea0..5380f2fcc 100644 --- a/dev/functional/cxx_functional_polyfill.h +++ b/dev/functional/cxx_functional_polyfill.h @@ -14,9 +14,14 @@ namespace sqlite_orm { namespace internal { namespace polyfill { // C++20 or later (unfortunately there's no feature test macro). - // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13. + // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13 and libstd++-v3 10 + // (the latter is used on Linux). + // gcc got it right and reports C++20 only starting with v10. + // The check here doesn't care and checks the library versions in use. + // // Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges -#if(__cplusplus >= 202002L) && (!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13) +#if(__cplusplus >= 202002L) && \ + ((!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13) && (!_GLIBCXX_RELEASE || _GLIBCXX_RELEASE >= 10)) using std::identity; #else struct identity { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9fc8c2729..97c3f0a08 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -7932,9 +7932,14 @@ namespace sqlite_orm { namespace internal { namespace polyfill { // C++20 or later (unfortunately there's no feature test macro). - // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13. + // Stupidly, clang says C++20, but `std::identity` was only implemented in libc++ 13 and libstd++-v3 10 + // (the latter is used on Linux). + // gcc got it right and reports C++20 only starting with v10. + // The check here doesn't care and checks the library versions in use. + // // Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges -#if(__cplusplus >= 202002L) && (!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13) +#if(__cplusplus >= 202002L) && \ + ((!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13) && (!_GLIBCXX_RELEASE || _GLIBCXX_RELEASE >= 10)) using std::identity; #else struct identity { From a37e08319b5007d11be7c3042de72768d711334b Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 13 Feb 2023 22:30:17 +0200 Subject: [PATCH 027/100] Ability to select all columns from multiple tables * Streamlined collection of serialized column expressions * column expression collector doesn't modify serialization context anymore --- dev/column_names_getter.h | 150 +++++------ dev/column_result.h | 5 +- dev/select_constraints.h | 6 + dev/statement_serializer.h | 46 ++-- dev/tuple_helper/tuple_fy.h | 21 ++ include/sqlite_orm/sqlite_orm.h | 236 ++++++++++-------- .../statements/select.cpp | 20 +- .../statements/update_all.cpp | 2 +- tests/static_tests/column_result_t.cpp | 138 +++++----- 9 files changed, 341 insertions(+), 283 deletions(-) create mode 100644 dev/tuple_helper/tuple_fy.h diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index 31868e249..fb38a5a2e 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -1,14 +1,20 @@ #pragma once -#include // std::system_error #include // std::string #include // std::vector #include // std::reference_wrapper +#include +#include // std::move +#include // std::make_move_iterator +#include "functional/cxx_universal.h" // ::size_t +#include "functional/cxx_type_traits_polyfill.h" // polyfill::remove_cvref_t +#include "tuple_helper/tuple_traits.h" #include "error_code.h" -#include "serializer_context.h" #include "select_constraints.h" -#include "serializing_util.h" +#include "alias.h" +#include "storage_lookup.h" // pick_table +#include "serializer_context.h" #include "util.h" namespace sqlite_orm { @@ -18,97 +24,95 @@ namespace sqlite_orm { template std::string serialize(const T& t, const serializer_context& context); - template - struct column_names_getter { - using expression_type = T; - - template - std::vector operator()(const expression_type& t, const Ctx& context) const { - auto newContext = context; - newContext.skip_table_name = false; - auto columnName = serialize(t, newContext); - if(!columnName.empty()) { - return {std::move(columnName)}; - } else { - throw std::system_error{orm_error_code::column_not_found}; - } - } - }; - - template - std::vector get_column_names(const T& t, const Ctx& context) { - column_names_getter serializer; - return serializer(t, context); - } - template - std::vector collect_table_column_names(bool definedOrder, const Ctx& context) { + std::vector& collect_table_column_names(std::vector& collectedExpressions, + bool definedOrder, + const Ctx& context) { if(definedOrder) { - std::vector quotedNames; auto& table = pick_table>(context.db_objects); - quotedNames.reserve(table.count_columns_amount()); - table.for_each_column(["edNames](const column_identifier& column) { + collectedExpressions.reserve(collectedExpressions.size() + table.count_columns_amount()); + table.for_each_column([qualified = !context.skip_table_name, + &tableName = table.name, + &collectedExpressions](const column_identifier& column) { if(std::is_base_of::value) { - quotedNames.push_back(quote_identifier(alias_extractor::get()) + "." + - quote_identifier(column.name)); + collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + "." + + quote_identifier(column.name)); + } else if(qualified) { + collectedExpressions.push_back(quote_identifier(tableName) + "." + + quote_identifier(column.name)); } else { - quotedNames.push_back(quote_identifier(column.name)); + collectedExpressions.push_back(quote_identifier(column.name)); } }); - return quotedNames; - } else if(std::is_base_of::value) { - return {quote_identifier(alias_extractor::get()) + ".*"}; } else { - return {"*"}; + collectedExpressions.reserve(collectedExpressions.size() + 1); + if(std::is_base_of::value) { + collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + ".*"); + } else if(!context.skip_table_name) { + const basic_table& table = pick_table>(context.db_objects); + collectedExpressions.push_back(quote_identifier(table.name) + ".*"); + } else { + collectedExpressions.emplace_back("*"); + } } - } - template - struct column_names_getter, void> { - using expression_type = std::reference_wrapper; + return collectedExpressions; + } - template - std::vector operator()(const expression_type& expression, const Ctx& context) const { - return get_column_names(expression.get(), context); + /** @short Column expression collector. + */ + struct column_names_getter { + /** + * The default implementation simply serializes the passed argument. + */ + template + std::vector& operator()(const E& t, const Ctx& context) { + auto columnExpression = serialize(t, context); + if(columnExpression.empty()) { + throw std::system_error{orm_error_code::column_not_found}; + } + collectedExpressions.reserve(collectedExpressions.size() + 1); + collectedExpressions.push_back(std::move(columnExpression)); + return collectedExpressions; } - }; - - template - struct column_names_getter> { - using expression_type = asterisk_t; - template - std::vector operator()(const expression_type& expression, const Ctx& context) const { - return collect_table_column_names(expression.defined_order, context); + template + std::vector& operator()(const std::reference_wrapper& expression, const Ctx& context) { + return (*this)(expression.get(), context); } - }; - - template - struct column_names_getter, void> { - using expression_type = object_t; - template - std::vector operator()(const expression_type& expression, const Ctx& context) const { - return collect_table_column_names(expression.defined_order, context); + template + std::vector& operator()(const asterisk_t& expression, const Ctx& context) { + return collect_table_column_names(collectedExpressions, expression.defined_order, context); } - }; - template - struct column_names_getter, void> { - using expression_type = columns_t; + template + std::vector& operator()(const object_t& expression, const Ctx& context) { + return collect_table_column_names(collectedExpressions, expression.defined_order, context); + } - template - std::vector operator()(const expression_type& cols, const Ctx& context) const { - std::vector columnNames; - columnNames.reserve(static_cast(cols.count)); - auto newContext = context; - newContext.skip_table_name = false; - iterate_tuple(cols.columns, [&columnNames, &newContext](auto& m) { - columnNames.push_back(serialize(m, newContext)); + template + std::vector& operator()(const columns_t& cols, const Ctx& context) { + collectedExpressions.reserve(collectedExpressions.size() + cols.count); + iterate_tuple(cols.columns, [this, &context](auto& colExpr) { + (*this)(colExpr, context); }); - return columnNames; + // note: `capacity() > size()` can occur in case `asterisk_t<>` does spell out the columns in defined order + if(mpl::instantiate, + typename columns_t::columns_type>::value && + collectedExpressions.capacity() > collectedExpressions.size()) { + collectedExpressions.shrink_to_fit(); + } + return collectedExpressions; } + + std::vector collectedExpressions; }; + template + std::vector get_column_names(const T& t, const Ctx& context) { + column_names_getter serializer; + return serializer(t, context); + } } } diff --git a/dev/column_result.h b/dev/column_result.h index ed005bc44..c4366c6d4 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -5,6 +5,9 @@ #include // std::reference_wrapper #include "functional/cxx_universal.h" +#include "tuple_helper/tuple_traits.h" +#include "tuple_helper/tuple_fy.h" +#include "tuple_helper/tuple_filter.h" #include "type_traits.h" #include "member_traits/member_traits.h" #include "core_functions.h" @@ -200,7 +203,7 @@ namespace sqlite_orm { template struct column_result_t, void> { - using type = std::tuple>...>; + using type = tuple_cat_t>>...>; }; template diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 9d18ce778..592b21e21 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -123,6 +123,12 @@ namespace sqlite_orm { } }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; + + template + using is_column_pointer = polyfill::bool_constant>; + /** * Subselect object type. */ diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 1f5e37366..5c45dc8fc 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -307,18 +307,20 @@ namespace sqlite_orm { } }; - template - struct statement_serializer { - using statement_type = F O::*; + template + struct statement_serializer< + E, + std::enable_if_t, is_column_pointer>>> { + using statement_type = E; template - std::string operator()(const statement_type& m, const Ctx& context) const { + std::string operator()(const statement_type& e, const Ctx& context) const { std::stringstream ss; - if(!context.skip_table_name) { - ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; - } - if(auto* columnName = find_column_name(context.db_objects, m)) { - ss << streaming_identifier(*columnName); + if(auto* columnName = find_column_name(context.db_objects, e)) { + ss << streaming_identifier( + !context.skip_table_name ? lookup_table_name>(context.db_objects) : "", + *columnName, + ""); } else { throw std::system_error{orm_error_code::column_not_found}; } @@ -470,25 +472,6 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = column_pointer; - - template - std::string operator()(const statement_type& c, const Ctx& context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; - } - if(auto* columnName = find_column_name(context.db_objects, c)) { - ss << streaming_identifier(*columnName); - } else { - throw std::system_error{orm_error_code::column_not_found}; - } - return ss.str(); - } - }; - template struct statement_serializer, void> { using statement_type = cast_t; @@ -1228,7 +1211,8 @@ namespace sqlite_orm { if(context.use_parentheses) { ss << '('; } - ss << streaming_expressions_tuple(statement.columns, context); + // note: pass `statement` itself + ss << streaming_serialized(get_column_names(statement, context)); if(context.use_parentheses) { ss << ')'; } @@ -1493,7 +1477,9 @@ namespace sqlite_orm { using statement_type = select_t; template - std::string operator()(const statement_type& sel, const Ctx& context) const { + std::string operator()(const statement_type& sel, Ctx context) const { + context.skip_table_name = false; + std::stringstream ss; constexpr bool isCompoundOperator = is_base_of_template_v; if(!isCompoundOperator) { diff --git a/dev/tuple_helper/tuple_fy.h b/dev/tuple_helper/tuple_fy.h new file mode 100644 index 000000000..3e2ec3b7d --- /dev/null +++ b/dev/tuple_helper/tuple_fy.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace sqlite_orm { + + namespace internal { + + template + struct tuplify { + using type = std::tuple; + }; + template + struct tuplify> { + using type = std::tuple; + }; + + template + using tuplify_t = typename tuplify::type; + } +} diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 97c3f0a08..ea2b6ff9a 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -6754,6 +6754,12 @@ namespace sqlite_orm { } }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; + + template + using is_column_pointer = polyfill::bool_constant>; + /** * Subselect object type. */ @@ -9204,6 +9210,32 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" +// #include "tuple_helper/tuple_traits.h" + +// #include "tuple_helper/tuple_fy.h" + +#include + +namespace sqlite_orm { + + namespace internal { + + template + struct tuplify { + using type = std::tuple; + }; + template + struct tuplify> { + using type = std::tuple; + }; + + template + using tuplify_t = typename tuplify::type; + } +} + +// #include "tuple_helper/tuple_filter.h" + // #include "type_traits.h" // #include "member_traits/member_traits.h" @@ -9864,7 +9896,7 @@ namespace sqlite_orm { template struct column_result_t, void> { - using type = std::tuple>...>; + using type = tuple_cat_t>>...>; }; template @@ -15005,18 +15037,28 @@ namespace sqlite_orm { // #include "column_names_getter.h" -#include // std::system_error #include // std::string #include // std::vector #include // std::reference_wrapper +#include +#include // std::move +#include // std::make_move_iterator -// #include "error_code.h" +// #include "functional/cxx_universal.h" +// ::size_t +// #include "functional/cxx_type_traits_polyfill.h" +// polyfill::remove_cvref_t +// #include "tuple_helper/tuple_traits.h" -// #include "serializer_context.h" +// #include "error_code.h" // #include "select_constraints.h" -// #include "serializing_util.h" +// #include "alias.h" + +// #include "storage_lookup.h" +// pick_table +// #include "serializer_context.h" // #include "util.h" @@ -15027,98 +15069,96 @@ namespace sqlite_orm { template std::string serialize(const T& t, const serializer_context& context); - template - struct column_names_getter { - using expression_type = T; - - template - std::vector operator()(const expression_type& t, const Ctx& context) const { - auto newContext = context; - newContext.skip_table_name = false; - auto columnName = serialize(t, newContext); - if(!columnName.empty()) { - return {std::move(columnName)}; - } else { - throw std::system_error{orm_error_code::column_not_found}; - } - } - }; - - template - std::vector get_column_names(const T& t, const Ctx& context) { - column_names_getter serializer; - return serializer(t, context); - } - template - std::vector collect_table_column_names(bool definedOrder, const Ctx& context) { + std::vector& collect_table_column_names(std::vector& collectedExpressions, + bool definedOrder, + const Ctx& context) { if(definedOrder) { - std::vector quotedNames; auto& table = pick_table>(context.db_objects); - quotedNames.reserve(table.count_columns_amount()); - table.for_each_column(["edNames](const column_identifier& column) { + collectedExpressions.reserve(collectedExpressions.size() + table.count_columns_amount()); + table.for_each_column([qualified = !context.skip_table_name, + &tableName = table.name, + &collectedExpressions](const column_identifier& column) { if(std::is_base_of::value) { - quotedNames.push_back(quote_identifier(alias_extractor::get()) + "." + - quote_identifier(column.name)); + collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + "." + + quote_identifier(column.name)); + } else if(qualified) { + collectedExpressions.push_back(quote_identifier(tableName) + "." + + quote_identifier(column.name)); } else { - quotedNames.push_back(quote_identifier(column.name)); + collectedExpressions.push_back(quote_identifier(column.name)); } }); - return quotedNames; - } else if(std::is_base_of::value) { - return {quote_identifier(alias_extractor::get()) + ".*"}; } else { - return {"*"}; + collectedExpressions.reserve(collectedExpressions.size() + 1); + if(std::is_base_of::value) { + collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + ".*"); + } else if(!context.skip_table_name) { + const basic_table& table = pick_table>(context.db_objects); + collectedExpressions.push_back(quote_identifier(table.name) + ".*"); + } else { + collectedExpressions.emplace_back("*"); + } } - } - template - struct column_names_getter, void> { - using expression_type = std::reference_wrapper; + return collectedExpressions; + } - template - std::vector operator()(const expression_type& expression, const Ctx& context) const { - return get_column_names(expression.get(), context); + /** @short Column expression collector. + */ + struct column_names_getter { + /** + * The default implementation simply serializes the passed argument. + */ + template + std::vector& operator()(const E& t, const Ctx& context) { + auto columnExpression = serialize(t, context); + if(columnExpression.empty()) { + throw std::system_error{orm_error_code::column_not_found}; + } + collectedExpressions.reserve(collectedExpressions.size() + 1); + collectedExpressions.push_back(std::move(columnExpression)); + return collectedExpressions; } - }; - - template - struct column_names_getter> { - using expression_type = asterisk_t; - template - std::vector operator()(const expression_type& expression, const Ctx& context) const { - return collect_table_column_names(expression.defined_order, context); + template + std::vector& operator()(const std::reference_wrapper& expression, const Ctx& context) { + return (*this)(expression.get(), context); } - }; - - template - struct column_names_getter, void> { - using expression_type = object_t; - template - std::vector operator()(const expression_type& expression, const Ctx& context) const { - return collect_table_column_names(expression.defined_order, context); + template + std::vector& operator()(const asterisk_t& expression, const Ctx& context) { + return collect_table_column_names(collectedExpressions, expression.defined_order, context); } - }; - template - struct column_names_getter, void> { - using expression_type = columns_t; + template + std::vector& operator()(const object_t& expression, const Ctx& context) { + return collect_table_column_names(collectedExpressions, expression.defined_order, context); + } - template - std::vector operator()(const expression_type& cols, const Ctx& context) const { - std::vector columnNames; - columnNames.reserve(static_cast(cols.count)); - auto newContext = context; - newContext.skip_table_name = false; - iterate_tuple(cols.columns, [&columnNames, &newContext](auto& m) { - columnNames.push_back(serialize(m, newContext)); + template + std::vector& operator()(const columns_t& cols, const Ctx& context) { + collectedExpressions.reserve(collectedExpressions.size() + cols.count); + iterate_tuple(cols.columns, [this, &context](auto& colExpr) { + (*this)(colExpr, context); }); - return columnNames; + // note: `capacity() > size()` can occur in case `asterisk_t<>` does spell out the columns in defined order + if(mpl::instantiate, + typename columns_t::columns_type>::value && + collectedExpressions.capacity() > collectedExpressions.size()) { + collectedExpressions.shrink_to_fit(); + } + return collectedExpressions; } + + std::vector collectedExpressions; }; + template + std::vector get_column_names(const T& t, const Ctx& context) { + column_names_getter serializer; + return serializer(t, context); + } } } @@ -15478,18 +15518,20 @@ namespace sqlite_orm { } }; - template - struct statement_serializer { - using statement_type = F O::*; + template + struct statement_serializer< + E, + std::enable_if_t, is_column_pointer>>> { + using statement_type = E; template - std::string operator()(const statement_type& m, const Ctx& context) const { + std::string operator()(const statement_type& e, const Ctx& context) const { std::stringstream ss; - if(!context.skip_table_name) { - ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; - } - if(auto* columnName = find_column_name(context.db_objects, m)) { - ss << streaming_identifier(*columnName); + if(auto* columnName = find_column_name(context.db_objects, e)) { + ss << streaming_identifier( + !context.skip_table_name ? lookup_table_name>(context.db_objects) : "", + *columnName, + ""); } else { throw std::system_error{orm_error_code::column_not_found}; } @@ -15641,25 +15683,6 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = column_pointer; - - template - std::string operator()(const statement_type& c, const Ctx& context) const { - std::stringstream ss; - if(!context.skip_table_name) { - ss << streaming_identifier(lookup_table_name(context.db_objects)) << "."; - } - if(auto* columnName = find_column_name(context.db_objects, c)) { - ss << streaming_identifier(*columnName); - } else { - throw std::system_error{orm_error_code::column_not_found}; - } - return ss.str(); - } - }; - template struct statement_serializer, void> { using statement_type = cast_t; @@ -16399,7 +16422,8 @@ namespace sqlite_orm { if(context.use_parentheses) { ss << '('; } - ss << streaming_expressions_tuple(statement.columns, context); + // note: pass `statement` itself + ss << streaming_serialized(get_column_names(statement, context)); if(context.use_parentheses) { ss << ')'; } @@ -16664,7 +16688,9 @@ namespace sqlite_orm { using statement_type = select_t; template - std::string operator()(const statement_type& sel, const Ctx& context) const { + std::string operator()(const statement_type& sel, Ctx context) const { + context.skip_table_name = false; + std::stringstream ss; constexpr bool isCompoundOperator = is_base_of_template_v; if(!isCompoundOperator) { diff --git a/tests/statement_serializer_tests/statements/select.cpp b/tests/statement_serializer_tests/statements/select.cpp index efe7a1096..bdd8f1be3 100644 --- a/tests/statement_serializer_tests/statements/select.cpp +++ b/tests/statement_serializer_tests/statements/select.cpp @@ -106,19 +106,19 @@ TEST_CASE("statement_serializer select_t") { auto expression = select(asterisk()); expression.highest_level = true; stringValue = serialize(expression, context); - expected = R"(SELECT * FROM "users")"; + expected = R"(SELECT "users".* FROM "users")"; } SECTION("mapped, implicit select order") { auto expression = select(asterisk(false)); expression.highest_level = true; stringValue = serialize(expression, context); - expected = R"(SELECT * FROM "users")"; + expected = R"(SELECT "users".* FROM "users")"; } SECTION("mapped, defined select order") { auto expression = select(asterisk(true)); expression.highest_level = true; stringValue = serialize(expression, context); - expected = R"(SELECT "id", "name" FROM "users")"; + expected = R"(SELECT "users"."id", "users"."name" FROM "users")"; } SECTION("alias, implicit select order") { using als_u = alias_u; @@ -140,19 +140,27 @@ TEST_CASE("statement_serializer select_t") { auto expression = select(object()); expression.highest_level = true; stringValue = serialize(expression, context); - expected = R"(SELECT * FROM "users")"; + expected = R"(SELECT "users".* FROM "users")"; } SECTION("object, implicit select order") { auto expression = select(object(false)); expression.highest_level = true; stringValue = serialize(expression, context); - expected = R"(SELECT * FROM "users")"; + expected = R"(SELECT "users".* FROM "users")"; } SECTION("object, defined select order") { auto expression = select(object(true)); expression.highest_level = true; stringValue = serialize(expression, context); - expected = R"(SELECT "id", "name" FROM "users")"; + expected = R"(SELECT "users"."id", "users"."name" FROM "users")"; + } + // issue #1106 + SECTION("multi") { + auto expression = columns(asterisk(), asterisk(true)); + context.skip_table_name = false; + context.use_parentheses = false; + stringValue = serialize(expression, context); + expected = R"("users".*, "users"."id", "users"."name")"; } SECTION("issue #945") { struct Employee { diff --git a/tests/statement_serializer_tests/statements/update_all.cpp b/tests/statement_serializer_tests/statements/update_all.cpp index 6931a5a85..1f51b1496 100644 --- a/tests/statement_serializer_tests/statements/update_all.cpp +++ b/tests/statement_serializer_tests/statements/update_all.cpp @@ -55,6 +55,6 @@ TEST_CASE("statement_serializer update_all") { update_all(set(c(&Contact::phone) = select(&Customer::phone, from(), where(c(&Customer::id) == 1)))); auto value = serialize(statement, context); decltype(value) expected = - R"(UPDATE "contacts" SET "phone" = (SELECT "customers"."Phone" FROM "customers" WHERE (("CustomerId" = 1))))"; + R"(UPDATE "contacts" SET "phone" = (SELECT "customers"."Phone" FROM "customers" WHERE (("customers"."CustomerId" = 1))))"; REQUIRE(value == expected); } diff --git a/tests/static_tests/column_result_t.cpp b/tests/static_tests/column_result_t.cpp index bab71581e..dbbe96395 100644 --- a/tests/static_tests/column_result_t.cpp +++ b/tests/static_tests/column_result_t.cpp @@ -4,13 +4,17 @@ using namespace sqlite_orm; -template -void runTest(V /*value*/) { - using Type = internal::column_result_of_t; +template +void do_assert() { STATIC_REQUIRE(std::is_same::value); } -TEST_CASE("column_result_t") { +template +void runTest(V /*value*/) { + do_assert, E>(); +} + +TEST_CASE("column_result_of_t") { struct User { int id = 0; std::string name; @@ -37,78 +41,78 @@ TEST_CASE("column_result_t") { int id = 0; std::string comment; }; - auto storage = - make_storage({}, make_table("users", make_column("id", &User::id), make_column("name", &User::name))); + auto dbObjects = + std::make_tuple(make_table("users", make_column("id", &User::id), make_column("name", &User::name))); + using db_objects_t = decltype(dbObjects); - using Storage = decltype(storage); - runTest(&User::id); - runTest(&User::name); - runTest(in(&User::id, {1, 2, 3})); + runTest(&User::id); + runTest(&User::name); + runTest(in(&User::id, {1, 2, 3})); { std::vector vector; - vector.push_back(1); - vector.push_back(2); - vector.push_back(3); - runTest(in(&User::id, vector)); + vector.insert(vector.cend(), {1, 2, 3}); + runTest(in(&User::id, vector)); } - runTest(in(&User::id, select(&User::id))); - runTest(c(&User::id).in(1, 2, 3)); - runTest(&Visit::getId); - runTest(&Visit::getComment); - runTest(&Visit::setId); - runTest(&Visit::setComment); - runTest>(sqlite_orm::abs(&User::id)); - runTest(sqlite_orm::length(&User::id)); - runTest(sqlite_orm::unicode(&User::id)); - runTest(sqlite_orm::typeof_(&User::id)); - runTest(sqlite_orm::lower(&User::id)); - runTest(sqlite_orm::upper(&User::id)); - runTest>(max(&User::id, 4)); - runTest>(min(&User::id, 4)); - runTest>(max(&User::id)); - runTest>(max(&User::name)); - runTest>(min(&User::id)); - runTest>(min(&User::name)); - runTest(count()); - runTest(count()); + runTest(in(&User::id, select(&User::id))); + runTest(c(&User::id).in(1, 2, 3)); + runTest(&Visit::getId); + runTest(&Visit::getComment); + runTest(&Visit::setId); + runTest(&Visit::setComment); + runTest>(sqlite_orm::abs(&User::id)); + runTest(sqlite_orm::length(&User::id)); + runTest(sqlite_orm::unicode(&User::id)); + runTest(sqlite_orm::typeof_(&User::id)); + runTest(sqlite_orm::lower(&User::id)); + runTest(sqlite_orm::upper(&User::id)); + runTest>(max(&User::id, 4)); + runTest>(min(&User::id, 4)); + runTest>(max(&User::id)); + runTest>(max(&User::name)); + runTest>(min(&User::id)); + runTest>(min(&User::name)); + runTest(count()); + runTest(count()); { struct RandomFunc { int operator()() const { return 4; } }; - runTest(func()); + runTest(func()); } - runTest(distinct(&User::id)); - runTest(distinct(&User::name)); - runTest(all(&User::id)); - runTest(all(&User::name)); - runTest(conc(&User::name, &User::id)); - runTest(c(&User::name) || &User::id); - runTest(add(&User::id, 5)); - runTest(c(&User::id) + 5); - runTest(sub(&User::id, 5)); - runTest(c(&User::id) - 5); - runTest(mul(&User::id, 5)); - runTest(c(&User::id) * 5); - runTest(sqlite_orm::div(&User::id, 5)); - runTest(c(&User::id) / 5); - runTest(mod(&User::id, 5)); - runTest(c(&User::id) % 5); - runTest(bitwise_shift_left(&User::id, 4)); - runTest(bitwise_shift_right(&User::id, 4)); - runTest(bitwise_and(&User::id, 4)); - runTest(bitwise_or(&User::id, 4)); - runTest(bitwise_not(&User::id)); - runTest(rowid()); - runTest(oid()); - runTest(_rowid_()); - runTest(rowid()); - runTest(oid()); - runTest(_rowid_()); - runTest>(asterisk()); - runTest>(asterisk>()); - runTest>(columns(&User::id, &User::name)); - runTest(column(&User::id)); - runTest(object()); + runTest(distinct(&User::id)); + runTest(distinct(&User::name)); + runTest(all(&User::id)); + runTest(all(&User::name)); + runTest(conc(&User::name, &User::id)); + runTest(c(&User::name) || &User::id); + runTest(add(&User::id, 5)); + runTest(c(&User::id) + 5); + runTest(sub(&User::id, 5)); + runTest(c(&User::id) - 5); + runTest(mul(&User::id, 5)); + runTest(c(&User::id) * 5); + runTest(sqlite_orm::div(&User::id, 5)); + runTest(c(&User::id) / 5); + runTest(mod(&User::id, 5)); + runTest(c(&User::id) % 5); + runTest(bitwise_shift_left(&User::id, 4)); + runTest(bitwise_shift_right(&User::id, 4)); + runTest(bitwise_and(&User::id, 4)); + runTest(bitwise_or(&User::id, 4)); + runTest(bitwise_not(&User::id)); + runTest(rowid()); + runTest(oid()); + runTest(_rowid_()); + runTest(rowid()); + runTest(oid()); + runTest(_rowid_()); + runTest>(columns(&User::id, &User::name)); + runTest>(asterisk()); + runTest>(asterisk>()); + runTest>(columns(asterisk(), asterisk())); + runTest(column(&User::id)); + runTest(alias_column>(&User::id)); + runTest(object()); } From 5ebab9932bae66790ef6b49e2d22d09becd8a2b5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 13 Feb 2023 22:33:05 +0200 Subject: [PATCH 028/100] Removed a couple of `internal` namespace qualifiers --- dev/column_result.h | 6 +++--- include/sqlite_orm/sqlite_orm.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/column_result.h b/dev/column_result.h index c4366c6d4..55ce40e4e 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -80,12 +80,12 @@ namespace sqlite_orm { }; template - struct column_result_t, S, X, Rest...>, void> { + struct column_result_t, S, X, Rest...>, void> { using type = std::unique_ptr>; }; template - struct column_result_t, S, X>, void> { + struct column_result_t, S, X>, void> { using type = std::unique_ptr>; }; @@ -131,7 +131,7 @@ namespace sqlite_orm { }; template - struct column_result_t, void> { + struct column_result_t, void> { using type = double; }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ea2b6ff9a..6a73e363b 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9773,12 +9773,12 @@ namespace sqlite_orm { }; template - struct column_result_t, S, X, Rest...>, void> { + struct column_result_t, S, X, Rest...>, void> { using type = std::unique_ptr>; }; template - struct column_result_t, S, X>, void> { + struct column_result_t, S, X>, void> { using type = std::unique_ptr>; }; @@ -9824,7 +9824,7 @@ namespace sqlite_orm { }; template - struct column_result_t, void> { + struct column_result_t, void> { using type = double; }; From 34afdf3005172761bd3b9f43c9c8669ff231d578 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 13 Feb 2023 23:50:36 +0200 Subject: [PATCH 029/100] RIP `join_iterator` --- dev/conditions.h | 3 + dev/join_iterator.h | 103 ------------- dev/statement_serializer.h | 26 ++-- dev/type_traits.h | 3 + include/sqlite_orm/sqlite_orm.h | 135 +++--------------- .../sqlite_orm/sqlite_orm.h | 1 - third_party/amalgamate/config.json | 7 +- 7 files changed, 45 insertions(+), 233 deletions(-) delete mode 100644 dev/join_iterator.h diff --git a/dev/conditions.h b/dev/conditions.h index a97792bcb..a6b69c23b 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -803,6 +803,9 @@ namespace sqlite_orm { template using is_from = polyfill::is_specialization_of; + + template + using is_any_join = polyfill::is_detected; } /** diff --git a/dev/join_iterator.h b/dev/join_iterator.h deleted file mode 100644 index e4f2f75a4..000000000 --- a/dev/join_iterator.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include "conditions.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct join_iterator; - - template<> - struct join_iterator<> { - - template - void operator()(const L&) const { - //.. - } - }; - - template - struct join_iterator : public join_iterator { - using super = join_iterator; - - template - void operator()(const L& l) const { - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = cross_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = natural_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_outer_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = inner_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - } -} diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 5c45dc8fc..d52128fb0 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1492,18 +1492,22 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; - if(!explicitFromItemsCount) { + using conditions_tuple = std::tuple; + constexpr bool hasExplicitFrom = tuple_has::value; + if(!hasExplicitFrom) { auto tableNames = collect_table_names(sel, context); - join_iterator()([&tableNames, &context](const auto& c) { - using original_join_type = typename std::decay_t::join_type::type; - using cross_join_type = mapped_type_proxy_t; - auto crossJoinedTableName = lookup_table_name(context.db_objects); - auto tableAliasString = alias_extractor::get(); - std::pair tableNameWithAlias{std::move(crossJoinedTableName), - std::move(tableAliasString)}; - tableNames.erase(tableNameWithAlias); - }); + using joins_index_sequence = filter_tuple_sequence_t; + iterate_tuple( + joins_index_sequence{}, + [&tableNames, &context](auto* joinTypeDummy) { + using original_join_type = typename std::remove_pointer_t::type; + using cross_join_type = mapped_type_proxy_t; + auto crossJoinedTableName = lookup_table_name(context.db_objects); + auto tableAliasString = alias_extractor::get(); + std::pair tableNameWithAlias{std::move(crossJoinedTableName), + std::move(tableAliasString)}; + tableNames.erase(tableNameWithAlias); + }); if(!tableNames.empty() && !isCompoundOperator) { ss << " FROM " << streaming_identifiers(tableNames); } diff --git a/dev/type_traits.h b/dev/type_traits.h index 43ca1807c..a3a162836 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -54,5 +54,8 @@ namespace sqlite_orm { template using target_type_t = typename T::target_type; + + template + using on_type_t = typename T::on_type; } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 6a73e363b..663f3b415 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -327,6 +327,9 @@ namespace sqlite_orm { template using target_type_t = typename T::target_type; + + template + using on_type_t = typename T::on_type; } } #pragma once @@ -3574,6 +3577,9 @@ namespace sqlite_orm { template using is_from = polyfill::is_specialization_of; + + template + using is_any_join = polyfill::is_detected; } /** @@ -4219,109 +4225,6 @@ namespace sqlite_orm { } #pragma once -// #include "conditions.h" - -namespace sqlite_orm { - - namespace internal { - - template - struct join_iterator; - - template<> - struct join_iterator<> { - - template - void operator()(const L&) const { - //.. - } - }; - - template - struct join_iterator : public join_iterator { - using super = join_iterator; - - template - void operator()(const L& l) const { - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = cross_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = natural_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = left_outer_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - - template - struct join_iterator, Tail...> : public join_iterator { - using super = join_iterator; - using join_type = inner_join_t; - - template - void operator()(const L& l) const { - l(*this); - this->super::operator()(l); - } - }; - } -} -#pragma once - #include // std::string #include // std::make_tuple, std::tuple_size #include // std::forward, std::is_base_of, std::enable_if @@ -16703,18 +16606,22 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - constexpr bool explicitFromItemsCount = count_tuple, is_from>::value; - if(!explicitFromItemsCount) { + using conditions_tuple = std::tuple; + constexpr bool hasExplicitFrom = tuple_has::value; + if(!hasExplicitFrom) { auto tableNames = collect_table_names(sel, context); - join_iterator()([&tableNames, &context](const auto& c) { - using original_join_type = typename std::decay_t::join_type::type; - using cross_join_type = mapped_type_proxy_t; - auto crossJoinedTableName = lookup_table_name(context.db_objects); - auto tableAliasString = alias_extractor::get(); - std::pair tableNameWithAlias{std::move(crossJoinedTableName), - std::move(tableAliasString)}; - tableNames.erase(tableNameWithAlias); - }); + using joins_index_sequence = filter_tuple_sequence_t; + iterate_tuple( + joins_index_sequence{}, + [&tableNames, &context](auto* joinTypeDummy) { + using original_join_type = typename std::remove_pointer_t::type; + using cross_join_type = mapped_type_proxy_t; + auto crossJoinedTableName = lookup_table_name(context.db_objects); + auto tableAliasString = alias_extractor::get(); + std::pair tableNameWithAlias{std::move(crossJoinedTableName), + std::move(tableAliasString)}; + tableNames.erase(tableNameWithAlias); + }); if(!tableNames.empty() && !isCompoundOperator) { ss << " FROM " << streaming_identifiers(tableNames); } diff --git a/not_single_header_include/sqlite_orm/sqlite_orm.h b/not_single_header_include/sqlite_orm/sqlite_orm.h index 1c8d2dfd1..c01387366 100644 --- a/not_single_header_include/sqlite_orm/sqlite_orm.h +++ b/not_single_header_include/sqlite_orm/sqlite_orm.h @@ -12,7 +12,6 @@ #include "../../dev/field_printer.h" #include "../../dev/conditions.h" #include "../../dev/alias.h" -#include "../../dev/join_iterator.h" #include "../../dev/core_functions.h" #include "../../dev/select_constraints.h" #include "../../dev/table_info.h" diff --git a/third_party/amalgamate/config.json b/third_party/amalgamate/config.json index e56ebbb8f..95eed5962 100755 --- a/third_party/amalgamate/config.json +++ b/third_party/amalgamate/config.json @@ -1,6 +1,6 @@ { - "project": "SQLite ORM", - "target": "include/sqlite_orm/sqlite_orm.h", + "project": "SQLite ORM", + "target": "include/sqlite_orm/sqlite_orm.h", "sources": [ "dev/functional/start_macros.h", "dev/type_traits.h", @@ -14,7 +14,6 @@ "dev/field_printer.h", "dev/conditions.h", "dev/alias.h", - "dev/join_iterator.h", "dev/core_functions.h", "dev/typed_comparator.h", "dev/select_constraints.h", @@ -42,5 +41,5 @@ "dev/interface_definitions.h", "dev/functional/finish_macros.h" ], - "include_paths": ["dev"] + "include_paths": [ "dev" ] } From 928631d52decb037bdca978a945a30dccd5ff14d Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 14 Feb 2023 10:04:03 +0200 Subject: [PATCH 030/100] Clean up includes in column_names_getter.h --- dev/column_names_getter.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index fb38a5a2e..dd797374f 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -1,11 +1,11 @@ #pragma once +#include // std::is_base_of #include // std::string #include // std::vector #include // std::reference_wrapper #include #include // std::move -#include // std::make_move_iterator #include "functional/cxx_universal.h" // ::size_t #include "functional/cxx_type_traits_polyfill.h" // polyfill::remove_cvref_t diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 663f3b415..bb4990109 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -14940,12 +14940,12 @@ namespace sqlite_orm { // #include "column_names_getter.h" +#include // std::is_base_of #include // std::string #include // std::vector #include // std::reference_wrapper #include #include // std::move -#include // std::make_move_iterator // #include "functional/cxx_universal.h" // ::size_t From 8f30dfaaeb101bcbda69ae2a4c653e3cb6e4dc49 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 14 Feb 2023 11:25:05 +0200 Subject: [PATCH 031/100] Consistency with the renaming made in sqlite_orm_plus --- dev/statement_binder.h | 4 ++-- dev/storage.h | 28 ++++++++++++++-------------- include/sqlite_orm/sqlite_orm.h | 32 ++++++++++++++++---------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/dev/statement_binder.h b/dev/statement_binder.h index 0f38a2022..b16fe3c87 100644 --- a/dev/statement_binder.h +++ b/dev/statement_binder.h @@ -285,7 +285,7 @@ namespace sqlite_orm { void operator()(const T& t) { int rc = statement_binder{}.bind(this->stmt, this->index++, t); if(SQLITE_OK != rc) { - throw_translated_sqlite_error(stmt); + throw_translated_sqlite_error(this->stmt); } } @@ -342,7 +342,7 @@ namespace sqlite_orm { void bind(const T& t, size_t idx) const { int rc = statement_binder{}.bind(this->stmt, int(idx + 1), t); if(SQLITE_OK != rc) { - throw_translated_sqlite_error(stmt); + throw_translated_sqlite_error(this->stmt); } } diff --git a/dev/storage.h b/dev/storage.h index 9e37b6752..b87d7e393 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -1160,10 +1160,10 @@ namespace sqlite_orm { sqlite3_stmt* stmt = reset_stmt(statement.stmt); auto processObject = [&table = this->get_table(), - bind_value = field_value_binder{stmt}](auto& object) mutable { + bindValue = field_value_binder{stmt}](auto& object) mutable { table.template for_each_column_excluding( - call_as_template_base([&bind_value, &object](auto& column) { - bind_value(polyfill::invoke(column.member_pointer, object)); + call_as_template_base([&bindValue, &object](auto& column) { + bindValue(polyfill::invoke(column.member_pointer, object)); })); }; @@ -1201,14 +1201,14 @@ namespace sqlite_orm { sqlite3_stmt* stmt = reset_stmt(statement.stmt); auto processObject = [&table = this->get_table(), - bind_value = field_value_binder{stmt}](auto& object) mutable { + bindValue = field_value_binder{stmt}](auto& object) mutable { using is_without_rowid = typename std::decay_t::is_without_rowid; table.template for_each_column_excluding< mpl::conjunction>, mpl::disjunction_fn>>( - call_as_template_base([&table, &bind_value, &object](auto& column) { + call_as_template_base([&table, &bindValue, &object](auto& column) { if(!table.exists_in_composite_primary_key(column)) { - bind_value(polyfill::invoke(column.member_pointer, object)); + bindValue(polyfill::invoke(column.member_pointer, object)); } })); }; @@ -1255,17 +1255,17 @@ namespace sqlite_orm { sqlite3_stmt* stmt = reset_stmt(statement.stmt); auto& table = this->get_table(); - field_value_binder bind_value{stmt}; + field_value_binder bindValue{stmt}; auto& object = get_object(statement.expression); table.template for_each_column_excluding>( - call_as_template_base([&table, &bind_value, &object](auto& column) { + call_as_template_base([&table, &bindValue, &object](auto& column) { if(!table.exists_in_composite_primary_key(column)) { - bind_value(polyfill::invoke(column.member_pointer, object)); + bindValue(polyfill::invoke(column.member_pointer, object)); } })); - table.for_each_column([&table, &bind_value, &object](auto& column) { + table.for_each_column([&table, &bindValue, &object](auto& column) { if(column.template is() || table.exists_in_composite_primary_key(column)) { - bind_value(polyfill::invoke(column.member_pointer, object)); + bindValue(polyfill::invoke(column.member_pointer, object)); } }); perform_step(stmt); @@ -1348,9 +1348,9 @@ namespace sqlite_orm { template void execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); - conditional_binder bind_node{stmt}; - iterate_ast(statement.expression.set, bind_node); - iterate_ast(statement.expression.conditions, bind_node); + conditional_binder bindNode{stmt}; + iterate_ast(statement.expression.set, bindNode); + iterate_ast(statement.expression.conditions, bindNode); perform_step(stmt); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index bb4990109..6e679ea76 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8184,7 +8184,7 @@ namespace sqlite_orm { void operator()(const T& t) { int rc = statement_binder{}.bind(this->stmt, this->index++, t); if(SQLITE_OK != rc) { - throw_translated_sqlite_error(stmt); + throw_translated_sqlite_error(this->stmt); } } @@ -8241,7 +8241,7 @@ namespace sqlite_orm { void bind(const T& t, size_t idx) const { int rc = statement_binder{}.bind(this->stmt, int(idx + 1), t); if(SQLITE_OK != rc) { - throw_translated_sqlite_error(stmt); + throw_translated_sqlite_error(this->stmt); } } @@ -18304,10 +18304,10 @@ namespace sqlite_orm { sqlite3_stmt* stmt = reset_stmt(statement.stmt); auto processObject = [&table = this->get_table(), - bind_value = field_value_binder{stmt}](auto& object) mutable { + bindValue = field_value_binder{stmt}](auto& object) mutable { table.template for_each_column_excluding( - call_as_template_base([&bind_value, &object](auto& column) { - bind_value(polyfill::invoke(column.member_pointer, object)); + call_as_template_base([&bindValue, &object](auto& column) { + bindValue(polyfill::invoke(column.member_pointer, object)); })); }; @@ -18345,14 +18345,14 @@ namespace sqlite_orm { sqlite3_stmt* stmt = reset_stmt(statement.stmt); auto processObject = [&table = this->get_table(), - bind_value = field_value_binder{stmt}](auto& object) mutable { + bindValue = field_value_binder{stmt}](auto& object) mutable { using is_without_rowid = typename std::decay_t::is_without_rowid; table.template for_each_column_excluding< mpl::conjunction>, mpl::disjunction_fn>>( - call_as_template_base([&table, &bind_value, &object](auto& column) { + call_as_template_base([&table, &bindValue, &object](auto& column) { if(!table.exists_in_composite_primary_key(column)) { - bind_value(polyfill::invoke(column.member_pointer, object)); + bindValue(polyfill::invoke(column.member_pointer, object)); } })); }; @@ -18399,17 +18399,17 @@ namespace sqlite_orm { sqlite3_stmt* stmt = reset_stmt(statement.stmt); auto& table = this->get_table(); - field_value_binder bind_value{stmt}; + field_value_binder bindValue{stmt}; auto& object = get_object(statement.expression); table.template for_each_column_excluding>( - call_as_template_base([&table, &bind_value, &object](auto& column) { + call_as_template_base([&table, &bindValue, &object](auto& column) { if(!table.exists_in_composite_primary_key(column)) { - bind_value(polyfill::invoke(column.member_pointer, object)); + bindValue(polyfill::invoke(column.member_pointer, object)); } })); - table.for_each_column([&table, &bind_value, &object](auto& column) { + table.for_each_column([&table, &bindValue, &object](auto& column) { if(column.template is() || table.exists_in_composite_primary_key(column)) { - bind_value(polyfill::invoke(column.member_pointer, object)); + bindValue(polyfill::invoke(column.member_pointer, object)); } }); perform_step(stmt); @@ -18492,9 +18492,9 @@ namespace sqlite_orm { template void execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); - conditional_binder bind_node{stmt}; - iterate_ast(statement.expression.set, bind_node); - iterate_ast(statement.expression.conditions, bind_node); + conditional_binder bindNode{stmt}; + iterate_ast(statement.expression.set, bindNode); + iterate_ast(statement.expression.conditions, bindNode); perform_step(stmt); } From d4171fb1f94a14b18c858cf31955ce9d6c3b6943 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 14 Feb 2023 12:34:44 +0200 Subject: [PATCH 032/100] Update iteration over joined tables --- dev/statement_serializer.h | 21 +++++++++------------ include/sqlite_orm/sqlite_orm.h | 21 +++++++++------------ 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index d52128fb0..c888916ca 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1492,22 +1492,19 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - using conditions_tuple = std::tuple; + using conditions_tuple = typename statement_type::conditions_type; constexpr bool hasExplicitFrom = tuple_has::value; if(!hasExplicitFrom) { auto tableNames = collect_table_names(sel, context); using joins_index_sequence = filter_tuple_sequence_t; - iterate_tuple( - joins_index_sequence{}, - [&tableNames, &context](auto* joinTypeDummy) { - using original_join_type = typename std::remove_pointer_t::type; - using cross_join_type = mapped_type_proxy_t; - auto crossJoinedTableName = lookup_table_name(context.db_objects); - auto tableAliasString = alias_extractor::get(); - std::pair tableNameWithAlias{std::move(crossJoinedTableName), - std::move(tableAliasString)}; - tableNames.erase(tableNameWithAlias); - }); + iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) { + using original_join_type = typename std::decay_t::type; + using cross_join_type = mapped_type_proxy_t; + std::pair tableNameWithAlias{ + lookup_table_name(context.db_objects), + alias_extractor::get()}; + tableNames.erase(tableNameWithAlias); + }); if(!tableNames.empty() && !isCompoundOperator) { ss << " FROM " << streaming_identifiers(tableNames); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 6e679ea76..8f81d2f3c 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16606,22 +16606,19 @@ namespace sqlite_orm { ss << static_cast(distinct(0)) << " "; } ss << streaming_serialized(get_column_names(sel.col, context)); - using conditions_tuple = std::tuple; + using conditions_tuple = typename statement_type::conditions_type; constexpr bool hasExplicitFrom = tuple_has::value; if(!hasExplicitFrom) { auto tableNames = collect_table_names(sel, context); using joins_index_sequence = filter_tuple_sequence_t; - iterate_tuple( - joins_index_sequence{}, - [&tableNames, &context](auto* joinTypeDummy) { - using original_join_type = typename std::remove_pointer_t::type; - using cross_join_type = mapped_type_proxy_t; - auto crossJoinedTableName = lookup_table_name(context.db_objects); - auto tableAliasString = alias_extractor::get(); - std::pair tableNameWithAlias{std::move(crossJoinedTableName), - std::move(tableAliasString)}; - tableNames.erase(tableNameWithAlias); - }); + iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) { + using original_join_type = typename std::decay_t::type; + using cross_join_type = mapped_type_proxy_t; + std::pair tableNameWithAlias{ + lookup_table_name(context.db_objects), + alias_extractor::get()}; + tableNames.erase(tableNameWithAlias); + }); if(!tableNames.empty() && !isCompoundOperator) { ss << " FROM " << streaming_identifiers(tableNames); } From 8c8dfd06ff50c2bd1a3425b2600a0187ab1539fa Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 14 Feb 2023 12:41:15 +0200 Subject: [PATCH 033/100] Provided an example for selecting all columns from multiple tables --- dev/storage.h | 2 +- examples/select.cpp | 128 +++++++++++++++++++++++++------- include/sqlite_orm/sqlite_orm.h | 2 +- 3 files changed, 102 insertions(+), 30 deletions(-) diff --git a/dev/storage.h b/dev/storage.h index b87d7e393..868d92023 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -975,7 +975,7 @@ namespace sqlite_orm { * specified in `make_storage`, `make_table` and `make_column` calls. The best practice is to call this * function right after storage creation. * @param preserve affects function's behaviour in case it is needed to remove a column. If it is `false` - * so table will be dropped if there is column to remove if SQLite version is < 3.35.0 and rmeove column if SQLite version >= 3.35.0, + * so table will be dropped if there is column to remove if SQLite version is < 3.35.0 and remove column if SQLite version >= 3.35.0, * if `true` - table is being copied into another table, dropped and copied table is renamed with source table name. * Warning: sync_schema doesn't check foreign keys cause it is unable to do so in sqlite3. If you know how to get foreign key info please * submit an issue https://github.com/fnc12/sqlite_orm/issues diff --git a/examples/select.cpp b/examples/select.cpp index d8632e5e0..eaf6cbf3e 100644 --- a/examples/select.cpp +++ b/examples/select.cpp @@ -6,20 +6,21 @@ #include -struct Employee { - int id; - std::string name; - int age; - std::unique_ptr address; // optional - std::unique_ptr salary; // optional -}; - using namespace sqlite_orm; - using std::cout; using std::endl; +using std::make_unique; +using std::string; + +void all_employees() { + struct Employee { + int id; + std::string name; + int age; + std::unique_ptr address; // optional + std::unique_ptr salary; // optional + }; -int main(int, char**) { auto storage = make_storage("select.sqlite", make_table("COMPANY", make_column("ID", &Employee::id, primary_key()), @@ -31,13 +32,13 @@ int main(int, char**) { storage.remove_all(); // remove all old employees in case they exist in db.. // create employees.. - Employee paul{-1, "Paul", 32, std::make_unique("California"), std::make_unique(20000.0)}; - Employee allen{-1, "Allen", 25, std::make_unique("Texas"), std::make_unique(15000.0)}; - Employee teddy{-1, "Teddy", 23, std::make_unique("Norway"), std::make_unique(20000.0)}; - Employee mark{-1, "Mark", 25, std::make_unique("Rich-Mond"), std::make_unique(65000.0)}; - Employee david{-1, "David", 27, std::make_unique("Texas"), std::make_unique(85000.0)}; - Employee kim{-1, "Kim", 22, std::make_unique("South-Hall"), std::make_unique(45000.0)}; - Employee james{-1, "James", 24, std::make_unique("Houston"), std::make_unique(10000.0)}; + Employee paul{-1, "Paul", 32, make_unique("California"), make_unique(20000.0)}; + Employee allen{-1, "Allen", 25, make_unique("Texas"), make_unique(15000.0)}; + Employee teddy{-1, "Teddy", 23, make_unique("Norway"), make_unique(20000.0)}; + Employee mark{-1, "Mark", 25, make_unique("Rich-Mond"), make_unique(65000.0)}; + Employee david{-1, "David", 27, make_unique("Texas"), make_unique(85000.0)}; + Employee kim{-1, "Kim", 22, make_unique("South-Hall"), make_unique(45000.0)}; + Employee james{-1, "James", 24, make_unique("Houston"), make_unique(10000.0)}; // insert employees. `insert` function returns id of inserted object.. paul.id = storage.insert(paul); @@ -65,11 +66,10 @@ int main(int, char**) { // now let's select id, name and salary.. auto idsNamesSalarys = storage.select(columns(&Employee::id, &Employee::name, &Employee::salary)); - // decltype(idsNamesSalarys) = vector>> - for(auto& tpl: idsNamesSalarys) { - cout << "id = " << std::get<0>(tpl) << ", name = " << std::get<1>(tpl) << ", salary = "; - if(std::get<2>(tpl)) { - cout << *std::get<2>(tpl); + for(auto& row: idsNamesSalarys) { // row's type is tuple> + cout << "id = " << get<0>(row) << ", name = " << get<1>(row) << ", salary = "; + if(get<2>(row)) { + cout << *get<2>(row); } else { cout << "null"; } @@ -78,22 +78,94 @@ int main(int, char**) { cout << endl; - auto allEmployeesTuples = storage.select(asterisk()); - cout << "allEmployeesTuples count = " << allEmployeesTuples.size() << endl; - for(auto& row: allEmployeesTuples) { // row is std::tuple, + auto allEmployeeTuples = storage.select(asterisk()); + cout << "allEmployeeTuples count = " << allEmployeeTuples.size() << endl; + for(auto& row: allEmployeeTuples) { // row's type is std::tuple, // std::unique_ptr> - cout << std::get<0>(row) << '\t' << std::get<1>(row) << '\t' << std::get<2>(row) << '\t'; - if(auto& value = std::get<3>(row)) { + cout << get<0>(row) << '\t' << get<1>(row) << '\t' << get<2>(row) << '\t'; + if(auto& value = get<3>(row)) { + cout << *value; + } else { + cout << "null"; + } + cout << '\t'; + if(auto& value = get<4>(row)) { + cout << *value; + } else { + cout << "null"; + } + cout << '\t' << endl; + } + + cout << endl; + + auto allEmployeeObjects = storage.select(object()); + cout << "allEmployeeObjects count = " << allEmployeeObjects.size() << endl; + for(auto& employee: allEmployeeObjects) { + cout << employee.id << '\t' << employee.name << '\t' << employee.age << '\t'; + if(auto& value = employee.address) { cout << *value; } else { cout << "null"; } cout << '\t'; - if(auto& value = std::get<4>(row)) { + if(auto& value = employee.salary) { cout << *value; } else { cout << "null"; } cout << '\t' << endl; } + + cout << endl; +} + +void all_artists() { + struct Artist { + int id; + std::string name; + }; + + struct Album { + int id; + int artist_id; + }; + + auto storage = make_storage("", + make_table("artists", + make_column("id", &Artist::id, primary_key().autoincrement()), + make_column("name", &Artist::name)), + make_table("albums", + make_column("id", &Album::id, primary_key().autoincrement()), + make_column("artist_id", &Album::artist_id), + foreign_key(&Album::artist_id).references(&Artist::id))); + storage.sync_schema(); + storage.transaction([&storage] { + auto artistPk = storage.insert(Artist{-1, "Artist"}); + storage.insert(Album{-1, artistPk}); + storage.insert(Album{-1, artistPk}); + return true; + }); + + // SELECT artists.*, albums.* FROM artists JOIN albums ON albums.artist_id = artist.id + + cout << "artists.*, albums.*\n"; + // row's type is std::tuple + for(auto& row: storage.select(columns(asterisk(), asterisk()), + join(on(c(&Album::artist_id) == &Artist::id)))) { + cout << get<0>(row) << '\t' << get<1>(row) << '\t' << get<2>(row) << '\t' << get<3>(row) << '\n'; + } + cout << endl; +} + +int main() { + + try { + all_employees(); + all_artists(); + } catch(const std::system_error& e) { + cout << "[" << e.code() << "] " << e.what(); + } + + return 0; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 8f81d2f3c..325292e43 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -18116,7 +18116,7 @@ namespace sqlite_orm { * specified in `make_storage`, `make_table` and `make_column` calls. The best practice is to call this * function right after storage creation. * @param preserve affects function's behaviour in case it is needed to remove a column. If it is `false` - * so table will be dropped if there is column to remove if SQLite version is < 3.35.0 and rmeove column if SQLite version >= 3.35.0, + * so table will be dropped if there is column to remove if SQLite version is < 3.35.0 and remove column if SQLite version >= 3.35.0, * if `true` - table is being copied into another table, dropped and copied table is renamed with source table name. * Warning: sync_schema doesn't check foreign keys cause it is unable to do so in sqlite3. If you know how to get foreign key info please * submit an issue https://github.com/fnc12/sqlite_orm/issues From 3d24f957dd44d6f90f9bfbc340dc2508a43d32c2 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 07:48:58 +0200 Subject: [PATCH 034/100] Enabled parallel builds on appveyor if possible --- appveyor.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 7eb6d8551..4e0922596 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,12 +25,15 @@ environment: CC: clang CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_14=ON" + cmake_build_parallel: --parallel - job_name: gcc, C++14 appveyor_build_worker_image: Ubuntu CC: gcc CXX: g++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_14=ON" + # gcc was stuck with a parallel build + cmake_build_parallel: "" # Representative for C++14 - job_name: Visual Studio 2022, x64, C++14 @@ -43,24 +46,28 @@ environment: CC: clang CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" + cmake_build_parallel: --parallel - job_name: clang, C++20 appveyor_build_worker_image: Ubuntu CC: clang CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" + cmake_build_parallel: --parallel - job_name: gcc, C++17 appveyor_build_worker_image: Ubuntu CC: gcc CXX: g++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" + cmake_build_parallel: "" - job_name: gcc, C++20 appveyor_build_worker_image: Ubuntu CC: gcc CXX: g++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" + cmake_build_parallel: "" - job_name: Visual Studio 2022, x64, C++17 appveyor_build_worker_image: Visual Studio 2022 @@ -111,7 +118,7 @@ for: # build examples, and run tests (ie make & make test) build_script: - |- - cmake --build . --config %configuration% + cmake --build . --config %configuration% -- /m ctest --verbose --output-on-failure --build-config %configuration% - @@ -140,7 +147,7 @@ for: # build examples, and run tests (ie make & make test) build_script: - |- - cmake --build . + cmake --build . $cmake_build_parallel ctest --verbose --output-on-failure - # macOS @@ -166,5 +173,5 @@ for: # build examples, and run tests (ie make & make test) build_script: - |- - cmake --build . + cmake --build . --parallel ctest --verbose --output-on-failure From 858dc32435debdf3b8b810bca6cb8feaebde323f Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 20:47:17 +0200 Subject: [PATCH 035/100] Pimped tables and column aliases * Dedicated unit tests for aliases * Type traits for aliases * Syntactic sugar for easier creation and usage of aliased expressions (pointer-member-pointer operator, ad-hoc string aliases) * Column aliases are usable on their own in expressions --- dev/alias.h | 183 +++++- dev/alias_traits.h | 64 ++ dev/ast_iterator.h | 15 +- dev/column_names_getter.h | 14 +- dev/column_pointer.h | 62 ++ dev/column_result.h | 13 +- dev/conditions.h | 51 +- dev/functional/cxx_compiler_quirks.h | 6 + dev/functional/cxx_core_features.h | 4 + dev/mapped_type_proxy.h | 13 +- dev/node_tuple.h | 8 + dev/select_constraints.h | 61 +- dev/statement_serializer.h | 28 +- dev/storage_lookup.h | 4 +- dev/table.h | 10 +- dev/table_name_collector.h | 17 +- examples/column_aliases.cpp | 18 +- examples/custom_aliases.cpp | 30 + examples/exists.cpp | 31 +- examples/self_join.cpp | 27 +- examples/subquery.cpp | 14 + include/sqlite_orm/sqlite_orm.h | 572 ++++++++++++++---- tests/CMakeLists.txt | 1 + tests/ast_iterator_tests.cpp | 133 ++-- .../alias_extractor.cpp | 9 +- .../column_names.cpp | 19 + .../select_constraints.cpp | 14 + tests/static_tests/alias.cpp | 44 ++ tests/static_tests/node_tuple.cpp | 7 +- 29 files changed, 1152 insertions(+), 320 deletions(-) create mode 100644 dev/alias_traits.h create mode 100644 dev/column_pointer.h create mode 100644 tests/static_tests/alias.cpp diff --git a/dev/alias.h b/dev/alias.h index 69338910c..40a63011b 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -1,31 +1,53 @@ #pragma once -#include // std::enable_if, std::is_base_of, std::is_member_pointer -#include // std::stringstream +#include // std::enable_if, std::is_base_of, std::is_member_pointer, std::remove_const +#include // std::index_sequence, std::make_index_sequence #include // std::string +#include // std::stringstream +#include // std::copy_n +#include "functional/cxx_universal.h" +#include "functional/cxx_type_traits_polyfill.h" #include "type_traits.h" +#include "alias_traits.h" namespace sqlite_orm { - /** - * This is base class for every class which is used as a custom table alias, column alias or expression alias. - * For more information please look through self_join.cpp example - */ - struct alias_tag {}; - namespace internal { +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + /* + * Helper class to facilitate user-defined string literal operator template + */ + template + struct string_identifier_template { + static constexpr size_t size() { + return N - 1; + } + + constexpr string_identifier_template(const char (&id)[N]) { + std::copy_n(id, N, this->id); + } + + char id[N]; + }; + + template class Alias, string_identifier_template t, size_t... Idx> + consteval auto to_alias(std::index_sequence) { + return Alias{}; + } +#endif + /** * This is a common built-in class used for custom single character table aliases. - * For convenience there exist type aliases `alias_a`, `alias_b`, ... + * For convenience there exist public type aliases `alias_a`, `alias_b`, ... */ - template + template struct table_alias : alias_tag { using type = T; - static char get() { - return A; + static std::string get() { + return {A, X...}; } }; @@ -40,20 +62,39 @@ namespace sqlite_orm { column_type column; }; + /* + * Encapsulates extracting the alias identifier of a non-alias. + */ template struct alias_extractor { - static std::string get() { + static std::string extract() { + return {}; + } + + static std::string as_alias() { return {}; } }; - template - struct alias_extractor::value>> { - static std::string get() { + /* + * Encapsulates extracting the alias identifier of an alias. + * + * `extract()` always returns the alias identifier. + * `as_alias()` is used in contexts where a table is aliased. + */ + template + struct alias_extractor> { + static std::string extract() { std::stringstream ss; - ss << T::get(); + ss << A::get(); return ss.str(); } + + // for column and regular table aliases -> alias identifier + template, A> = true> + static std::string as_alias() { + return alias_extractor::extract(); + } }; /** @@ -71,41 +112,105 @@ namespace sqlite_orm { * This is a common built-in class used for custom single-character column aliases. * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... */ - template + template struct column_alias : alias_tag { static std::string get() { - return std::string(1u, A); + return {A, X...}; } }; template struct alias_holder { using type = T; + + alias_holder() = default; }; + +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template + struct table_alias_builder { + static_assert(sizeof...(C) == 0 && ((A >= 'A' && 'Z' <= A) || (A >= 'a' && 'z' <= A)), + "Table alias identifiers shall consist of a single alphabetic character, in order to evade " + "clashes with CTE aliases."); + + template + [[nodiscard]] consteval internal::table_alias, A, C...> for_() const { + return {}; + } + + template + [[nodiscard]] consteval internal::table_alias for_() const { + return {}; + } + }; +#endif } /** * @return column with table alias attached. Place it instead of a column statement in case you need to specify a - * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example + * column with table alias prefix like 'a.column'. */ - template + template, bool> = true> internal::alias_column_t alias_column(C c) { using table_type = internal::type_t; - static_assert(std::is_same, table_type>::value, + static_assert(std::is_same, table_type>::value, "Column must be from aliased table"); return {c}; } - template - internal::as_t as(E expression) { +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template, + std::enable_if_t, bool> = true> + auto alias_column(C c) { + using table_type = internal::type_t; + static_assert(std::is_same_v, table_type>, + "Column must be from aliased table"); + return internal::alias_column_t{c}; + } + + template, bool> = true> + constexpr auto operator->*(const A& /*tableAlias*/, F field) { + return alias_column(std::move(field)); + } +#endif + + /** + * Alias a column expression. + */ + template = true> + internal::as_t as(E expression) { return {std::move(expression)}; } - template - internal::alias_holder get() { +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto as(E expression) { + return internal::as_t, E>{std::move(expression)}; + } + + /** + * Alias a column expression. + */ + template = true> + internal::as_t operator>>=(E expression, const A&) { + return {std::move(expression)}; + } +#endif + + template = true> + internal::alias_holder get() { return {}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto get() { + return internal::alias_holder>{}; + } +#endif + template using alias_a = internal::table_alias; template @@ -168,4 +273,30 @@ namespace sqlite_orm { using colalias_g = internal::column_alias<'g'>; using colalias_h = internal::column_alias<'h'>; using colalias_i = internal::column_alias<'i'>; + +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + /** @short Create aliased tables e.g. `constexpr auto z_alias = alias_<'z'>.for_()`. + */ + template + inline constexpr internal::table_alias_builder alias_{}; + + /** @short Create a table alias. + * + * Examples: + * constexpr auto z_alias = "z"_alias.for_(); + */ + template + [[nodiscard]] consteval auto operator"" _alias() { + return internal::to_alias(std::make_index_sequence{}); + } + + /** @short Create a column alias. + * column_alias<'a'[, ...]> from a string literal. + * E.g. "a"_col, "b"_col + */ + template + [[nodiscard]] consteval auto operator"" _col() { + return internal::to_alias(std::make_index_sequence{}); + } +#endif } diff --git a/dev/alias_traits.h b/dev/alias_traits.h new file mode 100644 index 000000000..dd959cf9f --- /dev/null +++ b/dev/alias_traits.h @@ -0,0 +1,64 @@ +#pragma once + +#include // std::remove_const, std::is_base_of, std::is_same + +#include "functional/cxx_universal.h" +#include "functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { + + /** + * Base class for a custom table alias, column alias or expression alias. + * For more information please look through self_join.cpp example + */ + struct alias_tag {}; + + namespace internal { + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_alias_v = std::is_base_of::value; + + template + using is_alias = polyfill::bool_constant>; + + /** Alias for a column in a record set. + * + * A column alias has the following traits: + * - is derived from `alias_tag` + * + * @note: Currently, there is no distinguishing property of a column alias other than that it is derived from "alias_tag". + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = is_alias_v; + + template + using is_column_alias = is_alias; + + /** Alias for any type of record set. + * + * A record set alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to a mapped object. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_recordset_alias_v = + polyfill::conjunction_v, polyfill::is_detected>; + + template + using is_recordset_alias = polyfill::bool_constant>; + + /** Alias for a concrete table. + * + * A concrete table alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< + std::is_base_of, + polyfill::negation, std::remove_const_t>>>; + + template + using is_table_alias = polyfill::bool_constant>; + } +} diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 795ce22dd..970519120 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -4,7 +4,9 @@ #include // std::reference_wrapper #include "tuple_helper/tuple_iteration.h" +#include "type_traits.h" #include "conditions.h" +#include "alias.h" #include "select_constraints.h" #include "operators.h" #include "core_functions.h" @@ -673,7 +675,7 @@ namespace sqlite_orm { }; /** - * Column alias or literal + * Column alias or literal: skipped */ template struct ast_iterator< @@ -686,6 +688,17 @@ namespace sqlite_orm { void operator()(const node_type& /*node*/, L& /*lambda*/) const {} }; + /** + * Column alias: skipped + */ + template + struct ast_iterator, void> { + using node_type = column_alias; + + template + void operator()(const node_type& /*node*/, L& /*lambda*/) const {} + }; + template struct ast_iterator, void> { using node_type = order_by_t; diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index dd797374f..6dd70c690 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -7,12 +7,12 @@ #include #include // std::move -#include "functional/cxx_universal.h" // ::size_t -#include "functional/cxx_type_traits_polyfill.h" // polyfill::remove_cvref_t #include "tuple_helper/tuple_traits.h" +#include "tuple_helper/tuple_iteration.h" #include "error_code.h" +#include "mapped_type_proxy.h" +#include "alias_traits.h" #include "select_constraints.h" -#include "alias.h" #include "storage_lookup.h" // pick_table #include "serializer_context.h" #include "util.h" @@ -34,8 +34,8 @@ namespace sqlite_orm { table.for_each_column([qualified = !context.skip_table_name, &tableName = table.name, &collectedExpressions](const column_identifier& column) { - if(std::is_base_of::value) { - collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + "." + + if(is_alias_v) { + collectedExpressions.push_back(quote_identifier(alias_extractor::extract()) + "." + quote_identifier(column.name)); } else if(qualified) { collectedExpressions.push_back(quote_identifier(tableName) + "." + @@ -46,8 +46,8 @@ namespace sqlite_orm { }); } else { collectedExpressions.reserve(collectedExpressions.size() + 1); - if(std::is_base_of::value) { - collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + ".*"); + if(is_alias_v) { + collectedExpressions.push_back(quote_identifier(alias_extractor::extract()) + ".*"); } else if(!context.skip_table_name) { const basic_table& table = pick_table>(context.db_objects); collectedExpressions.push_back(quote_identifier(table.name) + ".*"); diff --git a/dev/column_pointer.h b/dev/column_pointer.h new file mode 100644 index 000000000..1fd06e7c5 --- /dev/null +++ b/dev/column_pointer.h @@ -0,0 +1,62 @@ +#pragma once + +#include // std::string +#include // std::move + +#include "functional/cxx_core_features.h" +#include "conditions.h" +#include "alias_traits.h" + +namespace sqlite_orm { + namespace internal { + /** + * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). + * Is useful when mapped type is derived from other type and base class has members mapped to a storage. + */ + template + struct column_pointer { + using self = column_pointer; + using type = T; + using field_type = F; + + field_type field; + + template + is_equal_t operator==(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + is_not_equal_t operator!=(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + lesser_than_t operator<(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + lesser_or_equal_t operator<=(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + greater_than_t operator>(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + greater_or_equal_t operator>=(R rhs) const { + return {*this, std::move(rhs)}; + } + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; + + template + using is_column_pointer = polyfill::bool_constant>; + + } +} diff --git a/dev/column_result.h b/dev/column_result.h index 55ce40e4e..d766e7627 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -15,7 +15,6 @@ #include "operators.h" #include "rowid.h" #include "alias.h" -#include "column.h" #include "storage_traits.h" #include "function.h" @@ -24,6 +23,8 @@ namespace sqlite_orm { namespace internal { /** + * Obains the result type of expressions that form the columns of a select statement. + * * This is a proxy class used to define what type must have result type depending on select * arguments (member pointer, aggregate functions, etc). Below you can see specializations * for different types. E.g. specialization for internal::length_t has `type` int cause @@ -32,6 +33,8 @@ namespace sqlite_orm { * DBOs - db_objects_tuple type * T - C++ type * SFINAE - sfinae argument + * + * Note (implementation): could be possibly implemented by utilizing column_expression_of_t */ template struct column_result_t; @@ -248,12 +251,8 @@ namespace sqlite_orm { struct column_result_t, void> : column_result_t> {}; template - struct column_result_t, match_if_not> - : storage_traits::storage_mapped_columns {}; - - template - struct column_result_t, match_if> - : storage_traits::storage_mapped_columns> {}; + struct column_result_t, void> + : storage_traits::storage_mapped_columns> {}; template struct column_result_t, void> { diff --git a/dev/conditions.h b/dev/conditions.h index a6b69c23b..9c490fc32 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1,9 +1,9 @@ #pragma once #include // std::string -#include // std::enable_if, std::is_same +#include // std::enable_if, std::is_same, std::remove_const #include // std::vector -#include // std::tuple, std::tuple_size +#include // std::tuple #include // std::stringstream #include "functional/cxx_universal.h" @@ -14,6 +14,7 @@ #include "optional_container.h" #include "serializer_context.h" #include "tags.h" +#include "alias_traits.h" #include "expression.h" #include "type_printer.h" #include "literal.h" @@ -812,12 +813,24 @@ namespace sqlite_orm { * Explicit FROM function. Usage: * `storage.select(&User::id, from());` */ - template - internal::from_t from() { - static_assert(std::tuple_size>::value > 0, ""); + template + internal::from_t from() { + static_assert(sizeof...(Tables) > 0, ""); return {}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + /** + * Explicit FROM function. Usage: + * `storage.select(&User::id, from<"a"_alias.for_>());` + */ + template + auto from() { + static_assert(sizeof...(tables) > 0); + return internal::from_t...>{}; + } +#endif + template = true> internal::negated_condition_t operator!(T arg) { return {std::move(arg)}; @@ -1015,21 +1028,49 @@ namespace sqlite_orm { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto left_join(O o) { + return internal::left_join_t, O>{std::move(o)}; + } +#endif + template internal::join_t join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto join(O o) { + return internal::join_t, O>{std::move(o)}; + } +#endif + template internal::left_outer_join_t left_outer_join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto left_outer_join(O o) { + return internal::left_outer_join_t, O>{std::move(o)}; + } +#endif + template internal::inner_join_t inner_join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto inner_join(O o) { + return internal::inner_join_t, O>{std::move(o)}; + } +#endif + template internal::offset_t offset(T off) { return {std::move(off)}; diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index ab84d2980..59ec1b3a7 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -28,3 +28,9 @@ #if defined(_MSC_VER) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif + +// overwrite SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#if(__cpp_nontype_template_args < 201911L) && \ + (defined(__clang__) && (__clang_major__ >= 12) && (__cplusplus >= 202002L)) +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index a1679fd40..9ea0d4269 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -70,3 +70,7 @@ #if __cpp_concepts >= 201907L #define SQLITE_ORM_CONCEPTS_SUPPORTED #endif + +#if __cpp_nontype_template_args >= 201911L +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif diff --git a/dev/mapped_type_proxy.h b/dev/mapped_type_proxy.h index 22c988eec..fd914d0b7 100644 --- a/dev/mapped_type_proxy.h +++ b/dev/mapped_type_proxy.h @@ -1,24 +1,23 @@ #pragma once -#include // std::enable_if, std::is_base_of, std::remove_const +#include // std::remove_const -#include "alias.h" +#include "type_traits.h" +#include "alias_traits.h" namespace sqlite_orm { namespace internal { /** - * If T is alias than mapped_type_proxy::type is alias::type - * otherwise T is unqualified T. + * If T is a recordset alias then the typename mapped_type_proxy::type is the unqualified aliased type, + * otherwise unqualified T. */ template struct mapped_type_proxy : std::remove_const {}; template - struct mapped_type_proxy::value>> { - using type = typename T::type; - }; + struct mapped_type_proxy> : std::remove_const> {}; template using mapped_type_proxy_t = typename mapped_type_proxy::type; diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 4f10bdb52..2a62d8aa3 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -1,10 +1,12 @@ #pragma once +#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" #include "conditions.h" #include "operators.h" @@ -73,6 +75,12 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; + /** + * Column alias + */ + template + struct node_tuple, void> : node_tuple {}; + /** * Literal */ diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 592b21e21..2c7a299ee 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -1,7 +1,8 @@ #pragma once +#include // std::remove_const #include // std::string -#include // std::declval +#include // std::move #include // std::tuple, std::get, std::tuple_size #include "functional/cxx_optional.h" @@ -13,6 +14,8 @@ #include "ast/where.h" #include "ast/group_by.h" #include "core_functions.h" +#include "alias_traits.h" +#include "column_pointer.h" namespace sqlite_orm { @@ -80,55 +83,6 @@ namespace sqlite_orm { template using is_columns = polyfill::bool_constant>; - /** - * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). - * Is useful when mapped type is derived from other type and base class has members mapped to a storage. - */ - template - struct column_pointer { - using self = column_pointer; - using type = T; - using field_type = F; - - field_type field; - - template - internal::is_equal_t operator==(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::is_not_equal_t operator!=(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::lesser_than_t operator<(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::lesser_or_equal_t operator<=(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::greater_than_t operator>(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::greater_or_equal_t operator>=(R rhs) const { - return {*this, std::move(rhs)}; - } - }; - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; - - template - using is_column_pointer = polyfill::bool_constant>; - /** * Subselect object type. */ @@ -455,6 +409,13 @@ namespace sqlite_orm { return {definedOrder}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto asterisk(bool definedOrder = false) { + return internal::asterisk_t>{definedOrder}; + } +#endif + /** * `SELECT * FROM T` expression that fetches results as objects of type T. * T is a type mapped to a storage, or an alias of it. diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index c888916ca..ecc431ce7 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -212,6 +212,18 @@ namespace sqlite_orm { } }; + template + struct statement_serializer, void> { + using statement_type = column_alias; + + template + std::string operator()(const statement_type&, const Ctx&) { + std::stringstream ss; + ss << streaming_identifier(statement_type::get()); + return ss.str(); + } + }; + template struct statement_serializer, std::tuple>, void> { using statement_type = upsert_clause, std::tuple>; @@ -285,7 +297,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; - ss << serialize(c.expression, context) + " AS " << streaming_identifier(alias_extractor::get()); + ss << serialize(c.expression, context) + " AS " << streaming_identifier(alias_extractor::extract()); return ss.str(); } }; @@ -298,7 +310,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; if(!context.skip_table_name) { - ss << streaming_identifier(alias_extractor::get()) << "."; + ss << streaming_identifier(alias_extractor::extract()) << "."; } auto newContext = context; newContext.skip_table_name = true; @@ -1502,7 +1514,7 @@ namespace sqlite_orm { using cross_join_type = mapped_type_proxy_t; std::pair tableNameWithAlias{ lookup_table_name(context.db_objects), - alias_extractor::get()}; + alias_extractor::as_alias()}; tableNames.erase(tableNameWithAlias); }); if(!tableNames.empty() && !isCompoundOperator) { @@ -1598,7 +1610,7 @@ namespace sqlite_orm { constexpr std::array sep = {", ", ""}; ss << sep[std::exchange(first, false)] << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()); + alias_extractor::as_alias()); }); return ss.str(); } @@ -1840,7 +1852,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << serialize(l.constraint, context); return ss.str(); } @@ -1869,7 +1881,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << " " << serialize(l.constraint, context); return ss.str(); } @@ -1884,7 +1896,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << " " << serialize(l.constraint, context); return ss.str(); } @@ -1899,7 +1911,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << " " << serialize(l.constraint, context); return ss.str(); } diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index 6cbc47820..07366813e 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -1,8 +1,8 @@ #pragma once -#include // std::true_type, std::false_type, std::remove_const, std::enable_if +#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 +#include // std::index_sequence, std::make_index_sequence #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" diff --git a/dev/table.h b/dev/table.h index 3d1b6cdbb..0aede4255 100644 --- a/dev/table.h +++ b/dev/table.h @@ -37,9 +37,9 @@ namespace sqlite_orm { /** * Table definition. */ - template + template struct table_t : basic_table { - using object_type = T; + using object_type = O; using elements_type = std::tuple; static constexpr bool is_without_rowid_v = WithoutRowId; @@ -52,7 +52,7 @@ namespace sqlite_orm { basic_table{std::move(name_)}, elements{std::move(elements_)} {} #endif - table_t without_rowid() const { + table_t without_rowid() const { return {this->name, this->elements}; } @@ -236,11 +236,11 @@ namespace sqlite_orm { iterate_tuple(this->elements, fk_index_sequence{}, lambda); } - template + template void for_each_foreign_key_to(L&& lambda) const { using fk_index_sequence = filter_tuple_sequence_t; using filtered_index_sequence = filter_tuple_sequence_t::template fn, + check_if_is_type::template fn, target_type_t, fk_index_sequence>; iterate_tuple(this->elements, filtered_index_sequence{}, lambda); diff --git a/dev/table_name_collector.h b/dev/table_name_collector.h index 0c5e80d64..549b8c82f 100644 --- a/dev/table_name_collector.h +++ b/dev/table_name_collector.h @@ -6,6 +6,7 @@ #include "functional/cxx_type_traits_polyfill.h" #include "type_traits.h" +#include "mapped_type_proxy.h" #include "select_constraints.h" #include "alias.h" #include "core_functions.h" @@ -48,7 +49,7 @@ namespace sqlite_orm { void operator()(const alias_column_t&) { // note: instead of accessing the column, we are interested in the type the column is aliased into auto tableName = lookup_table_name>(this->db_objects); - this->table_names.emplace(std::move(tableName), alias_extractor::get()); + this->table_names.emplace(std::move(tableName), alias_extractor::as_alias()); } template @@ -59,18 +60,10 @@ namespace sqlite_orm { } } - template = true> - void operator()(const asterisk_t&) { - this->table_names.emplace(lookup_table_name(this->db_objects), ""); - } - - template = true> + template void operator()(const asterisk_t&) { - // note: not all alias classes have a nested A::type - static_assert(polyfill::is_detected_v, - "alias must have a nested alias::type typename"); - auto tableName = lookup_table_name>(this->db_objects); - this->table_names.emplace(std::move(tableName), alias_extractor::get()); + auto tableName = lookup_table_name>(this->db_objects); + table_names.emplace(std::move(tableName), alias_extractor::as_alias()); } template diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index 163d8cd2a..afcb100e8 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -58,12 +58,26 @@ void marvel_hero_ordered_by_o_pos() { } } cout << endl; +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + { + // SELECT name, instr(abilities, 'o') i + // FROM marvel + // WHERE i > 0 + // ORDER BY i + auto rows = storage.select(columns(&MarvelHero::name, as<"i"_col>(instr(&MarvelHero::abilities, "o"))), + where("i"_col > c(0)), + order_by("i"_col)); + for(auto& row: rows) { + cout << get<0>(row) << '\t' << get<1>(row) << '\n'; + } + } + cout << endl; +#endif { // SELECT name, instr(abilities, 'o') // FROM marvel // ORDER BY 2 - auto rows = - storage.select(columns(&MarvelHero::name, as(instr(&MarvelHero::abilities, "o"))), order_by(2)); + auto rows = storage.select(columns(&MarvelHero::name, instr(&MarvelHero::abilities, "o")), order_by(2)); for(auto& row: rows) { cout << get<0>(row) << '\t' << get<1>(row) << '\n'; } diff --git a/examples/custom_aliases.cpp b/examples/custom_aliases.cpp index 0d6ffa7ca..c02e3cb09 100644 --- a/examples/custom_aliases.cpp +++ b/examples/custom_aliases.cpp @@ -104,6 +104,35 @@ int main(int, char** argv) { // SELECT C.ID, C.NAME, C.AGE, D.DEPT // FROM COMPANY AS C, DEPARTMENT AS D // WHERE C.ID = D.EMP_ID; +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + constexpr auto c_als = "c"_alias.for_(); + constexpr auto d = "d"_alias.for_(); + static_assert(std::is_empty_v); + constexpr auto empId = EmployeeIdAlias{}; + auto rowsWithTableAliases = storage.select( + columns(c_als->*&Employee::id, c_als->*&Employee::name, c_als->*&Employee::age, d->*&Department::dept), + where(is_equal(c_als->*&Employee::id, d->*&Department::empId))); + assert(rowsWithTableAliases == simpleRows); + + // SELECT COMPANY.ID as COMPANY_ID, COMPANY.NAME AS COMPANY_NAME, COMPANY.AGE, DEPARTMENT.DEPT + // FROM COMPANY, DEPARTMENT + // WHERE COMPANY_ID = DEPARTMENT.EMP_ID; + auto rowsWithColumnAliases = storage.select( + columns(&Employee::id >>= empId, as(&Employee::name), &Employee::age, &Department::dept), + where(is_equal(get(), &Department::empId))); + assert(rowsWithColumnAliases == rowsWithTableAliases); + + // SELECT C.ID AS COMPANY_ID, C.NAME AS COMPANY_NAME, C.AGE, D.DEPT + // FROM COMPANY AS C, DEPARTMENT AS D + // WHERE C.ID = D.EMP_ID; + auto rowsWithBothTableAndColumnAliases = + storage.select(columns(c_als->*& Employee::id >>= empId, + as(c_als->*&Employee::name), + c_als->*&Employee::age, + d->*&Department::dept), + where(is_equal(c_als->*&Employee::id, d->*&Department::empId))); + assert(rowsWithBothTableAndColumnAliases == rowsWithBothTableAndColumnAliases); +#else using als_c = alias_c; using als_d = alias_d; auto rowsWithTableAliases = @@ -134,6 +163,7 @@ int main(int, char** argv) { alias_column(&Department::dept)), where(is_equal(alias_column(&Employee::id), alias_column(&Department::empId)))); assert(rowsWithBothTableAndColumnAliases == rowsWithBothTableAndColumnAliases); +#endif return 0; } diff --git a/examples/exists.cpp b/examples/exists.cpp index ec2d82d19..83b8735dd 100644 --- a/examples/exists.cpp +++ b/examples/exists.cpp @@ -435,12 +435,11 @@ int main(int, char**) { // WHERE grade=2 // GROUP BY grade // HAVING COUNT(*)>2); - auto rows = - storage.select(columns(&Customer::code, &Customer::name, &Customer::city, &Customer::grade), - where(is_equal(&Customer::grade, 2) and exists(select(count(), - where(is_equal(&Customer::grade, 2)), - group_by(&Customer::grade), - having(greater_than(count(), 2)))))); + auto rows = storage.select(columns(&Customer::code, &Customer::name, &Customer::city, &Customer::grade), + where(is_equal(&Customer::grade, 2) and + exists(select(count(), + where(is_equal(&Customer::grade, 2)), + group_by(&Customer::grade).having(greater_than(count(), 2)))))); cout << "CUST_CODE CUST_NAME CUST_CITY GRADE" << endl; cout << "---------- ---------- ----------------------------------- ----------" << endl; for(auto& row: rows) { @@ -476,6 +475,25 @@ int main(int, char**) { // ) // ORDER BY 'c'."PAYMENT_AMT" +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + constexpr auto c_als = "c"_alias.for_(); + constexpr auto d = "d"_alias.for_(); + + double amount = 2000; + auto where_clause = select(d->*&Customer::agentCode, + from(), + where(is_equal(c_als->*&Customer::paymentAmt, std::ref(amount)) and + (d->*&Customer::agentCode == c(c_als->*&Customer::agentCode)))); + + amount = 7000; + + auto statement = storage.prepare(select( + columns(&Order::agentCode, &Order::num, &Order::amount, &Order::custCode, c_als->*&Customer::paymentAmt), + from(), + inner_join(using_(&Customer::agentCode)), + where(not exists(where_clause)), + order_by(c_als->*&Customer::paymentAmt))); +#else using als = alias_c; using als_2 = alias_d; @@ -498,6 +516,7 @@ int main(int, char**) { inner_join(on(alias_column(&Customer::agentCode) == c(&Order::agentCode))), where(not exists(where_clause)), order_by(alias_column(&Customer::paymentAmt)))); +#endif auto sql = statement.expanded_sql(); auto rows = storage.execute(statement); diff --git a/examples/self_join.cpp b/examples/self_join.cpp index 224c4b73e..716299e9d 100644 --- a/examples/self_join.cpp +++ b/examples/self_join.cpp @@ -29,8 +29,8 @@ struct Employee { /** * This is how custom alias is made: - * 1) it must have `type` alias which is equal to your mapped class - * 2) is must have static function with `get()` signature and return type with `operator<<` + * 1) it must have a `type` alias which is equal to your mapped class + * 2) it must have a static function with `get()` signature and return type with `operator<<` */ template struct custom_alias : sqlite_orm::alias_tag { @@ -199,6 +199,16 @@ int main() { // FROM employees // INNER JOIN employees m // ON m.ReportsTo = employees.EmployeeId +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + constexpr auto m = "m"_alias.for_(); + auto firstNames = storage.select(columns(m->*&Employee::firstName || c(" ") || m->*&Employee::lastName, + &Employee::firstName || c(" ") || &Employee::lastName), + inner_join(on(m->*&Employee::reportsTo == c(&Employee::employeeId)))); + cout << "firstNames count = " << firstNames.size() << endl; + for(auto& row: firstNames) { + cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; + } +#else using als = alias_m; auto firstNames = storage.select( columns(alias_column(&Employee::firstName) || c(" ") || alias_column(&Employee::lastName), @@ -208,6 +218,7 @@ int main() { for(auto& row: firstNames) { cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; } +#endif assert(storage.count() == storage.count>()); } @@ -219,6 +230,17 @@ int main() { // FROM employees // INNER JOIN employees emp // ON emp.ReportsTo = employees.EmployeeId +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + static_assert(std::is_empty_v>); + constexpr auto emp = custom_alias{}; + auto firstNames = storage.select(columns(emp->*&Employee::firstName || c(" ") || emp->*&Employee::lastName, + &Employee::firstName || c(" ") || &Employee::lastName), + inner_join(on(emp->*&Employee::reportsTo == c(&Employee::employeeId)))); + cout << "firstNames count = " << firstNames.size() << endl; + for(auto& row: firstNames) { + cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; + } +#else using als = custom_alias; auto firstNames = storage.select( columns(alias_column(&Employee::firstName) || c(" ") || alias_column(&Employee::lastName), @@ -228,6 +250,7 @@ int main() { for(auto& row: firstNames) { cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; } +#endif } return 0; diff --git a/examples/subquery.cpp b/examples/subquery.cpp index 1310f1ce9..ecd48c89a 100644 --- a/examples/subquery.cpp +++ b/examples/subquery.cpp @@ -1346,6 +1346,19 @@ int main(int, char**) { // WHERE salary >(SELECT AVG(salary) // FROM employees // WHERE department_id = e.department_id); +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + constexpr auto e = "e"_alias.for_(); + auto rows = storage.select( + columns(e->*&Employee::lastName, e->*&Employee::salary, e->*&Employee::departmentId), + where(greater_than(e->*&Employee::salary, + select(avg(&Employee::salary), + where(is_equal(&Employee::departmentId, e->*&Employee::departmentId)))))); + cout << "last_name salary department_id" << endl; + cout << "---------- ---------- -------------" << endl; + for(auto& row: rows) { + cout << std::get<0>(row) << '\t' << std::get<1>(row) << '\t' << std::get<2>(row) << endl; + } +#else using als = alias_e; auto rows = storage.select( columns(alias_column(&Employee::lastName), @@ -1360,6 +1373,7 @@ int main(int, char**) { for(auto& row: rows) { cout << std::get<0>(row) << '\t' << std::get<1>(row) << '\t' << std::get<2>(row) << endl; } +#endif } { // SELECT first_name, last_name, employee_id, job_id diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 325292e43..ebe4a834c 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -105,6 +105,10 @@ using std::nullptr_t; #define SQLITE_ORM_CONCEPTS_SUPPORTED #endif +#if __cpp_nontype_template_args >= 201911L +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif + // #include "cxx_compiler_quirks.h" #ifdef __clang__ @@ -136,6 +140,12 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif +// overwrite SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#if(__cpp_nontype_template_args < 201911L) && \ + (defined(__clang__) && (__clang_major__ >= 12) && (__cplusplus >= 202002L)) +#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#endif + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -2598,9 +2608,9 @@ namespace sqlite_orm { #pragma once #include // std::string -#include // std::enable_if, std::is_same +#include // std::enable_if, std::is_same, std::remove_const #include // std::vector -#include // std::tuple, std::tuple_size +#include // std::tuple #include // std::stringstream // #include "functional/cxx_universal.h" @@ -2688,6 +2698,72 @@ namespace sqlite_orm { // #include "tags.h" +// #include "alias_traits.h" + +#include // std::remove_const, std::is_base_of, std::is_same + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" + +namespace sqlite_orm { + + /** + * Base class for a custom table alias, column alias or expression alias. + * For more information please look through self_join.cpp example + */ + struct alias_tag {}; + + namespace internal { + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_alias_v = std::is_base_of::value; + + template + using is_alias = polyfill::bool_constant>; + + /** Alias for a column in a record set. + * + * A column alias has the following traits: + * - is derived from `alias_tag` + * + * @note: Currently, there is no distinguishing property of a column alias other than that it is derived from "alias_tag". + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = is_alias_v; + + template + using is_column_alias = is_alias; + + /** Alias for any type of record set. + * + * A record set alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to a mapped object. + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_recordset_alias_v = + polyfill::conjunction_v, polyfill::is_detected>; + + template + using is_recordset_alias = polyfill::bool_constant>; + + /** Alias for a concrete table. + * + * A concrete table alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + */ + template + SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< + std::is_base_of, + polyfill::negation, std::remove_const_t>>>; + + template + using is_table_alias = polyfill::bool_constant>; + } +} + // #include "expression.h" #include @@ -3586,12 +3662,24 @@ namespace sqlite_orm { * Explicit FROM function. Usage: * `storage.select(&User::id, from());` */ - template - internal::from_t from() { - static_assert(std::tuple_size>::value > 0, ""); + template + internal::from_t from() { + static_assert(sizeof...(Tables) > 0, ""); return {}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + /** + * Explicit FROM function. Usage: + * `storage.select(&User::id, from<"a"_alias.for_>());` + */ + template + auto from() { + static_assert(sizeof...(tables) > 0); + return internal::from_t...>{}; + } +#endif + template = true> internal::negated_condition_t operator!(T arg) { return {std::move(arg)}; @@ -3789,21 +3877,49 @@ namespace sqlite_orm { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto left_join(O o) { + return internal::left_join_t, O>{std::move(o)}; + } +#endif + template internal::join_t join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto join(O o) { + return internal::join_t, O>{std::move(o)}; + } +#endif + template internal::left_outer_join_t left_outer_join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto left_outer_join(O o) { + return internal::left_outer_join_t, O>{std::move(o)}; + } +#endif + template internal::inner_join_t inner_join(O o) { return {std::move(o)}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto inner_join(O o) { + return internal::inner_join_t, O>{std::move(o)}; + } +#endif + template internal::offset_t offset(T off) { return {std::move(off)}; @@ -4054,32 +4170,57 @@ namespace sqlite_orm { } #pragma once -#include // std::enable_if, std::is_base_of, std::is_member_pointer -#include // std::stringstream +#include // std::enable_if, std::is_base_of, std::is_member_pointer, std::remove_const +#include // std::index_sequence, std::make_index_sequence #include // std::string +#include // std::stringstream +#include // std::copy_n + +// #include "functional/cxx_universal.h" + +// #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" -namespace sqlite_orm { +// #include "alias_traits.h" - /** - * This is base class for every class which is used as a custom table alias, column alias or expression alias. - * For more information please look through self_join.cpp example - */ - struct alias_tag {}; +namespace sqlite_orm { namespace internal { +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + /* + * Helper class to facilitate user-defined string literal operator template + */ + template + struct string_identifier_template { + static constexpr size_t size() { + return N - 1; + } + + constexpr string_identifier_template(const char (&id)[N]) { + std::copy_n(id, N, this->id); + } + + char id[N]; + }; + + template class Alias, string_identifier_template t, size_t... Idx> + consteval auto to_alias(std::index_sequence) { + return Alias{}; + } +#endif + /** * This is a common built-in class used for custom single character table aliases. - * For convenience there exist type aliases `alias_a`, `alias_b`, ... + * For convenience there exist public type aliases `alias_a`, `alias_b`, ... */ - template + template struct table_alias : alias_tag { using type = T; - static char get() { - return A; + static std::string get() { + return {A, X...}; } }; @@ -4094,20 +4235,39 @@ namespace sqlite_orm { column_type column; }; + /* + * Encapsulates extracting the alias identifier of a non-alias. + */ template struct alias_extractor { - static std::string get() { + static std::string extract() { + return {}; + } + + static std::string as_alias() { return {}; } }; - template - struct alias_extractor::value>> { - static std::string get() { + /* + * Encapsulates extracting the alias identifier of an alias. + * + * `extract()` always returns the alias identifier. + * `as_alias()` is used in contexts where a table is aliased. + */ + template + struct alias_extractor> { + static std::string extract() { std::stringstream ss; - ss << T::get(); + ss << A::get(); return ss.str(); } + + // for column and regular table aliases -> alias identifier + template, A> = true> + static std::string as_alias() { + return alias_extractor::extract(); + } }; /** @@ -4125,41 +4285,105 @@ namespace sqlite_orm { * This is a common built-in class used for custom single-character column aliases. * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... */ - template + template struct column_alias : alias_tag { static std::string get() { - return std::string(1u, A); + return {A, X...}; } }; template struct alias_holder { using type = T; + + alias_holder() = default; + }; + +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template + struct table_alias_builder { + static_assert(sizeof...(C) == 0 && ((A >= 'A' && 'Z' <= A) || (A >= 'a' && 'z' <= A)), + "Table alias identifiers shall consist of a single alphabetic character, in order to evade " + "clashes with CTE aliases."); + + template + [[nodiscard]] consteval internal::table_alias, A, C...> for_() const { + return {}; + } + + template + [[nodiscard]] consteval internal::table_alias for_() const { + return {}; + } }; +#endif } /** * @return column with table alias attached. Place it instead of a column statement in case you need to specify a - * column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example + * column with table alias prefix like 'a.column'. */ - template + template, bool> = true> internal::alias_column_t alias_column(C c) { using table_type = internal::type_t; - static_assert(std::is_same, table_type>::value, + static_assert(std::is_same, table_type>::value, "Column must be from aliased table"); return {c}; } - template - internal::as_t as(E expression) { +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template, + std::enable_if_t, bool> = true> + auto alias_column(C c) { + using table_type = internal::type_t; + static_assert(std::is_same_v, table_type>, + "Column must be from aliased table"); + return internal::alias_column_t{c}; + } + + template, bool> = true> + constexpr auto operator->*(const A& /*tableAlias*/, F field) { + return alias_column(std::move(field)); + } +#endif + + /** + * Alias a column expression. + */ + template = true> + internal::as_t as(E expression) { return {std::move(expression)}; } - template - internal::alias_holder get() { +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto as(E expression) { + return internal::as_t, E>{std::move(expression)}; + } + + /** + * Alias a column expression. + */ + template = true> + internal::as_t operator>>=(E expression, const A&) { + return {std::move(expression)}; + } +#endif + + template = true> + internal::alias_holder get() { return {}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto get() { + return internal::alias_holder>{}; + } +#endif + template using alias_a = internal::table_alias; template @@ -4222,6 +4446,32 @@ namespace sqlite_orm { using colalias_g = internal::column_alias<'g'>; using colalias_h = internal::column_alias<'h'>; using colalias_i = internal::column_alias<'i'>; + +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + /** @short Create aliased tables e.g. `constexpr auto z_alias = alias_<'z'>.for_()`. + */ + template + inline constexpr internal::table_alias_builder alias_{}; + + /** @short Create a table alias. + * + * Examples: + * constexpr auto z_alias = "z"_alias.for_(); + */ + template + [[nodiscard]] consteval auto operator"" _alias() { + return internal::to_alias(std::make_index_sequence{}); + } + + /** @short Create a column alias. + * column_alias<'a'[, ...]> from a string literal. + * E.g. "a"_col, "b"_col + */ + template + [[nodiscard]] consteval auto operator"" _col() { + return internal::to_alias(std::make_index_sequence{}); + } +#endif } #pragma once @@ -6400,8 +6650,9 @@ namespace sqlite_orm { } #pragma once +#include // std::remove_const #include // std::string -#include // std::declval +#include // std::move #include // std::tuple, std::get, std::tuple_size // #include "functional/cxx_optional.h" @@ -6548,6 +6799,73 @@ namespace sqlite_orm { // #include "core_functions.h" +// #include "alias_traits.h" + +// #include "column_pointer.h" + +#include // std::string +#include // std::move + +// #include "functional/cxx_core_features.h" + +// #include "conditions.h" + +// #include "alias_traits.h" + +namespace sqlite_orm { + namespace internal { + /** + * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). + * Is useful when mapped type is derived from other type and base class has members mapped to a storage. + */ + template + struct column_pointer { + using self = column_pointer; + using type = T; + using field_type = F; + + field_type field; + + template + is_equal_t operator==(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + is_not_equal_t operator!=(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + lesser_than_t operator<(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + lesser_or_equal_t operator<=(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + greater_than_t operator>(R rhs) const { + return {*this, std::move(rhs)}; + } + + template + greater_or_equal_t operator>=(R rhs) const { + return {*this, std::move(rhs)}; + } + }; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; + + template + using is_column_pointer = polyfill::bool_constant>; + + } +} + namespace sqlite_orm { namespace internal { @@ -6614,55 +6932,6 @@ namespace sqlite_orm { template using is_columns = polyfill::bool_constant>; - /** - * This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter). - * Is useful when mapped type is derived from other type and base class has members mapped to a storage. - */ - template - struct column_pointer { - using self = column_pointer; - using type = T; - using field_type = F; - - field_type field; - - template - internal::is_equal_t operator==(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::is_not_equal_t operator!=(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::lesser_than_t operator<(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::lesser_or_equal_t operator<=(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::greater_than_t operator>(R rhs) const { - return {*this, std::move(rhs)}; - } - - template - internal::greater_or_equal_t operator>=(R rhs) const { - return {*this, std::move(rhs)}; - } - }; - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_column_pointer_v = polyfill::is_specialization_of_v; - - template - using is_column_pointer = polyfill::bool_constant>; - /** * Subselect object type. */ @@ -6989,6 +7258,13 @@ namespace sqlite_orm { return {definedOrder}; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + template = true> + auto asterisk(bool definedOrder = false) { + return internal::asterisk_t>{definedOrder}; + } +#endif + /** * `SELECT * FROM T` expression that fetches results as objects of type T. * T is a type mapped to a storage, or an alias of it. @@ -9012,25 +9288,25 @@ namespace sqlite_orm { } #pragma once -#include // std::enable_if, std::is_base_of, std::remove_const +#include // std::remove_const -// #include "alias.h" +// #include "type_traits.h" + +// #include "alias_traits.h" namespace sqlite_orm { namespace internal { /** - * If T is alias than mapped_type_proxy::type is alias::type - * otherwise T is unqualified T. + * If T is a recordset alias then the typename mapped_type_proxy::type is the unqualified aliased type, + * otherwise unqualified T. */ template struct mapped_type_proxy : std::remove_const {}; template - struct mapped_type_proxy::value>> { - using type = typename T::type; - }; + struct mapped_type_proxy> : std::remove_const> {}; template using mapped_type_proxy_t = typename mapped_type_proxy::type; @@ -9153,8 +9429,6 @@ namespace sqlite_orm { // #include "alias.h" -// #include "column.h" - // #include "storage_traits.h" #include // std::tuple @@ -9194,9 +9468,9 @@ namespace sqlite_orm { // #include "storage_lookup.h" -#include // std::true_type, std::false_type, std::remove_const, std::enable_if +#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 +#include // std::index_sequence, std::make_index_sequence // #include "functional/cxx_universal.h" @@ -9620,6 +9894,8 @@ namespace sqlite_orm { namespace internal { /** + * Obains the result type of expressions that form the columns of a select statement. + * * This is a proxy class used to define what type must have result type depending on select * arguments (member pointer, aggregate functions, etc). Below you can see specializations * for different types. E.g. specialization for internal::length_t has `type` int cause @@ -9628,6 +9904,8 @@ namespace sqlite_orm { * DBOs - db_objects_tuple type * T - C++ type * SFINAE - sfinae argument + * + * Note (implementation): could be possibly implemented by utilizing column_expression_of_t */ template struct column_result_t; @@ -9844,12 +10122,8 @@ namespace sqlite_orm { struct column_result_t, void> : column_result_t> {}; template - struct column_result_t, match_if_not> - : storage_traits::storage_mapped_columns {}; - - template - struct column_result_t, match_if> - : storage_traits::storage_mapped_columns> {}; + struct column_result_t, void> + : storage_traits::storage_mapped_columns> {}; template struct column_result_t, void> { @@ -10141,9 +10415,9 @@ namespace sqlite_orm { /** * Table definition. */ - template + template struct table_t : basic_table { - using object_type = T; + using object_type = O; using elements_type = std::tuple; static constexpr bool is_without_rowid_v = WithoutRowId; @@ -10156,7 +10430,7 @@ namespace sqlite_orm { basic_table{std::move(name_)}, elements{std::move(elements_)} {} #endif - table_t without_rowid() const { + table_t without_rowid() const { return {this->name, this->elements}; } @@ -10340,11 +10614,11 @@ namespace sqlite_orm { iterate_tuple(this->elements, fk_index_sequence{}, lambda); } - template + template void for_each_foreign_key_to(L&& lambda) const { using fk_index_sequence = filter_tuple_sequence_t; using filtered_index_sequence = filter_tuple_sequence_t::template fn, + check_if_is_type::template fn, target_type_t, fk_index_sequence>; iterate_tuple(this->elements, filtered_index_sequence{}, lambda); @@ -10817,8 +11091,12 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" +// #include "type_traits.h" + // #include "conditions.h" +// #include "alias.h" + // #include "select_constraints.h" // #include "operators.h" @@ -11047,6 +11325,8 @@ namespace sqlite_orm { // #include "type_traits.h" +// #include "mapped_type_proxy.h" + // #include "select_constraints.h" // #include "alias.h" @@ -11092,7 +11372,7 @@ namespace sqlite_orm { void operator()(const alias_column_t&) { // note: instead of accessing the column, we are interested in the type the column is aliased into auto tableName = lookup_table_name>(this->db_objects); - this->table_names.emplace(std::move(tableName), alias_extractor::get()); + this->table_names.emplace(std::move(tableName), alias_extractor::as_alias()); } template @@ -11103,18 +11383,10 @@ namespace sqlite_orm { } } - template = true> - void operator()(const asterisk_t&) { - this->table_names.emplace(lookup_table_name(this->db_objects), ""); - } - - template = true> + template void operator()(const asterisk_t&) { - // note: not all alias classes have a nested A::type - static_assert(polyfill::is_detected_v, - "alias must have a nested alias::type typename"); - auto tableName = lookup_table_name>(this->db_objects); - this->table_names.emplace(std::move(tableName), alias_extractor::get()); + auto tableName = lookup_table_name>(this->db_objects); + table_names.emplace(std::move(tableName), alias_extractor::as_alias()); } template @@ -12704,7 +12976,7 @@ namespace sqlite_orm { }; /** - * Column alias or literal + * Column alias or literal: skipped */ template struct ast_iterator< @@ -12717,6 +12989,17 @@ namespace sqlite_orm { void operator()(const node_type& /*node*/, L& /*lambda*/) const {} }; + /** + * Column alias: skipped + */ + template + struct ast_iterator, void> { + using node_type = column_alias; + + template + void operator()(const node_type& /*node*/, L& /*lambda*/) const {} + }; + template struct ast_iterator, void> { using node_type = order_by_t; @@ -14947,17 +15230,17 @@ namespace sqlite_orm { #include #include // std::move -// #include "functional/cxx_universal.h" -// ::size_t -// #include "functional/cxx_type_traits_polyfill.h" -// polyfill::remove_cvref_t // #include "tuple_helper/tuple_traits.h" +// #include "tuple_helper/tuple_iteration.h" + // #include "error_code.h" -// #include "select_constraints.h" +// #include "mapped_type_proxy.h" -// #include "alias.h" +// #include "alias_traits.h" + +// #include "select_constraints.h" // #include "storage_lookup.h" // pick_table @@ -14982,8 +15265,8 @@ namespace sqlite_orm { table.for_each_column([qualified = !context.skip_table_name, &tableName = table.name, &collectedExpressions](const column_identifier& column) { - if(std::is_base_of::value) { - collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + "." + + if(is_alias_v) { + collectedExpressions.push_back(quote_identifier(alias_extractor::extract()) + "." + quote_identifier(column.name)); } else if(qualified) { collectedExpressions.push_back(quote_identifier(tableName) + "." + @@ -14994,8 +15277,8 @@ namespace sqlite_orm { }); } else { collectedExpressions.reserve(collectedExpressions.size() + 1); - if(std::is_base_of::value) { - collectedExpressions.push_back(quote_identifier(alias_extractor::get()) + ".*"); + if(is_alias_v) { + collectedExpressions.push_back(quote_identifier(alias_extractor::extract()) + ".*"); } else if(!context.skip_table_name) { const basic_table& table = pick_table>(context.db_objects); collectedExpressions.push_back(quote_identifier(table.name) + ".*"); @@ -15326,6 +15609,18 @@ namespace sqlite_orm { } }; + template + struct statement_serializer, void> { + using statement_type = column_alias; + + template + std::string operator()(const statement_type&, const Ctx&) { + std::stringstream ss; + ss << streaming_identifier(statement_type::get()); + return ss.str(); + } + }; + template struct statement_serializer, std::tuple>, void> { using statement_type = upsert_clause, std::tuple>; @@ -15399,7 +15694,7 @@ namespace sqlite_orm { template std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; - ss << serialize(c.expression, context) + " AS " << streaming_identifier(alias_extractor::get()); + ss << serialize(c.expression, context) + " AS " << streaming_identifier(alias_extractor::extract()); return ss.str(); } }; @@ -15412,7 +15707,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& c, const Ctx& context) const { std::stringstream ss; if(!context.skip_table_name) { - ss << streaming_identifier(alias_extractor::get()) << "."; + ss << streaming_identifier(alias_extractor::extract()) << "."; } auto newContext = context; newContext.skip_table_name = true; @@ -16616,7 +16911,7 @@ namespace sqlite_orm { using cross_join_type = mapped_type_proxy_t; std::pair tableNameWithAlias{ lookup_table_name(context.db_objects), - alias_extractor::get()}; + alias_extractor::as_alias()}; tableNames.erase(tableNameWithAlias); }); if(!tableNames.empty() && !isCompoundOperator) { @@ -16712,7 +17007,7 @@ namespace sqlite_orm { constexpr std::array sep = {", ", ""}; ss << sep[std::exchange(first, false)] << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()); + alias_extractor::as_alias()); }); return ss.str(); } @@ -16954,7 +17249,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << serialize(l.constraint, context); return ss.str(); } @@ -16983,7 +17278,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << " " << serialize(l.constraint, context); return ss.str(); } @@ -16998,7 +17293,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << " " << serialize(l.constraint, context); return ss.str(); } @@ -17013,7 +17308,7 @@ namespace sqlite_orm { std::stringstream ss; ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::get()) + alias_extractor::as_alias()) << " " << serialize(l.constraint, context); return ss.str(); } @@ -18579,11 +18874,14 @@ namespace sqlite_orm { } #pragma once +#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" // #include "conditions.h" @@ -18664,6 +18962,12 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; + /** + * Column alias + */ + template + struct node_tuple, void> : node_tuple {}; + /** * Literal */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b1e4b093..6e4aeb56e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(unit_tests static_tests/aggregate_function_return_types.cpp static_tests/core_function_return_types.cpp static_tests/column_result_t.cpp + static_tests/alias.cpp static_tests/is_primary_key_insertable.cpp static_tests/is_column_with_insertable_primary_key.cpp tuple_iteration.cpp diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index a58aac769..7473868af 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -4,6 +4,11 @@ #include // std::type_index using namespace sqlite_orm; +using internal::alias_column_t; +using internal::alias_holder; +using internal::column_alias; +using internal::column_pointer; +using internal::iterate_ast; TEST_CASE("ast_iterator") { struct User { @@ -18,62 +23,62 @@ TEST_CASE("ast_iterator") { SECTION("bindables") { auto node = select(1); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("aggregate functions") { SECTION("avg") { auto node = avg(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("avg filter") { auto node = avg(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("count(*)") { auto node = count(); expected.push_back(typeid(node)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("count(*) filter") { auto node = count().filter(where(length(&User::name) > 5)); expected.push_back(typeid(decltype(count()))); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("count(X)") { auto node = count(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("count(X) filter") { auto node = count(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("group_concat(X)") { auto node = group_concat(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("group_concat(X) filter") { auto node = group_concat(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("group_concat(X,Y)") { auto node = group_concat(&User::id, std::string("-")); expected.push_back(typeid(&User::id)); expected.push_back(typeid(std::string)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("group_concat(X,Y) filter") { auto node = group_concat(&User::id, std::string("-")).filter(where(length(&User::name) > 5)); @@ -81,55 +86,55 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(std::string)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("max(X)") { auto node = max(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("max(X) filter") { auto node = max(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("min(X)") { auto node = min(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("min(X) filter") { auto node = min(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("sum(X)") { auto node = sum(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("sum(X) filter") { auto node = sum(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("total(X)") { auto node = total(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("total(X) filter") { auto node = total(&User::id).filter(where(length(&User::name) > 5)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } } SECTION("scalar functions") { @@ -137,76 +142,80 @@ TEST_CASE("ast_iterator") { auto node = max(&User::id, 4); expected.push_back(typeid(&User::id)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("min(X,Y)") { auto node = min(&User::id, 4); expected.push_back(typeid(&User::id)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } } SECTION("on") { auto node = on(&User::id == c(0)); expected.push_back(typeid(&User::id)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("using") { auto node = using_(&User::id); - expected.push_back(typeid(internal::column_pointer{&User::id})); - internal::iterate_ast(node, lambda); + expected.push_back(typeid(column_pointer)); + iterate_ast(node, lambda); } SECTION("exists") { auto node = exists(select(5)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("order_by") { SECTION("expression") { auto node = order_by(c(&User::id) == 0); expected.push_back(typeid(&User::id)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("bindable") { auto node = order_by(""); expected.push_back(typeid(const char*)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("positional ordinal") { auto node = order_by(1); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("sole column alias") { auto node = order_by(get()); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); + } + SECTION("direct sole column alias") { + auto node = order_by(colalias_a{}); + iterate_ast(node, lambda); } SECTION("column alias in expression") { auto node = order_by(get() > c(1)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } } SECTION("group_by") { auto node = group_by(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("excluded") { auto node = excluded(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("upsert_clause") { auto node = on_conflict(&User::id).do_update(set(c(&User::name) = excluded(&User::name))); expected.push_back(typeid(&User::name)); expected.push_back(typeid(&User::name)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("into") { auto node = into(); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("replace") { auto node = @@ -215,7 +224,7 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); expected.push_back(typeid(std::string)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("insert") { auto node = @@ -224,19 +233,19 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(&User::name)); expected.push_back(typeid(int)); expected.push_back(typeid(std::string)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("values") { auto node = values(std::make_tuple(1, std::string("hi"))); expected.push_back(typeid(int)); expected.push_back(typeid(std::string)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("tuple") { auto node = std::make_tuple(1, std::string("hi")); expected.push_back(typeid(int)); expected.push_back(typeid(std::string)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("in") { SECTION("static") { @@ -245,7 +254,7 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(int)); expected.push_back(typeid(int)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } SECTION("dynamic") { auto node = in(&User::id, {1, 2, 3}); @@ -253,7 +262,7 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(int)); expected.push_back(typeid(int)); expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); } } SECTION("function_call") { @@ -264,7 +273,49 @@ TEST_CASE("ast_iterator") { }; auto node = func(&User::id); expected.push_back(typeid(&User::id)); - internal::iterate_ast(node, lambda); + iterate_ast(node, lambda); + } + SECTION("aliases") { + SECTION("holder") { + auto expression = get() > c(0); + expected.push_back(typeid(int)); + iterate_ast(expression, lambda); + } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + { + SECTION("direct") { + auto expression = "a"_col > c(0); + expected.push_back(typeid(int)); + iterate_ast(expression, lambda); + } + } +#endif + } + SECTION("aliased regular column") { + using als = alias_z; + auto expression = alias_column(&User::id); + expected.push_back(typeid(alias_column_t, decltype(&User::id)>)); + iterate_ast(expression, lambda); + } + SECTION("aliased regular column pointer") { + using als = alias_z; + auto expression = alias_column(column(&User::id)); + expected.push_back(typeid(alias_column_t, column_pointer>)); + iterate_ast(expression, lambda); + } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + SECTION("aliased regular column 2") { + constexpr auto z_alias = "z"_alias.for_(); + auto expression = z_alias->*&User::id; + expected.push_back(typeid(alias_column_t, decltype(&User::id)>)); + iterate_ast(expression, lambda); + } + SECTION("aliased regular column pointer 2") { + constexpr auto z_alias = "z"_alias.for_(); + auto expression = z_alias->*column(&User::id); + expected.push_back(typeid(alias_column_t, column_pointer>)); + iterate_ast(expression, lambda); } +#endif REQUIRE(typeIndexes == expected); } diff --git a/tests/statement_serializer_tests/alias_extractor.cpp b/tests/statement_serializer_tests/alias_extractor.cpp index 3982acb95..462dd893e 100644 --- a/tests/statement_serializer_tests/alias_extractor.cpp +++ b/tests/statement_serializer_tests/alias_extractor.cpp @@ -8,12 +8,15 @@ TEST_CASE("alias extractor") { struct User {}; SECTION("column alias") { - REQUIRE(alias_extractor::get() == "a"); + REQUIRE(alias_extractor::extract() == "a"); + REQUIRE(alias_extractor::as_alias() == "a"); } SECTION("table") { - REQUIRE(alias_extractor::get() == ""); + REQUIRE(alias_extractor::extract() == ""); + REQUIRE(alias_extractor::as_alias() == ""); } SECTION("table alias") { - REQUIRE(alias_extractor>::get() == "a"); + REQUIRE(alias_extractor>::extract() == "a"); + REQUIRE(alias_extractor>::as_alias() == "a"); } } diff --git a/tests/statement_serializer_tests/column_names.cpp b/tests/statement_serializer_tests/column_names.cpp index 5b6ae2537..1b9a40efb 100644 --- a/tests/statement_serializer_tests/column_names.cpp +++ b/tests/statement_serializer_tests/column_names.cpp @@ -138,6 +138,25 @@ TEST_CASE("statement_serializer column names") { } } } + SECTION("aliased column") { + struct Object { + int id = 0; + }; + struct Object2 { + int id = 0; + }; + auto table = make_table("object", make_column("id", &Object::id)); + using db_objects_t = internal::db_objects_tuple; + db_objects_t dbObjects{table}; + SECTION("regular") { + using context_t = internal::serializer_context; + context_t context{dbObjects}; + context.skip_table_name = false; + using als = alias_a; + auto value = serialize(alias_column(&Object::id), context); + REQUIRE(value == R"("a"."id")"); + } + } SECTION("escaped identifiers") { struct Object1 { int id = 0; diff --git a/tests/statement_serializer_tests/select_constraints.cpp b/tests/statement_serializer_tests/select_constraints.cpp index 939a99068..6e3038c2b 100644 --- a/tests/statement_serializer_tests/select_constraints.cpp +++ b/tests/statement_serializer_tests/select_constraints.cpp @@ -71,6 +71,20 @@ TEST_CASE("statement_serializer select constraints") { value = serialize(expression, context); expected = R"(FROM "users" "u")"; } +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + { + SECTION("with alias 2") { + auto expression = from.for_()>(); + value = serialize(expression, context); + expected = R"(FROM "users" "u")"; + } + SECTION("with alias 3") { + auto expression = from<"u"_alias.for_()>(); + value = serialize(expression, context); + expected = R"(FROM "users" "u")"; + } + } +#endif } SECTION("function_call") { struct Func { diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp new file mode 100644 index 000000000..caf969dad --- /dev/null +++ b/tests/static_tests/alias.cpp @@ -0,0 +1,44 @@ +#include +#include // std::is_same +#include + +using namespace sqlite_orm; +using internal::alias_column_t; +using internal::alias_holder; +using internal::as_t; +using internal::column_alias; +using internal::column_pointer; +using internal::table_alias; + +template +void do_assert() { + STATIC_REQUIRE(std::is_same::value); +} + +template +void runTest(ColAlias /*colRef*/) { + do_assert(); +} + +TEST_CASE("aliases") { + struct User { + int id; + }; + + SECTION("column alias expressions") { + runTest>>(get()); + runTest, int User::*>>(as(&User::id)); +#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED + runTest>>(get<"a"_col>()); + runTest>("a"_col); + runTest, int User::*>>(&User::id >>= "a"_col); + constexpr auto z_alias = alias_<'z'>.for_(); + runTest>(z_alias); + runTest, int User::*>>(alias_column(&User::id)); + runTest, int User::*>>(z_alias->*&User::id); + runTest, column_pointer>>(z_alias->*column(&User::id)); + runTest, column_pointer>>( + alias_column(column(&User::id))); +#endif + } +} diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 7b4fadfe9..a4d6e93bf 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -3,6 +3,9 @@ #include // std::is_same using namespace sqlite_orm; +using internal::alias_holder; +using internal::column_alias; +using internal::column_pointer; template struct is_pair : std::false_type {}; @@ -837,7 +840,7 @@ TEST_CASE("Node tuple") { auto j = join(using_(&User::id)); using Join = decltype(j); using Tuple = node_tuple_t; - using Expected = tuple>; + using Expected = tuple>; static_assert(is_same::value, "join using"); } SECTION("join using explicit column") { @@ -845,7 +848,7 @@ TEST_CASE("Node tuple") { auto j = join(using_(column(&User::id))); using Join = decltype(j); using Tuple = node_tuple_t; - using Expected = tuple>; + using Expected = tuple>; static_assert(is_same::value, "join using explicit column"); } SECTION("left_outer_join") { From 7ca52000147f654ee4f0fae2d0d991d015b4501c Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 20:50:29 +0200 Subject: [PATCH 036/100] Updated very minor things --- dev/function.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- tests/operators/arithmetic_operators.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/function.h b/dev/function.h index ca851f203..83563221a 100644 --- a/dev/function.h +++ b/dev/function.h @@ -161,7 +161,7 @@ namespace sqlite_orm { template constexpr bool is_same_pvt_v> = true; -#if __cplusplus >= 201703L // using C++17 or higher +#if __cplusplus >= 201703L // C++17 or later template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ebe4a834c..48d6fcaa4 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9805,7 +9805,7 @@ namespace sqlite_orm { template constexpr bool is_same_pvt_v> = true; -#if __cplusplus >= 201703L // using C++17 or higher +#if __cplusplus >= 201703L // C++17 or later template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; diff --git a/tests/operators/arithmetic_operators.cpp b/tests/operators/arithmetic_operators.cpp index c54e4a64b..909cdd13c 100644 --- a/tests/operators/arithmetic_operators.cpp +++ b/tests/operators/arithmetic_operators.cpp @@ -35,11 +35,11 @@ TEST_CASE("Arithmetic operators") { } } { // + - auto rows = storage.select(columns(c(&Object::nameLen) + 1000)); + auto rows = storage.select(c(&Object::nameLen) + 1000); for(size_t i = 0; i < rows.size(); ++i) { auto& row = rows[i]; auto& name = names[i]; - REQUIRE(int(std::get<0>(row)) == name.length() + 1000); + REQUIRE(int(row) == name.length() + 1000); } } { // || @@ -71,11 +71,11 @@ TEST_CASE("Arithmetic operators") { } { // || std::string suffix = "ototo"; - auto rows = storage.select(columns(conc(&Object::name, suffix))); + auto rows = storage.select(conc(&Object::name, suffix)); for(size_t i = 0; i < rows.size(); ++i) { auto& row = rows[i]; auto& name = names[i]; - REQUIRE(std::get<0>(row) == name + suffix); + REQUIRE(row == name + suffix); } } { // different From 30d9824332dbfe22c0227eac228925df5d137624 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 21:00:30 +0200 Subject: [PATCH 037/100] Const-qualified `view_t` members where possible --- dev/view.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/view.h b/dev/view.h index 7a7d7f4f5..36c544258 100644 --- a/dev/view.h +++ b/dev/view.h @@ -39,11 +39,11 @@ namespace sqlite_orm { view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) : storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} - size_t size() { + size_t size() const { return this->storage.template count(); } - bool empty() { + bool empty() const { return !this->size(); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 48d6fcaa4..d29561cd6 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -13055,11 +13055,11 @@ namespace sqlite_orm { view_t(storage_type& stor, decltype(connection) conn, Args&&... args_) : storage(stor), connection(std::move(conn)), args{std::make_tuple(std::forward(args_)...)} {} - size_t size() { + size_t size() const { return this->storage.template count(); } - bool empty() { + bool empty() const { return !this->size(); } From 0eb8acf4111c6f1acdce4eeaff25a5e49f652345 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 21:01:23 +0200 Subject: [PATCH 038/100] Fixed conceptual requirement for `pick_table()` --- dev/storage_lookup.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index 07366813e..ecbd8b3f6 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -128,7 +128,7 @@ namespace sqlite_orm { * * Note: This function requires Lookup to be mapped, otherwise it is removed from the overload resolution set. */ - template = true> + template = true> auto& pick_table(DBOs& dbObjects) { using table_type = storage_pick_table_t; return std::get(dbObjects); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d29561cd6..e5daa9998 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9598,7 +9598,7 @@ namespace sqlite_orm { * * Note: This function requires Lookup to be mapped, otherwise it is removed from the overload resolution set. */ - template = true> + template = true> auto& pick_table(DBOs& dbObjects) { using table_type = storage_pick_table_t; return std::get(dbObjects); From 9d397c26c868ef0415d32df38db2c46c31473da1 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 21:04:52 +0200 Subject: [PATCH 039/100] Enclose serialized VALUES expression in parentheses --- dev/statement_serializer.h | 15 +++++++++++++-- include/sqlite_orm/sqlite_orm.h | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index ecc431ce7..1190634d2 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -2036,7 +2036,13 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << '(' << streaming_expressions_tuple(statement, context) << ')'; + if(context.use_parentheses) { + ss << '('; + } + ss << streaming_expressions_tuple(statement, context); + if(context.use_parentheses) { + ss << ')'; + } return ss.str(); } }; @@ -2051,7 +2057,12 @@ namespace sqlite_orm { if(context.use_parentheses) { ss << '('; } - ss << "VALUES " << streaming_expressions_tuple(statement.tuple, context); + ss << "VALUES "; + { + Ctx tupleContext = context; + tupleContext.use_parentheses = true; + ss << streaming_expressions_tuple(statement.tuple, tupleContext); + } if(context.use_parentheses) { ss << ')'; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index e5daa9998..32f556a34 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -17433,7 +17433,13 @@ namespace sqlite_orm { template std::string operator()(const statement_type& statement, const Ctx& context) const { std::stringstream ss; - ss << '(' << streaming_expressions_tuple(statement, context) << ')'; + if(context.use_parentheses) { + ss << '('; + } + ss << streaming_expressions_tuple(statement, context); + if(context.use_parentheses) { + ss << ')'; + } return ss.str(); } }; @@ -17448,7 +17454,12 @@ namespace sqlite_orm { if(context.use_parentheses) { ss << '('; } - ss << "VALUES " << streaming_expressions_tuple(statement.tuple, context); + ss << "VALUES "; + { + Ctx tupleContext = context; + tupleContext.use_parentheses = true; + ss << streaming_expressions_tuple(statement.tuple, tupleContext); + } if(context.use_parentheses) { ss << ')'; } From 99c3404d821542d476038862eb715c5dbc541840 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 21:06:25 +0200 Subject: [PATCH 040/100] Fixed 'employee' subquery example * Was missing explicit 'from' --- examples/subquery.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/subquery.cpp b/examples/subquery.cpp index ecd48c89a..1b45ad4d7 100644 --- a/examples/subquery.cpp +++ b/examples/subquery.cpp @@ -1350,8 +1350,10 @@ int main(int, char**) { constexpr auto e = "e"_alias.for_(); auto rows = storage.select( columns(e->*&Employee::lastName, e->*&Employee::salary, e->*&Employee::departmentId), + from(), where(greater_than(e->*&Employee::salary, select(avg(&Employee::salary), + from(), where(is_equal(&Employee::departmentId, e->*&Employee::departmentId)))))); cout << "last_name salary department_id" << endl; cout << "---------- ---------- -------------" << endl; @@ -1364,9 +1366,11 @@ int main(int, char**) { columns(alias_column(&Employee::lastName), alias_column(&Employee::salary), alias_column(&Employee::departmentId)), + from(), where(greater_than( alias_column(&Employee::salary), select(avg(&Employee::salary), + from(), where(is_equal(&Employee::departmentId, alias_column(&Employee::departmentId))))))); cout << "last_name salary department_id" << endl; cout << "---------- ---------- -------------" << endl; From f30c9935d9fe57f46ae32b4e7fd82191b304a36c Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 22:07:09 +0200 Subject: [PATCH 041/100] Introduced a configuration header, made universally available --- dev/alias.h | 12 +- dev/column_result.h | 1 + dev/conditions.h | 10 +- dev/functional/config.h | 8 + dev/functional/cxx_compiler_quirks.h | 5 + dev/functional/cxx_core_features.h | 5 + dev/functional/cxx_universal.h | 2 +- dev/get_prepared_statement.h | 3 + dev/select_constraints.h | 2 +- examples/column_aliases.cpp | 2 +- examples/custom_aliases.cpp | 2 +- examples/exists.cpp | 2 +- examples/self_join.cpp | 4 +- examples/subquery.cpp | 2 +- include/sqlite_orm/sqlite_orm.h | 2612 +++++++++-------- .../sqlite_orm/sqlite_orm.h | 6 +- tests/ast_iterator_tests.cpp | 4 +- .../select_constraints.cpp | 2 +- tests/static_tests/alias.cpp | 2 +- third_party/amalgamate/config.json | 4 +- 20 files changed, 1366 insertions(+), 1324 deletions(-) create mode 100644 dev/functional/config.h diff --git a/dev/alias.h b/dev/alias.h index 40a63011b..82a38d34b 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -15,7 +15,7 @@ namespace sqlite_orm { namespace internal { -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /* * Helper class to facilitate user-defined string literal operator template */ @@ -126,7 +126,7 @@ namespace sqlite_orm { alias_holder() = default; }; -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template struct table_alias_builder { static_assert(sizeof...(C) == 0 && ((A >= 'A' && 'Z' <= A) || (A >= 'a' && 'z' <= A)), @@ -158,7 +158,7 @@ namespace sqlite_orm { return {c}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template, @@ -184,7 +184,7 @@ namespace sqlite_orm { return {std::move(expression)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto as(E expression) { return internal::as_t, E>{std::move(expression)}; @@ -204,7 +204,7 @@ namespace sqlite_orm { return {}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto get() { return internal::alias_holder>{}; @@ -274,7 +274,7 @@ namespace sqlite_orm { using colalias_h = internal::column_alias<'h'>; using colalias_i = internal::column_alias<'i'>; -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** @short Create aliased tables e.g. `constexpr auto z_alias = alias_<'z'>.for_()`. */ template diff --git a/dev/column_result.h b/dev/column_result.h index d766e7627..13010294e 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -10,6 +10,7 @@ #include "tuple_helper/tuple_filter.h" #include "type_traits.h" #include "member_traits/member_traits.h" +#include "mapped_type_proxy.h" #include "core_functions.h" #include "select_constraints.h" #include "operators.h" diff --git a/dev/conditions.h b/dev/conditions.h index 9c490fc32..022b896d1 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -819,7 +819,7 @@ namespace sqlite_orm { return {}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** * Explicit FROM function. Usage: * `storage.select(&User::id, from<"a"_alias.for_>());` @@ -1028,7 +1028,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto left_join(O o) { return internal::left_join_t, O>{std::move(o)}; @@ -1040,7 +1040,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto join(O o) { return internal::join_t, O>{std::move(o)}; @@ -1052,7 +1052,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto left_outer_join(O o) { return internal::left_outer_join_t, O>{std::move(o)}; @@ -1064,7 +1064,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto inner_join(O o) { return internal::inner_join_t, O>{std::move(o)}; diff --git a/dev/functional/config.h b/dev/functional/config.h new file mode 100644 index 000000000..c4da4fff0 --- /dev/null +++ b/dev/functional/config.h @@ -0,0 +1,8 @@ +#pragma once + +#include "cxx_universal.h" + +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && \ + defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) +#define SQLITE_ORM_WITH_CPP20_ALIASES +#endif diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 59ec1b3a7..6fcde5084 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -1,5 +1,10 @@ #pragma once +/* + * This header defines macros for circumventing compiler quirks on which sqlite_orm depends. + * May amend cxx_core_features.h + */ + #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index 9ea0d4269..c4bf9b6a1 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -1,5 +1,10 @@ #pragma once +/* + * This header detects core C++ language features on which sqlite_orm depends. + * May be updated/overwritten by cxx_compiler_quirks.h + */ + #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else diff --git a/dev/functional/cxx_universal.h b/dev/functional/cxx_universal.h index 52b21e6d0..90c143299 100644 --- a/dev/functional/cxx_universal.h +++ b/dev/functional/cxx_universal.h @@ -4,7 +4,7 @@ * This header makes central C++ functionality on which sqlite_orm depends universally available: * - alternative operator representations * - ::size_t, ::ptrdiff_t, ::nullptr_t - * - C++ core feature macros + * - C++ core language feature macros * - macros for dealing with compiler quirks */ diff --git a/dev/get_prepared_statement.h b/dev/get_prepared_statement.h index fc30aefe4..dbd415d3a 100644 --- a/dev/get_prepared_statement.h +++ b/dev/get_prepared_statement.h @@ -1,10 +1,13 @@ #pragma once #include // std::is_same, std::decay, std::remove_reference +#include // std::get +#include "functional/cxx_universal.h" // ::size_t #include "functional/static_magic.h" #include "prepared_statement.h" #include "ast_iterator.h" +#include "node_tuple.h" #include "expression_object_type.h" namespace sqlite_orm { diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 2c7a299ee..32551c6b4 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -409,7 +409,7 @@ namespace sqlite_orm { return {definedOrder}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto asterisk(bool definedOrder = false) { return internal::asterisk_t>{definedOrder}; diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index afcb100e8..6cef93831 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -58,7 +58,7 @@ void marvel_hero_ordered_by_o_pos() { } } cout << endl; -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES { // SELECT name, instr(abilities, 'o') i // FROM marvel diff --git a/examples/custom_aliases.cpp b/examples/custom_aliases.cpp index c02e3cb09..79fbd4a8b 100644 --- a/examples/custom_aliases.cpp +++ b/examples/custom_aliases.cpp @@ -104,7 +104,7 @@ int main(int, char** argv) { // SELECT C.ID, C.NAME, C.AGE, D.DEPT // FROM COMPANY AS C, DEPARTMENT AS D // WHERE C.ID = D.EMP_ID; -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES constexpr auto c_als = "c"_alias.for_(); constexpr auto d = "d"_alias.for_(); static_assert(std::is_empty_v); diff --git a/examples/exists.cpp b/examples/exists.cpp index 83b8735dd..3213c2a44 100644 --- a/examples/exists.cpp +++ b/examples/exists.cpp @@ -475,7 +475,7 @@ int main(int, char**) { // ) // ORDER BY 'c'."PAYMENT_AMT" -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES constexpr auto c_als = "c"_alias.for_(); constexpr auto d = "d"_alias.for_(); diff --git a/examples/self_join.cpp b/examples/self_join.cpp index 716299e9d..b1f8aa525 100644 --- a/examples/self_join.cpp +++ b/examples/self_join.cpp @@ -199,7 +199,7 @@ int main() { // FROM employees // INNER JOIN employees m // ON m.ReportsTo = employees.EmployeeId -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES constexpr auto m = "m"_alias.for_(); auto firstNames = storage.select(columns(m->*&Employee::firstName || c(" ") || m->*&Employee::lastName, &Employee::firstName || c(" ") || &Employee::lastName), @@ -230,7 +230,7 @@ int main() { // FROM employees // INNER JOIN employees emp // ON emp.ReportsTo = employees.EmployeeId -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES static_assert(std::is_empty_v>); constexpr auto emp = custom_alias{}; auto firstNames = storage.select(columns(emp->*&Employee::firstName || c(" ") || emp->*&Employee::lastName, diff --git a/examples/subquery.cpp b/examples/subquery.cpp index 1b45ad4d7..63e94a76b 100644 --- a/examples/subquery.cpp +++ b/examples/subquery.cpp @@ -1346,7 +1346,7 @@ int main(int, char**) { // WHERE salary >(SELECT AVG(salary) // FROM employees // WHERE department_id = e.department_id); -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES constexpr auto e = "e"_alias.for_(); auto rows = storage.select( columns(e->*&Employee::lastName, e->*&Employee::salary, e->*&Employee::departmentId), diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 32f556a34..db3e0deeb 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8,19 +8,13 @@ __pragma(push_macro("max")) #endif // defined(_MSC_VER) #pragma once -#include // std::enable_if, std::is_same - -// #include "functional/cxx_type_traits_polyfill.h" - -#include - // #include "cxx_universal.h" /* * This header makes central C++ functionality on which sqlite_orm depends universally available: * - alternative operator representations * - ::size_t, ::ptrdiff_t, ::nullptr_t - * - C++ core feature macros + * - C++ core language feature macros * - macros for dealing with compiler quirks */ @@ -34,6 +28,11 @@ 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 + */ + #ifdef __has_cpp_attribute #define SQLITE_ORM_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else @@ -111,6 +110,11 @@ 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 + */ + #ifdef __clang__ #define SQLITE_ORM_DO_PRAGMA(...) _Pragma(#__VA_ARGS__) #endif @@ -146,6 +150,20 @@ using std::nullptr_t; #define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED #endif +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && \ + defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) +#define SQLITE_ORM_WITH_CPP20_ALIASES +#endif +#pragma once + +#include // std::enable_if, std::is_same + +// #include "functional/cxx_type_traits_polyfill.h" + +#include + +// #include "cxx_universal.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -3668,7 +3686,7 @@ namespace sqlite_orm { return {}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** * Explicit FROM function. Usage: * `storage.select(&User::id, from<"a"_alias.for_>());` @@ -3877,7 +3895,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto left_join(O o) { return internal::left_join_t, O>{std::move(o)}; @@ -3889,7 +3907,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto join(O o) { return internal::join_t, O>{std::move(o)}; @@ -3901,7 +3919,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto left_outer_join(O o) { return internal::left_outer_join_t, O>{std::move(o)}; @@ -3913,7 +3931,7 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto inner_join(O o) { return internal::inner_join_t, O>{std::move(o)}; @@ -4188,7 +4206,7 @@ namespace sqlite_orm { namespace internal { -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /* * Helper class to facilitate user-defined string literal operator template */ @@ -4299,7 +4317,7 @@ namespace sqlite_orm { alias_holder() = default; }; -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template struct table_alias_builder { static_assert(sizeof...(C) == 0 && ((A >= 'A' && 'Z' <= A) || (A >= 'a' && 'z' <= A)), @@ -4331,7 +4349,7 @@ namespace sqlite_orm { return {c}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template, @@ -4357,7 +4375,7 @@ namespace sqlite_orm { return {std::move(expression)}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto as(E expression) { return internal::as_t, E>{std::move(expression)}; @@ -4377,7 +4395,7 @@ namespace sqlite_orm { return {}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto get() { return internal::alias_holder>{}; @@ -4447,7 +4465,7 @@ namespace sqlite_orm { using colalias_h = internal::column_alias<'h'>; using colalias_i = internal::column_alias<'i'>; -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES /** @short Create aliased tables e.g. `constexpr auto z_alias = alias_<'z'>.for_()`. */ template @@ -7258,7 +7276,7 @@ namespace sqlite_orm { return {definedOrder}; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES template = true> auto asterisk(bool definedOrder = false) { return internal::asterisk_t>{definedOrder}; @@ -9288,32 +9306,6 @@ namespace sqlite_orm { } #pragma once -#include // std::remove_const - -// #include "type_traits.h" - -// #include "alias_traits.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * If T is a recordset alias then the typename mapped_type_proxy::type is the unqualified aliased type, - * otherwise unqualified T. - */ - template - struct mapped_type_proxy : std::remove_const {}; - - template - struct mapped_type_proxy> : std::remove_const> {}; - - template - using mapped_type_proxy_t = typename mapped_type_proxy::type; - } -} -#pragma once - #include // std::string namespace sqlite_orm { @@ -9383,1578 +9375,1604 @@ namespace sqlite_orm { } #pragma once -#include // std::enable_if, std::is_same, std::decay, std::is_arithmetic, std::is_base_of -#include // std::tuple -#include // std::reference_wrapper +#include // std::string +#include // std::remove_reference, std::is_same, std::decay +#include // std::vector +#include // std::tuple_size, std::tuple_element +#include // std::forward, std::move // #include "functional/cxx_universal.h" -// #include "tuple_helper/tuple_traits.h" +// #include "functional/cxx_type_traits_polyfill.h" -// #include "tuple_helper/tuple_fy.h" +// #include "functional/cxx_functional_polyfill.h" -#include +// #include "functional/static_magic.h" + +#ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED +#include // std::false_type, std::true_type, std::integral_constant +#endif +#include // std::forward namespace sqlite_orm { + // got from here + // https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co namespace internal { - template - struct tuplify { - using type = std::tuple; - }; - template - struct tuplify> { - using type = std::tuple; - }; - - template - using tuplify_t = typename tuplify::type; - } -} - -// #include "tuple_helper/tuple_filter.h" + template + decltype(auto) empty_callable() { + static auto res = [](auto&&...) -> R { + return R(); + }; + return (res); + } -// #include "type_traits.h" +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + template + decltype(auto) static_if([[maybe_unused]] T&& trueFn, [[maybe_unused]] F&& falseFn) { + if constexpr(B) { + return std::forward(trueFn); + } else { + return std::forward(falseFn); + } + } -// #include "member_traits/member_traits.h" + template + decltype(auto) static_if([[maybe_unused]] T&& trueFn) { + if constexpr(B) { + return std::forward(trueFn); + } else { + return empty_callable(); + } + } -// #include "core_functions.h" + template + void call_if_constexpr([[maybe_unused]] L&& lambda, [[maybe_unused]] Args&&... args) { + if constexpr(B) { + lambda(std::forward(args)...); + } + } +#else + template + decltype(auto) static_if(std::true_type, T&& trueFn, const F&) { + return std::forward(trueFn); + } -// #include "select_constraints.h" + template + decltype(auto) static_if(std::false_type, const T&, F&& falseFn) { + return std::forward(falseFn); + } -// #include "operators.h" + template + decltype(auto) static_if(T&& trueFn, F&& falseFn) { + return static_if(std::integral_constant{}, std::forward(trueFn), std::forward(falseFn)); + } -// #include "rowid.h" + template + decltype(auto) static_if(T&& trueFn) { + return static_if(std::integral_constant{}, std::forward(trueFn), empty_callable()); + } -// #include "alias.h" + template + void call_if_constexpr(L&& lambda, Args&&... args) { + static_if(std::forward(lambda))(std::forward(args)...); + } +#endif + } -// #include "storage_traits.h" +} -#include // std::tuple +// #include "functional/mpl.h" -// #include "functional/cxx_type_traits_polyfill.h" +// #include "functional/index_sequence_util.h" // #include "tuple_helper/tuple_filter.h" -// #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 "tuple_helper/tuple_traits.h" -// #include "type_traits.h" +// #include "tuple_helper/tuple_iteration.h" -// #include "storage_lookup.h" +#include // std::tuple, std::get, std::tuple_element, std::tuple_size +#include // std::index_sequence, std::make_index_sequence +#include // std::forward, std::move -#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 +// #include "../functional/cxx_universal.h" -// #include "functional/cxx_universal.h" +// #include "../functional/cxx_type_traits_polyfill.h" -// #include "functional/cxx_type_traits_polyfill.h" +// #include "../functional/cxx_functional_polyfill.h" -// #include "type_traits.h" +// #include "../functional/index_sequence_util.h" namespace sqlite_orm { namespace internal { - template - struct storage_t; + // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer + template + auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { + return (f.*functionPointer)(std::get(std::move(t))...); + } - template - using db_objects_tuple = std::tuple; + template + auto call(Function& f, FunctionPointer functionPointer, Tuple t) { + constexpr size_t size = std::tuple_size::value; + return call_impl(f, functionPointer, std::move(t), std::make_index_sequence{}); + } - template - struct is_storage : std::false_type {}; + template + auto call(Function& f, Tuple t) { + return call(f, &Function::operator(), std::move(t)); + } - template - struct is_storage> : std::true_type {}; - template - struct is_storage> : std::true_type {}; +#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { + if constexpr(reversed) { + iterate_tuple(tpl, reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + } else { + (lambda(std::get(tpl)), ...); + } + } +#else + template + void iterate_tuple(const Tpl& /*tpl*/, std::index_sequence<>, L&& /*lambda*/) {} - template - struct is_db_objects : std::false_type {}; + template + void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { +#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED + if constexpr(reversed) { +#else + if(reversed) { +#endif + iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + lambda(std::get(tpl)); + } else { + lambda(std::get(tpl)); + iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); + } + } +#endif + template + void iterate_tuple(const Tpl& tpl, L&& lambda) { + iterate_tuple(tpl, + std::make_index_sequence::value>{}, + std::forward(lambda)); + } - template - struct is_db_objects> : std::true_type {}; - template - struct is_db_objects> : std::true_type {}; +#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED + template + void iterate_tuple(std::index_sequence, L&& lambda) { + (lambda((std::tuple_element_t*)nullptr), ...); + } +#else + template + void iterate_tuple(std::index_sequence<>, L&& /*lambda*/) {} - /** - * std::true_type if given object is mapped, std::false_type otherwise. - * - * Note: unlike table_t<>, index_t<>::object_type and trigger_t<>::object_type is always void. - */ - template - struct object_type_matches : polyfill::conjunction>>, - std::is_same>> {}; + template + void iterate_tuple(std::index_sequence, L&& lambda) { + lambda((std::tuple_element_t*)nullptr); + iterate_tuple(std::index_sequence{}, std::forward(lambda)); + } +#endif + template + void iterate_tuple(L&& lambda) { + iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); + } - /** - * std::true_type if given lookup type (object) is mapped, std::false_type otherwise. - */ - template - struct lookup_type_matches : polyfill::disjunction> {}; - } + template + R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { + return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; + } - // pick/lookup metafunctions - namespace internal { + template + R create_from_tuple(Tpl&& tpl, Projection project = {}) { + return create_from_tuple( + std::forward(tpl), + std::make_index_sequence>::value>{}, + std::forward(project)); + } - /** - * Indirect enabler for DBO, accepting an index to disambiguate non-unique DBOs - */ - template - struct enable_found_table : std::enable_if::value, DBO> {}; + template class Base, class L> + struct lambda_as_template_base : L { +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + lambda_as_template_base(L&& lambda) : L{std::move(lambda)} {} +#endif + template + decltype(auto) operator()(const Base& object) { + return L::operator()(object); + } + }; - /** - * SFINAE friendly facility to pick a table definition (`table_t`) from a tuple of database objects. + /* + * This method wraps the specified callable in another function object, + * which in turn implicitly casts its single argument to the specified template base class, + * then passes the converted argument to the lambda. * - * Lookup - mapped data type - * Seq - index sequence matching the number of DBOs - * DBOs - db_objects_tuple type + * Note: This method is useful for reducing combinatorial instantiation of template lambdas, + * as long as this library supports compilers that do not implement + * explicit template parameters in generic lambdas [SQLITE_ORM_EXPLICIT_GENERIC_LAMBDA_SUPPORTED]. + * Unfortunately it doesn't work with user-defined conversion operators in order to extract + * parts of a class. In other words, the destination type must be a direct template base class. */ - template - struct storage_pick_table; + template class Base, class L> + lambda_as_template_base call_as_template_base(L lambda) { + return {std::move(lambda)}; + } + } +} - template - struct storage_pick_table, db_objects_tuple> - : enable_found_table... {}; +// #include "member_traits/member_traits.h" - /** - * SFINAE friendly facility to pick a table definition (`table_t`) from a tuple of database objects. - * - * Lookup - 'table' type, mapped data type - * DBOs - db_objects_tuple type, possibly const-qualified - */ - template - using storage_pick_table_t = typename storage_pick_table::value>, - std::remove_const_t>::type; +// #include "typed_comparator.h" - /** - * Find a table definition (`table_t`) from a tuple of database objects; - * `std::nonesuch` if not found. - * - * DBOs - db_objects_tuple type - * Lookup - mapped data type - */ - template - struct storage_find_table : polyfill::detected_or {}; +// #include "type_traits.h" - /** - * Find a table definition (`table_t`) from a tuple of database objects; - * `std::nonesuch` if not found. - * - * DBOs - db_objects_tuple type, possibly const-qualified - * Lookup - mapped data type - */ - template - using storage_find_table_t = typename storage_find_table>::type; +// #include "constraints.h" -#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template - struct is_mapped : std::false_type {}; - template - struct is_mapped>> : std::true_type {}; -#else - template> - struct is_mapped : std::true_type {}; - template - struct is_mapped : std::false_type {}; -#endif +// #include "table_info.h" - template - SQLITE_ORM_INLINE_VAR constexpr bool is_mapped_v = is_mapped::value; - } -} +// #include "column.h" -// runtime lookup functions namespace sqlite_orm { + namespace internal { - /** - * Pick the table definition for the specified lookup type from the given tuple of schema objects. - * - * Note: This function requires Lookup to be mapped, otherwise it is removed from the overload resolution set. - */ - template = true> - auto& pick_table(DBOs& dbObjects) { - using table_type = storage_pick_table_t; - return std::get(dbObjects); - } - template = true> - auto lookup_table(const DBOs& dbObjects); + struct basic_table { - template = true> - decltype(auto) lookup_table_name(const DBOs& dbObjects); + /** + * Table name. + */ + std::string name; + }; - } -} + /** + * Table definition. + */ + template + struct table_t : basic_table { + using object_type = O; + using elements_type = std::tuple; -namespace sqlite_orm { + static constexpr bool is_without_rowid_v = WithoutRowId; + using is_without_rowid = polyfill::bool_constant; - namespace internal { + elements_type elements; - namespace storage_traits { +#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED + table_t(std::string name_, elements_type elements_) : + basic_table{std::move(name_)}, elements{std::move(elements_)} {} +#endif + + table_t without_rowid() const { + return {this->name, this->elements}; + } /** - * DBO - db object (table) + * Returns foreign keys count in table definition */ - template - struct storage_mapped_columns_impl - : tuple_transformer, is_column>, field_type_t> {}; - - template<> - struct storage_mapped_columns_impl { - using type = std::tuple<>; - }; + constexpr int foreign_keys_count() const { +#if SQLITE_VERSION_NUMBER >= 3006019 + using fk_index_sequence = filter_tuple_sequence_t; + return int(fk_index_sequence::size()); +#else + return 0; +#endif + } /** - * DBOs - db_objects_tuple type - * Lookup - mapped or unmapped data type + * Function used to get field value from object by mapped member pointer/setter/getter. + * + * For a setter the corresponding getter has to be searched, + * so the method returns a pointer to the field as returned by the found getter. + * Otherwise the method invokes the member pointer and returns its result. */ - template - struct storage_mapped_columns : storage_mapped_columns_impl> {}; - } - } -} - -// #include "function.h" + template = true> + decltype(auto) object_field_value(const object_type& object, M memberPointer) const { + return polyfill::invoke(memberPointer, object); + } -#include -#include -#include // std::string -#include // std::tuple -#include // std::function -#include // std::min -#include // std::move, std::forward + template = true> + const member_field_type_t* object_field_value(const object_type& object, M memberPointer) const { + using field_type = member_field_type_t; + const field_type* res = nullptr; + iterate_tuple(this->elements, + col_index_sequence_with_field_type{}, + call_as_template_base([&res, &memberPointer, &object](const auto& column) { + if(compare_any(column.setter, memberPointer)) { + res = &polyfill::invoke(column.member_pointer, object); + } + })); + return res; + } -// #include "functional/cxx_universal.h" + const basic_generated_always::storage_type* + find_column_generated_storage_type(const std::string& name) const { + const basic_generated_always::storage_type* result = nullptr; +#if SQLITE_VERSION_NUMBER >= 3031000 + iterate_tuple(this->elements, + col_index_sequence_with{}, + [&result, &name](auto& column) { + if(column.name != name) { + return; + } + using generated_op_index_sequence = + filter_tuple_sequence_t, + is_generated_always>; + constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); + result = &get(column.constraints).storage; + }); +#endif + return result; + } -// #include "functional/cxx_type_traits_polyfill.h" - -namespace sqlite_orm { - - struct arg_values; - - template - struct pointer_arg; - template - class pointer_binding; - - namespace internal { - - struct user_defined_function_base { - using func_call = std::function< - void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; - using final_call = std::function; - - std::string name; - int argumentsCount = 0; - std::function create; - void (*destroy)(int*) = nullptr; - -#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - user_defined_function_base(decltype(name) name_, - decltype(argumentsCount) argumentsCount_, - decltype(create) create_, - decltype(destroy) destroy_) : - name(std::move(name_)), - argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} -#endif - }; - - struct user_defined_scalar_function_t : user_defined_function_base { - func_call run; - - user_defined_scalar_function_t(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(run) run_, - decltype(destroy) destroy_) : - user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, - run(std::move(run_)) {} - }; - - struct user_defined_aggregate_function_t : user_defined_function_base { - func_call step; - final_call finalCall; - - user_defined_aggregate_function_t(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(step) step_, - decltype(finalCall) finalCall_, - decltype(destroy) destroy_) : - user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, - step(std::move(step_)), finalCall(std::move(finalCall_)) {} - }; - - template - using scalar_call_function_t = decltype(&F::operator()); - - template - using aggregate_step_function_t = decltype(&F::step); - - template - using aggregate_fin_function_t = decltype(&F::fin); - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v = false; - template - SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v>> = - true; - - template - SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v = false; - template - SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v< - F, - polyfill::void_t, - aggregate_fin_function_t, - std::enable_if_t>::value>, - std::enable_if_t>::value>>> = - true; - - template - struct member_function_arguments; - - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...) const; - using tuple_type = std::tuple...>; - using return_type = R; - }; - - template - struct member_function_arguments { - using member_function_type = R (O::*)(Args...); - using tuple_type = std::tuple...>; - using return_type = R; - }; - - template - struct callable_arguments_impl; + template + bool exists_in_composite_primary_key(const column_field& column) const { + bool res = false; + this->for_each_primary_key([&column, &res](auto& primaryKey) { + using colrefs_tuple = decltype(primaryKey.columns); + using same_type_index_sequence = + filter_tuple_sequence_t>::template fn, + member_field_type_t>; + iterate_tuple(primaryKey.columns, same_type_index_sequence{}, [&res, &column](auto& memberPointer) { + if(compare_any(memberPointer, column.member_pointer) || + compare_any(memberPointer, column.setter)) { + res = true; + } + }); + }); + return res; + } - template - struct callable_arguments_impl>> { - using args_tuple = typename member_function_arguments>::tuple_type; - using return_type = typename member_function_arguments>::return_type; - }; + /** + * Call passed lambda with all defined primary keys. + */ + template + void for_each_primary_key(L&& lambda) const { + using pk_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->elements, pk_index_sequence{}, lambda); + } - template - struct callable_arguments_impl>> { - using args_tuple = typename member_function_arguments>::tuple_type; - using return_type = typename member_function_arguments>::return_type; - }; + std::vector composite_key_columns_names() const { + std::vector res; + this->for_each_primary_key([this, &res](auto& primaryKey) { + res = this->composite_key_columns_names(primaryKey); + }); + return res; + } - template - struct callable_arguments : callable_arguments_impl {}; + std::vector primary_key_column_names() const { + using pkcol_index_sequence = col_index_sequence_with; - template - struct function_call { - using function_type = F; - using args_tuple = std::tuple; + if(pkcol_index_sequence::size() > 0) { + return create_from_tuple>(this->elements, + pkcol_index_sequence{}, + &column_identifier::name); + } else { + return this->composite_key_columns_names(); + } + } - args_tuple args; - }; + template + void for_each_primary_key_column(L&& lambda) const { + iterate_tuple(this->elements, + col_index_sequence_with{}, + call_as_template_base([&lambda](const auto& column) { + lambda(column.member_pointer); + })); + this->for_each_primary_key([&lambda](auto& primaryKey) { + iterate_tuple(primaryKey.columns, lambda); + }); + } - template - struct unpacked_arg { - using type = T; - }; - template - struct unpacked_arg> { - using type = typename callable_arguments::return_type; - }; - template - using unpacked_arg_t = typename unpacked_arg::type; + template + std::vector composite_key_columns_names(const primary_key_t& primaryKey) const { + return create_from_tuple>(primaryKey.columns, + [this, empty = std::string{}](auto& memberPointer) { + if(const std::string* columnName = + this->find_column_name(memberPointer)) { + return *columnName; + } else { + return empty; + } + }); + } - template - SQLITE_ORM_CONSTEVAL bool expected_pointer_value() { - static_assert(polyfill::always_false_v, "Expected a pointer value for I-th argument"); - return false; - } + /** + * Searches column name by class member pointer passed as the first argument. + * @return column name or empty string if nothing found. + */ + template = true> + const std::string* find_column_name(M m) const { + const std::string* res = nullptr; + using field_type = member_field_type_t; + iterate_tuple(this->elements, + col_index_sequence_with_field_type{}, + [&res, m](auto& c) { + if(compare_any(c.member_pointer, m) || compare_any(c.setter, m)) { + res = &c.name; + } + }); + return res; + } - template - constexpr bool is_same_pvt_v = expected_pointer_value(); + /** + * 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->count_columns_amount(); +#endif + } - // Always allow binding nullptr to a pointer argument - template - constexpr bool is_same_pvt_v> = true; + /** + * 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()); + } -#if __cplusplus >= 201703L // C++17 or later - template - SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { - constexpr bool valid = Binding == PointerArg; - static_assert(valid, "Pointer value types of I-th argument do not match"); - return valid; - } + /** + * Call passed lambda with all defined foreign keys. + * @param lambda Lambda called for each column. Function signature: `void(auto& column)` + */ + template + void for_each_foreign_key(L&& lambda) const { + using fk_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->elements, fk_index_sequence{}, lambda); + } - template - constexpr bool - is_same_pvt_v> = - assert_same_pointer_type(); -#else - template - SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { - constexpr bool valid = Binding::value == PointerArg::value; - static_assert(valid, "Pointer value types of I-th argument do not match"); - return valid; - } + template + void for_each_foreign_key_to(L&& lambda) const { + using fk_index_sequence = filter_tuple_sequence_t; + using filtered_index_sequence = filter_tuple_sequence_t::template fn, + target_type_t, + fk_index_sequence>; + iterate_tuple(this->elements, filtered_index_sequence{}, lambda); + } - template - constexpr bool - is_same_pvt_v> = - assert_same_pointer_type(); -#endif + /** + * Call passed lambda with all defined columns. + * @param lambda Lambda called for each column. Function signature: `void(auto& column)` + */ + template + void for_each_column(L&& lambda) const { + using col_index_sequence = filter_tuple_sequence_t; + iterate_tuple(this->elements, col_index_sequence{}, lambda); + } - template - SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) { - return true; - } + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template class OpTraitFn, class L> + void for_each_column_excluding(L&& lambda) const { + iterate_tuple(this->elements, col_index_sequence_excluding{}, lambda); + } - template - SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) { - return is_same_pvt_v; - } + /** + * Call passed lambda with columns not having the specified constraint trait `OpTrait`. + * @param lambda Lambda called for each column. + */ + template = true> + void for_each_column_excluding(L&& lambda) const { + this->for_each_column_excluding(lambda); + } - template - SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { - return true; - } - template - SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { - using func_arg_t = std::tuple_element_t; - using passed_arg_t = unpacked_arg_t>; + std::vector get_table_info() const; + }; -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED - constexpr bool valid = validate_pointer_value_type, - unpacked_arg_t>>( - polyfill::bool_constant < (polyfill::is_specialization_of_v) || - (polyfill::is_specialization_of_v) > {}); + template + struct is_table : std::false_type {}; - return validate_pointer_value_types(polyfill::index_constant{}) && valid; -#else - return validate_pointer_value_types(polyfill::index_constant{}) && - validate_pointer_value_type, - unpacked_arg_t>>( - polyfill::bool_constant < (polyfill::is_specialization_of_v) || - (polyfill::is_specialization_of_v) > {}); -#endif - } + template + struct is_table> : std::true_type {}; } /** - * Used to call user defined function: `func(...);` + * Factory function for a table definition. + * + * The mapped object type is determined implicitly from the first column definition. */ - template - internal::function_call func(Args... args) { - using args_tuple = std::tuple; - using function_args_tuple = typename internal::callable_arguments::args_tuple; - constexpr auto argsCount = std::tuple_size::value; - constexpr auto functionArgsCount = std::tuple_size::value; - static_assert((argsCount == functionArgsCount && - !std::is_same>::value && - internal::validate_pointer_value_types( - polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || - std::is_same>::value, - "Number of arguments does not match"); - return {std::make_tuple(std::forward(args)...)}; + template>::object_type> + internal::table_t make_table(std::string name, Cs... args) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::make_tuple(std::forward(args)...)}); } + /** + * Factory function for a table definition. + * + * The mapped object type is explicitly specified. + */ + template + internal::table_t make_table(std::string name, Cs... args) { + SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( + return {std::move(name), std::make_tuple(std::forward(args)...)}); + } } +#pragma once -namespace sqlite_orm { +#include // std::string - namespace internal { +// #include "functional/cxx_universal.h" +// ::nullptr_t +// #include "functional/static_magic.h" - /** - * Obains the result type of expressions that form the columns of a select statement. - * - * This is a proxy class used to define what type must have result type depending on select - * arguments (member pointer, aggregate functions, etc). Below you can see specializations - * for different types. E.g. specialization for internal::length_t has `type` int cause - * LENGTH returns INTEGER in sqlite. Every column_result_t must have `type` type that equals - * c++ SELECT return type for T - * DBOs - db_objects_tuple type - * T - C++ type - * SFINAE - sfinae argument - * - * Note (implementation): could be possibly implemented by utilizing column_expression_of_t - */ - template - struct column_result_t; +// #include "tuple_helper/tuple_filter.h" - template - using column_result_of_t = typename column_result_t::type; +// #include "tuple_helper/tuple_iteration.h" -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - template - struct column_result_t, void> { - using type = std::optional>; - }; +// #include "type_traits.h" - template - struct column_result_t, void> { - using type = std::optional; - }; -#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +// #include "select_constraints.h" - template - struct column_result_t, void> { - using type = bool; - }; +// #include "storage_lookup.h" - template - struct column_result_t, void> { - using type = bool; - }; +#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 - template - struct column_result_t> : member_field_type {}; +// #include "functional/cxx_universal.h" - template - struct column_result_t, void> { - using type = R; - }; +// #include "functional/cxx_type_traits_polyfill.h" - template - struct column_result_t, void> { - using type = R; - }; +// #include "type_traits.h" - template - struct column_result_t, void> { - using type = typename callable_arguments::return_type; - }; +namespace sqlite_orm { + namespace internal { - template - struct column_result_t, S, X, Rest...>, void> { - using type = std::unique_ptr>; - }; + template + struct storage_t; - template - struct column_result_t, S, X>, void> { - using type = std::unique_ptr>; - }; + template + using db_objects_tuple = std::tuple; - template - struct column_result_t, void> { - using type = int; - }; + template + struct is_storage : std::false_type {}; - template - struct column_result_t { - using type = nullptr_t; - }; + template + struct is_storage> : std::true_type {}; + template + struct is_storage> : std::true_type {}; - template - struct column_result_t { - using type = int; - }; + template + struct is_db_objects : std::false_type {}; - template - struct column_result_t, void> : column_result_t {}; + template + struct is_db_objects> : std::true_type {}; + template + struct is_db_objects> : std::true_type {}; - template - struct column_result_t, void> : column_result_t {}; + /** + * std::true_type if given object is mapped, std::false_type otherwise. + * + * Note: unlike table_t<>, index_t<>::object_type and trigger_t<>::object_type is always void. + */ + template + struct object_type_matches : polyfill::conjunction>>, + std::is_same>> {}; - template - struct column_result_t, void> { - using type = std::string; - }; + /** + * std::true_type if given lookup type (object) is mapped, std::false_type otherwise. + */ + template + struct lookup_type_matches : polyfill::disjunction> {}; + } + + // pick/lookup metafunctions + namespace internal { + + /** + * Indirect enabler for DBO, accepting an index to disambiguate non-unique DBOs + */ + template + struct enable_found_table : std::enable_if::value, DBO> {}; + + /** + * SFINAE friendly facility to pick a table definition (`table_t`) from a tuple of database objects. + * + * Lookup - mapped data type + * Seq - index sequence matching the number of DBOs + * DBOs - db_objects_tuple type + */ + template + struct storage_pick_table; + + template + struct storage_pick_table, db_objects_tuple> + : enable_found_table... {}; - template - struct column_result_t, void> { - using type = double; - }; + /** + * SFINAE friendly facility to pick a table definition (`table_t`) from a tuple of database objects. + * + * Lookup - 'table' type, mapped data type + * DBOs - db_objects_tuple type, possibly const-qualified + */ + template + using storage_pick_table_t = typename storage_pick_table::value>, + std::remove_const_t>::type; - template - struct column_result_t, void> { - using type = double; - }; + /** + * Find a table definition (`table_t`) from a tuple of database objects; + * `std::nonesuch` if not found. + * + * DBOs - db_objects_tuple type + * Lookup - mapped data type + */ + template + struct storage_find_table : polyfill::detected_or {}; - template - struct column_result_t, void> { - using type = double; - }; + /** + * Find a table definition (`table_t`) from a tuple of database objects; + * `std::nonesuch` if not found. + * + * DBOs - db_objects_tuple type, possibly const-qualified + * Lookup - mapped data type + */ + template + using storage_find_table_t = typename storage_find_table>::type; - template - struct column_result_t, void> { - using type = double; - }; +#ifndef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template + struct is_mapped : std::false_type {}; + template + struct is_mapped>> : std::true_type {}; +#else + template> + struct is_mapped : std::true_type {}; + template + struct is_mapped : std::false_type {}; +#endif - template - struct column_result_t, void> { - using type = double; - }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_mapped_v = is_mapped::value; + } +} - template - struct column_result_t, void> { - using type = int; - }; +// runtime lookup functions +namespace sqlite_orm { + namespace internal { + /** + * Pick the table definition for the specified lookup type from the given tuple of schema objects. + * + * Note: This function requires Lookup to be mapped, otherwise it is removed from the overload resolution set. + */ + template = true> + auto& pick_table(DBOs& dbObjects) { + using table_type = storage_pick_table_t; + return std::get(dbObjects); + } - template - struct column_result_t, void> { - using type = int; - }; + template = true> + auto lookup_table(const DBOs& dbObjects); - template - struct column_result_t, void> { - using type = int; - }; + template = true> + decltype(auto) lookup_table_name(const DBOs& dbObjects); - template - struct column_result_t, void> { - using type = int; - }; + } +} - template - struct column_result_t, void> { - using type = int; - }; +// interface functions +namespace sqlite_orm { + namespace internal { template - struct column_result_t { - using type = int64; - }; + using tables_index_sequence = filter_tuple_sequence_t; - template - struct column_result_t { - using type = int64; - }; + template = true> + 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(); + }); + return res; + } - template - struct column_result_t { - using type = int64; - }; + template> + auto lookup_table(const DBOs& dbObjects) { + return static_if>( + [](const auto& dbObjects) { + return &pick_table(dbObjects); + }, + empty_callable())(dbObjects); + } - template - struct column_result_t, void> { - using type = int64; - }; + template> + decltype(auto) lookup_table_name(const DBOs& dbObjects) { + return static_if>( + [](const auto& dbObjects) -> const std::string& { + return pick_table(dbObjects).name; + }, + empty_callable())(dbObjects); + } - template - struct column_result_t, void> { - using type = int64; - }; + /** + * Find column name by its type and member pointer. + */ + template = true> + const std::string* find_column_name(const DBOs& dbObjects, F O::*field) { + return pick_table(dbObjects).find_column_name(field); + } - template - struct column_result_t, void> { - using type = int64; - }; + /** + * Materialize column pointer: + * 1. by explicit object type and member pointer. + */ + template = true> + constexpr decltype(auto) materialize_column_pointer(const DBOs&, const column_pointer& cp) { + return cp.field; + } - template - struct column_result_t, void> : column_result_t {}; + /** + * Find column name by: + * 1. by explicit object type and member pointer. + */ + template = true> + const std::string* find_column_name(const DBOs& dbObjects, const column_pointer& cp) { + auto field = materialize_column_pointer(dbObjects, cp); + return pick_table(dbObjects).find_column_name(field); + } + } +} +#pragma once - template - struct column_result_t, void> : column_result_t {}; +#include // std::string - template - struct column_result_t, void> { - using type = tuple_cat_t>>...>; - }; +// #include "constraints.h" - template - struct column_result_t> : column_result_t {}; +// #include "serializer_context.h" - template - struct column_result_t>> { - using left_result = column_result_of_t; - using right_result = column_result_of_t; - static_assert(std::is_same::value, - "Compound subselect queries must return same types"); - using type = left_result; - }; +// #include "storage_lookup.h" - template - struct column_result_t>> { - using type = typename T::result_type; - }; +namespace sqlite_orm { - /** - * Result for the most simple queries like `SELECT 1` - */ - template - struct column_result_t> { - using type = T; - }; + namespace internal { + + template + std::string serialize(const T& t, const serializer_context& context); /** - * Result for the most simple queries like `SELECT 'ototo'` + * Serialize default value of a column's default valu */ - template - struct column_result_t { - using type = std::string; - }; + template + std::string serialize_default_value(const default_t& dft) { + db_objects_tuple<> dbObjects; + serializer_context> context{dbObjects}; + return serialize(dft.value, context); + } - template - struct column_result_t { - using type = std::string; - }; + } - template - struct column_result_t, void> : column_result_t> {}; +} +#pragma once + +#include +#include // std::unique_ptr/shared_ptr, std::make_unique/std::make_shared +#include // std::system_error +#include // std::string +#include // std::remove_reference, std::is_base_of, std::decay, std::false_type, std::true_type +#include // std::identity +#include // std::stringstream +#include // std::map +#include // std::vector +#include // std::tuple_size, std::tuple, std::make_tuple, std::tie +#include // std::forward, std::pair +#include // std::for_each, std::ranges::for_each +// #include "functional/cxx_optional.h" + +// #include "functional/cxx_universal.h" - template - struct column_result_t, void> - : storage_traits::storage_mapped_columns> {}; +// #include "functional/cxx_functional_polyfill.h" - template - struct column_result_t, void> { - using type = T; - }; +// #include "functional/static_magic.h" - template - struct column_result_t, void> { - using type = T; - }; +// #include "functional/mpl.h" - template - struct column_result_t, void> { - using type = R; - }; +// #include "tuple_helper/tuple_traits.h" - template - struct column_result_t, void> { - using type = bool; - }; +// #include "tuple_helper/tuple_filter.h" - template - struct column_result_t, void> { - using type = bool; - }; +// #include "tuple_helper/tuple_iteration.h" - template - struct column_result_t, void> { - using type = bool; - }; +// #include "type_traits.h" - template - struct column_result_t, void> : column_result_t {}; - } -} -#pragma once +// #include "alias.h" -#include // std::string -#include // std::remove_reference, std::is_same, std::decay -#include // std::vector -#include // std::tuple_size, std::tuple_element -#include // std::forward, std::move +// #include "row_extractor_builder.h" // #include "functional/cxx_universal.h" -// #include "functional/cxx_type_traits_polyfill.h" +// #include "row_extractor.h" -// #include "functional/cxx_functional_polyfill.h" +// #include "mapped_row_extractor.h" + +#include + +// #include "object_from_column_builder.h" + +#include +#include // std::is_member_object_pointer // #include "functional/static_magic.h" -#ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED -#include // std::false_type, std::true_type, std::integral_constant -#endif -#include // std::forward +// #include "row_extractor.h" namespace sqlite_orm { - // got from here - // https://stackoverflow.com/questions/37617677/implementing-a-compile-time-static-if-logic-for-different-string-types-in-a-co namespace internal { - template - decltype(auto) empty_callable() { - static auto res = [](auto&&...) -> R { - return R(); - }; - return (res); - } + struct object_from_column_builder_base { + sqlite3_stmt* stmt = nullptr; + int index = 0; -#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED - template - decltype(auto) static_if([[maybe_unused]] T&& trueFn, [[maybe_unused]] F&& falseFn) { - if constexpr(B) { - return std::forward(trueFn); - } else { - return std::forward(falseFn); - } - } +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + object_from_column_builder_base(sqlite3_stmt* stmt) : stmt{stmt} {} +#endif + }; - template - decltype(auto) static_if([[maybe_unused]] T&& trueFn) { - if constexpr(B) { - return std::forward(trueFn); - } else { - return empty_callable(); - } - } + /** + * This is a cute lambda replacement which is used in several places. + */ + template + struct object_from_column_builder : object_from_column_builder_base { + using object_type = O; - template - void call_if_constexpr([[maybe_unused]] L&& lambda, [[maybe_unused]] Args&&... args) { - if constexpr(B) { - lambda(std::forward(args)...); + object_type& object; + + object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : + object_from_column_builder_base{stmt_}, object(object_) {} + + template + void operator()(const column_field& column) { + auto value = row_extractor>().extract(this->stmt, this->index++); + static_if::value>( + [&value, &object = this->object](const auto& column) { + object.*column.member_pointer = std::move(value); + }, + [&value, &object = this->object](const auto& column) { + (object.*column.setter)(std::move(value)); + })(column); } - } -#else - template - decltype(auto) static_if(std::true_type, T&& trueFn, const F&) { - return std::forward(trueFn); - } + }; + } +} - template - decltype(auto) static_if(std::false_type, const T&, F&& falseFn) { - return std::forward(falseFn); - } +namespace sqlite_orm { - template - decltype(auto) static_if(T&& trueFn, F&& falseFn) { - return static_if(std::integral_constant{}, std::forward(trueFn), std::forward(falseFn)); - } + namespace internal { - template - decltype(auto) static_if(T&& trueFn) { - return static_if(std::integral_constant{}, std::forward(trueFn), empty_callable()); - } + /** + * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. + * Main difference from regular `row_extractor` is that this class takes table info which is required + * for constructing objects by member pointers. To construct please use `make_row_extractor()`. + * Type arguments: + * V is value type just like regular `row_extractor` has + * T is table info class `table_t` + */ + template + struct mapped_row_extractor { + using table_type = Table; + + V extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { + V res; + object_from_column_builder builder{res, stmt}; + this->tableInfo.for_each_column(builder); + return res; + } + + const table_type& tableInfo; + }; - template - void call_if_constexpr(L&& lambda, Args&&... args) { - static_if(std::forward(lambda))(std::forward(args)...); - } -#endif } } -// #include "functional/mpl.h" +namespace sqlite_orm { -// #include "functional/index_sequence_util.h" + namespace internal { -// #include "tuple_helper/tuple_filter.h" + template + row_extractor make_row_extractor(nullptr_t) { + return {}; + } -// #include "tuple_helper/tuple_traits.h" + template + mapped_row_extractor make_row_extractor(const Table* table) { + return {*table}; + } + } -// #include "tuple_helper/tuple_iteration.h" +} -#include // std::tuple, std::get, std::tuple_element, std::tuple_size -#include // std::index_sequence, std::make_index_sequence -#include // std::forward, std::move +// #include "error_code.h" -// #include "../functional/cxx_universal.h" +// #include "type_printer.h" -// #include "../functional/cxx_type_traits_polyfill.h" +// #include "constraints.h" -// #include "../functional/cxx_functional_polyfill.h" +// #include "field_printer.h" -// #include "../functional/index_sequence_util.h" +// #include "rowid.h" -namespace sqlite_orm { - namespace internal { +// #include "operators.h" - // got it form here https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer - template - auto call_impl(Function& f, FunctionPointer functionPointer, Tuple t, std::index_sequence) { - return (f.*functionPointer)(std::get(std::move(t))...); - } +// #include "select_constraints.h" - template - auto call(Function& f, FunctionPointer functionPointer, Tuple t) { - constexpr size_t size = std::tuple_size::value; - return call_impl(f, functionPointer, std::move(t), std::make_index_sequence{}); - } +// #include "core_functions.h" - template - auto call(Function& f, Tuple t) { - return call(f, &Function::operator(), std::move(t)); - } +// #include "conditions.h" -#if defined(SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED) && defined(SQLITE_ORM_IF_CONSTEXPR_SUPPORTED) - template - void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { - if constexpr(reversed) { - iterate_tuple(tpl, reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); - } else { - (lambda(std::get(tpl)), ...); - } - } -#else - template - void iterate_tuple(const Tpl& /*tpl*/, std::index_sequence<>, L&& /*lambda*/) {} +// #include "statement_binder.h" - template - void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { -#ifdef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED - if constexpr(reversed) { -#else - if(reversed) { -#endif - iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); - lambda(std::get(tpl)); - } else { - lambda(std::get(tpl)); - iterate_tuple(tpl, std::index_sequence{}, std::forward(lambda)); - } - } -#endif - template - void iterate_tuple(const Tpl& tpl, L&& lambda) { - iterate_tuple(tpl, - std::make_index_sequence::value>{}, - std::forward(lambda)); - } +// #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 -#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED - template - void iterate_tuple(std::index_sequence, L&& lambda) { - (lambda((std::tuple_element_t*)nullptr), ...); - } -#else - template - void iterate_tuple(std::index_sequence<>, L&& /*lambda*/) {} +// #include "functional/cxx_universal.h" - template - void iterate_tuple(std::index_sequence, L&& lambda) { - lambda((std::tuple_element_t*)nullptr); - iterate_tuple(std::index_sequence{}, std::forward(lambda)); - } -#endif - template - void iterate_tuple(L&& lambda) { - iterate_tuple(std::make_index_sequence::value>{}, std::forward(lambda)); - } +// #include "tuple_helper/tuple_traits.h" - template - R create_from_tuple(Tpl&& tpl, std::index_sequence, Projection project = {}) { - return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; - } +// #include "tuple_helper/tuple_fy.h" - 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 - template class Base, class L> - struct lambda_as_template_base : L { -#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - lambda_as_template_base(L&& lambda) : L{std::move(lambda)} {} -#endif - template - decltype(auto) operator()(const Base& object) { - return L::operator()(object); - } +namespace sqlite_orm { + + namespace internal { + + template + struct tuplify { + using type = std::tuple; + }; + template + struct tuplify> { + using type = std::tuple; }; - /* - * This method wraps the specified callable in another function object, - * which in turn implicitly casts its single argument to the specified template base class, - * then passes the converted argument to the lambda. - * - * Note: This method is useful for reducing combinatorial instantiation of template lambdas, - * as long as this library supports compilers that do not implement - * explicit template parameters in generic lambdas [SQLITE_ORM_EXPLICIT_GENERIC_LAMBDA_SUPPORTED]. - * Unfortunately it doesn't work with user-defined conversion operators in order to extract - * parts of a class. In other words, the destination type must be a direct template base class. - */ - template class Base, class L> - lambda_as_template_base call_as_template_base(L lambda) { - return {std::move(lambda)}; - } + template + using tuplify_t = typename tuplify::type; } } -// #include "member_traits/member_traits.h" - -// #include "typed_comparator.h" +// #include "tuple_helper/tuple_filter.h" // #include "type_traits.h" -// #include "constraints.h" +// #include "member_traits/member_traits.h" -// #include "table_info.h" +// #include "mapped_type_proxy.h" -// #include "column.h" +#include // std::remove_const -namespace sqlite_orm { +// #include "type_traits.h" - namespace internal { +// #include "alias_traits.h" - struct basic_table { +namespace sqlite_orm { - /** - * Table name. - */ - std::string name; - }; + namespace internal { /** - * Table definition. + * If T is a recordset alias then the typename mapped_type_proxy::type is the unqualified aliased type, + * otherwise unqualified T. */ - template - struct table_t : basic_table { - using object_type = O; - using elements_type = std::tuple; + template + struct mapped_type_proxy : std::remove_const {}; - static constexpr bool is_without_rowid_v = WithoutRowId; - using is_without_rowid = polyfill::bool_constant; + template + struct mapped_type_proxy> : std::remove_const> {}; - elements_type elements; + template + using mapped_type_proxy_t = typename mapped_type_proxy::type; + } +} -#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED - table_t(std::string name_, elements_type elements_) : - basic_table{std::move(name_)}, elements{std::move(elements_)} {} -#endif +// #include "core_functions.h" - table_t without_rowid() const { - return {this->name, this->elements}; - } +// #include "select_constraints.h" - /** - * Returns foreign keys count in table definition - */ - constexpr int foreign_keys_count() const { -#if SQLITE_VERSION_NUMBER >= 3006019 - using fk_index_sequence = filter_tuple_sequence_t; - return int(fk_index_sequence::size()); -#else - return 0; -#endif - } +// #include "operators.h" - /** - * Function used to get field value from object by mapped member pointer/setter/getter. - * - * For a setter the corresponding getter has to be searched, - * so the method returns a pointer to the field as returned by the found getter. - * Otherwise the method invokes the member pointer and returns its result. - */ - template = true> - decltype(auto) object_field_value(const object_type& object, M memberPointer) const { - return polyfill::invoke(memberPointer, object); - } +// #include "rowid.h" - template = true> - const member_field_type_t* object_field_value(const object_type& object, M memberPointer) const { - using field_type = member_field_type_t; - const field_type* res = nullptr; - iterate_tuple(this->elements, - col_index_sequence_with_field_type{}, - call_as_template_base([&res, &memberPointer, &object](const auto& column) { - if(compare_any(column.setter, memberPointer)) { - res = &polyfill::invoke(column.member_pointer, object); - } - })); - return res; - } +// #include "alias.h" - const basic_generated_always::storage_type* - find_column_generated_storage_type(const std::string& name) const { - const basic_generated_always::storage_type* result = nullptr; -#if SQLITE_VERSION_NUMBER >= 3031000 - iterate_tuple(this->elements, - col_index_sequence_with{}, - [&result, &name](auto& column) { - if(column.name != name) { - return; - } - using generated_op_index_sequence = - filter_tuple_sequence_t, - is_generated_always>; - constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); - result = &get(column.constraints).storage; - }); -#endif - return result; - } +// #include "storage_traits.h" - template - bool exists_in_composite_primary_key(const column_field& column) const { - bool res = false; - this->for_each_primary_key([&column, &res](auto& primaryKey) { - using colrefs_tuple = decltype(primaryKey.columns); - using same_type_index_sequence = - filter_tuple_sequence_t>::template fn, - member_field_type_t>; - iterate_tuple(primaryKey.columns, same_type_index_sequence{}, [&res, &column](auto& memberPointer) { - if(compare_any(memberPointer, column.member_pointer) || - compare_any(memberPointer, column.setter)) { - res = true; - } - }); - }); - return res; - } +#include // std::tuple - /** - * Call passed lambda with all defined primary keys. - */ - template - void for_each_primary_key(L&& lambda) const { - using pk_index_sequence = filter_tuple_sequence_t; - iterate_tuple(this->elements, pk_index_sequence{}, lambda); - } +// #include "functional/cxx_type_traits_polyfill.h" - std::vector composite_key_columns_names() const { - std::vector res; - this->for_each_primary_key([this, &res](auto& primaryKey) { - res = this->composite_key_columns_names(primaryKey); - }); - return res; - } +// #include "tuple_helper/tuple_filter.h" - std::vector primary_key_column_names() const { - using pkcol_index_sequence = col_index_sequence_with; +// #include "tuple_helper/tuple_transformer.h" - if(pkcol_index_sequence::size() > 0) { - return create_from_tuple>(this->elements, - pkcol_index_sequence{}, - &column_identifier::name); - } else { - return this->composite_key_columns_names(); - } - } +#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" + +namespace sqlite_orm { - template - void for_each_primary_key_column(L&& lambda) const { - iterate_tuple(this->elements, - col_index_sequence_with{}, - call_as_template_base([&lambda](const auto& column) { - lambda(column.member_pointer); - })); - this->for_each_primary_key([&lambda](auto& primaryKey) { - iterate_tuple(primaryKey.columns, lambda); - }); - } + namespace internal { - template - std::vector composite_key_columns_names(const primary_key_t& primaryKey) const { - return create_from_tuple>(primaryKey.columns, - [this, empty = std::string{}](auto& memberPointer) { - if(const std::string* columnName = - this->find_column_name(memberPointer)) { - return *columnName; - } else { - return empty; - } - }); - } + namespace storage_traits { /** - * Searches column name by class member pointer passed as the first argument. - * @return column name or empty string if nothing found. + * DBO - db object (table) */ - template = true> - const std::string* find_column_name(M m) const { - const std::string* res = nullptr; - using field_type = member_field_type_t; - iterate_tuple(this->elements, - col_index_sequence_with_field_type{}, - [&res, m](auto& c) { - if(compare_any(c.member_pointer, m) || compare_any(c.setter, m)) { - res = &c.name; - } - }); - return res; - } + template + struct storage_mapped_columns_impl + : tuple_transformer, is_column>, field_type_t> {}; - /** - * 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->count_columns_amount(); -#endif - } + template<> + struct storage_mapped_columns_impl { + using type = std::tuple<>; + }; /** - * Counts and returns amount of columns. Skips constraints. + * DBOs - db_objects_tuple type + * Lookup - mapped or unmapped data type */ - constexpr int count_columns_amount() const { - using col_index_sequence = filter_tuple_sequence_t; - return int(col_index_sequence::size()); - } + template + struct storage_mapped_columns : storage_mapped_columns_impl> {}; + } + } +} - /** - * Call passed lambda with all defined foreign keys. - * @param lambda Lambda called for each column. Function signature: `void(auto& column)` - */ - template - void for_each_foreign_key(L&& lambda) const { - using fk_index_sequence = filter_tuple_sequence_t; - iterate_tuple(this->elements, fk_index_sequence{}, lambda); - } +// #include "function.h" - template - void for_each_foreign_key_to(L&& lambda) const { - using fk_index_sequence = filter_tuple_sequence_t; - using filtered_index_sequence = filter_tuple_sequence_t::template fn, - target_type_t, - fk_index_sequence>; - iterate_tuple(this->elements, filtered_index_sequence{}, lambda); - } +#include +#include +#include // std::string +#include // std::tuple +#include // std::function +#include // std::min +#include // std::move, std::forward - /** - * Call passed lambda with all defined columns. - * @param lambda Lambda called for each column. Function signature: `void(auto& column)` - */ - template - void for_each_column(L&& lambda) const { - using col_index_sequence = filter_tuple_sequence_t; - iterate_tuple(this->elements, col_index_sequence{}, lambda); - } +// #include "functional/cxx_universal.h" - /** - * Call passed lambda with columns not having the specified constraint trait `OpTrait`. - * @param lambda Lambda called for each column. - */ - template class OpTraitFn, class L> - void for_each_column_excluding(L&& lambda) const { - iterate_tuple(this->elements, col_index_sequence_excluding{}, lambda); - } +// #include "functional/cxx_type_traits_polyfill.h" - /** - * Call passed lambda with columns not having the specified constraint trait `OpTrait`. - * @param lambda Lambda called for each column. - */ - template = true> - void for_each_column_excluding(L&& lambda) const { - this->for_each_column_excluding(lambda); - } +namespace sqlite_orm { - std::vector get_table_info() const; + struct arg_values; + + template + struct pointer_arg; + template + class pointer_binding; + + namespace internal { + + struct user_defined_function_base { + using func_call = std::function< + void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; + using final_call = std::function; + + std::string name; + int argumentsCount = 0; + std::function create; + void (*destroy)(int*) = nullptr; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + user_defined_function_base(decltype(name) name_, + decltype(argumentsCount) argumentsCount_, + decltype(create) create_, + decltype(destroy) destroy_) : + name(std::move(name_)), + argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} +#endif + }; + + struct user_defined_scalar_function_t : user_defined_function_base { + func_call run; + + user_defined_scalar_function_t(decltype(name) name_, + int argumentsCount_, + decltype(create) create_, + decltype(run) run_, + decltype(destroy) destroy_) : + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + run(std::move(run_)) {} + }; + + struct user_defined_aggregate_function_t : user_defined_function_base { + func_call step; + final_call finalCall; + + user_defined_aggregate_function_t(decltype(name) name_, + int argumentsCount_, + decltype(create) create_, + decltype(step) step_, + decltype(finalCall) finalCall_, + decltype(destroy) destroy_) : + user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, + step(std::move(step_)), finalCall(std::move(finalCall_)) {} }; + template + using scalar_call_function_t = decltype(&F::operator()); + + template + using aggregate_step_function_t = decltype(&F::step); + + template + using aggregate_fin_function_t = decltype(&F::fin); + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v>> = + true; + + template + SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v = false; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v< + F, + polyfill::void_t, + aggregate_fin_function_t, + std::enable_if_t>::value>, + std::enable_if_t>::value>>> = + true; + template - struct is_table : std::false_type {}; + struct member_function_arguments; - template - struct is_table> : std::true_type {}; - } + template + struct member_function_arguments { + using member_function_type = R (O::*)(Args...) const; + using tuple_type = std::tuple...>; + using return_type = R; + }; - /** - * Factory function for a table definition. - * - * The mapped object type is determined implicitly from the first column definition. - */ - template>::object_type> - internal::table_t make_table(std::string name, Cs... args) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(args)...)}); - } + template + struct member_function_arguments { + using member_function_type = R (O::*)(Args...); + using tuple_type = std::tuple...>; + using return_type = R; + }; - /** - * Factory function for a table definition. - * - * The mapped object type is explicitly specified. - */ - template - internal::table_t make_table(std::string name, Cs... args) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(args)...)}); - } -} -#pragma once + template + struct callable_arguments_impl; -#include // std::string + template + struct callable_arguments_impl>> { + using args_tuple = typename member_function_arguments>::tuple_type; + using return_type = typename member_function_arguments>::return_type; + }; -// #include "functional/cxx_universal.h" -// ::nullptr_t -// #include "functional/static_magic.h" + template + struct callable_arguments_impl>> { + using args_tuple = typename member_function_arguments>::tuple_type; + using return_type = typename member_function_arguments>::return_type; + }; -// #include "tuple_helper/tuple_filter.h" + template + struct callable_arguments : callable_arguments_impl {}; -// #include "tuple_helper/tuple_iteration.h" + template + struct function_call { + using function_type = F; + using args_tuple = std::tuple; -// #include "type_traits.h" + args_tuple args; + }; -// #include "select_constraints.h" + template + struct unpacked_arg { + using type = T; + }; + template + struct unpacked_arg> { + using type = typename callable_arguments::return_type; + }; + template + using unpacked_arg_t = typename unpacked_arg::type; -// #include "storage_lookup.h" + template + SQLITE_ORM_CONSTEVAL bool expected_pointer_value() { + static_assert(polyfill::always_false_v, "Expected a pointer value for I-th argument"); + return false; + } -// interface functions -namespace sqlite_orm { - namespace internal { + template + constexpr bool is_same_pvt_v = expected_pointer_value(); - template - using tables_index_sequence = filter_tuple_sequence_t; + // Always allow binding nullptr to a pointer argument + template + constexpr bool is_same_pvt_v> = true; - template = true> - 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(); - }); - return res; +#if __cplusplus >= 201703L // C++17 or later + template + SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { + constexpr bool valid = Binding == PointerArg; + static_assert(valid, "Pointer value types of I-th argument do not match"); + return valid; } - template> - auto lookup_table(const DBOs& dbObjects) { - return static_if>( - [](const auto& dbObjects) { - return &pick_table(dbObjects); - }, - empty_callable())(dbObjects); + template + constexpr bool + is_same_pvt_v> = + assert_same_pointer_type(); +#else + template + SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { + constexpr bool valid = Binding::value == PointerArg::value; + static_assert(valid, "Pointer value types of I-th argument do not match"); + return valid; } - template> - decltype(auto) lookup_table_name(const DBOs& dbObjects) { - return static_if>( - [](const auto& dbObjects) -> const std::string& { - return pick_table(dbObjects).name; - }, - empty_callable())(dbObjects); - } + template + constexpr bool + is_same_pvt_v> = + assert_same_pointer_type(); +#endif - /** - * Find column name by its type and member pointer. - */ - template = true> - const std::string* find_column_name(const DBOs& dbObjects, F O::*field) { - return pick_table(dbObjects).find_column_name(field); + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) { + return true; } - /** - * Materialize column pointer: - * 1. by explicit object type and member pointer. - */ - template = true> - constexpr decltype(auto) materialize_column_pointer(const DBOs&, const column_pointer& cp) { - return cp.field; + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) { + return is_same_pvt_v; } - /** - * Find column name by: - * 1. by explicit object type and member pointer. - */ - template = true> - const std::string* find_column_name(const DBOs& dbObjects, const column_pointer& cp) { - auto field = materialize_column_pointer(dbObjects, cp); - return pick_table(dbObjects).find_column_name(field); + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { + return true; } - } -} -#pragma once + template + SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { + using func_arg_t = std::tuple_element_t; + using passed_arg_t = unpacked_arg_t>; -#include // std::string +#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED + constexpr bool valid = validate_pointer_value_type, + unpacked_arg_t>>( + polyfill::bool_constant < (polyfill::is_specialization_of_v) || + (polyfill::is_specialization_of_v) > {}); -// #include "constraints.h" + return validate_pointer_value_types(polyfill::index_constant{}) && valid; +#else + return validate_pointer_value_types(polyfill::index_constant{}) && + validate_pointer_value_type, + unpacked_arg_t>>( + polyfill::bool_constant < (polyfill::is_specialization_of_v) || + (polyfill::is_specialization_of_v) > {}); +#endif + } + } -// #include "serializer_context.h" + /** + * Used to call user defined function: `func(...);` + */ + template + internal::function_call func(Args... args) { + using args_tuple = std::tuple; + using function_args_tuple = typename internal::callable_arguments::args_tuple; + constexpr auto argsCount = std::tuple_size::value; + constexpr auto functionArgsCount = std::tuple_size::value; + static_assert((argsCount == functionArgsCount && + !std::is_same>::value && + internal::validate_pointer_value_types( + polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || + std::is_same>::value, + "Number of arguments does not match"); + return {std::make_tuple(std::forward(args)...)}; + } -// #include "storage_lookup.h" +} namespace sqlite_orm { namespace internal { - template - std::string serialize(const T& t, const serializer_context& context); - /** - * Serialize default value of a column's default valu + * Obains the result type of expressions that form the columns of a select statement. + * + * This is a proxy class used to define what type must have result type depending on select + * arguments (member pointer, aggregate functions, etc). Below you can see specializations + * for different types. E.g. specialization for internal::length_t has `type` int cause + * LENGTH returns INTEGER in sqlite. Every column_result_t must have `type` type that equals + * c++ SELECT return type for T + * DBOs - db_objects_tuple type + * T - C++ type + * SFINAE - sfinae argument + * + * Note (implementation): could be possibly implemented by utilizing column_expression_of_t */ - template - std::string serialize_default_value(const default_t& dft) { - db_objects_tuple<> dbObjects; - serializer_context> context{dbObjects}; - return serialize(dft.value, context); - } - - } + template + struct column_result_t; -} -#pragma once + template + using column_result_of_t = typename column_result_t::type; -#include -#include // std::unique_ptr/shared_ptr, std::make_unique/std::make_shared -#include // std::system_error -#include // std::string -#include // std::remove_reference, std::is_base_of, std::decay, std::false_type, std::true_type -#include // std::identity -#include // std::stringstream -#include // std::map -#include // std::vector -#include // std::tuple_size, std::tuple, std::make_tuple, std::tie -#include // std::forward, std::pair -#include // std::for_each, std::ranges::for_each -// #include "functional/cxx_optional.h" +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + template + struct column_result_t, void> { + using type = std::optional>; + }; -// #include "functional/cxx_universal.h" + template + struct column_result_t, void> { + using type = std::optional; + }; +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED -// #include "functional/cxx_functional_polyfill.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "functional/static_magic.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "functional/mpl.h" + template + struct column_result_t> : member_field_type {}; -// #include "tuple_helper/tuple_traits.h" + template + struct column_result_t, void> { + using type = R; + }; -// #include "tuple_helper/tuple_filter.h" + template + struct column_result_t, void> { + using type = R; + }; -// #include "tuple_helper/tuple_iteration.h" + template + struct column_result_t, void> { + using type = typename callable_arguments::return_type; + }; -// #include "type_traits.h" + template + struct column_result_t, S, X, Rest...>, void> { + using type = std::unique_ptr>; + }; -// #include "alias.h" + template + struct column_result_t, S, X>, void> { + using type = std::unique_ptr>; + }; -// #include "row_extractor_builder.h" + template + struct column_result_t, void> { + using type = int; + }; -// #include "functional/cxx_universal.h" + template + struct column_result_t { + using type = nullptr_t; + }; -// #include "row_extractor.h" + template + struct column_result_t { + using type = int; + }; -// #include "mapped_row_extractor.h" + template + struct column_result_t, void> : column_result_t {}; -#include + template + struct column_result_t, void> : column_result_t {}; -// #include "object_from_column_builder.h" + template + struct column_result_t, void> { + using type = std::string; + }; -#include -#include // std::is_member_object_pointer + template + struct column_result_t, void> { + using type = double; + }; -// #include "functional/static_magic.h" + template + struct column_result_t, void> { + using type = double; + }; -// #include "row_extractor.h" + template + struct column_result_t, void> { + using type = double; + }; -namespace sqlite_orm { + template + struct column_result_t, void> { + using type = double; + }; - namespace internal { + template + struct column_result_t, void> { + using type = double; + }; - struct object_from_column_builder_base { - sqlite3_stmt* stmt = nullptr; - int index = 0; + template + struct column_result_t, void> { + using type = int; + }; -#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - object_from_column_builder_base(sqlite3_stmt* stmt) : stmt{stmt} {} -#endif + template + struct column_result_t, void> { + using type = int; }; - /** - * This is a cute lambda replacement which is used in several places. - */ - template - struct object_from_column_builder : object_from_column_builder_base { - using object_type = O; + template + struct column_result_t, void> { + using type = int; + }; - object_type& object; + template + struct column_result_t, void> { + using type = int; + }; - object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : - object_from_column_builder_base{stmt_}, object(object_) {} + template + struct column_result_t, void> { + using type = int; + }; - template - void operator()(const column_field& column) { - auto value = row_extractor>().extract(this->stmt, this->index++); - static_if::value>( - [&value, &object = this->object](const auto& column) { - object.*column.member_pointer = std::move(value); - }, - [&value, &object = this->object](const auto& column) { - (object.*column.setter)(std::move(value)); - })(column); - } + template + struct column_result_t { + using type = int64; }; - } -} -namespace sqlite_orm { + template + struct column_result_t { + using type = int64; + }; - namespace internal { + template + struct column_result_t { + using type = int64; + }; - /** - * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. - * Main difference from regular `row_extractor` is that this class takes table info which is required - * for constructing objects by member pointers. To construct please use `make_row_extractor()`. - * Type arguments: - * V is value type just like regular `row_extractor` has - * T is table info class `table_t` - */ - template - struct mapped_row_extractor { - using table_type = Table; + template + struct column_result_t, void> { + using type = int64; + }; - V extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { - V res; - object_from_column_builder builder{res, stmt}; - this->tableInfo.for_each_column(builder); - return res; - } + template + struct column_result_t, void> { + using type = int64; + }; - const table_type& tableInfo; + template + struct column_result_t, void> { + using type = int64; }; - } + template + struct column_result_t, void> : column_result_t {}; -} + template + struct column_result_t, void> : column_result_t {}; -namespace sqlite_orm { + template + struct column_result_t, void> { + using type = tuple_cat_t>>...>; + }; - namespace internal { + template + struct column_result_t> : column_result_t {}; - template - row_extractor make_row_extractor(nullptr_t) { - return {}; - } + template + struct column_result_t>> { + using left_result = column_result_of_t; + using right_result = column_result_of_t; + static_assert(std::is_same::value, + "Compound subselect queries must return same types"); + using type = left_result; + }; - template - mapped_row_extractor make_row_extractor(const Table* table) { - return {*table}; - } - } + template + struct column_result_t>> { + using type = typename T::result_type; + }; -} + /** + * Result for the most simple queries like `SELECT 1` + */ + template + struct column_result_t> { + using type = T; + }; -// #include "error_code.h" + /** + * Result for the most simple queries like `SELECT 'ototo'` + */ + template + struct column_result_t { + using type = std::string; + }; -// #include "type_printer.h" + template + struct column_result_t { + using type = std::string; + }; -// #include "constraints.h" + template + struct column_result_t, void> : column_result_t> {}; -// #include "field_printer.h" + template + struct column_result_t, void> + : storage_traits::storage_mapped_columns> {}; -// #include "rowid.h" + template + struct column_result_t, void> { + using type = T; + }; -// #include "operators.h" + template + struct column_result_t, void> { + using type = T; + }; -// #include "select_constraints.h" + template + struct column_result_t, void> { + using type = R; + }; -// #include "core_functions.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "conditions.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "statement_binder.h" + template + struct column_result_t, void> { + using type = bool; + }; -// #include "column_result.h" + template + struct column_result_t, void> : column_result_t {}; + } +} // #include "mapped_type_proxy.h" @@ -18885,6 +18903,19 @@ namespace sqlite_orm { } #pragma once +#include // std::is_same, std::decay, std::remove_reference +#include // std::get + +// #include "functional/cxx_universal.h" +// ::size_t +// #include "functional/static_magic.h" + +// #include "prepared_statement.h" + +// #include "ast_iterator.h" + +// #include "node_tuple.h" + #include // std::enable_if #include // std::tuple #include // std::pair @@ -19217,15 +19248,6 @@ namespace sqlite_orm { }; } } -#pragma once - -#include // std::is_same, std::decay, std::remove_reference - -// #include "functional/static_magic.h" - -// #include "prepared_statement.h" - -// #include "ast_iterator.h" // #include "expression_object_type.h" diff --git a/not_single_header_include/sqlite_orm/sqlite_orm.h b/not_single_header_include/sqlite_orm/sqlite_orm.h index c01387366..0ca270086 100644 --- a/not_single_header_include/sqlite_orm/sqlite_orm.h +++ b/not_single_header_include/sqlite_orm/sqlite_orm.h @@ -1,6 +1,9 @@ #pragma once #include "../../dev/functional/start_macros.h" +// though each header is required to include everything it needs +// we include the configuration and all underlying c++ core features in order to make it universally available +#include "../../dev/functional/config.h" #include "../../dev/type_traits.h" #include "../../dev/error_code.h" #include "../../dev/type_printer.h" @@ -23,14 +26,11 @@ #include "../../dev/row_extractor.h" #include "../../dev/sync_schema_result.h" #include "../../dev/index.h" -#include "../../dev/mapped_type_proxy.h" #include "../../dev/rowid.h" -#include "../../dev/column_result.h" #include "../../dev/table.h" #include "../../dev/storage_impl.h" #include "../../dev/default_value_extractor.h" #include "../../dev/storage.h" -#include "../../dev/node_tuple.h" #include "../../dev/get_prepared_statement.h" #include "../../dev/carray.h" #include "../../dev/dbstat.h" diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 7473868af..0118faa73 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -281,7 +281,7 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(int)); iterate_ast(expression, lambda); } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES { SECTION("direct") { auto expression = "a"_col > c(0); @@ -303,7 +303,7 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(alias_column_t, column_pointer>)); iterate_ast(expression, lambda); } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES SECTION("aliased regular column 2") { constexpr auto z_alias = "z"_alias.for_(); auto expression = z_alias->*&User::id; diff --git a/tests/statement_serializer_tests/select_constraints.cpp b/tests/statement_serializer_tests/select_constraints.cpp index 6e3038c2b..2bc4b5747 100644 --- a/tests/statement_serializer_tests/select_constraints.cpp +++ b/tests/statement_serializer_tests/select_constraints.cpp @@ -71,7 +71,7 @@ TEST_CASE("statement_serializer select constraints") { value = serialize(expression, context); expected = R"(FROM "users" "u")"; } -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES { SECTION("with alias 2") { auto expression = from.for_()>(); diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp index caf969dad..e176f81ad 100644 --- a/tests/static_tests/alias.cpp +++ b/tests/static_tests/alias.cpp @@ -28,7 +28,7 @@ TEST_CASE("aliases") { SECTION("column alias expressions") { runTest>>(get()); runTest, int User::*>>(as(&User::id)); -#ifdef SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES runTest>>(get<"a"_col>()); runTest>("a"_col); runTest, int User::*>>(&User::id >>= "a"_col); diff --git a/third_party/amalgamate/config.json b/third_party/amalgamate/config.json index 95eed5962..11a7c2399 100755 --- a/third_party/amalgamate/config.json +++ b/third_party/amalgamate/config.json @@ -3,6 +3,7 @@ "target": "include/sqlite_orm/sqlite_orm.h", "sources": [ "dev/functional/start_macros.h", + "dev/functional/config.h", "dev/type_traits.h", "dev/error_code.h", "dev/type_printer.h", @@ -27,14 +28,11 @@ "dev/util.h", "dev/sync_schema_result.h", "dev/index.h", - "dev/mapped_type_proxy.h", "dev/rowid.h", - "dev/column_result.h", "dev/table.h", "dev/storage_impl.h", "dev/default_value_extractor.h", "dev/storage.h", - "dev/node_tuple.h", "dev/get_prepared_statement.h", "dev/carray.h", "dev/dbstat.h", From 1016f5babc9ebce128f79a49275e263c61e6b4dd Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 23:33:42 +0200 Subject: [PATCH 042/100] Concepts for C++20 based aliases --- dev/alias.h | 18 ++++++-------- dev/alias_traits.h | 13 +++++++++- dev/conditions.h | 10 ++++---- dev/select_constraints.h | 2 +- include/sqlite_orm/sqlite_orm.h | 43 ++++++++++++++++++++------------- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 82a38d34b..32978407e 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -159,20 +159,18 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template, - std::enable_if_t, bool> = true> + template auto alias_column(C c) { + using A = std::remove_const_t; using table_type = internal::type_t; static_assert(std::is_same_v, table_type>, "Column must be from aliased table"); return internal::alias_column_t{c}; } - template, bool> = true> - constexpr auto operator->*(const A& /*tableAlias*/, F field) { - return alias_column(std::move(field)); + template + constexpr auto operator->*(const A&, F field) { + return internal::alias_column_t{field}; } #endif @@ -185,7 +183,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto as(E expression) { return internal::as_t, E>{std::move(expression)}; } @@ -193,7 +191,7 @@ namespace sqlite_orm { /** * Alias a column expression. */ - template = true> + template internal::as_t operator>>=(E expression, const A&) { return {std::move(expression)}; } @@ -205,7 +203,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto get() { return internal::alias_holder>{}; } diff --git a/dev/alias_traits.h b/dev/alias_traits.h index dd959cf9f..71a554747 100644 --- a/dev/alias_traits.h +++ b/dev/alias_traits.h @@ -55,10 +55,21 @@ namespace sqlite_orm { */ template SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< - std::is_base_of, + is_recordset_alias, polyfill::negation, std::remove_const_t>>>; template using is_table_alias = polyfill::bool_constant>; } + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + concept orm_column_alias = internal::is_column_alias_v; + + template + concept orm_recordset_alias = internal::is_recordset_alias_v; + + template + concept orm_table_alias = internal::is_table_alias_v; +#endif } diff --git a/dev/conditions.h b/dev/conditions.h index 022b896d1..827795813 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -824,7 +824,7 @@ namespace sqlite_orm { * Explicit FROM function. Usage: * `storage.select(&User::id, from<"a"_alias.for_>());` */ - template + template auto from() { static_assert(sizeof...(tables) > 0); return internal::from_t...>{}; @@ -1029,7 +1029,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto left_join(O o) { return internal::left_join_t, O>{std::move(o)}; } @@ -1041,7 +1041,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto join(O o) { return internal::join_t, O>{std::move(o)}; } @@ -1053,7 +1053,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto left_outer_join(O o) { return internal::left_outer_join_t, O>{std::move(o)}; } @@ -1065,7 +1065,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto inner_join(O o) { return internal::inner_join_t, O>{std::move(o)}; } diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 32551c6b4..00eea2672 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -410,7 +410,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto asterisk(bool definedOrder = false) { return internal::asterisk_t>{definedOrder}; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index db3e0deeb..a92bfb9d7 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -2774,12 +2774,23 @@ namespace sqlite_orm { */ template SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< - std::is_base_of, + is_recordset_alias, polyfill::negation, std::remove_const_t>>>; template using is_table_alias = polyfill::bool_constant>; } + +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES + template + concept orm_column_alias = internal::is_column_alias_v; + + template + concept orm_recordset_alias = internal::is_recordset_alias_v; + + template + concept orm_table_alias = internal::is_table_alias_v; +#endif } // #include "expression.h" @@ -3691,7 +3702,7 @@ namespace sqlite_orm { * Explicit FROM function. Usage: * `storage.select(&User::id, from<"a"_alias.for_>());` */ - template + template auto from() { static_assert(sizeof...(tables) > 0); return internal::from_t...>{}; @@ -3896,7 +3907,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto left_join(O o) { return internal::left_join_t, O>{std::move(o)}; } @@ -3908,7 +3919,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto join(O o) { return internal::join_t, O>{std::move(o)}; } @@ -3920,7 +3931,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto left_outer_join(O o) { return internal::left_outer_join_t, O>{std::move(o)}; } @@ -3932,7 +3943,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto inner_join(O o) { return internal::inner_join_t, O>{std::move(o)}; } @@ -4350,20 +4361,18 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template, - std::enable_if_t, bool> = true> + template auto alias_column(C c) { + using A = std::remove_const_t; using table_type = internal::type_t; static_assert(std::is_same_v, table_type>, "Column must be from aliased table"); return internal::alias_column_t{c}; } - template, bool> = true> - constexpr auto operator->*(const A& /*tableAlias*/, F field) { - return alias_column(std::move(field)); + template + constexpr auto operator->*(const A&, F field) { + return internal::alias_column_t{field}; } #endif @@ -4376,7 +4385,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto as(E expression) { return internal::as_t, E>{std::move(expression)}; } @@ -4384,7 +4393,7 @@ namespace sqlite_orm { /** * Alias a column expression. */ - template = true> + template internal::as_t operator>>=(E expression, const A&) { return {std::move(expression)}; } @@ -4396,7 +4405,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto get() { return internal::alias_holder>{}; } @@ -7277,7 +7286,7 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template = true> + template auto asterisk(bool definedOrder = false) { return internal::asterisk_t>{definedOrder}; } From 024534abfa9c497579355b9b3595338a700e1bf9 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 15 Feb 2023 23:55:02 +0200 Subject: [PATCH 043/100] Moved textual replacement macros to functional/config.h --- dev/functional/config.h | 18 +++++++++++++++++ dev/functional/cxx_core_features.h | 14 ++----------- include/sqlite_orm/sqlite_orm.h | 32 +++++++++++++++++++----------- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/dev/functional/config.h b/dev/functional/config.h index c4da4fff0..1b74e89e2 100644 --- a/dev/functional/config.h +++ b/dev/functional/config.h @@ -2,6 +2,24 @@ #include "cxx_universal.h" +#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED +#define SQLITE_ORM_INLINE_VAR inline +#else +#define SQLITE_ORM_INLINE_VAR +#endif + +#if SQLITE_ORM_HAS_CPP_ATTRIBUTE(no_unique_address) >= 201803L +#define SQLITE_ORM_NOUNIQUEADDRESS [[no_unique_address]] +#else +#define SQLITE_ORM_NOUNIQUEADDRESS +#endif + +#ifdef SQLITE_ORM_CONSTEVAL_SUPPORTED +#define SQLITE_ORM_CONSTEVAL consteval +#else +#define SQLITE_ORM_CONSTEVAL constexpr +#endif + #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && \ defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) #define SQLITE_ORM_WITH_CPP20_ALIASES diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index c4bf9b6a1..5d16e913b 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -46,9 +46,7 @@ #endif #if __cpp_inline_variables >= 201606L -#define SQLITE_ORM_INLINE_VAR inline -#else -#define SQLITE_ORM_INLINE_VAR +#define SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #endif #if __cpp_generic_lambdas >= 201707L @@ -56,16 +54,8 @@ #else #endif -#if SQLITE_ORM_HAS_CPP_ATTRIBUTE(no_unique_address) >= 201803L -#define SQLITE_ORM_NOUNIQUEADDRESS [[no_unique_address]] -#else -#define SQLITE_ORM_NOUNIQUEADDRESS -#endif - #if __cpp_consteval >= 201811L -#define SQLITE_ORM_CONSTEVAL consteval -#else -#define SQLITE_ORM_CONSTEVAL constexpr +#define SQLITE_ORM_CONSTEVAL_SUPPORTED #endif #if __cpp_aggregate_paren_init >= 201902L diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index a92bfb9d7..cec8745a2 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -74,9 +74,7 @@ using std::nullptr_t; #endif #if __cpp_inline_variables >= 201606L -#define SQLITE_ORM_INLINE_VAR inline -#else -#define SQLITE_ORM_INLINE_VAR +#define SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #endif #if __cpp_generic_lambdas >= 201707L @@ -84,16 +82,8 @@ using std::nullptr_t; #else #endif -#if SQLITE_ORM_HAS_CPP_ATTRIBUTE(no_unique_address) >= 201803L -#define SQLITE_ORM_NOUNIQUEADDRESS [[no_unique_address]] -#else -#define SQLITE_ORM_NOUNIQUEADDRESS -#endif - #if __cpp_consteval >= 201811L -#define SQLITE_ORM_CONSTEVAL consteval -#else -#define SQLITE_ORM_CONSTEVAL constexpr +#define SQLITE_ORM_CONSTEVAL_SUPPORTED #endif #if __cpp_aggregate_paren_init >= 201902L @@ -150,6 +140,24 @@ using std::nullptr_t; #define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED #endif +#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED +#define SQLITE_ORM_INLINE_VAR inline +#else +#define SQLITE_ORM_INLINE_VAR +#endif + +#if SQLITE_ORM_HAS_CPP_ATTRIBUTE(no_unique_address) >= 201803L +#define SQLITE_ORM_NOUNIQUEADDRESS [[no_unique_address]] +#else +#define SQLITE_ORM_NOUNIQUEADDRESS +#endif + +#ifdef SQLITE_ORM_CONSTEVAL_SUPPORTED +#define SQLITE_ORM_CONSTEVAL consteval +#else +#define SQLITE_ORM_CONSTEVAL constexpr +#endif + #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && \ defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) #define SQLITE_ORM_WITH_CPP20_ALIASES From a7ddd20d4b877a27ebd8ade80ce7e5396723fcb9 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 16 Feb 2023 13:08:04 +0200 Subject: [PATCH 044/100] Improved concepts for C++20 based aliases --- dev/alias_traits.h | 67 +++++++++++++++----------- dev/functional/config.h | 12 ++++- dev/type_traits.h | 8 ++++ include/sqlite_orm/sqlite_orm.h | 84 ++++++++++++++++++++++----------- tests/static_tests/alias.cpp | 4 +- 5 files changed, 116 insertions(+), 59 deletions(-) diff --git a/dev/alias_traits.h b/dev/alias_traits.h index 71a554747..1458c91e3 100644 --- a/dev/alias_traits.h +++ b/dev/alias_traits.h @@ -1,15 +1,17 @@ #pragma once #include // std::remove_const, std::is_base_of, std::is_same +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES +#include +#endif #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "type_traits.h" namespace sqlite_orm { - /** - * Base class for a custom table alias, column alias or expression alias. - * For more information please look through self_join.cpp example + /** @short Base class for a custom table alias, column alias or expression alias. */ struct alias_tag {}; @@ -21,24 +23,16 @@ namespace sqlite_orm { template using is_alias = polyfill::bool_constant>; - /** Alias for a column in a record set. - * - * A column alias has the following traits: - * - is derived from `alias_tag` - * - * @note: Currently, there is no distinguishing property of a column alias other than that it is derived from "alias_tag". + /** @short Alias of a column in a record set, see `orm_column_alias`. */ template - SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = is_alias_v; + SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = + polyfill::conjunction_v, polyfill::negation>>; template using is_column_alias = is_alias; - /** Alias for any type of record set. - * - * A record set alias has the following traits: - * - is derived from `alias_tag`. - * - has a `type` typename, which refers to a mapped object. + /** @short Alias of any type of record set, see `orm_recordset_alias`. */ template SQLITE_ORM_INLINE_VAR constexpr bool is_recordset_alias_v = @@ -47,11 +41,7 @@ namespace sqlite_orm { template using is_recordset_alias = polyfill::bool_constant>; - /** Alias for a concrete table. - * - * A concrete table alias has the following traits: - * - is derived from `alias_tag`. - * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + /** @short Alias of a concrete table, see `orm_table_alias`. */ template SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< @@ -63,13 +53,34 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - concept orm_column_alias = internal::is_column_alias_v; - - template - concept orm_recordset_alias = internal::is_recordset_alias_v; - - template - concept orm_table_alias = internal::is_table_alias_v; + template + concept orm_alias = std::derived_from; + + /** @short Alias of a column in a record set. + * + * A column alias has the following traits: + * - is derived from `alias_tag` + * - must not have a nested `type` typename + */ + template + concept orm_column_alias = (orm_alias && !orm_names_type); + + /** @short Alias of any type of record set. + * + * A record set alias has the following traits: + * - is derived from `alias_tag`. + * - has a nested `type` typename, which refers to a mapped object. + */ + template + concept orm_recordset_alias = (orm_alias && orm_names_type); + + /** @short Alias of a concrete table. + * + * A concrete table alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + */ + template + concept orm_table_alias = (orm_recordset_alias && !std::same_as>); #endif } diff --git a/dev/functional/config.h b/dev/functional/config.h index 1b74e89e2..75a928e7a 100644 --- a/dev/functional/config.h +++ b/dev/functional/config.h @@ -2,6 +2,10 @@ #include "cxx_universal.h" +#if SQLITE_ORM_HAS_INCLUDE() +#include +#endif + #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #define SQLITE_ORM_INLINE_VAR inline #else @@ -20,7 +24,11 @@ #define SQLITE_ORM_CONSTEVAL constexpr #endif -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && \ - defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && __cpp_lib_concepts >= 202002L +#define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#endif + +#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED)) && \ + (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) #define SQLITE_ORM_WITH_CPP20_ALIASES #endif diff --git a/dev/type_traits.h b/dev/type_traits.h index a3a162836..64bf1ccdb 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -1,6 +1,9 @@ #pragma once #include // std::enable_if, std::is_same +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES +#include +#endif #include "functional/cxx_type_traits_polyfill.h" @@ -58,4 +61,9 @@ namespace sqlite_orm { template using on_type_t = typename T::on_type; } + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + template + concept orm_names_type = requires { typename T::type; }; +#endif } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index cec8745a2..c2b0b9231 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -140,6 +140,10 @@ using std::nullptr_t; #define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED #endif +#if SQLITE_ORM_HAS_INCLUDE() +#include +#endif + #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #define SQLITE_ORM_INLINE_VAR inline #else @@ -158,13 +162,20 @@ using std::nullptr_t; #define SQLITE_ORM_CONSTEVAL constexpr #endif -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && \ - defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && __cpp_lib_concepts >= 202002L +#define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#endif + +#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED)) && \ + (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) #define SQLITE_ORM_WITH_CPP20_ALIASES #endif #pragma once #include // std::enable_if, std::is_same +#ifdef SQLITE_ORM_WITH_CPP20_ALIASES +#include +#endif // #include "functional/cxx_type_traits_polyfill.h" @@ -367,6 +378,11 @@ namespace sqlite_orm { template using on_type_t = typename T::on_type; } + +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED + template + concept orm_names_type = requires { typename T::type; }; +#endif } #pragma once @@ -2727,16 +2743,19 @@ 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 +#endif // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" +// #include "type_traits.h" + namespace sqlite_orm { - /** - * Base class for a custom table alias, column alias or expression alias. - * For more information please look through self_join.cpp example + /** @short Base class for a custom table alias, column alias or expression alias. */ struct alias_tag {}; @@ -2748,24 +2767,16 @@ namespace sqlite_orm { template using is_alias = polyfill::bool_constant>; - /** Alias for a column in a record set. - * - * A column alias has the following traits: - * - is derived from `alias_tag` - * - * @note: Currently, there is no distinguishing property of a column alias other than that it is derived from "alias_tag". + /** @short Alias of a column in a record set, see `orm_column_alias`. */ template - SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = is_alias_v; + SQLITE_ORM_INLINE_VAR constexpr bool is_column_alias_v = + polyfill::conjunction_v, polyfill::negation>>; template using is_column_alias = is_alias; - /** Alias for any type of record set. - * - * A record set alias has the following traits: - * - is derived from `alias_tag`. - * - has a `type` typename, which refers to a mapped object. + /** @short Alias of any type of record set, see `orm_recordset_alias`. */ template SQLITE_ORM_INLINE_VAR constexpr bool is_recordset_alias_v = @@ -2774,11 +2785,7 @@ namespace sqlite_orm { template using is_recordset_alias = polyfill::bool_constant>; - /** Alias for a concrete table. - * - * A concrete table alias has the following traits: - * - is derived from `alias_tag`. - * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + /** @short Alias of a concrete table, see `orm_table_alias`. */ template SQLITE_ORM_INLINE_VAR constexpr bool is_table_alias_v = polyfill::conjunction_v< @@ -2790,14 +2797,35 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - concept orm_column_alias = internal::is_column_alias_v; + template + concept orm_alias = std::derived_from; - template - concept orm_recordset_alias = internal::is_recordset_alias_v; + /** @short Alias of a column in a record set. + * + * A column alias has the following traits: + * - is derived from `alias_tag` + * - must not have a nested `type` typename + */ + template + concept orm_column_alias = (orm_alias && !orm_names_type); - template - concept orm_table_alias = internal::is_table_alias_v; + /** @short Alias of any type of record set. + * + * A record set alias has the following traits: + * - is derived from `alias_tag`. + * - has a nested `type` typename, which refers to a mapped object. + */ + template + concept orm_recordset_alias = (orm_alias && orm_names_type); + + /** @short Alias of a concrete table. + * + * A concrete table alias has the following traits: + * - is derived from `alias_tag`. + * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). + */ + template + concept orm_table_alias = (orm_recordset_alias && !std::same_as>); #endif } diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp index e176f81ad..3cc390352 100644 --- a/tests/static_tests/alias.cpp +++ b/tests/static_tests/alias.cpp @@ -31,8 +31,10 @@ TEST_CASE("aliases") { #ifdef SQLITE_ORM_WITH_CPP20_ALIASES runTest>>(get<"a"_col>()); runTest>("a"_col); + runTest, int User::*>>(as<"a"_col>(&User::id)); runTest, int User::*>>(&User::id >>= "a"_col); - constexpr auto z_alias = alias_<'z'>.for_(); + runTest>(alias_<'z'>.for_()); + constexpr auto z_alias = "z"_alias.for_(); runTest>(z_alias); runTest, int User::*>>(alias_column(&User::id)); runTest, int User::*>>(z_alias->*&User::id); From f90cc41bd687087e23a8dec2252b40cf89cc60c8 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 16 Feb 2023 13:33:19 +0200 Subject: [PATCH 045/100] Cleaned up work on C++20 based aliases --- dev/alias.h | 17 +++++++---------- include/sqlite_orm/sqlite_orm.h | 17 +++++++---------- tests/static_tests/alias.cpp | 3 +++ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 32978407e..9ef6008f4 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -41,6 +41,7 @@ namespace sqlite_orm { /** * This is a common built-in class used for custom single character table aliases. * For convenience there exist public type aliases `alias_a`, `alias_b`, ... + * The easiest way to create a table alias is using `"z"_alias.for_()`. */ template struct table_alias : alias_tag { @@ -111,6 +112,7 @@ namespace sqlite_orm { /** * This is a common built-in class used for custom single-character column aliases. * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... + * The easiest way to create a column alias is using `"xyz"_col`. */ template struct column_alias : alias_tag { @@ -133,13 +135,8 @@ namespace sqlite_orm { "Table alias identifiers shall consist of a single alphabetic character, in order to evade " "clashes with CTE aliases."); - template - [[nodiscard]] consteval internal::table_alias, A, C...> for_() const { - return {}; - } - template - [[nodiscard]] consteval internal::table_alias for_() const { + [[nodiscard]] consteval table_alias for_() const { return {}; } }; @@ -152,8 +149,8 @@ namespace sqlite_orm { */ template, bool> = true> internal::alias_column_t alias_column(C c) { - using table_type = internal::type_t; - static_assert(std::is_same, table_type>::value, + using aliased_type = internal::type_t; + static_assert(std::is_same, aliased_type>::value, "Column must be from aliased table"); return {c}; } @@ -162,8 +159,8 @@ namespace sqlite_orm { template auto alias_column(C c) { using A = std::remove_const_t; - using table_type = internal::type_t; - static_assert(std::is_same_v, table_type>, + using aliased_type = internal::type_t; + static_assert(std::is_same_v, aliased_type>, "Column must be from aliased table"); return internal::alias_column_t{c}; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index c2b0b9231..bc43df9fc 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -4279,6 +4279,7 @@ namespace sqlite_orm { /** * This is a common built-in class used for custom single character table aliases. * For convenience there exist public type aliases `alias_a`, `alias_b`, ... + * The easiest way to create a table alias is using `"z"_alias.for_()`. */ template struct table_alias : alias_tag { @@ -4349,6 +4350,7 @@ namespace sqlite_orm { /** * This is a common built-in class used for custom single-character column aliases. * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... + * The easiest way to create a column alias is using `"xyz"_col`. */ template struct column_alias : alias_tag { @@ -4371,13 +4373,8 @@ namespace sqlite_orm { "Table alias identifiers shall consist of a single alphabetic character, in order to evade " "clashes with CTE aliases."); - template - [[nodiscard]] consteval internal::table_alias, A, C...> for_() const { - return {}; - } - template - [[nodiscard]] consteval internal::table_alias for_() const { + [[nodiscard]] consteval table_alias for_() const { return {}; } }; @@ -4390,8 +4387,8 @@ namespace sqlite_orm { */ template, bool> = true> internal::alias_column_t alias_column(C c) { - using table_type = internal::type_t; - static_assert(std::is_same, table_type>::value, + using aliased_type = internal::type_t; + static_assert(std::is_same, aliased_type>::value, "Column must be from aliased table"); return {c}; } @@ -4400,8 +4397,8 @@ namespace sqlite_orm { template auto alias_column(C c) { using A = std::remove_const_t; - using table_type = internal::type_t; - static_assert(std::is_same_v, table_type>, + using aliased_type = internal::type_t; + static_assert(std::is_same_v, aliased_type>, "Column must be from aliased table"); return internal::alias_column_t{c}; } diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp index 3cc390352..2be98bd91 100644 --- a/tests/static_tests/alias.cpp +++ b/tests/static_tests/alias.cpp @@ -28,6 +28,9 @@ TEST_CASE("aliases") { SECTION("column alias expressions") { runTest>>(get()); runTest, int User::*>>(as(&User::id)); + runTest, int User::*>>(alias_column>(&User::id)); + runTest, column_pointer>>( + alias_column>(column(&User::id))); #ifdef SQLITE_ORM_WITH_CPP20_ALIASES runTest>>(get<"a"_col>()); runTest>("a"_col); From 895239233e56b7da0c223db56ead6686a5b286cf Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 17:08:44 +0200 Subject: [PATCH 046/100] Dedicated type traits for compound, binary condition, built-in function --- dev/ast_iterator.h | 4 +- dev/column_result.h | 4 +- dev/conditions.h | 7 ++ dev/core_functions.h | 30 +++---- dev/node_tuple.h | 4 +- dev/select_constraints.h | 6 ++ dev/serializer_context.h | 3 + dev/statement_serializer.h | 16 ++-- dev/storage.h | 3 +- include/sqlite_orm/sqlite_orm.h | 152 +++++++++++++++++--------------- 10 files changed, 122 insertions(+), 107 deletions(-) diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 970519120..2cd7a2990 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -126,7 +126,7 @@ namespace sqlite_orm { }; template - struct ast_iterator>> { + struct ast_iterator> { using node_type = T; template @@ -202,7 +202,7 @@ namespace sqlite_orm { }; template - struct ast_iterator>> { + struct ast_iterator> { using node_type = T; template diff --git a/dev/column_result.h b/dev/column_result.h index 13010294e..c7235e7bc 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -214,7 +214,7 @@ namespace sqlite_orm { struct column_result_t> : column_result_t {}; template - struct column_result_t>> { + struct column_result_t> { using left_result = column_result_of_t; using right_result = column_result_of_t; static_assert(std::is_same::value, @@ -223,7 +223,7 @@ namespace sqlite_orm { }; template - struct column_result_t>> { + struct column_result_t> { using type = typename T::result_type; }; diff --git a/dev/conditions.h b/dev/conditions.h index 827795813..4aa13182f 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -8,6 +8,7 @@ #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" +#include "is_base_of_template.h" #include "type_traits.h" #include "collate_argument.h" #include "constraints.h" @@ -131,6 +132,12 @@ namespace sqlite_orm { binary_condition(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_binary_condition_v = is_base_of_template_v; + + template + using is_binary_condition = polyfill::bool_constant>; + struct and_condition_string { operator std::string() const { return "AND"; diff --git a/dev/core_functions.h b/dev/core_functions.h index 1c4a896d9..5461ada47 100644 --- a/dev/core_functions.h +++ b/dev/core_functions.h @@ -43,6 +43,12 @@ namespace sqlite_orm { built_in_function_t(args_type&& args_) : args(std::move(args_)) {} }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_built_in_function_v = is_base_of_template_v; + + template + using is_built_in_function = polyfill::bool_constant>; + template struct filtered_aggregate_function { using function_type = F; @@ -610,44 +616,32 @@ namespace sqlite_orm { /** * Cute operators for core functions */ - template, bool> = true> + template = true> internal::lesser_than_t operator<(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::lesser_or_equal_t operator<=(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::greater_than_t operator>(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::greater_or_equal_t operator>=(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::is_equal_t operator==(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::is_not_equal_t operator!=(F f, R r) { return {std::move(f), std::move(r)}; } diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 2a62d8aa3..3e07a82e4 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -91,7 +91,7 @@ namespace sqlite_orm { struct node_tuple, void> : node_tuple {}; template - struct node_tuple>> { + struct node_tuple> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; @@ -130,7 +130,7 @@ namespace sqlite_orm { }; template - struct node_tuple>> { + struct node_tuple> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 00eea2672..d8eb990d3 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -124,6 +124,12 @@ namespace sqlite_orm { } }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_compound_operator_v = is_base_of_template_v; + + template + using is_compound_operator = polyfill::bool_constant>; + struct union_base { bool all = false; diff --git a/dev/serializer_context.h b/dev/serializer_context.h index 8536f3d9f..c45f1a6f4 100644 --- a/dev/serializer_context.h +++ b/dev/serializer_context.h @@ -19,6 +19,9 @@ namespace sqlite_orm { serializer_context(const db_objects_type& dbObjects) : db_objects{dbObjects} {} }; + //template + //serializer_context(const DBOs&) -> serializer_context; + template struct serializer_context_builder { using storage_type = S; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 1190634d2..3d98ed045 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -498,7 +498,7 @@ namespace sqlite_orm { }; template - struct statement_serializer>> { + struct statement_serializer> { using statement_type = T; template @@ -587,7 +587,7 @@ namespace sqlite_orm { }; template - struct statement_serializer>> { + struct statement_serializer> { using statement_type = T; template @@ -647,14 +647,13 @@ namespace sqlite_orm { ss << "NOT IN"; } ss << " "; - constexpr bool isCompoundOperator = is_base_of_template_v; - if(isCompoundOperator) { + if(is_compound_operator_v) { ss << '('; } auto newContext = context; newContext.use_parentheses = true; ss << serialize(statement.argument, newContext); - if(isCompoundOperator) { + if(is_compound_operator_v) { ss << ')'; } return ss.str(); @@ -1493,8 +1492,7 @@ namespace sqlite_orm { context.skip_table_name = false; std::stringstream ss; - constexpr bool isCompoundOperator = is_base_of_template_v; - if(!isCompoundOperator) { + if(!is_compound_operator_v) { if(!sel.highest_level && context.use_parentheses) { ss << "("; } @@ -1517,12 +1515,12 @@ namespace sqlite_orm { alias_extractor::as_alias()}; tableNames.erase(tableNameWithAlias); }); - if(!tableNames.empty() && !isCompoundOperator) { + if(!tableNames.empty() && !is_compound_operator_v) { ss << " FROM " << streaming_identifiers(tableNames); } } ss << streaming_conditions_tuple(sel.conditions, context); - if(!is_base_of_template_v) { + if(!is_compound_operator_v) { if(!sel.highest_level && context.use_parentheses) { ss << ")"; } diff --git a/dev/storage.h b/dev/storage.h index 868d92023..fda117d5b 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -569,8 +569,7 @@ namespace sqlite_orm { */ template> std::vector select(T m, Args... args) { - static_assert(!is_base_of_template_v || - std::tuple_size>::value == 0, + static_assert(!is_compound_operator_v || sizeof...(Args) == 0, "Cannot use args with a compound operator"); auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); return this->execute(statement); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index bc43df9fc..1e1fd779d 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -2659,6 +2659,45 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" +// #include "is_base_of_template.h" + +#include // std::true_type, std::false_type, std::declval + +namespace sqlite_orm { + + namespace internal { + + /* + * This is because of bug in MSVC, for more information, please visit + * https://stackoverflow.com/questions/34672441/stdis-base-of-for-template-classes/34672753#34672753 + */ +#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION + template class Base> + struct is_base_of_template_impl { + template + static constexpr std::true_type test(const Base&); + + static constexpr std::false_type test(...); + }; + + template class C> + using is_base_of_template = decltype(is_base_of_template_impl::test(std::declval())); +#else + template class C, typename... Ts> + std::true_type is_base_of_template_impl(const C&); + + template class C> + std::false_type is_base_of_template_impl(...); + + template class C> + using is_base_of_template = decltype(is_base_of_template_impl(std::declval())); +#endif + + template class C> + SQLITE_ORM_INLINE_VAR constexpr bool is_base_of_template_v = is_base_of_template::value; + } +} + // #include "type_traits.h" // #include "collate_argument.h" @@ -2720,6 +2759,9 @@ namespace sqlite_orm { serializer_context(const db_objects_type& dbObjects) : db_objects{dbObjects} {} }; + //template + //serializer_context(const DBOs&) -> serializer_context; + template struct serializer_context_builder { using storage_type = S; @@ -3045,6 +3087,12 @@ namespace sqlite_orm { binary_condition(left_type l_, right_type r_) : l(std::move(l_)), r(std::move(r_)) {} }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_binary_condition_v = is_base_of_template_v; + + template + using is_binary_condition = polyfill::bool_constant>; + struct and_condition_string { operator std::string() const { return "AND"; @@ -4547,43 +4595,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" -#include // std::true_type, std::false_type, std::declval - -namespace sqlite_orm { - - namespace internal { - - /* - * This is because of bug in MSVC, for more information, please visit - * https://stackoverflow.com/questions/34672441/stdis-base-of-for-template-classes/34672753#34672753 - */ -#ifdef SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION - template class Base> - struct is_base_of_template_impl { - template - static constexpr std::true_type test(const Base&); - - static constexpr std::false_type test(...); - }; - - template class C> - using is_base_of_template = decltype(is_base_of_template_impl::test(std::declval())); -#else - template class C, typename... Ts> - std::true_type is_base_of_template_impl(const C&); - - template class C> - std::false_type is_base_of_template_impl(...); - - template class C> - using is_base_of_template = decltype(is_base_of_template_impl(std::declval())); -#endif - - template class C> - SQLITE_ORM_INLINE_VAR constexpr bool is_base_of_template_v = is_base_of_template::value; - } -} - // #include "tuple_helper/tuple_filter.h" // #include "serialize_result_type.h" @@ -4641,6 +4652,12 @@ namespace sqlite_orm { built_in_function_t(args_type&& args_) : args(std::move(args_)) {} }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_built_in_function_v = is_base_of_template_v; + + template + using is_built_in_function = polyfill::bool_constant>; + template struct filtered_aggregate_function { using function_type = F; @@ -5208,44 +5225,32 @@ namespace sqlite_orm { /** * Cute operators for core functions */ - template, bool> = true> + template = true> internal::lesser_than_t operator<(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::lesser_or_equal_t operator<=(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::greater_than_t operator>(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::greater_or_equal_t operator>=(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::is_equal_t operator==(F f, R r) { return {std::move(f), std::move(r)}; } - template, bool> = true> + template = true> internal::is_not_equal_t operator!=(F f, R r) { return {std::move(f), std::move(r)}; } @@ -7033,6 +7038,12 @@ namespace sqlite_orm { } }; + template + SQLITE_ORM_INLINE_VAR constexpr bool is_compound_operator_v = is_base_of_template_v; + + template + using is_compound_operator = polyfill::bool_constant>; + struct union_base { bool all = false; @@ -10940,7 +10951,7 @@ namespace sqlite_orm { struct column_result_t> : column_result_t {}; template - struct column_result_t>> { + struct column_result_t> { using left_result = column_result_of_t; using right_result = column_result_of_t; static_assert(std::is_same::value, @@ -10949,7 +10960,7 @@ namespace sqlite_orm { }; template - struct column_result_t>> { + struct column_result_t> { using type = typename T::result_type; }; @@ -12487,7 +12498,7 @@ namespace sqlite_orm { }; template - struct ast_iterator>> { + struct ast_iterator> { using node_type = T; template @@ -12563,7 +12574,7 @@ namespace sqlite_orm { }; template - struct ast_iterator>> { + struct ast_iterator> { using node_type = T; template @@ -15955,7 +15966,7 @@ namespace sqlite_orm { }; template - struct statement_serializer>> { + struct statement_serializer> { using statement_type = T; template @@ -16044,7 +16055,7 @@ namespace sqlite_orm { }; template - struct statement_serializer>> { + struct statement_serializer> { using statement_type = T; template @@ -16104,14 +16115,13 @@ namespace sqlite_orm { ss << "NOT IN"; } ss << " "; - constexpr bool isCompoundOperator = is_base_of_template_v; - if(isCompoundOperator) { + if(is_compound_operator_v) { ss << '('; } auto newContext = context; newContext.use_parentheses = true; ss << serialize(statement.argument, newContext); - if(isCompoundOperator) { + if(is_compound_operator_v) { ss << ')'; } return ss.str(); @@ -16950,8 +16960,7 @@ namespace sqlite_orm { context.skip_table_name = false; std::stringstream ss; - constexpr bool isCompoundOperator = is_base_of_template_v; - if(!isCompoundOperator) { + if(!is_compound_operator_v) { if(!sel.highest_level && context.use_parentheses) { ss << "("; } @@ -16974,12 +16983,12 @@ namespace sqlite_orm { alias_extractor::as_alias()}; tableNames.erase(tableNameWithAlias); }); - if(!tableNames.empty() && !isCompoundOperator) { + if(!tableNames.empty() && !is_compound_operator_v) { ss << " FROM " << streaming_identifiers(tableNames); } } ss << streaming_conditions_tuple(sel.conditions, context); - if(!is_base_of_template_v) { + if(!is_compound_operator_v) { if(!sel.highest_level && context.use_parentheses) { ss << ")"; } @@ -18076,8 +18085,7 @@ namespace sqlite_orm { */ template> std::vector select(T m, Args... args) { - static_assert(!is_base_of_template_v || - std::tuple_size>::value == 0, + static_assert(!is_compound_operator_v || sizeof...(Args) == 0, "Cannot use args with a compound operator"); auto statement = this->prepare(sqlite_orm::select(std::move(m), std::forward(args)...)); return this->execute(statement); @@ -19062,7 +19070,7 @@ namespace sqlite_orm { struct node_tuple, void> : node_tuple {}; template - struct node_tuple>> { + struct node_tuple> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; @@ -19101,7 +19109,7 @@ namespace sqlite_orm { }; template - struct node_tuple>> { + struct node_tuple> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; From 12d204e286542d40b085e8b8da6d3d0775c9ee86 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 17:12:09 +0200 Subject: [PATCH 047/100] C++14 appveyor test builds on Windows have been changed to use VS 2017 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4e0922596..004ebeb9b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,7 +36,7 @@ environment: cmake_build_parallel: "" # Representative for C++14 - - job_name: Visual Studio 2022, x64, C++14 + - job_name: Visual Studio 2017, x64, C++14 appveyor_build_worker_image: Visual Studio 2022 platform: x64 SQLITE_ORM_CXX_STANDARD: "" From 7d0ec0b63285470b7e9eb521fc2b89fb530b8ab4 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 18:09:53 +0200 Subject: [PATCH 048/100] Runner-up for appveyor test builds using VS 2017 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 004ebeb9b..301478cb1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ environment: # Representative for C++14 - job_name: Visual Studio 2017, x64, C++14 - appveyor_build_worker_image: Visual Studio 2022 + appveyor_build_worker_image: Visual Studio 2017 platform: x64 SQLITE_ORM_CXX_STANDARD: "" From 890700d03caab841a20611911eb1947419389c21 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 19:34:57 +0200 Subject: [PATCH 049/100] Runner-up 2 for appveyor test builds using VS 2017 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 301478cb1..6611caf38 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -92,7 +92,7 @@ for: # Windows matrix: only: - - appveyor_build_worker_image: Visual Studio 2015 + - appveyor_build_worker_image: Visual Studio 2017 - appveyor_build_worker_image: Visual Studio 2022 init: - |- From 383fc928517cdd1e42f1720781d9366b2956235e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 19:59:44 +0200 Subject: [PATCH 050/100] Runner-up 3 for appveyor test builds using VS 2017 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6611caf38..6404135ca 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -100,7 +100,7 @@ for: if "%platform%"=="x64" (set architecture=-A x64) if "%platform%"=="x86" (set architecture=-A Win32) if "%appveyor_build_worker_image%"=="Visual Studio 2022" (set generator="Visual Studio 17 2022" %architecture%) - if "%appveyor_build_worker_image%"=="Visual Studio 2015" (set generator="Visual Studio 14 2015" %architecture%) + if "%appveyor_build_worker_image%"=="Visual Studio 2017" (set generator="Visual Studio 15 2017" %architecture%) install: - |- cd C:\Tools\vcpkg From c3393af9b81d39db7a1e658a7a1c6dca893b2fc5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 20:57:40 +0200 Subject: [PATCH 051/100] CMake should prefer found Catch2 over building it from source --- CMakeLists.txt | 2 +- dependencies/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6626e2146..ff768c0cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.14.0) +cmake_minimum_required (VERSION 3.24.0) # PACKAGE_VERSION is used by cpack scripts currently # Both sqlite_orm_VERSION and PACKAGE_VERSION should be the same for now diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index c9ee443c0..598208613 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -5,6 +5,8 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.2.1 + # prefer find_package() over building from source + FIND_PACKAGE_ARGS ) add_subdirectory(catch2) endif() From 8b95c93b57d177841df4e046b5b8363fb85813dc Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 21:31:30 +0200 Subject: [PATCH 052/100] CMake (Windows): Suppress deprecation warning for unsecure CRT function --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff768c0cb..04d7274de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,10 @@ if (MSVC) if (MSVC_VERSION GREATER_EQUAL 1914) add_compile_options(/Zc:__cplusplus) endif() + # VC 2017 issues a deprecation warning for `strncpy` + if (MSVC_VERSION GREATER_EQUAL 1910) + add_compile_options(_CRT_SECURE_NO_WARNINGS) + end() add_compile_options(/MP) # multi-processor compilation if (CMAKE_CXX_STANDARD GREATER 14) add_compile_definitions(_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) From 17ea98e288ebe36f47673db3407f0eead2586e8e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 22:22:52 +0200 Subject: [PATCH 053/100] VC++ 2019 and earlier don't match differing partial specializations --- dev/ast_iterator.h | 19 ++++--------------- include/sqlite_orm/sqlite_orm.h | 19 ++++--------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 2cd7a2990..43281de35 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -678,27 +678,16 @@ namespace sqlite_orm { * Column alias or literal: skipped */ template - struct ast_iterator< - T, - std::enable_if_t, - polyfill::is_specialization_of>>> { + struct ast_iterator, + polyfill::is_specialization_of, + is_column_alias>>> { using node_type = T; template void operator()(const node_type& /*node*/, L& /*lambda*/) const {} }; - /** - * Column alias: skipped - */ - template - struct ast_iterator, void> { - using node_type = column_alias; - - template - void operator()(const node_type& /*node*/, L& /*lambda*/) const {} - }; - template struct ast_iterator, void> { using node_type = order_by_t; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 1e1fd779d..814a70185 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -13050,27 +13050,16 @@ namespace sqlite_orm { * Column alias or literal: skipped */ template - struct ast_iterator< - T, - std::enable_if_t, - polyfill::is_specialization_of>>> { + struct ast_iterator, + polyfill::is_specialization_of, + is_column_alias>>> { using node_type = T; template void operator()(const node_type& /*node*/, L& /*lambda*/) const {} }; - /** - * Column alias: skipped - */ - template - struct ast_iterator, void> { - using node_type = column_alias; - - template - void operator()(const node_type& /*node*/, L& /*lambda*/) const {} - }; - template struct ast_iterator, void> { using node_type = order_by_t; From 78a2e056cdf335ee6bdca4bb3e550e9a639c8c28 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 22:33:48 +0200 Subject: [PATCH 054/100] Fixed improperly ended if-condition in CMake file --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04d7274de..d9c714a45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,10 +59,10 @@ if (MSVC) if (MSVC_VERSION GREATER_EQUAL 1914) add_compile_options(/Zc:__cplusplus) endif() - # VC 2017 issues a deprecation warning for `strncpy` if (MSVC_VERSION GREATER_EQUAL 1910) + # VC 2017 issues a deprecation warning for `strncpy` add_compile_options(_CRT_SECURE_NO_WARNINGS) - end() + endif() add_compile_options(/MP) # multi-processor compilation if (CMAKE_CXX_STANDARD GREATER 14) add_compile_definitions(_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) From 8df4fb1a713e5ce183212b11eb6e6ac5f7da51a2 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 23:19:04 +0200 Subject: [PATCH 055/100] Use VC 2019 for appveyor builds due to more recent CMake dependency The appveyor Visual Studio 2017 build work image only comes with CMake 3.16. `FetchContent`'s `FIND_PACKAGE_ARGS` feature depends on CMake 3.24 --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 6404135ca..e5067d5cd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,8 +36,8 @@ environment: cmake_build_parallel: "" # Representative for C++14 - - job_name: Visual Studio 2017, x64, C++14 - appveyor_build_worker_image: Visual Studio 2017 + - job_name: Visual Studio 2019, x64, C++14 + appveyor_build_worker_image: Visual Studio 2019 platform: x64 SQLITE_ORM_CXX_STANDARD: "" @@ -92,7 +92,7 @@ for: # Windows matrix: only: - - appveyor_build_worker_image: Visual Studio 2017 + - appveyor_build_worker_image: Visual Studio 2019 - appveyor_build_worker_image: Visual Studio 2022 init: - |- @@ -100,7 +100,7 @@ for: if "%platform%"=="x64" (set architecture=-A x64) if "%platform%"=="x86" (set architecture=-A Win32) if "%appveyor_build_worker_image%"=="Visual Studio 2022" (set generator="Visual Studio 17 2022" %architecture%) - if "%appveyor_build_worker_image%"=="Visual Studio 2017" (set generator="Visual Studio 15 2017" %architecture%) + if "%appveyor_build_worker_image%"=="Visual Studio 2019" (set generator="Visual Studio 16 2019" %architecture%) install: - |- cd C:\Tools\vcpkg From d87938ef9b48204465030466b10955bd1b7dbb7f Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 17 Feb 2023 23:42:19 +0200 Subject: [PATCH 056/100] Pass `_CRT_SECURE_NO_WARNINGS` compile definition in a correct way --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d9c714a45..5e05ed59a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ if (MSVC) endif() if (MSVC_VERSION GREATER_EQUAL 1910) # VC 2017 issues a deprecation warning for `strncpy` - add_compile_options(_CRT_SECURE_NO_WARNINGS) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() add_compile_options(/MP) # multi-processor compilation if (CMAKE_CXX_STANDARD GREATER 14) From 5799d9b48ab92707faa2f0497ea154679332d6f2 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 21 Feb 2023 10:52:17 +0100 Subject: [PATCH 057/100] Resurrected arithmetic operator tests --- tests/operators/arithmetic_operators.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/operators/arithmetic_operators.cpp b/tests/operators/arithmetic_operators.cpp index 909cdd13c..c54e4a64b 100644 --- a/tests/operators/arithmetic_operators.cpp +++ b/tests/operators/arithmetic_operators.cpp @@ -35,11 +35,11 @@ TEST_CASE("Arithmetic operators") { } } { // + - auto rows = storage.select(c(&Object::nameLen) + 1000); + auto rows = storage.select(columns(c(&Object::nameLen) + 1000)); for(size_t i = 0; i < rows.size(); ++i) { auto& row = rows[i]; auto& name = names[i]; - REQUIRE(int(row) == name.length() + 1000); + REQUIRE(int(std::get<0>(row)) == name.length() + 1000); } } { // || @@ -71,11 +71,11 @@ TEST_CASE("Arithmetic operators") { } { // || std::string suffix = "ototo"; - auto rows = storage.select(conc(&Object::name, suffix)); + auto rows = storage.select(columns(conc(&Object::name, suffix))); for(size_t i = 0; i < rows.size(); ++i) { auto& row = rows[i]; auto& name = names[i]; - REQUIRE(row == name + suffix); + REQUIRE(std::get<0>(row) == name + suffix); } } { // different From 0d1b97f1590bbcf0f30e48188f6763a2fcd353fc Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 21 Feb 2023 11:07:16 +0100 Subject: [PATCH 058/100] Resolved things that were raised in the PR review --- dev/alias.h | 19 +++---- dev/conditions.h | 24 ++++---- dev/functional/config.h | 3 +- dev/select_constraints.h | 10 +++- examples/column_aliases.cpp | 7 ++- examples/custom_aliases.cpp | 2 +- include/sqlite_orm/sqlite_orm.h | 56 ++++++++++--------- .../select_constraints.cpp | 2 +- tests/static_tests/alias.cpp | 2 +- 9 files changed, 69 insertions(+), 56 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 9ef6008f4..967ee8bd0 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -6,7 +6,7 @@ #include // std::stringstream #include // std::copy_n -#include "functional/cxx_universal.h" +#include "functional/cxx_universal.h" // ::size_t #include "functional/cxx_type_traits_polyfill.h" #include "type_traits.h" #include "alias_traits.h" @@ -129,14 +129,10 @@ namespace sqlite_orm { }; #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template + template struct table_alias_builder { - static_assert(sizeof...(C) == 0 && ((A >= 'A' && 'Z' <= A) || (A >= 'a' && 'z' <= A)), - "Table alias identifiers shall consist of a single alphabetic character, in order to evade " - "clashes with CTE aliases."); - template - [[nodiscard]] consteval table_alias for_() const { + [[nodiscard]] consteval table_alias for_() const { return {}; } }; @@ -270,10 +266,13 @@ namespace sqlite_orm { using colalias_i = internal::column_alias<'i'>; #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** @short Create aliased tables e.g. `constexpr auto z_alias = alias_<'z'>.for_()`. + /** @short Create a table alias. + * + * Examples: + * constexpr auto z_alias = alias<'z'>.for_(); */ - template - inline constexpr internal::table_alias_builder alias_{}; + template + inline constexpr internal::table_alias_builder alias{}; /** @short Create a table alias. * diff --git a/dev/conditions.h b/dev/conditions.h index 4aa13182f..1f21332dc 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1036,9 +1036,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_join(O o) { - return internal::left_join_t, O>{std::move(o)}; + template + auto left_join(On on) { + return internal::left_join_t, On>{std::move(on)}; } #endif @@ -1048,9 +1048,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto join(O o) { - return internal::join_t, O>{std::move(o)}; + template + auto join(On on) { + return internal::join_t, On>{std::move(on)}; } #endif @@ -1060,9 +1060,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_outer_join(O o) { - return internal::left_outer_join_t, O>{std::move(o)}; + template + auto left_outer_join(On on) { + return internal::left_outer_join_t, On>{std::move(on)}; } #endif @@ -1072,9 +1072,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto inner_join(O o) { - return internal::inner_join_t, O>{std::move(o)}; + template + auto inner_join(On on) { + return internal::inner_join_t, On>{std::move(on)}; } #endif diff --git a/dev/functional/config.h b/dev/functional/config.h index 75a928e7a..d348fc543 100644 --- a/dev/functional/config.h +++ b/dev/functional/config.h @@ -28,7 +28,8 @@ #define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #endif -#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED)) && \ +#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \ + defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \ (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) #define SQLITE_ORM_WITH_CPP20_ALIASES #endif diff --git a/dev/select_constraints.h b/dev/select_constraints.h index d8eb990d3..83540e1c3 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -416,9 +416,15 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template + /** + * Example: + * constexpr auto m = "m"_alias.for_(); + * auto reportingTo = + * storage.select(asterisk(), inner_join(on(m->*&Employee::reportsTo == c(&Employee::employeeId)))); + */ + template auto asterisk(bool definedOrder = false) { - return internal::asterisk_t>{definedOrder}; + return internal::asterisk_t>{definedOrder}; } #endif diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index 6cef93831..1cba0a2b1 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -60,13 +60,14 @@ void marvel_hero_ordered_by_o_pos() { cout << endl; #ifdef SQLITE_ORM_WITH_CPP20_ALIASES { + constexpr auto i = "i"_col; // SELECT name, instr(abilities, 'o') i // FROM marvel // WHERE i > 0 // ORDER BY i - auto rows = storage.select(columns(&MarvelHero::name, as<"i"_col>(instr(&MarvelHero::abilities, "o"))), - where("i"_col > c(0)), - order_by("i"_col)); + auto rows = storage.select(columns(&MarvelHero::name, as(instr(&MarvelHero::abilities, "o"))), + where(i > c(0)), + order_by(i)); for(auto& row: rows) { cout << get<0>(row) << '\t' << get<1>(row) << '\n'; } diff --git a/examples/custom_aliases.cpp b/examples/custom_aliases.cpp index 79fbd4a8b..57dae223c 100644 --- a/examples/custom_aliases.cpp +++ b/examples/custom_aliases.cpp @@ -119,7 +119,7 @@ int main(int, char** argv) { // WHERE COMPANY_ID = DEPARTMENT.EMP_ID; auto rowsWithColumnAliases = storage.select( columns(&Employee::id >>= empId, as(&Employee::name), &Employee::age, &Department::dept), - where(is_equal(get(), &Department::empId))); + where(get() == c(&Department::empId))); assert(rowsWithColumnAliases == rowsWithTableAliases); // SELECT C.ID AS COMPANY_ID, C.NAME AS COMPANY_NAME, C.AGE, D.DEPT diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 814a70185..14807e894 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -166,7 +166,8 @@ using std::nullptr_t; #define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #endif -#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED)) && \ +#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \ + defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \ (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) #define SQLITE_ORM_WITH_CPP20_ALIASES #endif @@ -3991,9 +3992,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_join(O o) { - return internal::left_join_t, O>{std::move(o)}; + template + auto left_join(On on) { + return internal::left_join_t, On>{std::move(on)}; } #endif @@ -4003,9 +4004,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto join(O o) { - return internal::join_t, O>{std::move(o)}; + template + auto join(On on) { + return internal::join_t, On>{std::move(on)}; } #endif @@ -4015,9 +4016,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_outer_join(O o) { - return internal::left_outer_join_t, O>{std::move(o)}; + template + auto left_outer_join(On on) { + return internal::left_outer_join_t, On>{std::move(on)}; } #endif @@ -4027,9 +4028,9 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto inner_join(O o) { - return internal::inner_join_t, O>{std::move(o)}; + template + auto inner_join(On on) { + return internal::inner_join_t, On>{std::move(on)}; } #endif @@ -4290,7 +4291,7 @@ namespace sqlite_orm { #include // std::copy_n // #include "functional/cxx_universal.h" - +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -4415,14 +4416,10 @@ namespace sqlite_orm { }; #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template + template struct table_alias_builder { - static_assert(sizeof...(C) == 0 && ((A >= 'A' && 'Z' <= A) || (A >= 'a' && 'z' <= A)), - "Table alias identifiers shall consist of a single alphabetic character, in order to evade " - "clashes with CTE aliases."); - template - [[nodiscard]] consteval table_alias for_() const { + [[nodiscard]] consteval table_alias for_() const { return {}; } }; @@ -4556,10 +4553,13 @@ namespace sqlite_orm { using colalias_i = internal::column_alias<'i'>; #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** @short Create aliased tables e.g. `constexpr auto z_alias = alias_<'z'>.for_()`. + /** @short Create a table alias. + * + * Examples: + * constexpr auto z_alias = alias<'z'>.for_(); */ - template - inline constexpr internal::table_alias_builder alias_{}; + template + inline constexpr internal::table_alias_builder alias{}; /** @short Create a table alias. * @@ -7330,9 +7330,15 @@ namespace sqlite_orm { } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template + /** + * Example: + * constexpr auto m = "m"_alias.for_(); + * auto reportingTo = + * storage.select(asterisk(), inner_join(on(m->*&Employee::reportsTo == c(&Employee::employeeId)))); + */ + template auto asterisk(bool definedOrder = false) { - return internal::asterisk_t>{definedOrder}; + return internal::asterisk_t>{definedOrder}; } #endif diff --git a/tests/statement_serializer_tests/select_constraints.cpp b/tests/statement_serializer_tests/select_constraints.cpp index 2bc4b5747..354af39af 100644 --- a/tests/statement_serializer_tests/select_constraints.cpp +++ b/tests/statement_serializer_tests/select_constraints.cpp @@ -74,7 +74,7 @@ TEST_CASE("statement_serializer select constraints") { #ifdef SQLITE_ORM_WITH_CPP20_ALIASES { SECTION("with alias 2") { - auto expression = from.for_()>(); + auto expression = from.for_()>(); value = serialize(expression, context); expected = R"(FROM "users" "u")"; } diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp index 2be98bd91..5ae1f08e2 100644 --- a/tests/static_tests/alias.cpp +++ b/tests/static_tests/alias.cpp @@ -36,7 +36,7 @@ TEST_CASE("aliases") { runTest>("a"_col); runTest, int User::*>>(as<"a"_col>(&User::id)); runTest, int User::*>>(&User::id >>= "a"_col); - runTest>(alias_<'z'>.for_()); + runTest>(alias<'a', 'l', 's'>.for_()); constexpr auto z_alias = "z"_alias.for_(); runTest>(z_alias); runTest, int User::*>>(alias_column(&User::id)); From 0fbe37eba5addcf6e99ebdfe0ab9228d1f290405 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 21 Feb 2023 23:58:42 +0100 Subject: [PATCH 059/100] Build C++14 representative tests with appveyor's VS 2017 build image --- CMakeLists.txt | 4 +++- appveyor.yml | 14 +++++++++----- dependencies/CMakeLists.txt | 23 ++++++++++++++++------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e05ed59a..56970d752 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required (VERSION 3.24.0) +# note: the minimum required version needs to go hand in hand with appveyor builds, +# which is CMake 3.16 for the Visual Studio 2017 build worker image +cmake_minimum_required (VERSION 3.16.0) # PACKAGE_VERSION is used by cpack scripts currently # Both sqlite_orm_VERSION and PACKAGE_VERSION should be the same for now diff --git a/appveyor.yml b/appveyor.yml index e5067d5cd..a14be0e36 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,8 +36,8 @@ environment: cmake_build_parallel: "" # Representative for C++14 - - job_name: Visual Studio 2019, x64, C++14 - appveyor_build_worker_image: Visual Studio 2019 + - job_name: Visual Studio 2017, x64, C++14 + appveyor_build_worker_image: Visual Studio 2017 platform: x64 SQLITE_ORM_CXX_STANDARD: "" @@ -92,7 +92,7 @@ for: # Windows matrix: only: - - appveyor_build_worker_image: Visual Studio 2019 + - appveyor_build_worker_image: Visual Studio 2017 - appveyor_build_worker_image: Visual Studio 2022 init: - |- @@ -100,7 +100,7 @@ for: if "%platform%"=="x64" (set architecture=-A x64) if "%platform%"=="x86" (set architecture=-A Win32) if "%appveyor_build_worker_image%"=="Visual Studio 2022" (set generator="Visual Studio 17 2022" %architecture%) - if "%appveyor_build_worker_image%"=="Visual Studio 2019" (set generator="Visual Studio 16 2019" %architecture%) + if "%appveyor_build_worker_image%"=="Visual Studio 2017" (set generator="Visual Studio 15 2017" %architecture%) install: - |- cd C:\Tools\vcpkg @@ -109,7 +109,11 @@ for: C:\Tools\vcpkg\bootstrap-vcpkg.bat -disableMetrics C:\Tools\vcpkg\vcpkg integrate install set VCPKG_DEFAULT_TRIPLET=%platform%-windows - vcpkg install sqlite3 catch2 + vcpkg install sqlite3 + rem The Visual Studio 2017 build worker image comes with CMake 3.16 only, and sqlite_orm will build the Catch2 dependency from source + if not "%appveyor_build_worker_image%"=="Visual Studio 2017" ( + vcpkg install catch2 + ) before_build: - |- mkdir compile diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 598208613..84bd661db 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -1,13 +1,22 @@ include(FetchContent) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) - FetchContent_Declare( - Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.2.1 - # prefer find_package() over building from source - FIND_PACKAGE_ARGS - ) + # FIND_PACKAGE_ARGS is available since 3.24 + if(${CMAKE_VERSION} VERSION_LESS "3.24.0") + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.2.1 + ) + else() + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.2.1 + # prefer find_package() over building from source + FIND_PACKAGE_ARGS + ) + endif() add_subdirectory(catch2) endif() From b2fb422942ca40e6d0ddfa7377d696e13e1c2890 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 09:16:34 +0100 Subject: [PATCH 060/100] One-liner for appveyor Cmd script --- appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index a14be0e36..33eb32550 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -111,9 +111,7 @@ for: set VCPKG_DEFAULT_TRIPLET=%platform%-windows vcpkg install sqlite3 rem The Visual Studio 2017 build worker image comes with CMake 3.16 only, and sqlite_orm will build the Catch2 dependency from source - if not "%appveyor_build_worker_image%"=="Visual Studio 2017" ( - vcpkg install catch2 - ) + if not "%appveyor_build_worker_image%"=="Visual Studio 2017" (vcpkg install catch2) before_build: - |- mkdir compile From 110afe6ab45ebd970c9800abc1d10c217c020106 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 19:20:39 +0100 Subject: [PATCH 061/100] Renamed `internal::table_alias` to `internal::recordset_alias` --- dev/alias.h | 58 ++++++++++++++++----------------- include/sqlite_orm/sqlite_orm.h | 58 ++++++++++++++++----------------- tests/static_tests/alias.cpp | 6 ++-- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 967ee8bd0..0410906fa 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -39,12 +39,12 @@ namespace sqlite_orm { #endif /** - * This is a common built-in class used for custom single character table aliases. + * This is a common built-in class used for character based table aliases. * For convenience there exist public type aliases `alias_a`, `alias_b`, ... * The easiest way to create a table alias is using `"z"_alias.for_()`. */ template - struct table_alias : alias_tag { + struct recordset_alias : alias_tag { using type = T; static std::string get() { @@ -132,7 +132,7 @@ namespace sqlite_orm { template struct table_alias_builder { template - [[nodiscard]] consteval table_alias for_() const { + [[nodiscard]] consteval recordset_alias for_() const { return {}; } }; @@ -203,57 +203,57 @@ namespace sqlite_orm { #endif template - using alias_a = internal::table_alias; + using alias_a = internal::recordset_alias; template - using alias_b = internal::table_alias; + using alias_b = internal::recordset_alias; template - using alias_c = internal::table_alias; + using alias_c = internal::recordset_alias; template - using alias_d = internal::table_alias; + using alias_d = internal::recordset_alias; template - using alias_e = internal::table_alias; + using alias_e = internal::recordset_alias; template - using alias_f = internal::table_alias; + using alias_f = internal::recordset_alias; template - using alias_g = internal::table_alias; + using alias_g = internal::recordset_alias; template - using alias_h = internal::table_alias; + using alias_h = internal::recordset_alias; template - using alias_i = internal::table_alias; + using alias_i = internal::recordset_alias; template - using alias_j = internal::table_alias; + using alias_j = internal::recordset_alias; template - using alias_k = internal::table_alias; + using alias_k = internal::recordset_alias; template - using alias_l = internal::table_alias; + using alias_l = internal::recordset_alias; template - using alias_m = internal::table_alias; + using alias_m = internal::recordset_alias; template - using alias_n = internal::table_alias; + using alias_n = internal::recordset_alias; template - using alias_o = internal::table_alias; + using alias_o = internal::recordset_alias; template - using alias_p = internal::table_alias; + using alias_p = internal::recordset_alias; template - using alias_q = internal::table_alias; + using alias_q = internal::recordset_alias; template - using alias_r = internal::table_alias; + using alias_r = internal::recordset_alias; template - using alias_s = internal::table_alias; + using alias_s = internal::recordset_alias; template - using alias_t = internal::table_alias; + using alias_t = internal::recordset_alias; template - using alias_u = internal::table_alias; + using alias_u = internal::recordset_alias; template - using alias_v = internal::table_alias; + using alias_v = internal::recordset_alias; template - using alias_w = internal::table_alias; + using alias_w = internal::recordset_alias; template - using alias_x = internal::table_alias; + using alias_x = internal::recordset_alias; template - using alias_y = internal::table_alias; + using alias_y = internal::recordset_alias; template - using alias_z = internal::table_alias; + using alias_z = internal::recordset_alias; using colalias_a = internal::column_alias<'a'>; using colalias_b = internal::column_alias<'b'>; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 14807e894..9bcb9e99d 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -4326,12 +4326,12 @@ namespace sqlite_orm { #endif /** - * This is a common built-in class used for custom single character table aliases. + * This is a common built-in class used for character based table aliases. * For convenience there exist public type aliases `alias_a`, `alias_b`, ... * The easiest way to create a table alias is using `"z"_alias.for_()`. */ template - struct table_alias : alias_tag { + struct recordset_alias : alias_tag { using type = T; static std::string get() { @@ -4419,7 +4419,7 @@ namespace sqlite_orm { template struct table_alias_builder { template - [[nodiscard]] consteval table_alias for_() const { + [[nodiscard]] consteval recordset_alias for_() const { return {}; } }; @@ -4490,57 +4490,57 @@ namespace sqlite_orm { #endif template - using alias_a = internal::table_alias; + using alias_a = internal::recordset_alias; template - using alias_b = internal::table_alias; + using alias_b = internal::recordset_alias; template - using alias_c = internal::table_alias; + using alias_c = internal::recordset_alias; template - using alias_d = internal::table_alias; + using alias_d = internal::recordset_alias; template - using alias_e = internal::table_alias; + using alias_e = internal::recordset_alias; template - using alias_f = internal::table_alias; + using alias_f = internal::recordset_alias; template - using alias_g = internal::table_alias; + using alias_g = internal::recordset_alias; template - using alias_h = internal::table_alias; + using alias_h = internal::recordset_alias; template - using alias_i = internal::table_alias; + using alias_i = internal::recordset_alias; template - using alias_j = internal::table_alias; + using alias_j = internal::recordset_alias; template - using alias_k = internal::table_alias; + using alias_k = internal::recordset_alias; template - using alias_l = internal::table_alias; + using alias_l = internal::recordset_alias; template - using alias_m = internal::table_alias; + using alias_m = internal::recordset_alias; template - using alias_n = internal::table_alias; + using alias_n = internal::recordset_alias; template - using alias_o = internal::table_alias; + using alias_o = internal::recordset_alias; template - using alias_p = internal::table_alias; + using alias_p = internal::recordset_alias; template - using alias_q = internal::table_alias; + using alias_q = internal::recordset_alias; template - using alias_r = internal::table_alias; + using alias_r = internal::recordset_alias; template - using alias_s = internal::table_alias; + using alias_s = internal::recordset_alias; template - using alias_t = internal::table_alias; + using alias_t = internal::recordset_alias; template - using alias_u = internal::table_alias; + using alias_u = internal::recordset_alias; template - using alias_v = internal::table_alias; + using alias_v = internal::recordset_alias; template - using alias_w = internal::table_alias; + using alias_w = internal::recordset_alias; template - using alias_x = internal::table_alias; + using alias_x = internal::recordset_alias; template - using alias_y = internal::table_alias; + using alias_y = internal::recordset_alias; template - using alias_z = internal::table_alias; + using alias_z = internal::recordset_alias; using colalias_a = internal::column_alias<'a'>; using colalias_b = internal::column_alias<'b'>; diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp index 5ae1f08e2..b01e20f9e 100644 --- a/tests/static_tests/alias.cpp +++ b/tests/static_tests/alias.cpp @@ -8,7 +8,7 @@ using internal::alias_holder; using internal::as_t; using internal::column_alias; using internal::column_pointer; -using internal::table_alias; +using internal::recordset_alias; template void do_assert() { @@ -36,9 +36,9 @@ TEST_CASE("aliases") { runTest>("a"_col); runTest, int User::*>>(as<"a"_col>(&User::id)); runTest, int User::*>>(&User::id >>= "a"_col); - runTest>(alias<'a', 'l', 's'>.for_()); + runTest>(alias<'a', 'l', 's'>.for_()); constexpr auto z_alias = "z"_alias.for_(); - runTest>(z_alias); + runTest>(z_alias); runTest, int User::*>>(alias_column(&User::id)); runTest, int User::*>>(z_alias->*&User::id); runTest, column_pointer>>(z_alias->*column(&User::id)); From 87a094b4bb6f635511a5b97836fc24d33be3a243 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 19:20:49 +0100 Subject: [PATCH 062/100] Updated CMAKE_VERSION check --- dependencies/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 84bd661db..4d5a34723 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -2,7 +2,7 @@ include(FetchContent) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) # FIND_PACKAGE_ARGS is available since 3.24 - if(${CMAKE_VERSION} VERSION_LESS "3.24.0") + if(CMAKE_VERSION VERSION_LESS 3.24) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git From 0b537fabd178c8bc988652e35221b52e3a211afe Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 20:56:33 +0100 Subject: [PATCH 063/100] Test only: --debug-output --- appveyor.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 33eb32550..7deb0fc7f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,6 +20,12 @@ configuration: environment: appveyor_yml_disable_ps_linux: true matrix: + # Representative for C++14 + - job_name: Visual Studio 2017, x64, C++14 + appveyor_build_worker_image: Visual Studio 2017 + platform: x64 + SQLITE_ORM_CXX_STANDARD: "" + - job_name: clang, C++14 appveyor_build_worker_image: Ubuntu CC: clang @@ -35,12 +41,6 @@ environment: # gcc was stuck with a parallel build cmake_build_parallel: "" - # Representative for C++14 - - job_name: Visual Studio 2017, x64, C++14 - appveyor_build_worker_image: Visual Studio 2017 - platform: x64 - SQLITE_ORM_CXX_STANDARD: "" - - job_name: clang, C++17 appveyor_build_worker_image: Ubuntu CC: clang @@ -120,7 +120,7 @@ for: # build examples, and run tests (ie make & make test) build_script: - |- - cmake --build . --config %configuration% -- /m + cmake --debug-output --build . --config %configuration% -- /m ctest --verbose --output-on-failure --build-config %configuration% - From 886fcbcec87f6bcbf81595e8db62d6b1824d2626 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 21:00:01 +0100 Subject: [PATCH 064/100] Test only: --debug-output --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 7deb0fc7f..2f5b6b2d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -116,11 +116,11 @@ for: - |- mkdir compile cd compile - cmake %SQLITE_ORM_CXX_STANDARD% .. -G %generator% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake + cmake --debug-output %SQLITE_ORM_CXX_STANDARD% .. -G %generator% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake # build examples, and run tests (ie make & make test) build_script: - |- - cmake --debug-output --build . --config %configuration% -- /m + cmake --build . --config %configuration% -- /m ctest --verbose --output-on-failure --build-config %configuration% - From 93ad8bb91ce4378fecab4ed72e83b09ff94a10a3 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 21:50:35 +0100 Subject: [PATCH 065/100] Updated handling of Catch2 CMake dependency --- dependencies/CMakeLists.txt | 2 +- tests/CMakeLists.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 4d5a34723..5f588c80f 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -14,7 +14,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.2.1 # prefer find_package() over building from source - FIND_PACKAGE_ARGS + FIND_PACKAGE_ARGS 3 CONFIG REQUIRED ) endif() add_subdirectory(catch2) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6e4aeb56e..894be0c37 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,5 @@ cmake_minimum_required (VERSION 3.2) -find_package(Catch2 3 CONFIG REQUIRED) - option(SQLITE_ORM_OMITS_CODECVT "Omits codec testing" OFF) add_executable(unit_tests From 61cf74cc648a54f624188e14444d4ac05f255e99 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 22:04:46 +0100 Subject: [PATCH 066/100] Test only: --debug-output appveyor linux builds --- appveyor.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2f5b6b2d9..65e7cc952 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,12 +20,6 @@ configuration: environment: appveyor_yml_disable_ps_linux: true matrix: - # Representative for C++14 - - job_name: Visual Studio 2017, x64, C++14 - appveyor_build_worker_image: Visual Studio 2017 - platform: x64 - SQLITE_ORM_CXX_STANDARD: "" - - job_name: clang, C++14 appveyor_build_worker_image: Ubuntu CC: clang @@ -41,6 +35,12 @@ environment: # gcc was stuck with a parallel build cmake_build_parallel: "" + # Representative for C++14 + - job_name: Visual Studio 2017, x64, C++14 + appveyor_build_worker_image: Visual Studio 2017 + platform: x64 + SQLITE_ORM_CXX_STANDARD: "" + - job_name: clang, C++17 appveyor_build_worker_image: Ubuntu CC: clang @@ -116,7 +116,7 @@ for: - |- mkdir compile cd compile - cmake --debug-output %SQLITE_ORM_CXX_STANDARD% .. -G %generator% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake + cmake %SQLITE_ORM_CXX_STANDARD% .. -G %generator% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake # build examples, and run tests (ie make & make test) build_script: - |- @@ -145,7 +145,7 @@ for: - |- mkdir compile cd compile - cmake $SQLITE_ORM_CXX_STANDARD .. -DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake + cmake --debug-output $SQLITE_ORM_CXX_STANDARD .. -DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake # build examples, and run tests (ie make & make test) build_script: - |- From a0e1a8d09a3feedb46c392f0cee1dd9f7f24d598 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 22 Feb 2023 22:43:50 +0100 Subject: [PATCH 067/100] Trying yet another FIND_PACKAGE_ARGS variant --- dependencies/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 5f588c80f..4d5a34723 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -14,7 +14,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.2.1 # prefer find_package() over building from source - FIND_PACKAGE_ARGS 3 CONFIG REQUIRED + FIND_PACKAGE_ARGS ) endif() add_subdirectory(catch2) From f964d187ab53f6359f23b161f2f97ea9d3946102 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 18:24:30 +0100 Subject: [PATCH 068/100] CMake: Fixed option for building examples BUILD_EXAMPLES was always OFF because the description was missing. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56970d752..a8d521265 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) add_subdirectory(tests) endif() -option(BUILD_EXAMPLES ON) +option(BUILD_EXAMPLES "Build code examples" OFF) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_EXAMPLES) add_subdirectory(examples) endif() From a7b7180236a87af8aeb7925ae9ec712de2602fd9 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 18:25:44 +0100 Subject: [PATCH 069/100] appveyor: reordered arguments to cmake call --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 65e7cc952..502a1cd1f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -116,7 +116,7 @@ for: - |- mkdir compile cd compile - cmake %SQLITE_ORM_CXX_STANDARD% .. -G %generator% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake + cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% --toolchain C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- @@ -145,7 +145,7 @@ for: - |- mkdir compile cd compile - cmake --debug-output $SQLITE_ORM_CXX_STANDARD .. -DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake + cmake $SQLITE_ORM_CXX_STANDARD --toolchain $HOME/vcpkg/scripts/buildsystems/vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- @@ -171,7 +171,7 @@ for: - |- mkdir compile cd compile - cmake $SQLITE_ORM_CXX_STANDARD .. -DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake + cmake $SQLITE_ORM_CXX_STANDARD --toolchain $HOME/vcpkg/scripts/buildsystems/vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- From 71271fb152228ca3c19dc03fae4e718f11812325 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 19:01:34 +0100 Subject: [PATCH 070/100] CMake: Corrected dependency handling * SQLite3 should be found using Config mode. * Catch2" should be dealt with solely using "FetchContent". --- CMakeLists.txt | 4 ++-- dependencies/CMakeLists.txt | 6 +++--- dependencies/catch2/CMakeLists.txt | 1 + dependencies/sqlite3/CMakeLists.txt | 4 ++-- examples/CMakeLists.txt | 4 +++- tests/CMakeLists.txt | 5 ++++- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8d521265..2c8b7871d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # note: the minimum required version needs to go hand in hand with appveyor builds, # which is CMake 3.16 for the Visual Studio 2017 build worker image -cmake_minimum_required (VERSION 3.16.0) +cmake_minimum_required (VERSION 3.16) # PACKAGE_VERSION is used by cpack scripts currently # Both sqlite_orm_VERSION and PACKAGE_VERSION should be the same for now @@ -44,7 +44,7 @@ set(SqliteOrm_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include") add_library(sqlite_orm INTERFACE) add_library(sqlite_orm::sqlite_orm ALIAS sqlite_orm) -find_package(SQLite3 REQUIRED) +find_package(SQLite3 CONFIG REQUIRED) target_link_libraries(sqlite_orm INTERFACE SQLite::SQLite3) target_sources(sqlite_orm INTERFACE $) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 4d5a34723..e1135f32a 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -3,18 +3,18 @@ include(FetchContent) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) # FIND_PACKAGE_ARGS is available since 3.24 if(CMAKE_VERSION VERSION_LESS 3.24) - FetchContent_Declare( + FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.2.1 ) else() - FetchContent_Declare( + FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.2.1 # prefer find_package() over building from source - FIND_PACKAGE_ARGS + FIND_PACKAGE_ARGS 3 CONFIG ) endif() add_subdirectory(catch2) diff --git a/dependencies/catch2/CMakeLists.txt b/dependencies/catch2/CMakeLists.txt index ea8cd9518..a50da0b19 100644 --- a/dependencies/catch2/CMakeLists.txt +++ b/dependencies/catch2/CMakeLists.txt @@ -1 +1,2 @@ +# CMake <3.24: exposes targets only locally, but caches them. So call FetchContent_MakeAvailable again in the directory of usage FetchContent_MakeAvailable(Catch2) diff --git a/dependencies/sqlite3/CMakeLists.txt b/dependencies/sqlite3/CMakeLists.txt index 924d5feae..40452f1d6 100644 --- a/dependencies/sqlite3/CMakeLists.txt +++ b/dependencies/sqlite3/CMakeLists.txt @@ -1,2 +1,2 @@ -# find_package exposes targets only globally, but caches them. So call find_package again in the directory of usage -find_package(SQLite3 REQUIRED) +# CMake <3.24: exposes targets only locally, but caches them. So call find_package again in the directory of usage +find_package(SQLite3 CONFIG REQUIRED) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2857b659e..aec7acd62 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required (VERSION 3.2) +cmake_minimum_required (VERSION 3.16) + +# note: find_package(SQLite3 CONFIG REQUIRED) already done in top-level CMakeLists file(GLOB files "*.cpp") foreach(file ${files}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 894be0c37..436284a22 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,7 @@ -cmake_minimum_required (VERSION 3.2) +cmake_minimum_required (VERSION 3.16) + +# note: find_package(SQLite3 CONFIG REQUIRED) already done in top-level CMakeLists +FetchContent_MakeAvailable(Catch2) option(SQLITE_ORM_OMITS_CODECVT "Omits codec testing" OFF) From dc0691fd0e2a92ae114c2b95f2f384520fea5117 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 19:08:33 +0100 Subject: [PATCH 071/100] Flatten dependencies/**/CMakeLists.txt There's no value in having another subdirectory level for each dependency --- dependencies/CMakeLists.txt | 9 +++++++-- dependencies/catch2/CMakeLists.txt | 2 -- dependencies/sqlite3/CMakeLists.txt | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 dependencies/catch2/CMakeLists.txt delete mode 100644 dependencies/sqlite3/CMakeLists.txt diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index e1135f32a..60047f720 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -17,7 +17,12 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) FIND_PACKAGE_ARGS 3 CONFIG ) endif() - add_subdirectory(catch2) endif() -add_subdirectory(sqlite3) +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) + # CMake <3.24: exposes targets only locally, but caches them. So call FetchContent_MakeAvailable again in the directory of usage + FetchContent_MakeAvailable(Catch2) +endif() + +# CMake <3.24: exposes targets only locally, but caches them. So call find_package again in the directory of usage +find_package(SQLite3 CONFIG REQUIRED) diff --git a/dependencies/catch2/CMakeLists.txt b/dependencies/catch2/CMakeLists.txt deleted file mode 100644 index a50da0b19..000000000 --- a/dependencies/catch2/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# CMake <3.24: exposes targets only locally, but caches them. So call FetchContent_MakeAvailable again in the directory of usage -FetchContent_MakeAvailable(Catch2) diff --git a/dependencies/sqlite3/CMakeLists.txt b/dependencies/sqlite3/CMakeLists.txt deleted file mode 100644 index 40452f1d6..000000000 --- a/dependencies/sqlite3/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# CMake <3.24: exposes targets only locally, but caches them. So call find_package again in the directory of usage -find_package(SQLite3 CONFIG REQUIRED) From 02719df9a45f0c0bbc1741fce663c16f75d92f29 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 19:14:00 +0100 Subject: [PATCH 072/100] appveyor: let Clang in C++20 mode build the examples --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 502a1cd1f..f8c133ee7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -54,6 +54,7 @@ environment: CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" cmake_build_parallel: --parallel + cmake_build_examples: "-DBUILD_EXAMPLES=ON" - job_name: gcc, C++17 appveyor_build_worker_image: Ubuntu @@ -145,7 +146,7 @@ for: - |- mkdir compile cd compile - cmake $SQLITE_ORM_CXX_STANDARD --toolchain $HOME/vcpkg/scripts/buildsystems/vcpkg.cmake .. + cmake $SQLITE_ORM_CXX_STANDARD $cmake_build_examples --toolchain $HOME/vcpkg/scripts/buildsystems/vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- From 533960ac906cc76000efe9079a753cf116afcd22 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 19:18:59 +0100 Subject: [PATCH 073/100] appveyor: Used backslashes for path to vcpkg.cmake --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f8c133ee7..7d046f8fa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -117,7 +117,7 @@ for: - |- mkdir compile cd compile - cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% --toolchain C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. + cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% --toolchain C:\Tools\vcpkg\scripts\buildsystems\vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- From 1e7a9b65b4bed7d3f58aa0ef62c9b2f355cab3ab Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 20:29:01 +0100 Subject: [PATCH 074/100] CMake: leave finding of sqlite3 package in module mode --- CMakeLists.txt | 2 +- dependencies/CMakeLists.txt | 2 +- examples/CMakeLists.txt | 5 +++-- tests/CMakeLists.txt | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c8b7871d..a56294f29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ set(SqliteOrm_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include") add_library(sqlite_orm INTERFACE) add_library(sqlite_orm::sqlite_orm ALIAS sqlite_orm) -find_package(SQLite3 CONFIG REQUIRED) +find_package(SQLite3 REQUIRED) target_link_libraries(sqlite_orm INTERFACE SQLite::SQLite3) target_sources(sqlite_orm INTERFACE $) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 60047f720..282243910 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -25,4 +25,4 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) endif() # CMake <3.24: exposes targets only locally, but caches them. So call find_package again in the directory of usage -find_package(SQLite3 CONFIG REQUIRED) +find_package(SQLite3 REQUIRED) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index aec7acd62..c9268a7c7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,10 +1,11 @@ cmake_minimum_required (VERSION 3.16) -# note: find_package(SQLite3 CONFIG REQUIRED) already done in top-level CMakeLists +# note: find_package(SQLite3 REQUIRED) already done in top-level CMakeLists file(GLOB files "*.cpp") foreach(file ${files}) get_filename_component(file_basename ${file} NAME_WE) add_executable(${file_basename} ${file}) - target_link_libraries(${file_basename} PRIVATE sqlite_orm sqlite3) + # note: sqlite3 already linked in top-level CMakeLists + target_link_libraries(${file_basename} PRIVATE sqlite_orm) endforeach() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 436284a22..f1ad519bc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.16) -# note: find_package(SQLite3 CONFIG REQUIRED) already done in top-level CMakeLists +# note: find_package(SQLite3 REQUIRED) already done in top-level CMakeLists FetchContent_MakeAvailable(Catch2) option(SQLITE_ORM_OMITS_CODECVT "Omits codec testing" OFF) @@ -167,6 +167,7 @@ target_precompile_headers(unit_tests PRIVATE ) +# note: sqlite3 already linked in top-level CMakeLists target_link_libraries(unit_tests PRIVATE sqlite_orm Catch2::Catch2WithMain) add_test(NAME "All_in_one_unit_test" From 22171889c6ac107fb626ffa8c5d36e1119a976f0 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 19:18:59 +0100 Subject: [PATCH 075/100] Revert "appveyor: Used backslashes for path to vcpkg.cmake" This reverts commit 533960ac906cc76000efe9079a753cf116afcd22. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 7d046f8fa..f8c133ee7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -117,7 +117,7 @@ for: - |- mkdir compile cd compile - cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% --toolchain C:\Tools\vcpkg\scripts\buildsystems\vcpkg.cmake .. + cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% --toolchain C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- From 5d3d3930e71d8e40a32ff08580ba48ab802e9ded Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 22:07:23 +0100 Subject: [PATCH 076/100] appveyor: trying CMAKE_TOOLCHAIN_FILE instead of --toolchain option --- appveyor.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f8c133ee7..60862d58c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,6 +20,12 @@ configuration: environment: appveyor_yml_disable_ps_linux: true matrix: + # Representative for C++14 + - job_name: Visual Studio 2017, x64, C++14 + appveyor_build_worker_image: Visual Studio 2017 + platform: x64 + SQLITE_ORM_CXX_STANDARD: "" + - job_name: clang, C++14 appveyor_build_worker_image: Ubuntu CC: clang @@ -35,12 +41,6 @@ environment: # gcc was stuck with a parallel build cmake_build_parallel: "" - # Representative for C++14 - - job_name: Visual Studio 2017, x64, C++14 - appveyor_build_worker_image: Visual Studio 2017 - platform: x64 - SQLITE_ORM_CXX_STANDARD: "" - - job_name: clang, C++17 appveyor_build_worker_image: Ubuntu CC: clang @@ -117,7 +117,7 @@ for: - |- mkdir compile cd compile - cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% --toolchain C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. + cmake %SQLITE_ORM_CXX_STANDARD% -G %generator% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. # build examples, and run tests (ie make & make test) build_script: - |- From 836bdcf28516ac926beb67486f6f7f6126a8377f Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Feb 2023 22:14:34 +0100 Subject: [PATCH 077/100] appveyor: CMake --toolchain command option is only available since 3.21 --- appveyor.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 60862d58c..5a54f07a9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,12 +20,6 @@ configuration: environment: appveyor_yml_disable_ps_linux: true matrix: - # Representative for C++14 - - job_name: Visual Studio 2017, x64, C++14 - appveyor_build_worker_image: Visual Studio 2017 - platform: x64 - SQLITE_ORM_CXX_STANDARD: "" - - job_name: clang, C++14 appveyor_build_worker_image: Ubuntu CC: clang @@ -41,6 +35,12 @@ environment: # gcc was stuck with a parallel build cmake_build_parallel: "" + # Representative for C++14 + - job_name: Visual Studio 2017, x64, C++14 + appveyor_build_worker_image: Visual Studio 2017 + platform: x64 + SQLITE_ORM_CXX_STANDARD: "" + - job_name: clang, C++17 appveyor_build_worker_image: Ubuntu CC: clang @@ -98,6 +98,7 @@ for: init: - |- echo %appveyor_build_worker_image% - %platform% - %configuration% + cmake --version if "%platform%"=="x64" (set architecture=-A x64) if "%platform%"=="x86" (set architecture=-A Win32) if "%appveyor_build_worker_image%"=="Visual Studio 2022" (set generator="Visual Studio 17 2022" %architecture%) @@ -133,6 +134,7 @@ for: - |- echo $appveyor_build_worker_image $CXX --version + cmake --version # using custom vcpkg triplets for building and linking dynamic dependent libraries install: - |- @@ -161,6 +163,7 @@ for: - |- echo $appveyor_build_worker_image $CXX --version + cmake --version # using custom vcpkg triplets for building and linking dynamic dependent libraries install: - |- From ad80fa443e948c4c88c42068df166162b4144aa3 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 24 Feb 2023 11:44:08 +0100 Subject: [PATCH 078/100] appveyor: Trying Clang C++20 with examples first --- appveyor.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 5a54f07a9..521073eea 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,6 +20,15 @@ configuration: environment: appveyor_yml_disable_ps_linux: true matrix: + - job_name: clang, C++20 + appveyor_build_worker_image: Ubuntu + CC: clang + CXX: clang++ + SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" + # clang was stuck with a parallel build of examples + cmake_build_parallel: "" + cmake_build_examples: "-DBUILD_EXAMPLES=ON" + - job_name: clang, C++14 appveyor_build_worker_image: Ubuntu CC: clang @@ -48,14 +57,6 @@ environment: SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" cmake_build_parallel: --parallel - - job_name: clang, C++20 - appveyor_build_worker_image: Ubuntu - CC: clang - CXX: clang++ - SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" - cmake_build_parallel: --parallel - cmake_build_examples: "-DBUILD_EXAMPLES=ON" - - job_name: gcc, C++17 appveyor_build_worker_image: Ubuntu CC: gcc From 13b69800cff3702d95263a38e34bf3e356b82e79 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 24 Feb 2023 11:57:48 +0100 Subject: [PATCH 079/100] appveyor: Restored previous order of build environment --- appveyor.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 521073eea..c805e66be 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,15 +20,6 @@ configuration: environment: appveyor_yml_disable_ps_linux: true matrix: - - job_name: clang, C++20 - appveyor_build_worker_image: Ubuntu - CC: clang - CXX: clang++ - SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" - # clang was stuck with a parallel build of examples - cmake_build_parallel: "" - cmake_build_examples: "-DBUILD_EXAMPLES=ON" - - job_name: clang, C++14 appveyor_build_worker_image: Ubuntu CC: clang @@ -64,6 +55,15 @@ environment: SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" cmake_build_parallel: "" + - job_name: clang, C++20 + appveyor_build_worker_image: Ubuntu + CC: clang + CXX: clang++ + SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" + # clang was stuck with a parallel build of examples + cmake_build_parallel: "" + cmake_build_examples: "-DBUILD_EXAMPLES=ON" + - job_name: gcc, C++20 appveyor_build_worker_image: Ubuntu CC: gcc From e3ab412cb214e5b488cf53ba78d14020926ebcab Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 24 Feb 2023 22:50:38 +0100 Subject: [PATCH 080/100] Renamed `table_alias_builder` to `recordset_alias_builder` --- dev/alias.h | 6 +++--- include/sqlite_orm/sqlite_orm.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 0410906fa..47c3ac16b 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -130,7 +130,7 @@ namespace sqlite_orm { #ifdef SQLITE_ORM_WITH_CPP20_ALIASES template - struct table_alias_builder { + struct recordset_alias_builder { template [[nodiscard]] consteval recordset_alias for_() const { return {}; @@ -272,7 +272,7 @@ namespace sqlite_orm { * constexpr auto z_alias = alias<'z'>.for_(); */ template - inline constexpr internal::table_alias_builder alias{}; + inline constexpr internal::recordset_alias_builder alias{}; /** @short Create a table alias. * @@ -281,7 +281,7 @@ namespace sqlite_orm { */ template [[nodiscard]] consteval auto operator"" _alias() { - return internal::to_alias(std::make_index_sequence{}); + return internal::to_alias(std::make_index_sequence{}); } /** @short Create a column alias. diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9bcb9e99d..be8e5c217 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -4417,7 +4417,7 @@ namespace sqlite_orm { #ifdef SQLITE_ORM_WITH_CPP20_ALIASES template - struct table_alias_builder { + struct recordset_alias_builder { template [[nodiscard]] consteval recordset_alias for_() const { return {}; @@ -4559,7 +4559,7 @@ namespace sqlite_orm { * constexpr auto z_alias = alias<'z'>.for_(); */ template - inline constexpr internal::table_alias_builder alias{}; + inline constexpr internal::recordset_alias_builder alias{}; /** @short Create a table alias. * @@ -4568,7 +4568,7 @@ namespace sqlite_orm { */ template [[nodiscard]] consteval auto operator"" _alias() { - return internal::to_alias(std::make_index_sequence{}); + return internal::to_alias(std::make_index_sequence{}); } /** @short Create a column alias. From 0e266da3d1d4aff1eebbe760e55d1b21a7e599d3 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 27 Feb 2023 22:06:46 +0100 Subject: [PATCH 081/100] Corrected a few minor things --- dev/column_result.h | 4 +--- dev/serializer_context.h | 3 --- include/sqlite_orm/sqlite_orm.h | 7 +------ 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/dev/column_result.h b/dev/column_result.h index c7235e7bc..b5d2fd745 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -24,7 +24,7 @@ namespace sqlite_orm { namespace internal { /** - * Obains the result type of expressions that form the columns of a select statement. + * Obtains the result type of expressions that form the columns of a select statement. * * This is a proxy class used to define what type must have result type depending on select * arguments (member pointer, aggregate functions, etc). Below you can see specializations @@ -34,8 +34,6 @@ namespace sqlite_orm { * DBOs - db_objects_tuple type * T - C++ type * SFINAE - sfinae argument - * - * Note (implementation): could be possibly implemented by utilizing column_expression_of_t */ template struct column_result_t; diff --git a/dev/serializer_context.h b/dev/serializer_context.h index c45f1a6f4..8536f3d9f 100644 --- a/dev/serializer_context.h +++ b/dev/serializer_context.h @@ -19,9 +19,6 @@ namespace sqlite_orm { serializer_context(const db_objects_type& dbObjects) : db_objects{dbObjects} {} }; - //template - //serializer_context(const DBOs&) -> serializer_context; - template struct serializer_context_builder { using storage_type = S; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index be8e5c217..547f4cbd1 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -2760,9 +2760,6 @@ namespace sqlite_orm { serializer_context(const db_objects_type& dbObjects) : db_objects{dbObjects} {} }; - //template - //serializer_context(const DBOs&) -> serializer_context; - template struct serializer_context_builder { using storage_type = S; @@ -10767,7 +10764,7 @@ namespace sqlite_orm { namespace internal { /** - * Obains the result type of expressions that form the columns of a select statement. + * Obtains the result type of expressions that form the columns of a select statement. * * This is a proxy class used to define what type must have result type depending on select * arguments (member pointer, aggregate functions, etc). Below you can see specializations @@ -10777,8 +10774,6 @@ namespace sqlite_orm { * DBOs - db_objects_tuple type * T - C++ type * SFINAE - sfinae argument - * - * Note (implementation): could be possibly implemented by utilizing column_expression_of_t */ template struct column_result_t; From 10d843ede83dcbbed6b29fdff4cf943798c65b6c Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 28 Feb 2023 22:21:22 +0100 Subject: [PATCH 082/100] appveyor: Updated description for clang C++20 environment --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c805e66be..55bed4074 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -55,7 +55,7 @@ environment: SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" cmake_build_parallel: "" - - job_name: clang, C++20 + - job_name: clang, C++20 (with examples) appveyor_build_worker_image: Ubuntu CC: clang CXX: clang++ From cfd82b9e54bd880af4c9d779b5a82a689bbcb51c Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 28 Feb 2023 16:23:57 -0500 Subject: [PATCH 083/100] Update COMM-LICENSE --- COMM-LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMM-LICENSE b/COMM-LICENSE index ef5fd18a8..bc0c382b9 100644 --- a/COMM-LICENSE +++ b/COMM-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2021 Scott Chacon and others +Copyright (c) 2012-2021 Eugene Zakharov and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From ed7d1a6f43c3499aec7046837422c934149c2bfc Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 7 Mar 2023 12:00:28 +0000 Subject: [PATCH 084/100] Detected the absence of string_view's iterator range ctor differently. There are environments that don't support the iterator constructor of string_view yet. E.g. macos and XCode 14.2 ship with libc++ 14, yet XCode picks up libc++ 13 installed on the system. --- dev/serializing_util.h | 20 +++++++++++------ include/sqlite_orm/sqlite_orm.h | 38 +++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 125cd666c..d568226c8 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -6,12 +6,12 @@ #include #include #include // std::exchange, std::tuple_size -#if __cplusplus >= 202002L && __cpp_lib_concepts +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED #include #include // std::find #endif -#include "functional/cxx_universal.h" +#include "functional/cxx_universal.h" // ::size_t #include "functional/cxx_type_traits_polyfill.h" #include "tuple_helper/tuple_iteration.h" #include "error_code.h" @@ -29,9 +29,14 @@ namespace sqlite_orm { template std::string serialize_order_by(const T& t, const Ctx& context); -#if __cplusplus >= 202002L && \ - __cpp_lib_concepts // contiguous iterator ranges depend on contiguous_iterator, sized_sentinel_for in all major implementations - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + // optimized version when string_view's iterator range constructor is available + template + void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) + requires requires { + std::string_view{str.cbegin(), str.cend()}; + } + { for(std::string::const_iterator it = str.cbegin(), next; true; it = next + 1) { next = std::find(it, str.cend(), char2Escape); os << std::string_view{it, next}; @@ -42,7 +47,9 @@ namespace sqlite_orm { os << std::string(2, char2Escape); } } -#else + + template +#endif inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { if(str.find(char2Escape) == str.npos) { os << str; @@ -55,7 +62,6 @@ namespace sqlite_orm { } } } -#endif inline void stream_identifier(std::ostream& ss, const std::string& qualifier, diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 547f4cbd1..fd87913f2 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -13191,13 +13191,13 @@ namespace sqlite_orm { #include #include #include // std::exchange, std::tuple_size -#if __cplusplus >= 202002L && __cpp_lib_concepts +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED #include #include // std::find #endif // #include "functional/cxx_universal.h" - +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_iteration.h" @@ -13219,9 +13219,14 @@ namespace sqlite_orm { template std::string serialize_order_by(const T& t, const Ctx& context); -#if __cplusplus >= 202002L && \ - __cpp_lib_concepts // contiguous iterator ranges depend on contiguous_iterator, sized_sentinel_for in all major implementations - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + // optimized version when string_view's iterator range constructor is available + template + void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) + requires requires { + std::string_view{str.cbegin(), str.cend()}; + } + { for(std::string::const_iterator it = str.cbegin(), next; true; it = next + 1) { next = std::find(it, str.cend(), char2Escape); os << std::string_view{it, next}; @@ -13232,20 +13237,21 @@ namespace sqlite_orm { os << std::string(2, char2Escape); } } -#else - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; - } - os << c; + + template +#endif + inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { + if(str.find(char2Escape) == str.npos) { + os << str; + } else { + for(char c: str) { + if(c == char2Escape) { + os << char2Escape; } + os << c; } } -#endif + } inline void stream_identifier(std::ostream& ss, const std::string& qualifier, From d099e60d34b5008e54ed31af0714f1eda926904a Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 7 Mar 2023 21:50:07 +0000 Subject: [PATCH 085/100] Addressed Clang 10 choking on concepts using non-template parameters --- dev/functional/cxx_compiler_quirks.h | 7 +++++++ dev/serializing_util.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 11 +++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 6fcde5084..64e8ad78f 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -39,3 +39,10 @@ (defined(__clang__) && (__clang_major__ >= 12) && (__cplusplus >= 202002L)) #define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED #endif + +// clang 10 chokes on concepts that don't depend on template parameters; +// when it tries to instantiate an expression in a requires expression, which results in an error, +// the compiler reports an error instead of dismissing the templated function. +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && (defined(__clang__) && (__clang_major__ == 10)) +#define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS +#endif diff --git a/dev/serializing_util.h b/dev/serializing_util.h index d568226c8..fb1d696a0 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -6,7 +6,7 @@ #include #include #include // std::exchange, std::tuple_size -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) #include #include // std::find #endif @@ -29,7 +29,7 @@ namespace sqlite_orm { template std::string serialize_order_by(const T& t, const Ctx& context); -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) // optimized version when string_view's iterator range constructor is available template void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index fd87913f2..750c202d7 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -140,6 +140,13 @@ using std::nullptr_t; #define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED #endif +// clang 10 chokes on concepts that don't depend on template parameters; +// when it tries to instantiate an expression in a requires expression, which results in an error, +// the compiler reports an error instead of dismissing the templated function. +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && (defined(__clang__) && (__clang_major__ == 10)) +#define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS +#endif + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -13191,7 +13198,7 @@ namespace sqlite_orm { #include #include #include // std::exchange, std::tuple_size -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) #include #include // std::find #endif @@ -13219,7 +13226,7 @@ namespace sqlite_orm { template std::string serialize_order_by(const T& t, const Ctx& context); -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) // optimized version when string_view's iterator range constructor is available template void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) From 40389201d1fef74facd18ec17a345b653bccb029 Mon Sep 17 00:00:00 2001 From: Yevgeniy Zakharov Date: Tue, 7 Mar 2023 23:44:00 -0500 Subject: [PATCH 086/100] Update COMM-LICENSE --- COMM-LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMM-LICENSE b/COMM-LICENSE index bc0c382b9..d64eaa555 100644 --- a/COMM-LICENSE +++ b/COMM-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2021 Eugene Zakharov and others +Copyright (c) 2012-2023 Eugene Zakharov and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From ccca01c5c57c647333b8de63f271c7825ec172e8 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 10 Mar 2023 15:45:53 +0000 Subject: [PATCH 087/100] Properly checked everywhere for availability of 'upsert clause' feature --- dev/ast/upsert_clause.h | 12 +- dev/ast_iterator.h | 6 +- dev/node_tuple.h | 5 +- dev/statement_serializer.h | 6 +- include/sqlite_orm/sqlite_orm.h | 125 +++++++++--------- tests/ast_iterator_tests.cpp | 2 + .../ast/upsert_clause.cpp | 2 + tests/static_tests/node_tuple.cpp | 2 + 8 files changed, 88 insertions(+), 72 deletions(-) diff --git a/dev/ast/upsert_clause.h b/dev/ast/upsert_clause.h index d1a6d5714..3a3b26948 100644 --- a/dev/ast/upsert_clause.h +++ b/dev/ast/upsert_clause.h @@ -1,8 +1,9 @@ #pragma once -#include // std::tuple, std::make_tuple -#include // std::false_type, std::true_type +#if SQLITE_VERSION_NUMBER >= 3024000 +#include // std::tuple #include // std::forward, std::move +#endif #include "../functional/cxx_type_traits_polyfill.h" @@ -24,7 +25,7 @@ namespace sqlite_orm { template upsert_clause> do_update(ActionsArgs... actions) { - return {std::move(this->args), {std::make_tuple(std::forward(actions)...)}}; + return {std::move(this->args), {std::forward(actions)...}}; } }; @@ -40,8 +41,13 @@ namespace sqlite_orm { template using is_upsert_clause = polyfill::is_specialization_of; +#else + template + struct is_upsert_clause : polyfill::bool_constant {}; +#endif } +#if SQLITE_VERSION_NUMBER >= 3024000 /** * ON CONFLICT upsert clause builder function. * @example diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 43281de35..2427cfaae 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -105,9 +105,9 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, std::tuple>, void> { - using node_type = upsert_clause, std::tuple>; + template + struct ast_iterator> { + using node_type = T; template void operator()(const node_type& expression, L& lambda) const { diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 3e07a82e4..b737d1b91 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -54,9 +54,8 @@ namespace sqlite_orm { using type = tuple_cat_t; }; - template - struct node_tuple, std::tuple>, void> - : node_tuple> {}; + template + struct node_tuple> : node_tuple {}; template struct node_tuple, void> { diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 3d98ed045..93a079147 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -224,9 +224,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, std::tuple>, void> { - using statement_type = upsert_clause, std::tuple>; + template + struct statement_serializer> { + using statement_type = T; template std::string operator()(const statement_type& statement, const Ctx& context) const { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 750c202d7..b1b056f48 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -11325,9 +11325,10 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" -#include // std::tuple, std::make_tuple -#include // std::false_type, std::true_type +#if SQLITE_VERSION_NUMBER >= 3024000 +#include // std::tuple #include // std::forward, std::move +#endif // #include "../functional/cxx_type_traits_polyfill.h" @@ -11349,7 +11350,7 @@ namespace sqlite_orm { template upsert_clause> do_update(ActionsArgs... actions) { - return {std::move(this->args), {std::make_tuple(std::forward(actions)...)}}; + return {std::move(this->args), {std::forward(actions)...}}; } }; @@ -11365,8 +11366,13 @@ namespace sqlite_orm { template using is_upsert_clause = polyfill::is_specialization_of; +#else + template + struct is_upsert_clause : polyfill::bool_constant {}; +#endif } +#if SQLITE_VERSION_NUMBER >= 3024000 /** * ON CONFLICT upsert clause builder function. * @example @@ -12485,9 +12491,9 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, std::tuple>, void> { - using node_type = upsert_clause, std::tuple>; + template + struct ast_iterator> { + using node_type = T; template void operator()(const node_type& expression, L& lambda) const { @@ -14313,13 +14319,13 @@ namespace sqlite_orm { (this->extract(values[Idx], std::get(tuple)), ...); } #else - template - void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { - this->extract(values[I], std::get(tuple)); - (*this)(values, tuple, std::index_sequence{}); - } - template - void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} + template + void operator()(sqlite3_value** values, Tpl& tuple, std::index_sequence) const { + this->extract(values[I], std::get(tuple)); + (*this)(values, tuple, std::index_sequence{}); + } + template + void operator()(sqlite3_value** /*values*/, Tpl&, std::index_sequence) const {} #endif template void extract(sqlite3_value* value, T& t) const { @@ -15695,9 +15701,9 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, std::tuple>, void> { - using statement_type = upsert_clause, std::tuple>; + template + struct statement_serializer> { + using statement_type = T; template std::string operator()(const statement_type& statement, const Ctx& context) const { @@ -18375,7 +18381,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3035000 // DROP COLUMN feature exists (v3.35.0) res = sync_schema_result::old_columns_removed; #else - gottaCreateTable = true; + gottaCreateTable = true; #endif } else { res = sync_schema_result::old_columns_removed; @@ -18693,13 +18699,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18739,13 +18745,13 @@ namespace sqlite_orm { std::ref(processObject), std::ref(expression.transformer)); #else - auto& transformer = expression.transformer; - std::for_each(expression.range.first, - expression.range.second, - [&processObject, &transformer](auto& item) { - const object_type& object = polyfill::invoke(transformer, item); - processObject(object); - }); + auto& transformer = expression.transformer; + std::for_each(expression.range.first, + expression.range.second, + [&processObject, &transformer](auto& item) { + const object_type& object = polyfill::invoke(transformer, item); + processObject(object); + }); #endif }, [&processObject](auto& expression) { @@ -18837,22 +18843,22 @@ namespace sqlite_orm { } return std::move(res).value(); #else - auto& table = this->get_table(); - auto stepRes = sqlite3_step(stmt); - switch(stepRes) { - case SQLITE_ROW: { - T res; - object_from_column_builder builder{res, stmt}; - table.for_each_column(builder); - return res; - } break; - case SQLITE_DONE: { - throw std::system_error{orm_error_code::not_found}; - } break; - default: { - throw_translated_sqlite_error(stmt); - } + auto& table = this->get_table(); + auto stepRes = sqlite3_step(stmt); + switch(stepRes) { + case SQLITE_ROW: { + T res; + object_from_column_builder builder{res, stmt}; + table.for_each_column(builder); + return res; + } break; + case SQLITE_DONE: { + throw std::system_error{orm_error_code::not_found}; + } break; + default: { + throw_translated_sqlite_error(stmt); } + } #endif } @@ -19036,9 +19042,8 @@ namespace sqlite_orm { using type = tuple_cat_t; }; - template - struct node_tuple, std::tuple>, void> - : node_tuple> {}; + template + struct node_tuple> : node_tuple {}; template struct node_tuple, void> { @@ -19679,9 +19684,9 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto it = std::ranges::find(res, columnName, &table_xinfo::name); #else - auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { - return ti.name == columnName; - }); + auto it = std::find_if(res.begin(), res.end(), [&columnName](const table_xinfo& ti) { + return ti.name == columnName; + }); #endif if(it != res.end()) { it->pk = static_cast(i + 1); @@ -19754,9 +19759,9 @@ namespace sqlite_orm { } res = sync_schema_result::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, table, {}); - res = sync_schema_result::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, table, {}); + res = sync_schema_result::old_columns_removed; #endif } @@ -19820,11 +19825,11 @@ namespace sqlite_orm { #if __cpp_lib_ranges >= 201911L auto columnToIgnoreIt = std::ranges::find(columnsToIgnore, columnName, &table_xinfo::name); #else - auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), - columnsToIgnore.end(), - [&columnName](const table_xinfo* tableInfo) { - return columnName == tableInfo->name; - }); + auto columnToIgnoreIt = std::find_if(columnsToIgnore.begin(), + columnsToIgnore.end(), + [&columnName](const table_xinfo* tableInfo) { + return columnName == tableInfo->name; + }); #endif if(columnToIgnoreIt == columnsToIgnore.end()) { columnNames.push_back(cref(columnName)); diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 0118faa73..6dfe212c2 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -207,12 +207,14 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(&User::id)); iterate_ast(node, lambda); } +#if SQLITE_VERSION_NUMBER >= 3024000 SECTION("upsert_clause") { auto node = on_conflict(&User::id).do_update(set(c(&User::name) = excluded(&User::name))); expected.push_back(typeid(&User::name)); expected.push_back(typeid(&User::name)); iterate_ast(node, lambda); } +#endif SECTION("into") { auto node = into(); iterate_ast(node, lambda); diff --git a/tests/statement_serializer_tests/ast/upsert_clause.cpp b/tests/statement_serializer_tests/ast/upsert_clause.cpp index ab36b5e87..1f615e8e0 100644 --- a/tests/statement_serializer_tests/ast/upsert_clause.cpp +++ b/tests/statement_serializer_tests/ast/upsert_clause.cpp @@ -3,6 +3,7 @@ using namespace sqlite_orm; +#if SQLITE_VERSION_NUMBER >= 3024000 TEST_CASE("upsert_clause") { using internal::serialize; struct Vocabulary { @@ -102,3 +103,4 @@ TEST_CASE("upsert_clause") { } REQUIRE(value == expected); } +#endif diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index a4d6e93bf..5d28c4c50 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -925,6 +925,7 @@ TEST_CASE("Node tuple") { using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } +#if SQLITE_VERSION_NUMBER >= 3024000 SECTION("upsert_clause") { auto statement = on_conflict(&User::id).do_update(set(c(&User::name) = excluded(&User::name))); using Statement = decltype(statement); @@ -932,6 +933,7 @@ TEST_CASE("Node tuple") { using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } +#endif SECTION("group_by") { auto statement = group_by(&User::id); using Statement = decltype(statement); From fb5d51c67233f4de00587b1d9638d62f9f5c9382 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 10 Mar 2023 15:54:05 +0000 Subject: [PATCH 088/100] Avoided warning of unused parameter --- dev/table.h | 2 ++ include/sqlite_orm/sqlite_orm.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dev/table.h b/dev/table.h index 0aede4255..65073b6df 100644 --- a/dev/table.h +++ b/dev/table.h @@ -110,6 +110,8 @@ namespace sqlite_orm { constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); result = &get(column.constraints).storage; }); +#else + (void)name; #endif return result; } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index b1b056f48..73c5caf14 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -9765,6 +9765,8 @@ namespace sqlite_orm { constexpr size_t opIndex = first_index_sequence_value(generated_op_index_sequence{}); result = &get(column.constraints).storage; }); +#else + (void)name; #endif return result; } From ddee5003c8df9609c03976384c2000b27ba4e160 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 12 Mar 2023 16:25:05 +0000 Subject: [PATCH 089/100] One implementation of `stream_sql_escaped()` --- dev/serialize_result_type.h | 2 + dev/serializing_util.h | 51 +++++------------- include/sqlite_orm/sqlite_orm.h | 54 ++++++------------- .../column_names.cpp | 7 +-- 4 files changed, 37 insertions(+), 77 deletions(-) diff --git a/dev/serialize_result_type.h b/dev/serialize_result_type.h index ad9c8d236..ac5f606b8 100644 --- a/dev/serialize_result_type.h +++ b/dev/serialize_result_type.h @@ -9,8 +9,10 @@ namespace sqlite_orm { namespace internal { #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED using serialize_result_type = std::string_view; + using serialize_arg_type = std::string_view; #else using serialize_result_type = std::string; + using serialize_arg_type = const std::string&; #endif } } diff --git a/dev/serializing_util.h b/dev/serializing_util.h index fb1d696a0..376b5c4d4 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -6,16 +6,13 @@ #include #include #include // std::exchange, std::tuple_size -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) -#include -#include // std::find -#endif #include "functional/cxx_universal.h" // ::size_t #include "functional/cxx_type_traits_polyfill.h" #include "tuple_helper/tuple_iteration.h" #include "error_code.h" #include "serializer_context.h" +#include "serialize_result_type.h" #include "util.h" namespace sqlite_orm { @@ -29,44 +26,24 @@ namespace sqlite_orm { template std::string serialize_order_by(const T& t, const Ctx& context); -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) - // optimized version when string_view's iterator range constructor is available - template - void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) - requires requires { - std::string_view{str.cbegin(), str.cend()}; - } - { - for(std::string::const_iterator it = str.cbegin(), next; true; it = next + 1) { - next = std::find(it, str.cend(), char2Escape); - os << std::string_view{it, next}; - - if(next == str.cend()) [[likely]] { + inline void stream_sql_escaped(std::ostream& os, serialize_arg_type str, char char2Escape) { + for(size_t offset = 0, next; true; offset = next + 1) { + next = str.find(char2Escape, offset); + + if(next == str.npos) { + os.write(str.data() + offset, str.size() - offset); break; } - os << std::string(2, char2Escape); - } - } - template -#endif - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; - } - os << c; - } + os.write(str.data() + offset, next - offset + 1); + os.write(&char2Escape, 1); } } inline void stream_identifier(std::ostream& ss, - const std::string& qualifier, - const std::string& identifier, - const std::string& alias) { + serialize_arg_type qualifier, + serialize_arg_type identifier, + serialize_arg_type alias) { constexpr char quoteChar = '"'; constexpr char qualified[] = {quoteChar, '.', '\0'}; constexpr char aliased[] = {' ', quoteChar, '\0'}; @@ -92,11 +69,11 @@ namespace sqlite_orm { } inline void stream_identifier(std::ostream& ss, const std::string& identifier, const std::string& alias) { - return stream_identifier(ss, std::string{}, identifier, alias); + return stream_identifier(ss, "", identifier, alias); } inline void stream_identifier(std::ostream& ss, const std::string& identifier) { - return stream_identifier(ss, std::string{}, identifier, std::string{}); + return stream_identifier(ss, "", identifier, ""); } template diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 750c202d7..f224756af 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1935,8 +1935,10 @@ namespace sqlite_orm { namespace internal { #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED using serialize_result_type = std::string_view; + using serialize_arg_type = std::string_view; #else using serialize_result_type = std::string; + using serialize_arg_type = const std::string&; #endif } } @@ -13198,10 +13200,6 @@ namespace sqlite_orm { #include #include #include // std::exchange, std::tuple_size -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) -#include -#include // std::find -#endif // #include "functional/cxx_universal.h" // ::size_t @@ -13213,6 +13211,8 @@ namespace sqlite_orm { // #include "serializer_context.h" +// #include "serialize_result_type.h" + // #include "util.h" namespace sqlite_orm { @@ -13226,44 +13226,24 @@ namespace sqlite_orm { template std::string serialize_order_by(const T& t, const Ctx& context); -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && !defined(SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS) - // optimized version when string_view's iterator range constructor is available - template - void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) - requires requires { - std::string_view{str.cbegin(), str.cend()}; - } - { - for(std::string::const_iterator it = str.cbegin(), next; true; it = next + 1) { - next = std::find(it, str.cend(), char2Escape); - os << std::string_view{it, next}; - - if(next == str.cend()) [[likely]] { + inline void stream_sql_escaped(std::ostream& os, serialize_arg_type str, char char2Escape) { + for(size_t offset = 0, next; true; offset = next + 1) { + next = str.find(char2Escape, offset); + + if(next == str.npos) { + os.write(str.data() + offset, str.size() - offset); break; } - os << std::string(2, char2Escape); - } - } - template -#endif - inline void stream_sql_escaped(std::ostream& os, const std::string& str, char char2Escape) { - if(str.find(char2Escape) == str.npos) { - os << str; - } else { - for(char c: str) { - if(c == char2Escape) { - os << char2Escape; - } - os << c; - } + os.write(str.data() + offset, next - offset + 1); + os.write(&char2Escape, 1); } } inline void stream_identifier(std::ostream& ss, - const std::string& qualifier, - const std::string& identifier, - const std::string& alias) { + serialize_arg_type qualifier, + serialize_arg_type identifier, + serialize_arg_type alias) { constexpr char quoteChar = '"'; constexpr char qualified[] = {quoteChar, '.', '\0'}; constexpr char aliased[] = {' ', quoteChar, '\0'}; @@ -13289,11 +13269,11 @@ namespace sqlite_orm { } inline void stream_identifier(std::ostream& ss, const std::string& identifier, const std::string& alias) { - return stream_identifier(ss, std::string{}, identifier, alias); + return stream_identifier(ss, "", identifier, alias); } inline void stream_identifier(std::ostream& ss, const std::string& identifier) { - return stream_identifier(ss, std::string{}, identifier, std::string{}); + return stream_identifier(ss, "", identifier, ""); } template diff --git a/tests/statement_serializer_tests/column_names.cpp b/tests/statement_serializer_tests/column_names.cpp index 1b9a40efb..1e3e11a69 100644 --- a/tests/statement_serializer_tests/column_names.cpp +++ b/tests/statement_serializer_tests/column_names.cpp @@ -169,7 +169,7 @@ TEST_CASE("statement_serializer column names") { return R"(a"s)"; } }; - auto table1 = make_table(R"(ob"ject1)", make_column(R"(i"d)", &Object1::id)); + auto table1 = make_table(R"(object1"")", make_column(R"(i"d)", &Object1::id)); auto table2 = make_table(R"(ob"ject2)", make_column(R"(i"d)", &Object2::id)); using db_objects_t = internal::db_objects_tuple; db_objects_t dbObjects{table1, table2}; @@ -184,8 +184,9 @@ TEST_CASE("statement_serializer column names") { multi_order_by(order_by(get()), order_by(alias_column(&Object2::id)))); expression.highest_level = true; auto value = serialize(expression, context); - REQUIRE(value == R"(SELECT "ob""ject1"."i""d", "ob""ject1"."i""d" AS "a""s", "d"."i""d" FROM "ob""ject1" )" - R"(JOIN "ob""ject2" "d" USING ("i""d") ORDER BY "a""s", "d"."i""d")"); + REQUIRE(value == + R"(SELECT "object1"""""."i""d", "object1"""""."i""d" AS "a""s", "d"."i""d" FROM "object1""""" )" + R"(JOIN "ob""ject2" "d" USING ("i""d") ORDER BY "a""s", "d"."i""d")"); } } } From 72b09de8c7bc375d09068f3caea7a3466349d854 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 12 Mar 2023 16:26:19 +0000 Subject: [PATCH 090/100] Updated declaration of `serialize()` --- dev/column_names_getter.h | 4 ++-- dev/default_value_extractor.h | 4 ++-- dev/serializing_util.h | 6 +++--- dev/statement_serializer.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 18 +++++++++--------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dev/column_names_getter.h b/dev/column_names_getter.h index 6dd70c690..b35a4e359 100644 --- a/dev/column_names_getter.h +++ b/dev/column_names_getter.h @@ -21,8 +21,8 @@ namespace sqlite_orm { namespace internal { - template - std::string serialize(const T& t, const serializer_context& context); + template + std::string serialize(const T&, const serializer_context&); template std::vector& collect_table_column_names(std::vector& collectedExpressions, diff --git a/dev/default_value_extractor.h b/dev/default_value_extractor.h index 9ad38eeb8..ae8d90e20 100644 --- a/dev/default_value_extractor.h +++ b/dev/default_value_extractor.h @@ -10,8 +10,8 @@ namespace sqlite_orm { namespace internal { - template - std::string serialize(const T& t, const serializer_context& context); + template + std::string serialize(const T&, const serializer_context&); /** * Serialize default value of a column's default valu diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 376b5c4d4..b1e5d1948 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -20,11 +20,11 @@ namespace sqlite_orm { template struct order_by_t; - template - std::string serialize(const T& t, const serializer_context& context); + template + std::string serialize(const T&, const serializer_context&); template - std::string serialize_order_by(const T& t, const Ctx& context); + std::string serialize_order_by(const T&, const Ctx&); inline void stream_sql_escaped(std::ostream& os, serialize_arg_type str, char char2Escape) { for(size_t offset = 0, next; true; offset = next + 1) { diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 3d98ed045..cf9a5578f 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -51,8 +51,8 @@ namespace sqlite_orm { template struct statement_serializer; - template - std::string serialize(const T& t, const serializer_context& context) { + template + std::string serialize(const T& t, const serializer_context& context) { statement_serializer serializer; return serializer(t, context); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index f224756af..a0f67d5e9 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10202,8 +10202,8 @@ namespace sqlite_orm { namespace internal { - template - std::string serialize(const T& t, const serializer_context& context); + template + std::string serialize(const T&, const serializer_context&); /** * Serialize default value of a column's default valu @@ -13220,11 +13220,11 @@ namespace sqlite_orm { template struct order_by_t; - template - std::string serialize(const T& t, const serializer_context& context); + template + std::string serialize(const T&, const serializer_context&); template - std::string serialize_order_by(const T& t, const Ctx& context); + std::string serialize_order_by(const T&, const Ctx&); inline void stream_sql_escaped(std::ostream& os, serialize_arg_type str, char char2Escape) { for(size_t offset = 0, next; true; offset = next + 1) { @@ -15306,8 +15306,8 @@ namespace sqlite_orm { namespace internal { - template - std::string serialize(const T& t, const serializer_context& context); + template + std::string serialize(const T&, const serializer_context&); template std::vector& collect_table_column_names(std::vector& collectedExpressions, @@ -15502,8 +15502,8 @@ namespace sqlite_orm { template struct statement_serializer; - template - std::string serialize(const T& t, const serializer_context& context) { + template + std::string serialize(const T& t, const serializer_context& context) { statement_serializer serializer; return serializer(t, context); } From cd04472f6222417d832bf87c0d7daea1e01648b3 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 12 Mar 2023 23:59:12 +0000 Subject: [PATCH 091/100] Tests for constrained join clauses with regard to table collection --- dev/conditions.h | 2 +- dev/statement_serializer.h | 5 ++- include/sqlite_orm/sqlite_orm.h | 7 +-- .../select_constraints.cpp | 45 +++++++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/dev/conditions.h b/dev/conditions.h index 1f21332dc..67e89d762 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -813,7 +813,7 @@ namespace sqlite_orm { using is_from = polyfill::is_specialization_of; template - using is_any_join = polyfill::is_detected; + using is_constrained_join = polyfill::is_detected; } /** diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index f7dec68d7..dfb9def01 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1506,7 +1506,8 @@ namespace sqlite_orm { constexpr bool hasExplicitFrom = tuple_has::value; if(!hasExplicitFrom) { auto tableNames = collect_table_names(sel, context); - using joins_index_sequence = filter_tuple_sequence_t; + using joins_index_sequence = filter_tuple_sequence_t; + // deduplicate table names of constrained join statements iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) { using original_join_type = typename std::decay_t::type; using cross_join_type = mapped_type_proxy_t; @@ -1851,7 +1852,7 @@ namespace sqlite_orm { ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), alias_extractor::as_alias()) - << serialize(l.constraint, context); + << " " << serialize(l.constraint, context); return ss.str(); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 0406d6300..73013ac90 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3775,7 +3775,7 @@ namespace sqlite_orm { using is_from = polyfill::is_specialization_of; template - using is_any_join = polyfill::is_detected; + using is_constrained_join = polyfill::is_detected; } /** @@ -16965,7 +16965,8 @@ namespace sqlite_orm { constexpr bool hasExplicitFrom = tuple_has::value; if(!hasExplicitFrom) { auto tableNames = collect_table_names(sel, context); - using joins_index_sequence = filter_tuple_sequence_t; + using joins_index_sequence = filter_tuple_sequence_t; + // deduplicate table names of constrained join statements iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) { using original_join_type = typename std::decay_t::type; using cross_join_type = mapped_type_proxy_t; @@ -17310,7 +17311,7 @@ namespace sqlite_orm { ss << static_cast(l) << " " << streaming_identifier(lookup_table_name>(context.db_objects), alias_extractor::as_alias()) - << serialize(l.constraint, context); + << " " << serialize(l.constraint, context); return ss.str(); } }; diff --git a/tests/statement_serializer_tests/select_constraints.cpp b/tests/statement_serializer_tests/select_constraints.cpp index 354af39af..60c51c45e 100644 --- a/tests/statement_serializer_tests/select_constraints.cpp +++ b/tests/statement_serializer_tests/select_constraints.cpp @@ -86,6 +86,51 @@ TEST_CASE("statement_serializer select constraints") { } #endif } + // tests whether the statement serializer for a select with joins + // properly deduplicates the table names when no explicit from is used + SECTION("deduplicated table names") { + struct UserProps { + int id = 0; + std::string name; + }; + auto table2 = + make_table("user_props", make_column("id", &UserProps::id), make_column("name", &UserProps::name)); + using db_objects_t = internal::db_objects_tuple; + auto dbObjects = db_objects_t{table, table2}; + internal::serializer_context context{dbObjects}; + context.use_parentheses = false; + + SECTION("left join") { + auto expression = select(asterisk(), left_join(using_(&UserProps::id))); + value = serialize(expression, context); + expected = R"(SELECT "users".* FROM "users" LEFT JOIN "user_props" USING ("id"))"; + } + SECTION("join") { + auto expression = select(asterisk(), join(using_(&UserProps::id))); + value = serialize(expression, context); + expected = R"(SELECT "users".* FROM "users" JOIN "user_props" USING ("id"))"; + } + SECTION("left outer join") { + auto expression = select(asterisk(), left_outer_join(using_(&UserProps::id))); + value = serialize(expression, context); + expected = R"(SELECT "users".* FROM "users" LEFT OUTER JOIN "user_props" USING ("id"))"; + } + SECTION("inner join") { + auto expression = select(asterisk(), inner_join(using_(&UserProps::id))); + value = serialize(expression, context); + expected = R"(SELECT "users".* FROM "users" INNER JOIN "user_props" USING ("id"))"; + } + SECTION("cross join") { + auto expression = select(asterisk(), cross_join()); + value = serialize(expression, context); + expected = R"(SELECT "users".* FROM "users" CROSS JOIN "user_props")"; + } + SECTION("natural join") { + auto expression = select(asterisk(), natural_join()); + value = serialize(expression, context); + expected = R"(SELECT "users".* FROM "users" NATURAL JOIN "user_props")"; + } + } SECTION("function_call") { struct Func { bool operator()(int arg) const { From 4adda953c4ec31a1cd8d393bb97b9ce40375be01 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 13 Mar 2023 10:12:58 +0000 Subject: [PATCH 092/100] Unified serialization and iteration of joins --- dev/ast_iterator.h | 44 ++-------- dev/statement_serializer.h | 93 +++++----------------- include/sqlite_orm/sqlite_orm.h | 137 ++++++-------------------------- 3 files changed, 52 insertions(+), 222 deletions(-) diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 2427cfaae..5dcc9bc5b 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -497,13 +497,13 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, void> { - using node_type = left_join_t; + template + struct ast_iterator> { + using node_type = Join; template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); + void operator()(const node_type& join, L& lambda) const { + iterate_ast(join.constraint, lambda); } }; @@ -512,8 +512,8 @@ namespace sqlite_orm { using node_type = on_t; template - void operator()(const node_type& o, L& lambda) const { - iterate_ast(o.arg, lambda); + void operator()(const node_type& on, L& lambda) const { + iterate_ast(on.arg, lambda); } }; @@ -529,36 +529,6 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, void> { - using node_type = join_t; - - template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); - } - }; - - template - struct ast_iterator, void> { - using node_type = left_outer_join_t; - - template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); - } - }; - - template - struct ast_iterator, void> { - using node_type = inner_join_t; - - template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); - } - }; - template struct ast_iterator, void> { using node_type = simple_case_t; diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index dfb9def01..c8c96e4c9 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -1829,30 +1829,33 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = cross_join_t; + template + struct statement_serializer< + Join, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using statement_type = Join; template - std::string operator()(const statement_type& c, const Ctx& context) const { + std::string operator()(const statement_type& join, const Ctx& context) const { std::stringstream ss; - ss << static_cast(c) << " " - << streaming_identifier(lookup_table_name(context.db_objects)); + ss << static_cast(join) << " " + << streaming_identifier(lookup_table_name>(context.db_objects)); return ss.str(); } }; - template - struct statement_serializer, void> { - using statement_type = inner_join_t; + template + struct statement_serializer> { + using statement_type = Join; template - std::string operator()(const statement_type& l, const Ctx& context) const { + std::string operator()(const statement_type& join, const Ctx& context) const { std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); + ss << static_cast(join) << " " + << streaming_identifier(lookup_table_name>>(context.db_objects), + alias_extractor>::as_alias()) + << " " << serialize(join.constraint, context); return ss.str(); } }; @@ -1862,69 +1865,11 @@ namespace sqlite_orm { using statement_type = on_t; template - std::string operator()(const statement_type& t, const Ctx& context) const { + std::string operator()(const statement_type& on, const Ctx& context) const { std::stringstream ss; auto newContext = context; newContext.skip_table_name = false; - ss << static_cast(t) << " " << serialize(t.arg, newContext) << " "; - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = join_t; - - template - std::string operator()(const statement_type& l, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = left_join_t; - - template - std::string operator()(const statement_type& l, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = left_outer_join_t; - - template - std::string operator()(const statement_type& l, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = natural_join_t; - - template - std::string operator()(const statement_type& c, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(c) << " " - << streaming_identifier(lookup_table_name(context.db_objects)); + ss << static_cast(on) << " " << serialize(on.arg, newContext) << " "; return ss.str(); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 73013ac90..10e526f6b 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -12887,13 +12887,13 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, void> { - using node_type = left_join_t; + template + struct ast_iterator> { + using node_type = Join; template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); + void operator()(const node_type& join, L& lambda) const { + iterate_ast(join.constraint, lambda); } }; @@ -12902,8 +12902,8 @@ namespace sqlite_orm { using node_type = on_t; template - void operator()(const node_type& o, L& lambda) const { - iterate_ast(o.arg, lambda); + void operator()(const node_type& on, L& lambda) const { + iterate_ast(on.arg, lambda); } }; @@ -12919,36 +12919,6 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, void> { - using node_type = join_t; - - template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); - } - }; - - template - struct ast_iterator, void> { - using node_type = left_outer_join_t; - - template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); - } - }; - - template - struct ast_iterator, void> { - using node_type = inner_join_t; - - template - void operator()(const node_type& j, L& lambda) const { - iterate_ast(j.constraint, lambda); - } - }; - template struct ast_iterator, void> { using node_type = simple_case_t; @@ -17288,30 +17258,33 @@ namespace sqlite_orm { } }; - template - struct statement_serializer, void> { - using statement_type = cross_join_t; + template + struct statement_serializer< + Join, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using statement_type = Join; template - std::string operator()(const statement_type& c, const Ctx& context) const { + std::string operator()(const statement_type& join, const Ctx& context) const { std::stringstream ss; - ss << static_cast(c) << " " - << streaming_identifier(lookup_table_name(context.db_objects)); + ss << static_cast(join) << " " + << streaming_identifier(lookup_table_name>(context.db_objects)); return ss.str(); } }; - template - struct statement_serializer, void> { - using statement_type = inner_join_t; + template + struct statement_serializer> { + using statement_type = Join; template - std::string operator()(const statement_type& l, const Ctx& context) const { + std::string operator()(const statement_type& join, const Ctx& context) const { std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); + ss << static_cast(join) << " " + << streaming_identifier(lookup_table_name>>(context.db_objects), + alias_extractor>::as_alias()) + << " " << serialize(join.constraint, context); return ss.str(); } }; @@ -17321,69 +17294,11 @@ namespace sqlite_orm { using statement_type = on_t; template - std::string operator()(const statement_type& t, const Ctx& context) const { + std::string operator()(const statement_type& on, const Ctx& context) const { std::stringstream ss; auto newContext = context; newContext.skip_table_name = false; - ss << static_cast(t) << " " << serialize(t.arg, newContext) << " "; - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = join_t; - - template - std::string operator()(const statement_type& l, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = left_join_t; - - template - std::string operator()(const statement_type& l, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = left_outer_join_t; - - template - std::string operator()(const statement_type& l, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(l) << " " - << streaming_identifier(lookup_table_name>(context.db_objects), - alias_extractor::as_alias()) - << " " << serialize(l.constraint, context); - return ss.str(); - } - }; - - template - struct statement_serializer, void> { - using statement_type = natural_join_t; - - template - std::string operator()(const statement_type& c, const Ctx& context) const { - std::stringstream ss; - ss << static_cast(c) << " " - << streaming_identifier(lookup_table_name(context.db_objects)); + ss << static_cast(on) << " " << serialize(on.arg, newContext) << " "; return ss.str(); } }; From 612ea59da4bbfd86e698e22557178d063c0e824b Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sat, 18 Mar 2023 23:31:33 +0000 Subject: [PATCH 093/100] Moved operators for `expression_t` into internal namespace --- dev/conditions.h | 264 ++++++++++++++++---------------- include/sqlite_orm/sqlite_orm.h | 264 ++++++++++++++++---------------- tests/CMakeLists.txt | 1 + tests/operators/adl.cpp | 64 ++++++++ 4 files changed, 333 insertions(+), 260 deletions(-) create mode 100644 tests/operators/adl.cpp diff --git a/dev/conditions.h b/dev/conditions.h index 67e89d762..7b3dafaa3 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -843,167 +843,171 @@ namespace sqlite_orm { return {std::move(arg)}; } - /** - * Cute operators for columns - */ - template - internal::lesser_than_t operator<(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + // Delibaretly put operators for `expression_t` into the internal namespace + // to facilitate ADL (Argument Dependent Lookup) + namespace internal { + /** + * Cute operators for columns + */ + template + lesser_than_t operator<(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::lesser_than_t operator<(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + lesser_than_t operator<(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::lesser_or_equal_t operator<=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + lesser_or_equal_t operator<=(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::lesser_or_equal_t operator<=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + lesser_or_equal_t operator<=(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::greater_than_t operator>(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + greater_than_t operator>(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::greater_than_t operator>(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + greater_than_t operator>(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::greater_or_equal_t operator>=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + greater_or_equal_t operator>=(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::greater_or_equal_t operator>=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + greater_or_equal_t operator>=(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::is_equal_t operator==(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + is_equal_t operator==(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::is_equal_t operator==(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + is_equal_t operator==(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::is_not_equal_t operator!=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + is_not_equal_t operator!=(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::is_not_equal_t operator!=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + is_not_equal_t operator!=(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::conc_t operator||(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + conc_t operator||(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::conc_t operator||(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + conc_t operator||(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::conc_t operator||(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + conc_t operator||(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template = true> - internal::conc_t operator||(E expr, R r) { - return {std::move(expr), std::move(r)}; - } + template = true> + conc_t operator||(E expr, R r) { + return {std::move(expr), std::move(r)}; + } - template = true> - internal::conc_t operator||(L l, E expr) { - return {std::move(l), std::move(expr)}; - } + template = true> + conc_t operator||(L l, E expr) { + return {std::move(l), std::move(expr)}; + } - template - internal::add_t operator+(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + add_t operator+(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::add_t operator+(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + add_t operator+(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::add_t operator+(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + add_t operator+(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::sub_t operator-(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + sub_t operator-(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::sub_t operator-(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + sub_t operator-(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::sub_t operator-(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + sub_t operator-(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::mul_t operator*(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + mul_t operator*(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::mul_t operator*(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + mul_t operator*(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::mul_t operator*(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + mul_t operator*(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::div_t operator/(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + div_t operator/(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::div_t operator/(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + div_t operator/(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::div_t operator/(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + div_t operator/(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::mod_t operator%(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + mod_t operator%(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::mod_t operator%(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + mod_t operator%(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::mod_t operator%(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; + template + mod_t operator%(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } } template diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 10e526f6b..a2cbcb865 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3805,167 +3805,171 @@ namespace sqlite_orm { return {std::move(arg)}; } - /** - * Cute operators for columns - */ - template - internal::lesser_than_t operator<(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + // Delibaretly put operators for `expression_t` into the internal namespace + // to facilitate ADL (Argument Dependent Lookup) + namespace internal { + /** + * Cute operators for columns + */ + template + lesser_than_t operator<(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::lesser_than_t operator<(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + lesser_than_t operator<(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::lesser_or_equal_t operator<=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + lesser_or_equal_t operator<=(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::lesser_or_equal_t operator<=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + lesser_or_equal_t operator<=(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::greater_than_t operator>(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + greater_than_t operator>(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::greater_than_t operator>(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + greater_than_t operator>(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::greater_or_equal_t operator>=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + greater_or_equal_t operator>=(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::greater_or_equal_t operator>=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + greater_or_equal_t operator>=(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::is_equal_t operator==(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + is_equal_t operator==(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::is_equal_t operator==(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + is_equal_t operator==(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::is_not_equal_t operator!=(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + is_not_equal_t operator!=(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::is_not_equal_t operator!=(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + is_not_equal_t operator!=(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::conc_t operator||(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + conc_t operator||(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::conc_t operator||(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + conc_t operator||(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::conc_t operator||(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + conc_t operator||(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template = true> - internal::conc_t operator||(E expr, R r) { - return {std::move(expr), std::move(r)}; - } + template = true> + conc_t operator||(E expr, R r) { + return {std::move(expr), std::move(r)}; + } - template = true> - internal::conc_t operator||(L l, E expr) { - return {std::move(l), std::move(expr)}; - } + template = true> + conc_t operator||(L l, E expr) { + return {std::move(l), std::move(expr)}; + } - template - internal::add_t operator+(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + add_t operator+(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::add_t operator+(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + add_t operator+(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::add_t operator+(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + add_t operator+(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::sub_t operator-(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + sub_t operator-(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::sub_t operator-(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + sub_t operator-(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::sub_t operator-(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + sub_t operator-(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::mul_t operator*(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + mul_t operator*(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::mul_t operator*(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + mul_t operator*(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::mul_t operator*(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + mul_t operator*(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::div_t operator/(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + div_t operator/(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::div_t operator/(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + div_t operator/(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::div_t operator/(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; - } + template + div_t operator/(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } - template - internal::mod_t operator%(internal::expression_t expr, R r) { - return {std::move(expr.value), std::move(r)}; - } + template + mod_t operator%(expression_t expr, R r) { + return {std::move(expr.value), std::move(r)}; + } - template - internal::mod_t operator%(L l, internal::expression_t expr) { - return {std::move(l), std::move(expr.value)}; - } + template + mod_t operator%(L l, expression_t expr) { + return {std::move(l), std::move(expr.value)}; + } - template - internal::mod_t operator%(internal::expression_t l, internal::expression_t r) { - return {std::move(l.value), std::move(r.value)}; + template + mod_t operator%(expression_t l, expression_t r) { + return {std::move(l.value), std::move(r.value)}; + } } template diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f1ad519bc..b956a1ab7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -55,6 +55,7 @@ add_executable(unit_tests operators/not_operator.cpp operators/bitwise.cpp operators/binary_operators.cpp + operators/adl.cpp prepared_statement_tests/select.cpp prepared_statement_tests/get_all.cpp prepared_statement_tests/get_all_pointer.cpp diff --git a/tests/operators/adl.cpp b/tests/operators/adl.cpp new file mode 100644 index 000000000..bca8f8e65 --- /dev/null +++ b/tests/operators/adl.cpp @@ -0,0 +1,64 @@ +#include +#include + +using sqlite_orm::c; +using sqlite_orm::internal::binary_operator; +using sqlite_orm::internal::greater_or_equal_t; +using sqlite_orm::internal::greater_than_t; +using sqlite_orm::internal::is_equal_t; +using sqlite_orm::internal::is_not_equal_t; +using sqlite_orm::internal::lesser_or_equal_t; +using sqlite_orm::internal::lesser_than_t; +using sqlite_orm::polyfill::is_specialization_of_v; + +TEST_CASE("ADL and expression operators") { + struct User { + int id; + }; + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v 42), greater_than_t>); + STATIC_REQUIRE(is_specialization_of_v c(&User::id)), greater_than_t>); + + STATIC_REQUIRE(is_specialization_of_v= 42), greater_or_equal_t>); + STATIC_REQUIRE(is_specialization_of_v= c(&User::id)), greater_or_equal_t>); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); +} From 2ddc81da76e0a8933a75a41312606c930f797c18 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sat, 18 Mar 2023 23:38:44 +0000 Subject: [PATCH 094/100] Fix typo in comment --- dev/conditions.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/conditions.h b/dev/conditions.h index 7b3dafaa3..83be6a6ab 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -843,7 +843,7 @@ namespace sqlite_orm { return {std::move(arg)}; } - // Delibaretly put operators for `expression_t` into the internal namespace + // Deliberately put operators for `expression_t` into the internal namespace // to facilitate ADL (Argument Dependent Lookup) namespace internal { /** diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index a2cbcb865..2c2d831c9 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3805,7 +3805,7 @@ namespace sqlite_orm { return {std::move(arg)}; } - // Delibaretly put operators for `expression_t` into the internal namespace + // Deliberately put operators for `expression_t` into the internal namespace // to facilitate ADL (Argument Dependent Lookup) namespace internal { /** From 46fa6c9d1cf9a8178f3d2b7709077a5ede53840a Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 19 Mar 2023 09:45:54 +0000 Subject: [PATCH 095/100] Moved unit tests for operators and ADL below 'static UT' subfolder --- tests/CMakeLists.txt | 4 ++-- tests/{operators/adl.cpp => static_tests/operators_adl.cpp} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/{operators/adl.cpp => static_tests/operators_adl.cpp} (100%) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b956a1ab7..945d275da 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(unit_tests static_tests/alias.cpp static_tests/is_primary_key_insertable.cpp static_tests/is_column_with_insertable_primary_key.cpp + static_tests/operators_adl.cpp tuple_iteration.cpp sync_schema_tests.cpp tests.cpp @@ -55,7 +56,6 @@ add_executable(unit_tests operators/not_operator.cpp operators/bitwise.cpp operators/binary_operators.cpp - operators/adl.cpp prepared_statement_tests/select.cpp prepared_statement_tests/get_all.cpp prepared_statement_tests/get_all_pointer.cpp @@ -89,7 +89,7 @@ add_executable(unit_tests statement_serializer_tests/bindables.cpp statement_serializer_tests/ast/upsert_clause.cpp statement_serializer_tests/ast/excluded.cpp - statement_serializer_tests/ast/set.cpp + statement_serializer_tests/ast/set.cpp statement_serializer_tests/arithmetic_operators.cpp statement_serializer_tests/base_types.cpp statement_serializer_tests/collate.cpp diff --git a/tests/operators/adl.cpp b/tests/static_tests/operators_adl.cpp similarity index 100% rename from tests/operators/adl.cpp rename to tests/static_tests/operators_adl.cpp From e730fee77a200415c1b9754746dee0d1aa4cf8db Mon Sep 17 00:00:00 2001 From: Vittorio Romeo Date: Sun, 19 Mar 2023 14:26:15 +0100 Subject: [PATCH 096/100] Simplify reverse tuple iteration --- dev/functional/index_sequence_util.h | 31 ------------------------- dev/tuple_helper/tuple_iteration.h | 3 ++- include/sqlite_orm/sqlite_orm.h | 34 ++-------------------------- 3 files changed, 4 insertions(+), 64 deletions(-) diff --git a/dev/functional/index_sequence_util.h b/dev/functional/index_sequence_util.h index 061627247..73a355ec9 100644 --- a/dev/functional/index_sequence_util.h +++ b/dev/functional/index_sequence_util.h @@ -17,37 +17,6 @@ namespace sqlite_orm { return I; } -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED - /** - * Reorder the values of an index_sequence according to the positions from a second sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reorder_index_sequence(std::index_sequence, - std::index_sequence) { - constexpr std::array values{Value...}; - return std::index_sequence{}; - } - - template - SQLITE_ORM_CONSTEVAL std::index_sequence reorder_index_sequence(std::index_sequence, - std::index_sequence) { - return {}; - } - - inline SQLITE_ORM_CONSTEVAL std::index_sequence<> reorder_index_sequence(std::index_sequence<>, - std::index_sequence<>) { - return {}; - } - - /** - * Reverse the values of an index_sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { - return reorder_index_sequence(std::index_sequence{}, std::make_index_sequence{}); - } -#endif - template struct flatten_idxseq { using type = std::index_sequence<>; diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index cb37f7cbe..26b834f51 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -33,7 +33,8 @@ namespace sqlite_orm { template void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { - iterate_tuple(tpl, reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + int sink; + ((lambda(std::get(tpl)), sink) = ... = 0); } else { (lambda(std::get(tpl)), ...); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 10e526f6b..7b3075a7c 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1128,37 +1128,6 @@ namespace sqlite_orm { return I; } -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED - /** - * Reorder the values of an index_sequence according to the positions from a second sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reorder_index_sequence(std::index_sequence, - std::index_sequence) { - constexpr std::array values{Value...}; - return std::index_sequence{}; - } - - template - SQLITE_ORM_CONSTEVAL std::index_sequence reorder_index_sequence(std::index_sequence, - std::index_sequence) { - return {}; - } - - inline SQLITE_ORM_CONSTEVAL std::index_sequence<> reorder_index_sequence(std::index_sequence<>, - std::index_sequence<>) { - return {}; - } - - /** - * Reverse the values of an index_sequence. - */ - template - SQLITE_ORM_CONSTEVAL auto reverse_index_sequence(std::index_sequence) { - return reorder_index_sequence(std::index_sequence{}, std::make_index_sequence{}); - } -#endif - template struct flatten_idxseq { using type = std::index_sequence<>; @@ -9574,7 +9543,8 @@ namespace sqlite_orm { template void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { - iterate_tuple(tpl, reverse_index_sequence(std::index_sequence{}), std::forward(lambda)); + int sink; + ((lambda(std::get(tpl)), sink) = ... = 0); } else { (lambda(std::get(tpl)), ...); } From 1dc9cdcbdf469960e12476ef6cc0338eaa7a56ac Mon Sep 17 00:00:00 2001 From: Vittorio Romeo Date: Mon, 20 Mar 2023 01:49:19 +0100 Subject: [PATCH 097/100] Apply review suggestions --- dev/functional/index_sequence_util.h | 3 --- include/sqlite_orm/sqlite_orm.h | 5 +---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dev/functional/index_sequence_util.h b/dev/functional/index_sequence_util.h index 73a355ec9..b13343663 100644 --- a/dev/functional/index_sequence_util.h +++ b/dev/functional/index_sequence_util.h @@ -3,9 +3,6 @@ #include // std::index_sequence, std::make_index_sequence #include "../functional/cxx_universal.h" -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED -#include -#endif namespace sqlite_orm { namespace internal { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 7b3075a7c..4dcc1bcd8 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1114,10 +1114,6 @@ namespace sqlite_orm { // #include "../functional/cxx_universal.h" -#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED -#include -#endif - namespace sqlite_orm { namespace internal { /** @@ -9543,6 +9539,7 @@ namespace sqlite_orm { template void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { + // nifty fold expression trick: make use of guaranteed right-to-left evaluation order when folding over operator= int sink; ((lambda(std::get(tpl)), sink) = ... = 0); } else { From e64e23b297d5fb932499fb50d66d1296c3404f06 Mon Sep 17 00:00:00 2001 From: Vittorio Romeo Date: Mon, 20 Mar 2023 01:51:51 +0100 Subject: [PATCH 098/100] Apply review suggestions --- dev/tuple_helper/tuple_iteration.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tuple_helper/tuple_iteration.h b/dev/tuple_helper/tuple_iteration.h index 26b834f51..4d0a971fc 100644 --- a/dev/tuple_helper/tuple_iteration.h +++ b/dev/tuple_helper/tuple_iteration.h @@ -33,6 +33,7 @@ namespace sqlite_orm { template void iterate_tuple(const Tpl& tpl, std::index_sequence, L&& lambda) { if constexpr(reversed) { + // nifty fold expression trick: make use of guaranteed right-to-left evaluation order when folding over operator= int sink; ((lambda(std::get(tpl)), sink) = ... = 0); } else { From 8b0704ec5fea895e3a1cc381c2c0c70caf33fca5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 20 Mar 2023 20:18:06 +0000 Subject: [PATCH 099/100] Removed C++20 aliases for v1.8.2 --- dev/alias.h | 100 -------- dev/alias_traits.h | 35 --- dev/conditions.h | 40 ---- dev/functional/config.h | 14 -- dev/functional/cxx_compiler_quirks.h | 6 - dev/functional/cxx_core_features.h | 4 - dev/select_constraints.h | 13 -- dev/type_traits.h | 8 - examples/column_aliases.cpp | 16 -- examples/custom_aliases.cpp | 30 --- examples/exists.cpp | 20 -- examples/self_join.cpp | 23 -- examples/subquery.cpp | 16 -- include/sqlite_orm/sqlite_orm.h | 216 ------------------ tests/ast_iterator_tests.cpp | 23 -- .../select_constraints.cpp | 14 -- tests/static_tests/alias.cpp | 14 -- 17 files changed, 592 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 47c3ac16b..eb5aad0b5 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -15,29 +15,6 @@ namespace sqlite_orm { namespace internal { -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /* - * Helper class to facilitate user-defined string literal operator template - */ - template - struct string_identifier_template { - static constexpr size_t size() { - return N - 1; - } - - constexpr string_identifier_template(const char (&id)[N]) { - std::copy_n(id, N, this->id); - } - - char id[N]; - }; - - template class Alias, string_identifier_template t, size_t... Idx> - consteval auto to_alias(std::index_sequence) { - return Alias{}; - } -#endif - /** * This is a common built-in class used for character based table aliases. * For convenience there exist public type aliases `alias_a`, `alias_b`, ... @@ -127,16 +104,6 @@ namespace sqlite_orm { alias_holder() = default; }; - -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - struct recordset_alias_builder { - template - [[nodiscard]] consteval recordset_alias for_() const { - return {}; - } - }; -#endif } /** @@ -151,22 +118,6 @@ namespace sqlite_orm { return {c}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto alias_column(C c) { - using A = std::remove_const_t; - using aliased_type = internal::type_t; - static_assert(std::is_same_v, aliased_type>, - "Column must be from aliased table"); - return internal::alias_column_t{c}; - } - - template - constexpr auto operator->*(const A&, F field) { - return internal::alias_column_t{field}; - } -#endif - /** * Alias a column expression. */ @@ -175,33 +126,11 @@ namespace sqlite_orm { return {std::move(expression)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto as(E expression) { - return internal::as_t, E>{std::move(expression)}; - } - - /** - * Alias a column expression. - */ - template - internal::as_t operator>>=(E expression, const A&) { - return {std::move(expression)}; - } -#endif - template = true> internal::alias_holder get() { return {}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto get() { - return internal::alias_holder>{}; - } -#endif - template using alias_a = internal::recordset_alias; template @@ -264,33 +193,4 @@ namespace sqlite_orm { using colalias_g = internal::column_alias<'g'>; using colalias_h = internal::column_alias<'h'>; using colalias_i = internal::column_alias<'i'>; - -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** @short Create a table alias. - * - * Examples: - * constexpr auto z_alias = alias<'z'>.for_(); - */ - template - inline constexpr internal::recordset_alias_builder alias{}; - - /** @short Create a table alias. - * - * Examples: - * constexpr auto z_alias = "z"_alias.for_(); - */ - template - [[nodiscard]] consteval auto operator"" _alias() { - return internal::to_alias(std::make_index_sequence{}); - } - - /** @short Create a column alias. - * column_alias<'a'[, ...]> from a string literal. - * E.g. "a"_col, "b"_col - */ - template - [[nodiscard]] consteval auto operator"" _col() { - return internal::to_alias(std::make_index_sequence{}); - } -#endif } diff --git a/dev/alias_traits.h b/dev/alias_traits.h index 1458c91e3..fae7966ca 100644 --- a/dev/alias_traits.h +++ b/dev/alias_traits.h @@ -1,9 +1,6 @@ #pragma once #include // std::remove_const, std::is_base_of, std::is_same -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES -#include -#endif #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" @@ -51,36 +48,4 @@ namespace sqlite_orm { template using is_table_alias = polyfill::bool_constant>; } - -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - concept orm_alias = std::derived_from; - - /** @short Alias of a column in a record set. - * - * A column alias has the following traits: - * - is derived from `alias_tag` - * - must not have a nested `type` typename - */ - template - concept orm_column_alias = (orm_alias && !orm_names_type); - - /** @short Alias of any type of record set. - * - * A record set alias has the following traits: - * - is derived from `alias_tag`. - * - has a nested `type` typename, which refers to a mapped object. - */ - template - concept orm_recordset_alias = (orm_alias && orm_names_type); - - /** @short Alias of a concrete table. - * - * A concrete table alias has the following traits: - * - is derived from `alias_tag`. - * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). - */ - template - concept orm_table_alias = (orm_recordset_alias && !std::same_as>); -#endif } diff --git a/dev/conditions.h b/dev/conditions.h index 83be6a6ab..cc5e58c89 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -826,18 +826,6 @@ namespace sqlite_orm { return {}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** - * Explicit FROM function. Usage: - * `storage.select(&User::id, from<"a"_alias.for_>());` - */ - template - auto from() { - static_assert(sizeof...(tables) > 0); - return internal::from_t...>{}; - } -#endif - template = true> internal::negated_condition_t operator!(T arg) { return {std::move(arg)}; @@ -1039,49 +1027,21 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_join(On on) { - return internal::left_join_t, On>{std::move(on)}; - } -#endif - template internal::join_t join(O o) { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto join(On on) { - return internal::join_t, On>{std::move(on)}; - } -#endif - template internal::left_outer_join_t left_outer_join(O o) { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_outer_join(On on) { - return internal::left_outer_join_t, On>{std::move(on)}; - } -#endif - template internal::inner_join_t inner_join(O o) { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto inner_join(On on) { - return internal::inner_join_t, On>{std::move(on)}; - } -#endif - template internal::offset_t offset(T off) { return {std::move(off)}; diff --git a/dev/functional/config.h b/dev/functional/config.h index d348fc543..eb36d578d 100644 --- a/dev/functional/config.h +++ b/dev/functional/config.h @@ -2,10 +2,6 @@ #include "cxx_universal.h" -#if SQLITE_ORM_HAS_INCLUDE() -#include -#endif - #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #define SQLITE_ORM_INLINE_VAR inline #else @@ -23,13 +19,3 @@ #else #define SQLITE_ORM_CONSTEVAL constexpr #endif - -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && __cpp_lib_concepts >= 202002L -#define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED -#endif - -#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \ - defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \ - (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) -#define SQLITE_ORM_WITH_CPP20_ALIASES -#endif diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 64e8ad78f..e97b3e7ec 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -34,12 +34,6 @@ #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif -// overwrite SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED -#if(__cpp_nontype_template_args < 201911L) && \ - (defined(__clang__) && (__clang_major__ >= 12) && (__cplusplus >= 202002L)) -#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED -#endif - // clang 10 chokes on concepts that don't depend on template parameters; // when it tries to instantiate an expression in a requires expression, which results in an error, // the compiler reports an error instead of dismissing the templated function. diff --git a/dev/functional/cxx_core_features.h b/dev/functional/cxx_core_features.h index 5d16e913b..99474da39 100644 --- a/dev/functional/cxx_core_features.h +++ b/dev/functional/cxx_core_features.h @@ -65,7 +65,3 @@ #if __cpp_concepts >= 201907L #define SQLITE_ORM_CONCEPTS_SUPPORTED #endif - -#if __cpp_nontype_template_args >= 201911L -#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED -#endif diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 83540e1c3..7b1f690bd 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -415,19 +415,6 @@ namespace sqlite_orm { return {definedOrder}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** - * Example: - * constexpr auto m = "m"_alias.for_(); - * auto reportingTo = - * storage.select(asterisk(), inner_join(on(m->*&Employee::reportsTo == c(&Employee::employeeId)))); - */ - template - auto asterisk(bool definedOrder = false) { - return internal::asterisk_t>{definedOrder}; - } -#endif - /** * `SELECT * FROM T` expression that fetches results as objects of type T. * T is a type mapped to a storage, or an alias of it. diff --git a/dev/type_traits.h b/dev/type_traits.h index 64bf1ccdb..a3a162836 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -1,9 +1,6 @@ #pragma once #include // std::enable_if, std::is_same -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES -#include -#endif #include "functional/cxx_type_traits_polyfill.h" @@ -61,9 +58,4 @@ namespace sqlite_orm { template using on_type_t = typename T::on_type; } - -#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED - template - concept orm_names_type = requires { typename T::type; }; -#endif } diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index 1cba0a2b1..8333541cf 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -58,22 +58,6 @@ void marvel_hero_ordered_by_o_pos() { } } cout << endl; -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - { - constexpr auto i = "i"_col; - // SELECT name, instr(abilities, 'o') i - // FROM marvel - // WHERE i > 0 - // ORDER BY i - auto rows = storage.select(columns(&MarvelHero::name, as(instr(&MarvelHero::abilities, "o"))), - where(i > c(0)), - order_by(i)); - for(auto& row: rows) { - cout << get<0>(row) << '\t' << get<1>(row) << '\n'; - } - } - cout << endl; -#endif { // SELECT name, instr(abilities, 'o') // FROM marvel diff --git a/examples/custom_aliases.cpp b/examples/custom_aliases.cpp index 57dae223c..0d6ffa7ca 100644 --- a/examples/custom_aliases.cpp +++ b/examples/custom_aliases.cpp @@ -104,35 +104,6 @@ int main(int, char** argv) { // SELECT C.ID, C.NAME, C.AGE, D.DEPT // FROM COMPANY AS C, DEPARTMENT AS D // WHERE C.ID = D.EMP_ID; -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - constexpr auto c_als = "c"_alias.for_(); - constexpr auto d = "d"_alias.for_(); - static_assert(std::is_empty_v); - constexpr auto empId = EmployeeIdAlias{}; - auto rowsWithTableAliases = storage.select( - columns(c_als->*&Employee::id, c_als->*&Employee::name, c_als->*&Employee::age, d->*&Department::dept), - where(is_equal(c_als->*&Employee::id, d->*&Department::empId))); - assert(rowsWithTableAliases == simpleRows); - - // SELECT COMPANY.ID as COMPANY_ID, COMPANY.NAME AS COMPANY_NAME, COMPANY.AGE, DEPARTMENT.DEPT - // FROM COMPANY, DEPARTMENT - // WHERE COMPANY_ID = DEPARTMENT.EMP_ID; - auto rowsWithColumnAliases = storage.select( - columns(&Employee::id >>= empId, as(&Employee::name), &Employee::age, &Department::dept), - where(get() == c(&Department::empId))); - assert(rowsWithColumnAliases == rowsWithTableAliases); - - // SELECT C.ID AS COMPANY_ID, C.NAME AS COMPANY_NAME, C.AGE, D.DEPT - // FROM COMPANY AS C, DEPARTMENT AS D - // WHERE C.ID = D.EMP_ID; - auto rowsWithBothTableAndColumnAliases = - storage.select(columns(c_als->*& Employee::id >>= empId, - as(c_als->*&Employee::name), - c_als->*&Employee::age, - d->*&Department::dept), - where(is_equal(c_als->*&Employee::id, d->*&Department::empId))); - assert(rowsWithBothTableAndColumnAliases == rowsWithBothTableAndColumnAliases); -#else using als_c = alias_c; using als_d = alias_d; auto rowsWithTableAliases = @@ -163,7 +134,6 @@ int main(int, char** argv) { alias_column(&Department::dept)), where(is_equal(alias_column(&Employee::id), alias_column(&Department::empId)))); assert(rowsWithBothTableAndColumnAliases == rowsWithBothTableAndColumnAliases); -#endif return 0; } diff --git a/examples/exists.cpp b/examples/exists.cpp index 3213c2a44..ab5a888ba 100644 --- a/examples/exists.cpp +++ b/examples/exists.cpp @@ -475,25 +475,6 @@ int main(int, char**) { // ) // ORDER BY 'c'."PAYMENT_AMT" -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - constexpr auto c_als = "c"_alias.for_(); - constexpr auto d = "d"_alias.for_(); - - double amount = 2000; - auto where_clause = select(d->*&Customer::agentCode, - from(), - where(is_equal(c_als->*&Customer::paymentAmt, std::ref(amount)) and - (d->*&Customer::agentCode == c(c_als->*&Customer::agentCode)))); - - amount = 7000; - - auto statement = storage.prepare(select( - columns(&Order::agentCode, &Order::num, &Order::amount, &Order::custCode, c_als->*&Customer::paymentAmt), - from(), - inner_join(using_(&Customer::agentCode)), - where(not exists(where_clause)), - order_by(c_als->*&Customer::paymentAmt))); -#else using als = alias_c; using als_2 = alias_d; @@ -516,7 +497,6 @@ int main(int, char**) { inner_join(on(alias_column(&Customer::agentCode) == c(&Order::agentCode))), where(not exists(where_clause)), order_by(alias_column(&Customer::paymentAmt)))); -#endif auto sql = statement.expanded_sql(); auto rows = storage.execute(statement); diff --git a/examples/self_join.cpp b/examples/self_join.cpp index b1f8aa525..d135e5666 100644 --- a/examples/self_join.cpp +++ b/examples/self_join.cpp @@ -199,16 +199,6 @@ int main() { // FROM employees // INNER JOIN employees m // ON m.ReportsTo = employees.EmployeeId -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - constexpr auto m = "m"_alias.for_(); - auto firstNames = storage.select(columns(m->*&Employee::firstName || c(" ") || m->*&Employee::lastName, - &Employee::firstName || c(" ") || &Employee::lastName), - inner_join(on(m->*&Employee::reportsTo == c(&Employee::employeeId)))); - cout << "firstNames count = " << firstNames.size() << endl; - for(auto& row: firstNames) { - cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; - } -#else using als = alias_m; auto firstNames = storage.select( columns(alias_column(&Employee::firstName) || c(" ") || alias_column(&Employee::lastName), @@ -218,7 +208,6 @@ int main() { for(auto& row: firstNames) { cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; } -#endif assert(storage.count() == storage.count>()); } @@ -230,17 +219,6 @@ int main() { // FROM employees // INNER JOIN employees emp // ON emp.ReportsTo = employees.EmployeeId -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - static_assert(std::is_empty_v>); - constexpr auto emp = custom_alias{}; - auto firstNames = storage.select(columns(emp->*&Employee::firstName || c(" ") || emp->*&Employee::lastName, - &Employee::firstName || c(" ") || &Employee::lastName), - inner_join(on(emp->*&Employee::reportsTo == c(&Employee::employeeId)))); - cout << "firstNames count = " << firstNames.size() << endl; - for(auto& row: firstNames) { - cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; - } -#else using als = custom_alias; auto firstNames = storage.select( columns(alias_column(&Employee::firstName) || c(" ") || alias_column(&Employee::lastName), @@ -250,7 +228,6 @@ int main() { for(auto& row: firstNames) { cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl; } -#endif } return 0; diff --git a/examples/subquery.cpp b/examples/subquery.cpp index 63e94a76b..c2962034f 100644 --- a/examples/subquery.cpp +++ b/examples/subquery.cpp @@ -1346,21 +1346,6 @@ int main(int, char**) { // WHERE salary >(SELECT AVG(salary) // FROM employees // WHERE department_id = e.department_id); -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - constexpr auto e = "e"_alias.for_(); - auto rows = storage.select( - columns(e->*&Employee::lastName, e->*&Employee::salary, e->*&Employee::departmentId), - from(), - where(greater_than(e->*&Employee::salary, - select(avg(&Employee::salary), - from(), - where(is_equal(&Employee::departmentId, e->*&Employee::departmentId)))))); - cout << "last_name salary department_id" << endl; - cout << "---------- ---------- -------------" << endl; - for(auto& row: rows) { - cout << std::get<0>(row) << '\t' << std::get<1>(row) << '\t' << std::get<2>(row) << endl; - } -#else using als = alias_e; auto rows = storage.select( columns(alias_column(&Employee::lastName), @@ -1377,7 +1362,6 @@ int main(int, char**) { for(auto& row: rows) { cout << std::get<0>(row) << '\t' << std::get<1>(row) << '\t' << std::get<2>(row) << endl; } -#endif } { // SELECT first_name, last_name, employee_id, job_id diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 91c5cd0de..b70bac8d3 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -94,10 +94,6 @@ using std::nullptr_t; #define SQLITE_ORM_CONCEPTS_SUPPORTED #endif -#if __cpp_nontype_template_args >= 201911L -#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED -#endif - // #include "cxx_compiler_quirks.h" /* @@ -134,12 +130,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION #endif -// overwrite SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED -#if(__cpp_nontype_template_args < 201911L) && \ - (defined(__clang__) && (__clang_major__ >= 12) && (__cplusplus >= 202002L)) -#define SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED -#endif - // clang 10 chokes on concepts that don't depend on template parameters; // when it tries to instantiate an expression in a requires expression, which results in an error, // the compiler reports an error instead of dismissing the templated function. @@ -168,22 +158,9 @@ using std::nullptr_t; #else #define SQLITE_ORM_CONSTEVAL constexpr #endif - -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && __cpp_lib_concepts >= 202002L -#define SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED -#endif - -#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \ - defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \ - (defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED)) -#define SQLITE_ORM_WITH_CPP20_ALIASES -#endif #pragma once #include // std::enable_if, std::is_same -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES -#include -#endif // #include "functional/cxx_type_traits_polyfill.h" @@ -386,11 +363,6 @@ namespace sqlite_orm { template using on_type_t = typename T::on_type; } - -#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED - template - concept orm_names_type = requires { typename T::type; }; -#endif } #pragma once @@ -2757,9 +2729,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 -#endif // #include "functional/cxx_universal.h" @@ -2809,38 +2778,6 @@ namespace sqlite_orm { template using is_table_alias = polyfill::bool_constant>; } - -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - concept orm_alias = std::derived_from; - - /** @short Alias of a column in a record set. - * - * A column alias has the following traits: - * - is derived from `alias_tag` - * - must not have a nested `type` typename - */ - template - concept orm_column_alias = (orm_alias && !orm_names_type); - - /** @short Alias of any type of record set. - * - * A record set alias has the following traits: - * - is derived from `alias_tag`. - * - has a nested `type` typename, which refers to a mapped object. - */ - template - concept orm_recordset_alias = (orm_alias && orm_names_type); - - /** @short Alias of a concrete table. - * - * A concrete table alias has the following traits: - * - is derived from `alias_tag`. - * - has a `type` typename, which refers to another mapped object (i.e. doesn't refer to itself). - */ - template - concept orm_table_alias = (orm_recordset_alias && !std::same_as>); -#endif } // #include "expression.h" @@ -3753,18 +3690,6 @@ namespace sqlite_orm { return {}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** - * Explicit FROM function. Usage: - * `storage.select(&User::id, from<"a"_alias.for_>());` - */ - template - auto from() { - static_assert(sizeof...(tables) > 0); - return internal::from_t...>{}; - } -#endif - template = true> internal::negated_condition_t operator!(T arg) { return {std::move(arg)}; @@ -3966,49 +3891,21 @@ namespace sqlite_orm { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_join(On on) { - return internal::left_join_t, On>{std::move(on)}; - } -#endif - template internal::join_t join(O o) { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto join(On on) { - return internal::join_t, On>{std::move(on)}; - } -#endif - template internal::left_outer_join_t left_outer_join(O o) { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto left_outer_join(On on) { - return internal::left_outer_join_t, On>{std::move(on)}; - } -#endif - template internal::inner_join_t inner_join(O o) { return {std::move(o)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto inner_join(On on) { - return internal::inner_join_t, On>{std::move(on)}; - } -#endif - template internal::offset_t offset(T off) { return {std::move(off)}; @@ -4277,29 +4174,6 @@ namespace sqlite_orm { namespace internal { -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /* - * Helper class to facilitate user-defined string literal operator template - */ - template - struct string_identifier_template { - static constexpr size_t size() { - return N - 1; - } - - constexpr string_identifier_template(const char (&id)[N]) { - std::copy_n(id, N, this->id); - } - - char id[N]; - }; - - template class Alias, string_identifier_template t, size_t... Idx> - consteval auto to_alias(std::index_sequence) { - return Alias{}; - } -#endif - /** * This is a common built-in class used for character based table aliases. * For convenience there exist public type aliases `alias_a`, `alias_b`, ... @@ -4389,16 +4263,6 @@ namespace sqlite_orm { alias_holder() = default; }; - -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - struct recordset_alias_builder { - template - [[nodiscard]] consteval recordset_alias for_() const { - return {}; - } - }; -#endif } /** @@ -4413,22 +4277,6 @@ namespace sqlite_orm { return {c}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto alias_column(C c) { - using A = std::remove_const_t; - using aliased_type = internal::type_t; - static_assert(std::is_same_v, aliased_type>, - "Column must be from aliased table"); - return internal::alias_column_t{c}; - } - - template - constexpr auto operator->*(const A&, F field) { - return internal::alias_column_t{field}; - } -#endif - /** * Alias a column expression. */ @@ -4437,33 +4285,11 @@ namespace sqlite_orm { return {std::move(expression)}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto as(E expression) { - return internal::as_t, E>{std::move(expression)}; - } - - /** - * Alias a column expression. - */ - template - internal::as_t operator>>=(E expression, const A&) { - return {std::move(expression)}; - } -#endif - template = true> internal::alias_holder get() { return {}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - template - auto get() { - return internal::alias_holder>{}; - } -#endif - template using alias_a = internal::recordset_alias; template @@ -4526,35 +4352,6 @@ namespace sqlite_orm { using colalias_g = internal::column_alias<'g'>; using colalias_h = internal::column_alias<'h'>; using colalias_i = internal::column_alias<'i'>; - -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** @short Create a table alias. - * - * Examples: - * constexpr auto z_alias = alias<'z'>.for_(); - */ - template - inline constexpr internal::recordset_alias_builder alias{}; - - /** @short Create a table alias. - * - * Examples: - * constexpr auto z_alias = "z"_alias.for_(); - */ - template - [[nodiscard]] consteval auto operator"" _alias() { - return internal::to_alias(std::make_index_sequence{}); - } - - /** @short Create a column alias. - * column_alias<'a'[, ...]> from a string literal. - * E.g. "a"_col, "b"_col - */ - template - [[nodiscard]] consteval auto operator"" _col() { - return internal::to_alias(std::make_index_sequence{}); - } -#endif } #pragma once @@ -7304,19 +7101,6 @@ namespace sqlite_orm { return {definedOrder}; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - /** - * Example: - * constexpr auto m = "m"_alias.for_(); - * auto reportingTo = - * storage.select(asterisk(), inner_join(on(m->*&Employee::reportsTo == c(&Employee::employeeId)))); - */ - template - auto asterisk(bool definedOrder = false) { - return internal::asterisk_t>{definedOrder}; - } -#endif - /** * `SELECT * FROM T` expression that fetches results as objects of type T. * T is a type mapped to a storage, or an alias of it. diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 6dfe212c2..4bf126203 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -283,15 +283,6 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(int)); iterate_ast(expression, lambda); } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - { - SECTION("direct") { - auto expression = "a"_col > c(0); - expected.push_back(typeid(int)); - iterate_ast(expression, lambda); - } - } -#endif } SECTION("aliased regular column") { using als = alias_z; @@ -305,19 +296,5 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(alias_column_t, column_pointer>)); iterate_ast(expression, lambda); } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - SECTION("aliased regular column 2") { - constexpr auto z_alias = "z"_alias.for_(); - auto expression = z_alias->*&User::id; - expected.push_back(typeid(alias_column_t, decltype(&User::id)>)); - iterate_ast(expression, lambda); - } - SECTION("aliased regular column pointer 2") { - constexpr auto z_alias = "z"_alias.for_(); - auto expression = z_alias->*column(&User::id); - expected.push_back(typeid(alias_column_t, column_pointer>)); - iterate_ast(expression, lambda); - } -#endif REQUIRE(typeIndexes == expected); } diff --git a/tests/statement_serializer_tests/select_constraints.cpp b/tests/statement_serializer_tests/select_constraints.cpp index 60c51c45e..99fafce08 100644 --- a/tests/statement_serializer_tests/select_constraints.cpp +++ b/tests/statement_serializer_tests/select_constraints.cpp @@ -71,20 +71,6 @@ TEST_CASE("statement_serializer select constraints") { value = serialize(expression, context); expected = R"(FROM "users" "u")"; } -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - { - SECTION("with alias 2") { - auto expression = from.for_()>(); - value = serialize(expression, context); - expected = R"(FROM "users" "u")"; - } - SECTION("with alias 3") { - auto expression = from<"u"_alias.for_()>(); - value = serialize(expression, context); - expected = R"(FROM "users" "u")"; - } - } -#endif } // tests whether the statement serializer for a select with joins // properly deduplicates the table names when no explicit from is used diff --git a/tests/static_tests/alias.cpp b/tests/static_tests/alias.cpp index b01e20f9e..b0eaff9de 100644 --- a/tests/static_tests/alias.cpp +++ b/tests/static_tests/alias.cpp @@ -31,19 +31,5 @@ TEST_CASE("aliases") { runTest, int User::*>>(alias_column>(&User::id)); runTest, column_pointer>>( alias_column>(column(&User::id))); -#ifdef SQLITE_ORM_WITH_CPP20_ALIASES - runTest>>(get<"a"_col>()); - runTest>("a"_col); - runTest, int User::*>>(as<"a"_col>(&User::id)); - runTest, int User::*>>(&User::id >>= "a"_col); - runTest>(alias<'a', 'l', 's'>.for_()); - constexpr auto z_alias = "z"_alias.for_(); - runTest>(z_alias); - runTest, int User::*>>(alias_column(&User::id)); - runTest, int User::*>>(z_alias->*&User::id); - runTest, column_pointer>>(z_alias->*column(&User::id)); - runTest, column_pointer>>( - alias_column(column(&User::id))); -#endif } } From e041fb4b28bd5d194e137bdd98bae9a8e4cfe9d6 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 23 Mar 2023 00:18:47 +0000 Subject: [PATCH 100/100] Fixed syncing eponymous virtual table `dbstat` --- dev/implementations/storage_definitions.h | 3 ++- include/sqlite_orm/sqlite_orm.h | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dev/implementations/storage_definitions.h b/dev/implementations/storage_definitions.h index 0de285381..f832b6959 100644 --- a/dev/implementations/storage_definitions.h +++ b/dev/implementations/storage_definitions.h @@ -9,6 +9,7 @@ #include // std::find_if, std::ranges::find #include "../dbstat.h" +#include "../type_traits.h" #include "../util.h" #include "../serializing_util.h" #include "../storage.h" @@ -20,7 +21,7 @@ namespace sqlite_orm { template> sync_schema_result storage_t::sync_table(const Table& table, sqlite3* db, bool preserve) { #ifdef SQLITE_ENABLE_DBSTAT_VTAB - if(std::is_same::value) { + if(std::is_same, dbstat>::value) { return sync_schema_result::already_in_sync; } #endif // SQLITE_ENABLE_DBSTAT_VTAB diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index b70bac8d3..ae74309b2 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -137,10 +137,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS #endif -#if SQLITE_ORM_HAS_INCLUDE() -#include -#endif - #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #define SQLITE_ORM_INLINE_VAR inline #else @@ -19364,6 +19360,8 @@ namespace sqlite_orm { // #include "../dbstat.h" +// #include "../type_traits.h" + // #include "../util.h" // #include "../serializing_util.h" @@ -19377,7 +19375,7 @@ namespace sqlite_orm { template> sync_schema_result storage_t::sync_table(const Table& table, sqlite3* db, bool preserve) { #ifdef SQLITE_ENABLE_DBSTAT_VTAB - if(std::is_same::value) { + if(std::is_same, dbstat>::value) { return sync_schema_result::already_in_sync; } #endif // SQLITE_ENABLE_DBSTAT_VTAB