From 67debd9f71339e8ba035dd6c8727dcfffef4b9f1 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 11 Mar 2022 14:59:23 +0200 Subject: [PATCH 01/20] Removed superfluous space in output for order by clause and expressions --- dev/order_by_serializator.h | 8 ++++---- dev/statement_serializator.h | 3 +-- include/sqlite_orm/sqlite_orm.h | 15 +++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/dev/order_by_serializator.h b/dev/order_by_serializator.h index 037d560b9..eb5d8987a 100644 --- a/dev/order_by_serializator.h +++ b/dev/order_by_serializator.h @@ -27,16 +27,16 @@ namespace sqlite_orm { auto newContext = context; newContext.skip_table_name = false; auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; + ss << columnName; if(orderBy._collate_argument.length()) { - ss << "COLLATE " << orderBy._collate_argument << " "; + ss << " " "COLLATE " << orderBy._collate_argument; } switch(orderBy.asc_desc) { case 1: - ss << "ASC"; + ss << " " "ASC"; break; case -1: - ss << "DESC"; + ss << " " "DESC"; break; } return ss.str(); diff --git a/dev/statement_serializator.h b/dev/statement_serializator.h index 1bc73e21c..ab2e7da3e 100644 --- a/dev/statement_serializator.h +++ b/dev/statement_serializator.h @@ -2064,8 +2064,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& orderBy, const C& context) const { std::stringstream ss; ss << static_cast(orderBy) << " "; - auto orderByString = serialize_order_by(orderBy, context); - ss << orderByString << " "; + ss << serialize_order_by(orderBy, context); return ss.str(); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9e6dc2e09..7b3e5c3bf 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -14398,16 +14398,20 @@ namespace sqlite_orm { auto newContext = context; newContext.skip_table_name = false; auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; + ss << columnName; if(orderBy._collate_argument.length()) { - ss << "COLLATE " << orderBy._collate_argument << " "; + ss << " " + "COLLATE " + << orderBy._collate_argument; } switch(orderBy.asc_desc) { case 1: - ss << "ASC"; + ss << " " + "ASC"; break; case -1: - ss << "DESC"; + ss << " " + "DESC"; break; } return ss.str(); @@ -16493,8 +16497,7 @@ namespace sqlite_orm { std::string operator()(const statement_type& orderBy, const C& context) const { std::stringstream ss; ss << static_cast(orderBy) << " "; - auto orderByString = serialize_order_by(orderBy, context); - ss << orderByString << " "; + ss << serialize_order_by(orderBy, context); return ss.str(); } }; From fcd188564277bfef9629d748fb7eca318abb6e02 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 11 Mar 2022 15:02:34 +0200 Subject: [PATCH 02/20] Added a few tests specifically for testing ORDER BY expressions --- tests/CMakeLists.txt | 2 ++ tests/conditions.cpp | 30 +++++++++++++++++++ .../conditions.cpp | 21 +++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 tests/conditions.cpp create mode 100644 tests/statement_serializator_tests/conditions.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3c0093322..f1ad5f4bc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -67,6 +67,7 @@ add_executable(unit_tests constraints/unique.cpp constraints/foreign_key.cpp constraints/check.cpp + conditions.cpp table_tests.cpp statement_serializator_tests/column_constraints/generated.cpp statement_serializator_tests/column_constraints/default.cpp @@ -93,6 +94,7 @@ add_executable(unit_tests statement_serializator_tests/logical_operators.cpp statement_serializator_tests/statements/select.cpp statement_serializator_tests/select_constraints.cpp + statement_serializator_tests/conditions.cpp statement_serializator_tests/statements/insert_replace.cpp statement_serializator_tests/statements/update.cpp statement_serializator_tests/statements/remove.cpp diff --git a/tests/conditions.cpp b/tests/conditions.cpp new file mode 100644 index 000000000..87b8a1c2e --- /dev/null +++ b/tests/conditions.cpp @@ -0,0 +1,30 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("order by") { + struct Object { + int64 id; + int n; + }; + + auto storage = make_storage( + "", + make_table("object", make_column("id", &Object::id, primary_key()), make_column("n", &Object::n))); + storage.sync_schema(); + + storage.insert({0, 1}); + storage.insert({0, 0}); + + SECTION("column") { + std::vector expected{0, 1}; + auto rows = storage.select(&Object::n, order_by(&Object::n)); + REQUIRE(rows == expected); + } + SECTION("bindable") { + std::vector expected{1, 0}; + auto rows = storage.select(&Object::n, order_by(1)); + REQUIRE(rows == expected); + } +} diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp new file mode 100644 index 000000000..bddaf6d4b --- /dev/null +++ b/tests/statement_serializator_tests/conditions.cpp @@ -0,0 +1,21 @@ +#include +#include + +using namespace sqlite_orm; + +TEST_CASE("statement_serializator order by") { + internal::serializator_context_base context; + + SECTION("dump") { + context.replace_bindable_with_question = false; + auto ast = order_by(2); + auto value = serialize(ast, context); + REQUIRE(value == "ORDER BY 2"); + } + SECTION("bindable") { + context.replace_bindable_with_question = true; + auto ast = order_by(2); + auto value = serialize(ast, context); + REQUIRE(value == "ORDER BY ?"); + } +} From e5784d5dc479da39f2e2fd00192e9c2bf0be4658 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 11 Mar 2022 20:28:49 +0200 Subject: [PATCH 03/20] Amended conditions unit test --- tests/conditions.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/conditions.cpp b/tests/conditions.cpp index 87b8a1c2e..65f9bb1d1 100644 --- a/tests/conditions.cpp +++ b/tests/conditions.cpp @@ -19,12 +19,15 @@ TEST_CASE("order by") { SECTION("column") { std::vector expected{0, 1}; + // select n from object order by n auto rows = storage.select(&Object::n, order_by(&Object::n)); REQUIRE(rows == expected); } SECTION("bindable") { std::vector expected{1, 0}; - auto rows = storage.select(&Object::n, order_by(1)); + // select n from object order by ? + // ? = 1 + auto rows = storage.select(&Object::n, order_by(1)); REQUIRE(rows == expected); } } From d1ebf1a50a028023c2840a85192fd6b6d5a2d8f2 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 16 Mar 2022 19:03:22 +0200 Subject: [PATCH 04/20] Ability to order by positional column ordinal --- dev/conditions.h | 41 +++++++++- dev/statement_serializator.h | 15 ++++ dev/type_traits.h | 20 +++++ include/sqlite_orm/sqlite_orm.h | 77 ++++++++++++++++++- .../conditions.cpp | 60 ++++++++++++--- 5 files changed, 201 insertions(+), 12 deletions(-) diff --git a/dev/conditions.h b/dev/conditions.h index 2058e92e4..6e9d5eff6 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -6,6 +6,7 @@ #include // std::tuple, std::tuple_size #include // std::stringstream +#include "type_traits.h" #include "collate_argument.h" #include "constraints.h" #include "optional_container.h" @@ -1179,12 +1180,50 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } +#if __cplusplus >= 201703L // use of C++17 or higher + /** + * integral_constant from numeric literal. + * E.g. 1_nth_col, 2_nth_col + * + * @note Design desicion: + * A user-defined numeric literal is the C++ way to capture a numeric literal as a compile-time value, + * with the intention to form a literal positional ordinal in the SQL statement. + * It isn't possible with built-in literals. + * The user-defined literal might seem a bit inconvenient at first, + * however has the advantage of giving the literal contextual meaning. + */ + template + [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _nth_col() { + constexpr auto n = + internal::nth_constant{}, Chars...)>{}; + static_assert(n > 0u, "Column number must be greater than 0."); + return n; + } +#endif + /** * ORDER BY column - * Example: storage.select(&User::name, order_by(&User::id)) + * Examples: + * storage.select(&User::name, order_by(&User::id)) + * storage.select(&User::name, order_by(1_nth_col)) */ template internal::order_by_t order_by(O o) { + static_assert(!std::is_arithmetic::value && !std::is_base_of::value && + !std::is_same, const char*>::value +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + && !std::is_same::value +#endif +#ifndef SQLITE_ORM_OMITS_CODECVT + && !std::is_base_of::value && + !std::is_same, const wchar_t*>::value +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + && !std::is_same::value +#endif +#endif + , + "Binding a single value to an ORDER-BY expression is possible but not useful.\n" + "If your intention is to order by kth column then please use `order_by(1_nth_col)`"); return {std::move(o)}; } diff --git a/dev/statement_serializator.h b/dev/statement_serializator.h index 9373108cc..caf0ff276 100644 --- a/dev/statement_serializator.h +++ b/dev/statement_serializator.h @@ -126,6 +126,21 @@ namespace sqlite_orm { } }; + /** + * Constant which gets never replaced in a bindable context. + * Used together with order_by(1_nth_col). + */ + template + struct statement_serializator, void> { + using statement_type = nth_constant; + + template + std::string operator()(const statement_type& /*expression*/, const C& /*context*/) { + static_assert(N > 0, "Column number must be greater than 0."); + return std::to_string(N); + } + }; + template struct statement_serializator, void> { using statement_type = filtered_aggregate_function; diff --git a/dev/type_traits.h b/dev/type_traits.h index 9510c59da..e3b329d77 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -37,4 +37,24 @@ namespace sqlite_orm { template using object_type_t = typename T::object_type; } + + namespace internal { +#if __cplusplus >= 201703L // use of C++17 or higher + constexpr size_t _10_pow(size_t n) { + if(n == 0) { + return 1; + } else { + return 10 * _10_pow(n - 1); + } + } + + template + constexpr size_t n_from_literal(std::index_sequence, Chars... chars) { + return (((chars - '0') * _10_pow(sizeof...(Is) - 1u - Is /*reversed index sequence*/)) + ...); + } + + template + using nth_constant = std::integral_constant; +#endif + } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index bdccb4e67..682800aa6 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -130,6 +130,26 @@ namespace sqlite_orm { template using object_type_t = typename T::object_type; } + + namespace internal { +#if __cplusplus >= 201703L // use of C++17 or higher + constexpr size_t _10_pow(size_t n) { + if(n == 0) { + return 1; + } else { + return 10 * _10_pow(n - 1); + } + } + + template + constexpr size_t n_from_literal(std::index_sequence, Chars... chars) { + return (((chars - '0') * _10_pow(sizeof...(Is) - 1u - Is /*reversed index sequence*/)) + ...); + } + + template + using nth_constant = std::integral_constant; +#endif + } } #pragma once @@ -2600,6 +2620,8 @@ namespace sqlite_orm { #include // std::tuple, std::tuple_size #include // std::stringstream +// #include "type_traits.h" + // #include "collate_argument.h" // #include "constraints.h" @@ -3885,12 +3907,50 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } +#if __cplusplus >= 201703L // use of C++17 or higher + /** + * integral_constant from numeric literal. + * E.g. 1_nth_col, 2_nth_col + * + * @note Design desicion: + * A user-defined numeric literal is the C++ way to capture a numeric literal as a compile-time value, + * with the intention to form a literal positional ordinal in the SQL statement. + * It isn't possible with built-in literals. + * The user-defined literal might seem a bit inconvenient at first, + * however has the advantage of giving the literal contextual meaning. + */ + template + [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _nth_col() { + constexpr auto n = + internal::nth_constant{}, Chars...)>{}; + static_assert(n > 0u, "Column number must be greater than 0."); + return n; + } +#endif + /** * ORDER BY column - * Example: storage.select(&User::name, order_by(&User::id)) + * Examples: + * storage.select(&User::name, order_by(&User::id)) + * storage.select(&User::name, order_by(1_nth_col)) */ template internal::order_by_t order_by(O o) { + static_assert(!std::is_arithmetic::value && !std::is_base_of::value && + !std::is_same, const char*>::value +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + && !std::is_same::value +#endif +#ifndef SQLITE_ORM_OMITS_CODECVT + && !std::is_base_of::value && + !std::is_same, const wchar_t*>::value +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + && !std::is_same::value +#endif +#endif + , + "Binding a single value to an ORDER-BY expression is possible but not useful.\n" + "If your intention is to order by kth column then please use `order_by(1_nth_col)`"); return {std::move(o)}; } @@ -14571,6 +14631,21 @@ namespace sqlite_orm { } }; + /** + * Constant which gets never replaced in a bindable context. + * Used together with order_by(1_nth_col). + */ + template + struct statement_serializator, void> { + using statement_type = nth_constant; + + template + std::string operator()(const statement_type& /*expression*/, const C& /*context*/) { + static_assert(N > 0, "Column number must be greater than 0."); + return std::to_string(N); + } + }; + template struct statement_serializator, void> { using statement_type = filtered_aggregate_function; diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp index 98e8b8703..b7f3d8aad 100644 --- a/tests/statement_serializator_tests/conditions.cpp +++ b/tests/statement_serializator_tests/conditions.cpp @@ -4,22 +4,62 @@ using namespace sqlite_orm; TEST_CASE("statement_serializator conditions") { - SECTION("order by") { - internal::serializator_context_base context; + internal::serializator_context_base context; + SECTION("static assertions") { +#if __cplusplus >= 201703L // use of C++17 or higher + // must assert + //constexpr auto n = 0_nth_col; + + STATIC_REQUIRE(std::is_same_v, decltype(1_nth_col)>); + STATIC_REQUIRE(std::is_same_v, decltype(10_nth_col)>); +#endif + } + SECTION("literals") { + SECTION("dump") { + context.replace_bindable_with_question = false; + auto expr = 2_nth_col; + auto value = serialize(expr, context); + REQUIRE(value == "2"); + } + SECTION("bindable") { + context.replace_bindable_with_question = true; + auto expr = 2_nth_col; + auto value = serialize(expr, context); + REQUIRE(value == "2"); + } + } +#if 0 // outline; order_by statically asserts when passed bindable values + SECTION("order by bindable") { + order_by(std::wstring_view{L""}); SECTION("dump") { context.replace_bindable_with_question = false; - auto ast = order_by(2); - auto value = serialize(ast, context); + auto expr = order_by(2); + auto value = serialize(expr, context); REQUIRE(value == "ORDER BY 2"); } SECTION("bindable") { context.replace_bindable_with_question = true; - auto ast = order_by(2); - auto value = serialize(ast, context); + auto expr = order_by(2); + auto value = serialize(expr, context); REQUIRE(value == "ORDER BY ?"); } } +#endif + SECTION("order by kth column") { + SECTION("dump") { + context.replace_bindable_with_question = false; + auto expr = order_by(2_nth_col); + auto value = serialize(expr, context); + REQUIRE(value == "ORDER BY 2"); + } + SECTION("bindable") { + context.replace_bindable_with_question = true; + auto expr = order_by(2_nth_col); + auto value = serialize(expr, context); + REQUIRE(value == "ORDER BY 2"); + } + } SECTION("using") { struct User { int64 id; @@ -32,13 +72,13 @@ TEST_CASE("statement_serializator conditions") { internal::serializator_context ctx{storage}; SECTION("using column") { - auto ast = using_(&User::id); - auto value = serialize(ast, ctx); + auto expr = using_(&User::id); + auto value = serialize(expr, ctx); REQUIRE(value == R"(USING ("id"))"); } SECTION("using explicit column") { - auto ast = using_(column(&User::id)); - auto value = serialize(ast, ctx); + auto expr = using_(column(&User::id)); + auto value = serialize(expr, ctx); REQUIRE(value == R"(USING ("id"))"); } } From ce093212d30fe78e9a61ad30390440e45c0e428a Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 17 Mar 2022 23:38:27 +0200 Subject: [PATCH 05/20] Corrected code formatting --- dev/order_by_serializator.h | 12 ++++++++---- include/sqlite_orm/sqlite_orm.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dev/order_by_serializator.h b/dev/order_by_serializator.h index eb5d8987a..4c568336e 100644 --- a/dev/order_by_serializator.h +++ b/dev/order_by_serializator.h @@ -28,15 +28,19 @@ namespace sqlite_orm { newContext.skip_table_name = false; auto columnName = serialize(orderBy.expression, newContext); ss << columnName; - if(orderBy._collate_argument.length()) { - ss << " " "COLLATE " << orderBy._collate_argument; + if(!orderBy._collate_argument.empty()) { + ss << " " + "COLLATE " + << orderBy._collate_argument; } switch(orderBy.asc_desc) { case 1: - ss << " " "ASC"; + ss << " " + "ASC"; break; case -1: - ss << " " "DESC"; + ss << " " + "DESC"; break; } return ss.str(); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index feeef086e..39d65fc38 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -14512,7 +14512,7 @@ namespace sqlite_orm { newContext.skip_table_name = false; auto columnName = serialize(orderBy.expression, newContext); ss << columnName; - if(orderBy._collate_argument.length()) { + if(!orderBy._collate_argument.empty()) { ss << " " "COLLATE " << orderBy._collate_argument; From e7f75f01c3a7b429283f085c4b1f97890e71356e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 18 Mar 2022 15:43:47 +0200 Subject: [PATCH 06/20] Corrected compilation errors in C++14 --- dev/statement_serializator.h | 2 ++ include/sqlite_orm/sqlite_orm.h | 2 ++ tests/conditions.cpp | 8 +++++--- tests/statement_serializator_tests/conditions.cpp | 10 +++++++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/dev/statement_serializator.h b/dev/statement_serializator.h index ef1f50f60..944001c2a 100644 --- a/dev/statement_serializator.h +++ b/dev/statement_serializator.h @@ -126,6 +126,7 @@ namespace sqlite_orm { } }; +#if __cplusplus >= 201703L // use of C++17 or higher /** * Constant which gets never replaced in a bindable context. * Used together with order_by(1_nth_col). @@ -140,6 +141,7 @@ namespace sqlite_orm { return std::to_string(N); } }; +#endif template struct statement_serializator, void> { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 39d65fc38..fdbe0389e 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -14672,6 +14672,7 @@ namespace sqlite_orm { } }; +#if __cplusplus >= 201703L // use of C++17 or higher /** * Constant which gets never replaced in a bindable context. * Used together with order_by(1_nth_col). @@ -14686,6 +14687,7 @@ namespace sqlite_orm { return std::to_string(N); } }; +#endif template struct statement_serializator, void> { diff --git a/tests/conditions.cpp b/tests/conditions.cpp index 65f9bb1d1..8a10ece35 100644 --- a/tests/conditions.cpp +++ b/tests/conditions.cpp @@ -9,9 +9,9 @@ TEST_CASE("order by") { int n; }; - auto storage = make_storage( - "", - make_table("object", make_column("id", &Object::id, primary_key()), make_column("n", &Object::n))); + auto storage = + make_storage("", + make_table("object", make_column("id", &Object::id, primary_key()), make_column("n", &Object::n))); storage.sync_schema(); storage.insert({0, 1}); @@ -23,6 +23,7 @@ TEST_CASE("order by") { auto rows = storage.select(&Object::n, order_by(&Object::n)); REQUIRE(rows == expected); } +#if 0 // outline; order_by statically asserts when passing bindable values SECTION("bindable") { std::vector expected{1, 0}; // select n from object order by ? @@ -30,4 +31,5 @@ TEST_CASE("order by") { auto rows = storage.select(&Object::n, order_by(1)); REQUIRE(rows == expected); } +#endif } diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp index b7f3d8aad..7a70c82c4 100644 --- a/tests/statement_serializator_tests/conditions.cpp +++ b/tests/statement_serializator_tests/conditions.cpp @@ -17,19 +17,23 @@ TEST_CASE("statement_serializator conditions") { } SECTION("literals") { SECTION("dump") { +#if __cplusplus >= 201703L // use of C++17 or higher context.replace_bindable_with_question = false; auto expr = 2_nth_col; auto value = serialize(expr, context); REQUIRE(value == "2"); +#endif } SECTION("bindable") { +#if __cplusplus >= 201703L // use of C++17 or higher context.replace_bindable_with_question = true; auto expr = 2_nth_col; auto value = serialize(expr, context); REQUIRE(value == "2"); +#endif } } -#if 0 // outline; order_by statically asserts when passed bindable values +#if 0 // outline; order_by statically asserts when passing bindable values SECTION("order by bindable") { order_by(std::wstring_view{L""}); SECTION("dump") { @@ -48,16 +52,20 @@ TEST_CASE("statement_serializator conditions") { #endif SECTION("order by kth column") { SECTION("dump") { +#if __cplusplus >= 201703L // use of C++17 or higher context.replace_bindable_with_question = false; auto expr = order_by(2_nth_col); auto value = serialize(expr, context); REQUIRE(value == "ORDER BY 2"); +#endif } SECTION("bindable") { +#if __cplusplus >= 201703L // use of C++17 or higher context.replace_bindable_with_question = true; auto expr = order_by(2_nth_col); auto value = serialize(expr, context); REQUIRE(value == "ORDER BY 2"); +#endif } } SECTION("using") { From 3813a06a0d02cffaba1d3e65356fdc7a5065482d Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 18 Mar 2022 16:08:17 +0200 Subject: [PATCH 07/20] Renamed `nth_ constant` type alias to `positional_ordinal` struct --- dev/conditions.h | 3 ++- dev/statement_serializator.h | 4 ++-- dev/type_traits.h | 2 +- include/sqlite_orm/sqlite_orm.h | 9 +++++---- tests/statement_serializator_tests/conditions.cpp | 4 ++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/dev/conditions.h b/dev/conditions.h index 26824de52..d8312ca68 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1187,7 +1187,8 @@ namespace sqlite_orm { template [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _nth_col() { constexpr auto n = - internal::nth_constant{}, Chars...)>{}; + internal::positional_ordinal{}, + Chars...)>{}; static_assert(n > 0u, "Column number must be greater than 0."); return n; } diff --git a/dev/statement_serializator.h b/dev/statement_serializator.h index d122c54d6..ac6bed7fa 100644 --- a/dev/statement_serializator.h +++ b/dev/statement_serializator.h @@ -132,8 +132,8 @@ namespace sqlite_orm { * Used together with order_by(1_nth_col). */ template - struct statement_serializator, void> { - using statement_type = nth_constant; + struct statement_serializator, void> { + using statement_type = positional_ordinal; template std::string operator()(const statement_type& /*expression*/, const C& /*context*/) { diff --git a/dev/type_traits.h b/dev/type_traits.h index e3b329d77..df6d6efbf 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -54,7 +54,7 @@ namespace sqlite_orm { } template - using nth_constant = std::integral_constant; + struct positional_ordinal : std::integral_constant {}; #endif } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d7923d263..e73e7188f 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -147,7 +147,7 @@ namespace sqlite_orm { } template - using nth_constant = std::integral_constant; + struct positional_ordinal : std::integral_constant {}; #endif } } @@ -3943,7 +3943,8 @@ namespace sqlite_orm { template [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _nth_col() { constexpr auto n = - internal::nth_constant{}, Chars...)>{}; + internal::positional_ordinal{}, + Chars...)>{}; static_assert(n > 0u, "Column number must be greater than 0."); return n; } @@ -14687,8 +14688,8 @@ namespace sqlite_orm { * Used together with order_by(1_nth_col). */ template - struct statement_serializator, void> { - using statement_type = nth_constant; + struct statement_serializator, void> { + using statement_type = positional_ordinal; template std::string operator()(const statement_type& /*expression*/, const C& /*context*/) { diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp index 7a70c82c4..c27e8fa66 100644 --- a/tests/statement_serializator_tests/conditions.cpp +++ b/tests/statement_serializator_tests/conditions.cpp @@ -11,8 +11,8 @@ TEST_CASE("statement_serializator conditions") { // must assert //constexpr auto n = 0_nth_col; - STATIC_REQUIRE(std::is_same_v, decltype(1_nth_col)>); - STATIC_REQUIRE(std::is_same_v, decltype(10_nth_col)>); + STATIC_REQUIRE(std::is_same_v, decltype(1_nth_col)>); + STATIC_REQUIRE(std::is_same_v, decltype(10_nth_col)>); #endif } SECTION("literals") { From b9cd3d3e7cd17cd0cbb8538d1e9ed4227778097b Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Fri, 18 Mar 2022 16:11:13 +0200 Subject: [PATCH 08/20] Runner-up: Renamed `nth_ constant` type alias to `positional_ordinal` struct --- 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 d8312ca68..914ac8635 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1174,7 +1174,7 @@ namespace sqlite_orm { #if __cplusplus >= 201703L // use of C++17 or higher /** - * integral_constant from numeric literal. + * positional_ordinal from numeric literal. * E.g. 1_nth_col, 2_nth_col * * @note Design desicion: diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index e73e7188f..5c4ca8a7d 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3930,7 +3930,7 @@ namespace sqlite_orm { #if __cplusplus >= 201703L // use of C++17 or higher /** - * integral_constant from numeric literal. + * positional_ordinal from numeric literal. * E.g. 1_nth_col, 2_nth_col * * @note Design desicion: From c96d19ed2eb7073870509b8a75405a3578b602a1 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 22 Mar 2022 23:13:58 +0200 Subject: [PATCH 09/20] Treated bindables used as order-by expressions as literal values --- dev/ast_iterator.h | 11 ++- dev/conditions.h | 45 ++------- dev/node_tuple.h | 12 +++ dev/order_by_serializator.h | 18 ++-- dev/statement_serializator.h | 19 +--- dev/type_traits.h | 20 ---- tests/ast_iterator_tests.cpp | 14 ++- tests/conditions.cpp | 35 ------- .../conditions.cpp | 91 +++---------------- tests/static_tests/node_tuple.cpp | 11 +++ 10 files changed, 71 insertions(+), 205 deletions(-) delete mode 100644 tests/conditions.cpp diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 9f7d1e0a3..afec7eebd 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -655,7 +655,7 @@ namespace sqlite_orm { }; template - struct ast_iterator, void> { + struct ast_iterator, match_if_not> { using node_type = order_by_t; template @@ -664,6 +664,15 @@ namespace sqlite_orm { } }; + template + struct ast_iterator, match_if> { + using node_type = order_by_t; + + template + void operator()(const node_type& /*node*/, const L& /*l*/) const { + } + }; + template struct ast_iterator, void> { using node_type = collate_t; diff --git a/dev/conditions.h b/dev/conditions.h index 312b67253..30ece62b0 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1172,51 +1172,18 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } -#if __cplusplus >= 201703L // use of C++17 or higher /** - * positional_ordinal from numeric literal. - * E.g. 1_nth_col, 2_nth_col - * - * @note Design desicion: - * A user-defined numeric literal is the C++ way to capture a numeric literal as a compile-time value, - * with the intention to form a literal positional ordinal in the SQL statement. - * It isn't possible with built-in literals. - * The user-defined literal might seem a bit inconvenient at first, - * however has the advantage of giving the literal contextual meaning. - */ - template - [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _nth_col() { - constexpr auto n = - internal::positional_ordinal{}, - Chars...)>{}; - static_assert(n > 0u, "Column number must be greater than 0."); - return n; - } -#endif - - /** - * ORDER BY column + * ORDER BY column or literal value (including a column number) + * + * Note that a bindable will be serialized as a literal value. + * Only integral numbers make sense and SQLite will understand them as a positional column ordinal. + * * Examples: * storage.select(&User::name, order_by(&User::id)) - * storage.select(&User::name, order_by(1_nth_col)) + * storage.select(&User::name, order_by(1)) */ template internal::order_by_t order_by(O o) { - static_assert(!std::is_arithmetic::value && !std::is_base_of::value && - !std::is_same, const char*>::value -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - && !std::is_same::value -#endif -#ifndef SQLITE_ORM_OMITS_CODECVT - && !std::is_base_of::value && - !std::is_same, const wchar_t*>::value -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - && !std::is_same::value -#endif -#endif - , - "Binding a single value to an ORDER-BY expression is possible but not useful.\n" - "If your intention is to order by kth column then please use `order_by(1_nth_col)`"); return {std::move(o)}; } diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 3bd7f2c30..d1fdf5743 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -25,6 +25,12 @@ namespace sqlite_orm { namespace internal { template + struct node_tuple; + + template + using node_tuple_t = typename node_tuple::type; + + template struct node_tuple { using type = std::tuple; }; @@ -77,6 +83,12 @@ namespace sqlite_orm { using type = typename node_tuple::type; }; + template + struct node_tuple, match_if_not> : node_tuple {}; + + template + struct node_tuple, match_if> : node_tuple {}; + template struct node_tuple::value>::type> { using node_type = T; diff --git a/dev/order_by_serializator.h b/dev/order_by_serializator.h index dd66709ed..aa5af6b38 100644 --- a/dev/order_by_serializator.h +++ b/dev/order_by_serializator.h @@ -17,17 +17,17 @@ namespace sqlite_orm { return serializer(t, context); } - template - struct order_by_serializator, void> { - using statement_type = order_by_t; + template + struct order_by_serializator, void> { + using statement_type = order_by_t; template std::string operator()(const statement_type& orderBy, const C& context) const { std::stringstream ss; auto newContext = context; + newContext.replace_bindable_with_question = !is_bindable_v; newContext.skip_table_name = false; - auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; + ss << serialize(orderBy.expression, newContext); if(!orderBy._collate_argument.empty()) { ss << " COLLATE " << orderBy._collate_argument; } @@ -54,16 +54,16 @@ namespace sqlite_orm { std::string entryString; { std::stringstream ss; - ss << entry.name << " "; + ss << entry.name; if(!entry._collate_argument.empty()) { - ss << "COLLATE " << entry._collate_argument << " "; + ss << " COLLATE " << entry._collate_argument << " "; } switch(entry.asc_desc) { case 1: - ss << "ASC"; + ss << " ASC"; break; case -1: - ss << "DESC"; + ss << " DESC"; break; } entryString = ss.str(); diff --git a/dev/statement_serializator.h b/dev/statement_serializator.h index 965a02337..cdb4581d3 100644 --- a/dev/statement_serializator.h +++ b/dev/statement_serializator.h @@ -55,7 +55,7 @@ namespace sqlite_orm { * Serializer for bindable types. */ template - struct statement_serializator>> { + struct statement_serializator> { using statement_type = T; template @@ -126,23 +126,6 @@ namespace sqlite_orm { } }; -#if __cplusplus >= 201703L // use of C++17 or higher - /** - * Constant which gets never replaced in a bindable context. - * Used together with order_by(1_nth_col). - */ - template - struct statement_serializator, void> { - using statement_type = positional_ordinal; - - template - std::string operator()(const statement_type& /*expression*/, const C& /*context*/) { - static_assert(N > 0, "Column number must be greater than 0."); - return std::to_string(N); - } - }; -#endif - template struct statement_serializator, void> { using statement_type = filtered_aggregate_function; diff --git a/dev/type_traits.h b/dev/type_traits.h index 44b44a023..4a4d3283e 100644 --- a/dev/type_traits.h +++ b/dev/type_traits.h @@ -40,24 +40,4 @@ namespace sqlite_orm { template using object_type_t = typename T::object_type; } - - namespace internal { -#if __cplusplus >= 201703L // use of C++17 or higher - constexpr size_t _10_pow(size_t n) { - if(n == 0) { - return 1; - } else { - return 10 * _10_pow(n - 1); - } - } - - template - constexpr size_t n_from_literal(std::index_sequence, Chars... chars) { - return (((chars - '0') * _10_pow(sizeof...(Is) - 1u - Is /*reversed index sequence*/)) + ...); - } - - template - struct positional_ordinal : std::integral_constant {}; -#endif - } } diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 96eed6f13..35970d6c5 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -156,10 +156,16 @@ TEST_CASE("ast_iterator") { internal::iterate_ast(node, lambda); } SECTION("order_by") { - auto node = order_by(c(&User::id) == 0); - expected.push_back(typeid(&User::id)); - expected.push_back(typeid(int)); - internal::iterate_ast(node, lambda); + 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); + } + SECTION("literal") { + auto node = order_by(1); + internal::iterate_ast(node, lambda); + } } SECTION("group_by") { auto node = group_by(&User::id); diff --git a/tests/conditions.cpp b/tests/conditions.cpp deleted file mode 100644 index 8a10ece35..000000000 --- a/tests/conditions.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -using namespace sqlite_orm; - -TEST_CASE("order by") { - struct Object { - int64 id; - int n; - }; - - auto storage = - make_storage("", - make_table("object", make_column("id", &Object::id, primary_key()), make_column("n", &Object::n))); - storage.sync_schema(); - - storage.insert({0, 1}); - storage.insert({0, 0}); - - SECTION("column") { - std::vector expected{0, 1}; - // select n from object order by n - auto rows = storage.select(&Object::n, order_by(&Object::n)); - REQUIRE(rows == expected); - } -#if 0 // outline; order_by statically asserts when passing bindable values - SECTION("bindable") { - std::vector expected{1, 0}; - // select n from object order by ? - // ? = 1 - auto rows = storage.select(&Object::n, order_by(1)); - REQUIRE(rows == expected); - } -#endif -} diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp index c27e8fa66..0bbe1da52 100644 --- a/tests/statement_serializator_tests/conditions.cpp +++ b/tests/statement_serializator_tests/conditions.cpp @@ -1,93 +1,26 @@ #include #include +#include using namespace sqlite_orm; TEST_CASE("statement_serializator conditions") { - internal::serializator_context_base context; + internal::storage_impl<> storage; + internal::serializator_context context{storage}; - SECTION("static assertions") { -#if __cplusplus >= 201703L // use of C++17 or higher - // must assert - //constexpr auto n = 0_nth_col; + std::string value, expected; - STATIC_REQUIRE(std::is_same_v, decltype(1_nth_col)>); - STATIC_REQUIRE(std::is_same_v, decltype(10_nth_col)>); -#endif - } - SECTION("literals") { - SECTION("dump") { -#if __cplusplus >= 201703L // use of C++17 or higher - context.replace_bindable_with_question = false; - auto expr = 2_nth_col; - auto value = serialize(expr, context); - REQUIRE(value == "2"); -#endif - } - SECTION("bindable") { -#if __cplusplus >= 201703L // use of C++17 or higher + SECTION("order_by") { + SECTION("expression") { context.replace_bindable_with_question = true; - auto expr = 2_nth_col; - auto value = serialize(expr, context); - REQUIRE(value == "2"); -#endif - } - } -#if 0 // outline; order_by statically asserts when passing bindable values - SECTION("order by bindable") { - order_by(std::wstring_view{L""}); - SECTION("dump") { - context.replace_bindable_with_question = false; - auto expr = order_by(2); - auto value = serialize(expr, context); - REQUIRE(value == "ORDER BY 2"); - } - SECTION("bindable") { - context.replace_bindable_with_question = true; - auto expr = order_by(2); - auto value = serialize(expr, context); - REQUIRE(value == "ORDER BY ?"); - } - } -#endif - SECTION("order by kth column") { - SECTION("dump") { -#if __cplusplus >= 201703L // use of C++17 or higher - context.replace_bindable_with_question = false; - auto expr = order_by(2_nth_col); - auto value = serialize(expr, context); - REQUIRE(value == "ORDER BY 2"); -#endif + value = serialize(order_by(c(1) == 0), context); + expected = "ORDER BY (? == ?)"; } - SECTION("bindable") { -#if __cplusplus >= 201703L // use of C++17 or higher + SECTION("literal") { context.replace_bindable_with_question = true; - auto expr = order_by(2_nth_col); - auto value = serialize(expr, context); - REQUIRE(value == "ORDER BY 2"); -#endif - } - } - SECTION("using") { - struct User { - int64 id; - }; - - auto t1 = make_table("user", make_column("id", &User::id)); - auto storage = internal::storage_impl{t1}; - using storage_impl = decltype(storage); - - internal::serializator_context ctx{storage}; - - SECTION("using column") { - auto expr = using_(&User::id); - auto value = serialize(expr, ctx); - REQUIRE(value == R"(USING ("id"))"); - } - SECTION("using explicit column") { - auto expr = using_(column(&User::id)); - auto value = serialize(expr, ctx); - REQUIRE(value == R"(USING ("id"))"); + value = serialize(order_by(1), context); + expected = "ORDER BY 1"; } } + REQUIRE(value == expected); } diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index c0e1daf48..e46fe3314 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -19,7 +19,9 @@ struct is_tuple> : std::true_type {}; TEST_CASE("Node tuple") { using internal::bindable_filter; using internal::node_tuple; + using internal::node_tuple_t; using std::is_same; + using std::tuple; struct User { int id = 0; @@ -554,6 +556,15 @@ TEST_CASE("Node tuple") { "like(&User::name, std::string(\"pattern\")).escape(\"%\")"); } } + SECTION("order_by_t") { + SECTION("expression") { + STATIC_REQUIRE(is_same, + tuple>::value); + } + SECTION("literal") { + STATIC_REQUIRE(is_same, tuple<>>::value); + } + } SECTION("glob_t") { auto gl = glob(&User::name, "H*"); using Glob = decltype(gl); From 1d4ace097f8dcde529b3b24f89614073b37d5c18 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 22 Mar 2022 23:15:18 +0200 Subject: [PATCH 10/20] Introduced node tuple type alias --- dev/get_prepared_statement.h | 4 +- dev/node_tuple.h | 233 +++++--------- tests/static_tests/node_tuple.cpp | 490 +++++++++++++++--------------- 3 files changed, 317 insertions(+), 410 deletions(-) diff --git a/dev/get_prepared_statement.h b/dev/get_prepared_statement.h index 16e9d6331..7dff509c9 100644 --- a/dev/get_prepared_statement.h +++ b/dev/get_prepared_statement.h @@ -123,7 +123,7 @@ namespace sqlite_orm { const auto& get(const internal::prepared_statement_t& statement) { using statement_type = typename std::decay::type; using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; + using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; using result_tupe = typename std::tuple_element(N), bind_tuple>::type; const result_tupe* result = nullptr; @@ -146,7 +146,7 @@ namespace sqlite_orm { auto& get(internal::prepared_statement_t& statement) { using statement_type = typename std::decay::type; using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; + using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; using result_tupe = typename std::tuple_element(N), bind_tuple>::type; result_tupe* result = nullptr; diff --git a/dev/node_tuple.h b/dev/node_tuple.h index d1fdf5743..55c5d0b2a 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -41,47 +41,35 @@ namespace sqlite_orm { }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using type = typename node_tuple>::type; - }; + struct node_tuple, void> : node_tuple> {}; template struct node_tuple, void> { - using args_tuple = typename node_tuple>::type; - using expression_tuple = typename node_tuple::type; + using args_tuple = node_tuple_t>; + using expression_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template - struct node_tuple, std::tuple>, void> { - using type = typename node_tuple>::type; - }; + struct node_tuple, std::tuple>, void> + : node_tuple> {}; template struct node_tuple, void> { - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = where_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, match_if_not> : node_tuple {}; @@ -94,8 +82,8 @@ namespace sqlite_orm { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; + using left_node_tuple = node_tuple_t; + using right_node_tuple = node_tuple_t; using type = typename conc_tuple::type; }; @@ -104,30 +92,27 @@ namespace sqlite_orm { using node_type = binary_operator; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; + using left_node_tuple = node_tuple_t; + using right_node_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = columns_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = dynamic_in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename conc_tuple::type...>::type; + using left_tuple = node_tuple_t; + using right_tuple = typename conc_tuple...>::type; using type = typename conc_tuple::type; }; @@ -136,266 +121,188 @@ namespace sqlite_orm { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = select_t; - using columns_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; + using columns_tuple = node_tuple_t; + using args_tuple = typename conc_tuple...>::type; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = insert_raw_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = replace_raw_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using node_type = into_t; - using type = std::tuple<>; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = values_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = std::tuple; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = get_all_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = get_all_pointer_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template struct node_tuple, void> { - using node_type = get_all_optional_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template struct node_tuple, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; - using set_tuple = typename conc_tuple::type...>::type; - using conditions_tuple = typename conc_tuple::type...>::type; + using set_tuple = typename conc_tuple...>::type; + using conditions_tuple = typename conc_tuple...>::type; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = remove_all_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using node_type = having_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = cast_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = exists_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = optional_container; - using type = typename node_tuple::type; - }; - - template<> - struct node_tuple, void> { - using node_type = optional_container; - using type = std::tuple<>; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = like_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; - using escape_tuple = typename node_tuple::type; + using arg_tuple = node_tuple_t; + using pattern_tuple = node_tuple_t; + using escape_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = glob_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; + using arg_tuple = node_tuple_t; + using pattern_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = between_t; - using expression_tuple = typename node_tuple::type; - using lower_tuple = typename node_tuple::type; - using upper_tuple = typename node_tuple::type; + using expression_tuple = node_tuple_t; + using lower_tuple = node_tuple_t; + using upper_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template - struct node_tuple, void> { - using node_type = named_collate; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = is_null_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = is_not_null_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = negated_condition_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = built_in_function_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = built_in_aggregate_function_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = filtered_aggregate_function; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = function_call; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using node_type = left_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = on_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; // note: not strictly necessary as there's no binding support for USING; // we provide it nevertheless, in line with on_t. template - struct node_tuple, void> { - using node_type = using_t; - using type = typename node_tuple>::type; - }; + struct node_tuple, void> : node_tuple> {}; template - struct node_tuple, void> { - using node_type = join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = left_outer_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = inner_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = simple_case_t; - using case_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; - using else_tuple = typename node_tuple::type; + using case_tuple = node_tuple_t; + using args_tuple = typename conc_tuple...>::type; + using else_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = std::pair; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template - struct node_tuple, void> { - using node_type = as_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = limit_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; + using type = typename conc_tuple, node_tuple_t>::type; }; template struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; + using type = typename conc_tuple, node_tuple_t>::type; }; } } diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index e46fe3314..52026586e 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -30,16 +30,16 @@ TEST_CASE("Node tuple") { SECTION("simple") { SECTION("int") { - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "int"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("float") { - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "float"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } } SECTION("binary_condition") { @@ -47,280 +47,280 @@ TEST_CASE("Node tuple") { SECTION("5 < 6.0f") { auto c = lesser_than(5, 6.0f); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "lesser_than_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("id < 10") { auto c = lesser_than(&User::id, 10); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "lesser_than_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("5 <= 6.0f") { auto c = lesser_or_equal(5, 6.0f); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "lesser_or_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("id <= 10.0") { auto c = lesser_or_equal(&User::id, 10.0); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "lesser_or_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("5 > 6.0f") { auto c = greater_than(5, 6.0f); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "greater_than_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("id > 20") { auto c = greater_than(&User::id, 20); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "greater_than_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("5 >= 6.0f") { auto c = greater_or_equal(5, 6.0f); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "greater_or_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("5 >= id") { auto c = greater_or_equal(5, &User::id); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "greater_or_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("5 == 6.0f") { auto c = is_equal(5, 6.0f); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "is_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("'ototo' == name") { auto c = is_equal("ototo", &User::name); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "is_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("5 != 6.0f") { auto c = is_not_equal(5, 6.0f); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "is_not_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("name != std::string('ototo')") { auto c = is_not_equal(&User::name, std::string("ototo")); using C = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "is_not_equal_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("bool and int") { using Tuple = node_tuple>::type; - using Expected = std::tuple; + using Expected = tuple; static_assert(is_same::value, "and_condition_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("bool or int") { using Tuple = node_tuple>::type; - using Expected = std::tuple; + using Expected = tuple; static_assert(is_same::value, "or_condition_t"); - STATIC_REQUIRE(is_same::type, std::tuple>::value); + STATIC_REQUIRE(is_same::type, tuple>::value); } } SECTION("binary_operator") { using namespace internal; using CondTuple = node_tuple>::type; - static_assert(is_same>::value, "conc_t"); + static_assert(is_same>::value, "conc_t"); using AddTuple = node_tuple>::type; - static_assert(is_same>::value, "add_t"); + static_assert(is_same>::value, "add_t"); using SubTuple = node_tuple>::type; - static_assert(is_same>::value, "sub_t"); + static_assert(is_same>::value, "sub_t"); using MulTuple = node_tuple>::type; - static_assert(is_same>::value, "mul_t"); + static_assert(is_same>::value, "mul_t"); using DivTuple = node_tuple>::type; - static_assert(is_same>::value, "div_t"); + static_assert(is_same>::value, "div_t"); using ModTuple = node_tuple>::type; - static_assert(is_same>::value, "mod_t"); + static_assert(is_same>::value, "mod_t"); using AssignTuple = node_tuple>::type; - static_assert(is_same>::value, "assign_t"); + static_assert(is_same>::value, "assign_t"); } SECTION("columns") { auto cols = columns(&User::id, &User::name); using Cols = decltype(cols); - using ColsTuple = node_tuple::type; - static_assert(is_same>::value, "columns_t"); + using ColsTuple = node_tuple_t; + static_assert(is_same>::value, "columns_t"); } SECTION("in") { auto inValue = in(&User::id, {1, 2, 3}); using In = decltype(inValue); - using InTuple = node_tuple::type; - static_assert(is_same>>::value, "in_t"); + using InTuple = node_tuple_t; + static_assert(is_same>>::value, "in_t"); } SECTION("exists(select(&User::name, where(in(&User::id, {6, 7, 9}))))") { auto c = exists(select(&User::name, where(in(&User::id, {6, 7, 9})))); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple>; + using Tuple = node_tuple_t; + using Expected = tuple>; static_assert(is_same::value, "exists(select(&User::name, where(in(&User::id, {6, 7, 9}))))"); } SECTION("aggregate functions") { SECTION("avg") { auto node = avg(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "avg"); } SECTION("avg filter") { auto node = avg(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "avg filter"); } SECTION("count(*)") { auto node = count(); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "count(*)"); } SECTION("count(*) filter") { auto node = count().filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple()), decltype(&User::name), int>; + using Tuple = node_tuple_t; + using Expected = tuple()), decltype(&User::name), int>; static_assert(is_same::value, "count(*) filter"); } SECTION("count(X)") { auto node = count(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "count(X)"); } SECTION("count(X) filter") { auto node = count(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "count(X) filter"); } SECTION("group_concat(X)") { auto node = group_concat(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "group_concat(X)"); } SECTION("group_concat(X) filter") { auto node = group_concat(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "group_concat(X) filter"); } SECTION("group_concat(X,Y)") { auto node = group_concat(&User::id, std::string("-")); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "group_concat(X,Y)"); } SECTION("group_concat(X,Y) filter") { auto node = group_concat(&User::id, std::string("-")).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "group_concat(X,Y) filter"); } SECTION("max(X)") { auto node = max(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "max(X)"); } SECTION("max(X) filter") { auto node = max(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "max(X) filter"); } SECTION("min(X)") { auto node = min(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "min(X)"); } SECTION("min(X) filter") { auto node = min(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "min(X) filter"); } SECTION("sum(X)") { auto node = sum(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "sum(X)"); } SECTION("sum(X) filter") { auto node = sum(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "sum(X) filter"); } SECTION("total(X)") { auto node = total(&User::id); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "total(X)"); } SECTION("total(X) filter") { auto node = total(&User::id).filter(where(length(&User::name) > 5)); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "total(X) filter"); } } @@ -328,15 +328,15 @@ TEST_CASE("Node tuple") { SECTION("max(X,Y)") { auto node = max(&User::id, 4); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "max(X,Y)"); } SECTION("min(X,Y)") { auto node = min(&User::id, 4); using Node = decltype(node); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "min(X,Y)"); } } @@ -344,15 +344,15 @@ TEST_CASE("Node tuple") { SECTION("union_(select(1), select(2))") { auto un = union_(select(1), select(2)); using Union = decltype(un); - using Tuple = node_tuple::type; - static_assert(is_same>::value, "union_(select(1), select(2))"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "union_(select(1), select(2))"); } SECTION("union_all") { auto un = union_all(select(&User::id, where(is_equal(&User::name, "Alice"))), select(&User::id, where(is_equal(std::string("Bob"), &User::name)))); using Union = decltype(un); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Expected = tuple::type; - using Expected = std::tuple; + using Expected = tuple::type; + using Tuple = node_tuple_t; using Expected = - std::tuple; + tuple; static_assert(is_same::value, "intersect"); } } @@ -388,67 +388,67 @@ TEST_CASE("Node tuple") { auto expression = replace(into(), columns(&User::id, &User::name), values(std::make_tuple(1, std::string("Ellie")))); using Expression = decltype(expression); - using Tuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + using Tuple = node_tuple_t; + STATIC_REQUIRE(is_same>::value); } SECTION("insert_raw_t") { auto expression = insert(into(), columns(&User::id, &User::name), values(std::make_tuple(1, std::string("Ellie")))); using Expression = decltype(expression); - using Tuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + using Tuple = node_tuple_t; + STATIC_REQUIRE(is_same>::value); } SECTION("tuple") { auto expression = std::make_tuple(1, std::string("hi")); using Expression = decltype(expression); - using Tuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + using Tuple = node_tuple_t; + STATIC_REQUIRE(is_same>::value); } SECTION("values") { SECTION("int + string") { auto expression = values(1, std::string("hi")); using Expression = decltype(expression); - using Tuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + using Tuple = node_tuple_t; + STATIC_REQUIRE(is_same>::value); } SECTION("tuple") { auto expression = values(std::make_tuple(1, std::string("hi"))); using Expression = decltype(expression); - using Tuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + using Tuple = node_tuple_t; + STATIC_REQUIRE(is_same>::value); } } SECTION("into") { auto expression = into(); using Expression = decltype(expression); - using Tuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + using Tuple = node_tuple_t; + STATIC_REQUIRE(is_same>::value); } SECTION("select") { SECTION("select(&User::id)") { auto sel = select(&User::id); using Sel = decltype(sel); - using Tuple = node_tuple::type; - static_assert(is_same>::value, "select(&User::id)"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "select(&User::id)"); } SECTION("select(&User::name)") { auto sel = select(&User::name); using Sel = decltype(sel); - using Tuple = node_tuple::type; - static_assert(is_same>::value, "select(&User::name)"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "select(&User::name)"); } SECTION("select(&User::id, where(is_equal(&User::id, 5)))") { auto sel = select(&User::id, where(is_equal(&User::id, 5))); using Sel = decltype(sel); - using Tuple = node_tuple::type; - static_assert(is_same>::value, + using Tuple = node_tuple_t; + static_assert(is_same>::value, "select(&User::id, where(is_equal(&User::id, 5)))"); } SECTION("select(&User::name, where(lesser_than(&User::id, 10)))") { auto sel = select(&User::name, where(lesser_than(&User::id, 10))); using Sel = decltype(sel); - using Tuple = node_tuple::type; - static_assert(is_same>::value, + using Tuple = node_tuple_t; + static_assert(is_same>::value, "select(&User::name, where(lesser_than(&User::id, 10)))"); } SECTION("select(columns(&User::id, &User::name), where(greater_or_equal(&User::id, 10) and " @@ -456,7 +456,7 @@ TEST_CASE("Node tuple") { auto sel = select(columns(&User::id, &User::name), where(greater_or_equal(&User::id, 10) and lesser_or_equal(&User::id, 20))); using Sel = decltype(sel); - using Tuple = node_tuple::type; + using Tuple = node_tuple_t; using Expected = std:: tuple; static_assert(is_same::value, @@ -466,8 +466,8 @@ TEST_CASE("Node tuple") { SECTION("select(columns('ototo', 25))") { auto statement = select(columns("ototo", 25)); using Statement = decltype(statement); - using Tuple = node_tuple::type; - using ExpectedTuple = std::tuple; + using Tuple = node_tuple_t; + using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } } @@ -475,22 +475,22 @@ TEST_CASE("Node tuple") { SECTION("get_all()") { auto getAll = get_all(); using GetAll = decltype(getAll); - using Tuple = node_tuple::type; - static_assert(is_same>::value, "get_all()"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "get_all()"); } SECTION("get_all(where(is_equal(5.0, &User::id)))") { auto getAll = get_all(where(is_equal(5.0, &User::id))); using GetAll = decltype(getAll); - using Tuple = node_tuple::type; - static_assert(is_same>::value, + using Tuple = node_tuple_t; + static_assert(is_same>::value, "get_all(where(is_equal(5.0, &User::id)))"); } SECTION("get_all(where(is_equal(5.0, &User::id)))") { auto getAll = get_all(where(is_equal(&User::id, 1) or is_equal(std::string("Alex"), &User::name))); using GetAll = decltype(getAll); - using Tuple = node_tuple::type; + using Tuple = node_tuple_t; static_assert( - is_same>::value, + is_same>::value, "get_all(where(is_equal(5.0, &User::id)))"); } } @@ -498,28 +498,28 @@ TEST_CASE("Node tuple") { using namespace internal; auto hav = having(greater_or_equal(&User::id, 10)); using Having = decltype(hav); - using Tuple = node_tuple::type; - static_assert(is_same>::value, + using Tuple = node_tuple_t; + static_assert(is_same>::value, "having(greater_or_equal(&User::id, 10))"); } SECTION("cast_t") { auto sel = select(columns(cast(&User::id), cast(&User::name))); using Select = decltype(sel); - using Tuple = node_tuple; + static_assert(is_same>::value, "select(columns(cast(&User::id), cast(&User::name)))"); } SECTION("optional_container") { using namespace internal; SECTION("int") { using Op = optional_container; - using Tuple = node_tuple::type; - static_assert(is_same>::value, "optional_container"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "optional_container"); } SECTION("void") { using Op = optional_container; - using Tuple = node_tuple::type; - static_assert(is_same>::value, "optional_container"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "optional_container"); } } SECTION("like_t") { @@ -528,30 +528,30 @@ TEST_CASE("Node tuple") { using Like = decltype(lk); using NodeTuple = node_tuple; using ArgTuple = NodeTuple::arg_tuple; - static_assert(is_same>::value, "arg_tuple"); + static_assert(is_same>::value, "arg_tuple"); using PatternTuple = NodeTuple::pattern_tuple; - static_assert(is_same>::value, "pattern_tuple"); + static_assert(is_same>::value, "pattern_tuple"); using EscapeTuple = NodeTuple::escape_tuple; - static_assert(is_same>::value, "escape_tuple"); + static_assert(is_same>::value, "escape_tuple"); using Tuple = NodeTuple::type; static_assert(std::tuple_size::value == 2, "like(&User::name, \"S%\") size"); using Tuple0 = std::tuple_element<0, Tuple>::type; static_assert(is_same::value, "like(&User::name, \"S%\") type 0"); - static_assert(is_same>::value, + static_assert(is_same>::value, "like(&User::name, \"S%\")"); } SECTION("like(&User::name, std::string('pattern'), '%')") { auto lk = like(&User::name, std::string("pattern"), "%"); using Like = decltype(lk); - using NodeTuple = node_tuple::type; - using Expected = std::tuple; + using NodeTuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "like(&User::name, std::string(\"pattern\"), \"%\")"); } SECTION("like(&User::name, std::string('pattern')).escape('%')") { auto lk = like(&User::name, std::string("pattern")).escape("%"); using Like = decltype(lk); - using NodeTuple = node_tuple::type; - using Expected = std::tuple; + using NodeTuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "like(&User::name, std::string(\"pattern\")).escape(\"%\")"); } @@ -568,106 +568,106 @@ TEST_CASE("Node tuple") { SECTION("glob_t") { auto gl = glob(&User::name, "H*"); using Glob = decltype(gl); - using Tuple = node_tuple::type; - static_assert(is_same>::value, + using Tuple = node_tuple_t; + static_assert(is_same>::value, "glob(&User::name, \"H*\")"); } SECTION("between_t") { auto bet = between(&User::id, 10, 20); using Between = decltype(bet); - using Tuple = node_tuple::type; - static_assert(is_same>::value, "between(&User::id, 10, 20)"); + using Tuple = node_tuple_t; + static_assert(is_same>::value, "between(&User::id, 10, 20)"); } SECTION("named_collate") { auto sel = select(&User::name, where(is_equal(&User::name, "Mercury").collate("ototo"))); using Select = decltype(sel); - using Tuple = node_tuple; + using Expected = tuple; static_assert(is_same::value, "named_collate"); } SECTION("negated_condition_t") { SECTION("not is_equal(20, '20')") { auto c = not is_equal(20, "20"); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not is_equal(20, \"20\")"); } SECTION("not is_not_equal(&User::id, 15.0)") { auto c = not is_not_equal(&User::id, 15.0); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not is_not_equal(&User::id, 15.0)"); } SECTION("not greater_than(20.0f, &User::id)") { auto c = not greater_than(20.0f, &User::id); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not greater_than(20.0f, &User::id)"); } SECTION("not greater_or_equal(&User::id, 5)") { auto c = not greater_or_equal(&User::id, 5); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not greater_or_equal(&User::id, 5)"); } SECTION("not lesser_than(&User::id, std::string('6'))") { auto c = not lesser_than(&User::id, std::string("6")); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not lesser_than(&User::id, std::string(\"6\"))"); } SECTION("not lesser_or_equal(&User::id, 10)") { auto c = not lesser_or_equal(&User::id, 10); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not lesser_or_equal(&User::id, 10)"); } SECTION("not in(&User::id, {1, 2, 3})") { auto c = not in(&User::id, {1, 2, 3}); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple>; + using Tuple = node_tuple_t; + using Expected = tuple>; static_assert(is_same::value, "not in(&User::id, {1, 2, 3})"); } SECTION("not is_null(&User::name)") { auto c = not is_null(&User::name); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not is_null(&User::name)"); } SECTION("not is_not_null(&User::name)") { auto c = not is_not_null(&User::name); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not is_not_null(&User::name)"); } SECTION("not like(&User::name, '*D*')") { auto c = not like(&User::name, "*D*"); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not like(&User::name, \"*D*\")"); } SECTION("not glob(&User::name, std::string('_A_'))") { auto c = not glob(&User::name, std::string("_A_")); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "not glob(&User::name, std::string(\"_A_\"))"); } SECTION("not exists(select(&User::name, where(in(&User::id, {6, 7, 9}))))") { auto c = not exists(select(&User::name, where(in(&User::id, {6, 7, 9})))); using Con = decltype(c); - using Tuple = node_tuple::type; - using Expected = std::tuple>; + using Tuple = node_tuple_t; + using Expected = tuple>; static_assert(is_same::value, "not exists(select(&User::name, where(in(&User::id, {6, 7, 9}))))"); } @@ -676,132 +676,132 @@ TEST_CASE("Node tuple") { SECTION("lower") { auto f = lower(&User::name); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "lower"); } SECTION("upper") { auto f = upper("hi"); using Fun = decltype(f); - using Tuple = node_tuple::type; + using Tuple = node_tuple_t; using ArgType = std::tuple_element<0, Fun::args_type>::type; static_assert(is_same::value, "upper arg[0]"); - using Expected = std::tuple; + using Expected = tuple; static_assert(is_same::value, "upper"); } SECTION("total_changes") { auto f = total_changes(); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple<>; + using Tuple = node_tuple_t; + using Expected = tuple<>; static_assert(is_same::value, "total_changes"); } SECTION("changes") { auto f = changes(); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple<>; + using Tuple = node_tuple_t; + using Expected = tuple<>; static_assert(is_same::value, "changes"); } SECTION("trim(1)") { auto f = trim(&User::name); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "trim(1)"); } SECTION("trim(2)") { auto f = trim(&User::name, std::string("pay")); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "trim(2)"); } SECTION("ltrim(1)") { auto f = ltrim(&User::id); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "ltrim(1)"); } SECTION("ltrim(2)") { auto f = ltrim(&User::id, "see"); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "ltrim(2)"); } SECTION("rtrim(1)") { auto f = rtrim(&User::name); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "rtrim(1)"); } SECTION("rtrim(2)") { auto f = rtrim(&User::name, &User::id); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "rtrim(2)"); } #if SQLITE_VERSION_NUMBER >= 3007016 SECTION("char_") { auto f = char_(100, 20.0); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "char_"); } #endif SECTION("coalesce") { auto f = char_(10, 20); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "coalesce"); } SECTION("date") { auto f = date(std::string("now"), std::string("start of month"), std::string("+1 month"), std::string("-1 day")); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "date"); } SECTION("datetime") { auto f = datetime("now"); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "datetime"); } SECTION("julianday") { auto f = julianday("now"); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "julianday"); } SECTION("zeroblob") { auto f = zeroblob(10); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "zeroblob"); } SECTION("substr(2)") { auto f = substr(&User::name, 7); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "substr"); } SECTION("substr(3)") { auto f = substr(&User::name, 7, 20.f); using Fun = decltype(f); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "substr"); } } @@ -809,44 +809,44 @@ TEST_CASE("Node tuple") { SECTION("left_join") { auto j = left_join(on(is_equal(&User::id, 2))); using Join = decltype(j); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "left_join"); } SECTION("join on") { auto j = join(on(is_equal(&User::id, 2))); using Join = decltype(j); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "join on"); } SECTION("join using column") { auto j = join(using_(&User::id)); using Join = decltype(j); - using Tuple = node_tuple::type; - using Expected = std::tuple>; + using Tuple = node_tuple_t; + using Expected = tuple>; static_assert(is_same::value, "join using"); } SECTION("join using explicit column") { struct Derived : User {}; auto j = join(using_(column(&User::id))); using Join = decltype(j); - using Tuple = node_tuple::type; - using Expected = std::tuple>; + using Tuple = node_tuple_t; + using Expected = tuple>; static_assert(is_same::value, "join using explicit column"); } SECTION("left_outer_join") { auto j = left_outer_join(on(is_equal(&User::id, 2))); using Join = decltype(j); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "left_outer_join"); } SECTION("inner_join") { auto j = inner_join(on(is_equal(&User::id, 2))); using Join = decltype(j); - using Tuple = node_tuple::type; - using Expected = std::tuple; + using Tuple = node_tuple_t; + using Expected = tuple; static_assert(is_same::value, "inner_join"); } } @@ -854,10 +854,10 @@ TEST_CASE("Node tuple") { auto c = case_(&User::name).when("USA", then("Dosmetic")).else_("Foreign").end(); using Case = decltype(c); using CaseExpressionTuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + STATIC_REQUIRE(is_same>::value); - STATIC_REQUIRE(is_tuple>::value); - STATIC_REQUIRE(is_tuple>::value); + STATIC_REQUIRE(is_tuple>::value); + STATIC_REQUIRE(is_tuple>::value); STATIC_REQUIRE(!is_tuple::value); STATIC_REQUIRE(is_pair>::value); STATIC_REQUIRE(!is_pair::value); @@ -872,10 +872,10 @@ TEST_CASE("Node tuple") { STATIC_REQUIRE(is_same::value); using Arg0Second = Arg0::second_type; STATIC_REQUIRE(is_same::value); - STATIC_REQUIRE(is_same>>::value); + STATIC_REQUIRE(is_same>>::value); using ElseExpressionTuple = node_tuple::type; - STATIC_REQUIRE(is_same>::value); + STATIC_REQUIRE(is_same>::value); } SECTION("as") { struct GradeAlias : alias_tag { @@ -886,8 +886,8 @@ TEST_CASE("Node tuple") { }; auto a = as(&User::name); using A = decltype(a); - using Tuple = node_tuple::type; - using ExpectedTuple = std::tuple; + using Tuple = node_tuple_t; + using ExpectedTuple = tuple; STATIC_REQUIRE(is_same::value); } SECTION("function_call") { @@ -898,29 +898,29 @@ TEST_CASE("Node tuple") { }; auto statement = func(8); using Statement = decltype(statement); - using Tuple = node_tuple::type; - using ExpectedTuple = std::tuple; + using Tuple = node_tuple_t; + using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } SECTION("excluded") { auto statement = excluded(&User::id); using Statement = decltype(statement); - using Tuple = node_tuple::type; - using ExpectedTuple = std::tuple; + using Tuple = node_tuple_t; + using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } SECTION("upsert_clause") { auto statement = on_conflict(&User::id).do_update(set(c(&User::name) = excluded(&User::name))); using Statement = decltype(statement); - using Tuple = node_tuple::type; - using ExpectedTuple = std::tuple; + using Tuple = node_tuple_t; + using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } SECTION("group_by") { auto statement = group_by(&User::id); using Statement = decltype(statement); - using Tuple = node_tuple::type; - using ExpectedTuple = std::tuple; + using Tuple = node_tuple_t; + using ExpectedTuple = tuple; STATIC_REQUIRE(std::is_same::value); } } From f6a1f2520a56245dfde9962040202d85801a61f9 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 22 Mar 2022 23:23:59 +0200 Subject: [PATCH 11/20] Updated sqlite_orm.h --- include/sqlite_orm/sqlite_orm.h | 580 +++++++++++++++----------------- 1 file changed, 273 insertions(+), 307 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 6bc430629..3218f5b0c 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -39,11 +39,13 @@ __pragma(push_macro("min")) // #include "cxx_polyfill.h" + #include - // #include "start_macros.h" +// #include "start_macros.h" + - namespace sqlite_orm { +namespace sqlite_orm { namespace internal { namespace polyfill { #if __cplusplus < 201703L // before C++17 @@ -134,6 +136,7 @@ __pragma(push_macro("min")) } } + namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -170,26 +173,6 @@ namespace sqlite_orm { template using object_type_t = typename T::object_type; } - - namespace internal { -#if __cplusplus >= 201703L // use of C++17 or higher - constexpr size_t _10_pow(size_t n) { - if(n == 0) { - return 1; - } else { - return 10 * _10_pow(n - 1); - } - } - - template - constexpr size_t n_from_literal(std::index_sequence, Chars... chars) { - return (((chars - '0') * _10_pow(sizeof...(Is) - 1u - Is /*reversed index sequence*/)) + ...); - } - - template - struct positional_ordinal : std::integral_constant {}; -#endif - } } #pragma once @@ -363,6 +346,7 @@ namespace sqlite_orm { // #include "../static_magic.h" + #include // std::false_type, std::true_type, std::integral_constant namespace sqlite_orm { @@ -402,6 +386,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type @@ -814,12 +799,15 @@ namespace sqlite_orm { // #include "table_type.h" + #include // std::enable_if, std::is_member_pointer, std::is_member_function_pointer // #include "member_traits/getter_traits.h" + // #include "getters.h" + namespace sqlite_orm { namespace internal { @@ -862,6 +850,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -969,8 +958,10 @@ namespace sqlite_orm { // #include "member_traits/setter_traits.h" + // #include "setters.h" + namespace sqlite_orm { namespace internal { @@ -995,6 +986,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1042,10 +1034,12 @@ namespace sqlite_orm { // #include "member_traits/is_getter.h" + #include // std::false_type, std::true_type // #include "getters.h" + namespace sqlite_orm { namespace internal { @@ -1093,10 +1087,12 @@ namespace sqlite_orm { // #include "member_traits/is_setter.h" + #include // #include "setters.h" + namespace sqlite_orm { namespace internal { @@ -1124,6 +1120,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1173,6 +1170,7 @@ namespace sqlite_orm { // #include "type_printer.h" + namespace sqlite_orm { namespace internal { @@ -1756,6 +1754,7 @@ namespace sqlite_orm { // #include "serializator_context.h" + namespace sqlite_orm { namespace internal { @@ -1813,6 +1812,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -1846,6 +1846,7 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED // #include "tags.h" + namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1859,6 +1860,7 @@ namespace sqlite_orm { // #include "serialize_result_type.h" + #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED #include // string_view #else @@ -1875,6 +1877,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -2161,10 +2164,12 @@ namespace sqlite_orm { // #include "member_traits/member_traits.h" + #include // std::enable_if // #include "is_field_member_pointer.h" + #include // std::false_type, std::true_type, std::is_member_pointer, std::is_member_function_pointer namespace sqlite_orm { @@ -2185,10 +2190,12 @@ namespace sqlite_orm { // #include "field_member_traits.h" + #include // std::enable_if // #include "is_field_member_pointer.h" + namespace sqlite_orm { namespace internal { @@ -2209,6 +2216,7 @@ namespace sqlite_orm { // #include "setter_traits.h" + namespace sqlite_orm { namespace internal { @@ -2235,6 +2243,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -2535,6 +2544,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -2690,6 +2700,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -2729,6 +2740,7 @@ namespace sqlite_orm { // #include "expression.h" // #include "operators.h" + namespace sqlite_orm { namespace internal { @@ -2803,6 +2815,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -3961,51 +3974,18 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } -#if __cplusplus >= 201703L // use of C++17 or higher - /** - * positional_ordinal from numeric literal. - * E.g. 1_nth_col, 2_nth_col - * - * @note Design desicion: - * A user-defined numeric literal is the C++ way to capture a numeric literal as a compile-time value, - * with the intention to form a literal positional ordinal in the SQL statement. - * It isn't possible with built-in literals. - * The user-defined literal might seem a bit inconvenient at first, - * however has the advantage of giving the literal contextual meaning. - */ - template - [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _nth_col() { - constexpr auto n = - internal::positional_ordinal{}, - Chars...)>{}; - static_assert(n > 0u, "Column number must be greater than 0."); - return n; - } -#endif - /** - * ORDER BY column + * ORDER BY column or literal value (including a column number) + * + * Note that a bindable will be serialized as a literal value. + * Only integral numbers make sense and SQLite will understand them as a positional column ordinal. + * * Examples: * storage.select(&User::name, order_by(&User::id)) - * storage.select(&User::name, order_by(1_nth_col)) + * storage.select(&User::name, order_by(1)) */ template internal::order_by_t order_by(O o) { - static_assert(!std::is_arithmetic::value && !std::is_base_of::value && - !std::is_same, const char*>::value -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - && !std::is_same::value -#endif -#ifndef SQLITE_ORM_OMITS_CODECVT - && !std::is_base_of::value && - !std::is_same, const wchar_t*>::value -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - && !std::is_same::value -#endif -#endif - , - "Binding a single value to an ORDER-BY expression is possible but not useful.\n" - "If your intention is to order by kth column then please use `order_by(1_nth_col)`"); return {std::move(o)}; } @@ -4240,6 +4220,7 @@ namespace sqlite_orm { // #include "conditions.h" + namespace sqlite_orm { namespace internal { @@ -4351,6 +4332,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4394,6 +4376,7 @@ namespace sqlite_orm { // #include "tuple_helper/count_tuple.h" + namespace sqlite_orm { using int64 = sqlite_int64; @@ -6469,8 +6452,10 @@ namespace sqlite_orm { // #include "ast/where.h" + // #include "../serialize_result_type.h" + namespace sqlite_orm { namespace internal { @@ -6518,6 +6503,7 @@ namespace sqlite_orm { // #include "ast/group_by.h" + #include // std::tuple, std::make_tuple #include // std::true_type, std::false_type, std::forward @@ -6598,6 +6584,7 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { @@ -7065,6 +7052,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) @@ -7097,7 +7085,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : statements(std::make_tuple(std::forward(statements)...)), base(std::move(trigger_base)) {} - partial_trigger_t& end() { + partial_trigger_t &end() { return *this; } }; @@ -7127,7 +7115,7 @@ namespace sqlite_orm { */ elements_type elements; - trigger_t(const std::string& name, T trigger_base, elements_type statements) : + trigger_t(const std::string &name, T trigger_base, elements_type statements) : name(name), base(std::move(trigger_base)), elements(std::move(statements)) {} }; @@ -7162,7 +7150,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; } @@ -7321,7 +7309,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) { return {move(name), std::move(part.base), std::move(part.statements)}; } @@ -7385,6 +7373,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" + #include // std::integral_constant #ifdef __cpp_lib_concepts #include @@ -7394,6 +7383,7 @@ namespace sqlite_orm { // #include "cxx_polyfill.h" + namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7623,6 +7613,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { /** @@ -7812,6 +7803,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { /** @@ -8145,6 +8137,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::string #include // std::unique_ptr #include // std::array @@ -8209,6 +8202,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -8643,6 +8637,7 @@ namespace sqlite_orm { // #include "indexed_column.h" + #include // std::string namespace sqlite_orm { @@ -8725,6 +8720,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -8768,6 +8764,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { namespace internal { @@ -8882,6 +8879,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" + namespace sqlite_orm { namespace internal { @@ -9259,6 +9257,7 @@ namespace sqlite_orm { // #include "function.h" + #include #include // std::string #include // std::tuple @@ -9269,6 +9268,7 @@ namespace sqlite_orm { // #include "cxx_polyfill.h" + namespace sqlite_orm { struct arg_values; @@ -9282,13 +9282,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; user_defined_function_base(decltype(name) name_, decltype(argumentsCount) argumentsCount_, @@ -9335,7 +9335,7 @@ namespace sqlite_orm { struct SFINAE {}; template - static char test(SFINAE*); + static char test(SFINAE *); template static int test(...); @@ -9353,13 +9353,13 @@ namespace sqlite_orm { struct SFINAE {}; template - static char test(SFINAE*); + static char test(SFINAE *); template static int test(...); template - static char test2(SFINAE*); + static char test2(SFINAE *); template static int test2(...); @@ -9458,7 +9458,7 @@ namespace sqlite_orm { 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"); @@ -9532,6 +9532,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -9855,6 +9856,7 @@ namespace sqlite_orm { // #include "dbstat.h" + #include // std::string namespace sqlite_orm { @@ -9874,6 +9876,7 @@ namespace sqlite_orm { #endif // SQLITE_ENABLE_DBSTAT_VTAB } + namespace sqlite_orm { namespace internal { @@ -10248,10 +10251,12 @@ namespace sqlite_orm { // #include "field_value_holder.h" + #include // std::enable_if // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -10274,6 +10279,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -10668,18 +10674,22 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" + // #include "row_extractor.h" // #include "mapped_row_extractor.h" + #include // #include "object_from_column_builder.h" + #include // #include "row_extractor.h" + namespace sqlite_orm { namespace internal { @@ -10716,6 +10726,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -10748,6 +10759,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -10827,6 +10839,7 @@ namespace sqlite_orm { // #include "view.h" + #include // std::shared_ptr #include // std::string #include // std::forward, std::move @@ -10841,6 +10854,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include // std::shared_ptr, std::unique_ptr, std::make_shared #include #include // std::decay @@ -10857,6 +10871,7 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" + namespace sqlite_orm { namespace internal { @@ -10960,6 +10975,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -10975,6 +10991,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::iterator_traits #include // std::string @@ -10983,11 +11000,13 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include // std::string // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -11062,6 +11081,7 @@ namespace sqlite_orm { // #include "values.h" + #include // std::vector #include #include // std::tuple @@ -11103,6 +11123,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -11855,6 +11876,7 @@ namespace sqlite_orm { // #include "ast/excluded.h" + namespace sqlite_orm { namespace internal { @@ -11874,6 +11896,7 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" + #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type, std::forward @@ -11939,6 +11962,7 @@ namespace sqlite_orm { // #include "ast/into.h" + #include // std::true_type, std::false_type namespace sqlite_orm { @@ -11966,10 +11990,12 @@ namespace sqlite_orm { // #include "ast/exists.h" + #include // std::move // #include "tags.h" + namespace sqlite_orm { namespace internal { @@ -11998,6 +12024,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -12635,7 +12662,7 @@ namespace sqlite_orm { }; template - struct ast_iterator, void> { + struct ast_iterator, match_if_not> { using node_type = order_by_t; template @@ -12644,6 +12671,15 @@ namespace sqlite_orm { } }; + template + struct ast_iterator, match_if> { + using node_type = order_by_t; + + template + void operator()(const node_type& /*node*/, const L& /*l*/) const { + } + }; + template struct ast_iterator, void> { using node_type = collate_t; @@ -12661,6 +12697,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -12730,6 +12767,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include // std::function, std::bind #include #include // std::string @@ -12744,6 +12782,7 @@ namespace sqlite_orm { // #include "pragma.h" + #include // std::string #include #include // std::function @@ -12760,6 +12799,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -12916,6 +12956,7 @@ namespace sqlite_orm { // #include "limit_accesor.h" + #include #include // std::map #include // std::function @@ -12923,6 +12964,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13056,10 +13098,12 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13083,7 +13127,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(std::move(commit_func_)), rollback_func(std::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) { @@ -13100,7 +13144,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 @@ -13145,6 +13189,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::system_error #include // std::string @@ -13154,6 +13199,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13223,6 +13269,7 @@ namespace sqlite_orm { // #include "values_to_tuple.h" + #include #include // std::get, std::tuple_element @@ -13230,17 +13277,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 { @@ -13277,18 +13326,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]; @@ -13317,27 +13366,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; @@ -13370,10 +13419,11 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value** values = nullptr; + sqlite3_value **values = nullptr; }; } + namespace sqlite_orm { namespace internal { @@ -13385,7 +13435,7 @@ namespace sqlite_orm { template struct values_to_tuple { - void extract(sqlite3_value** values, T& tuple, int argsCount) const { + void extract(sqlite3_value **values, T &tuple, int argsCount) const { using element_type = typename std::tuple_element::type; std::get(tuple) = row_extractor().extract(values[I]); @@ -13395,14 +13445,14 @@ namespace sqlite_orm { template struct values_to_tuple { - void extract(sqlite3_value** values, T& tuple, int argsCount) const { + void extract(sqlite3_value **values, T &tuple, int argsCount) const { //.. } }; template<> struct values_to_tuple, 0> { - void extract(sqlite3_value** values, std::tuple& tuple, int argsCount) const { + void extract(sqlite3_value **values, std::tuple &tuple, int argsCount) const { std::get<0>(tuple) = arg_values(argsCount, values); } }; @@ -13411,6 +13461,7 @@ namespace sqlite_orm { // #include "arg_values.h" + namespace sqlite_orm { namespace internal { @@ -14123,11 +14174,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 { @@ -14278,6 +14331,7 @@ namespace sqlite_orm { // #include "statement_serializator.h" + #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14327,6 +14381,7 @@ namespace sqlite_orm { // #include "table_name_collector.h" + #include // std::set #include // std::string #include // std::function @@ -14342,6 +14397,7 @@ namespace sqlite_orm { // #include "core_functions.h" + namespace sqlite_orm { namespace internal { @@ -14358,7 +14414,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 {}; } @@ -14370,19 +14426,19 @@ namespace sqlite_orm { } template - void operator()(const column_pointer&) const { + void operator()(const column_pointer &) const { if(this->find_table_name) { table_names.insert({this->find_table_name(typeid(T)), ""}); } } template - void operator()(const alias_column_t& a) const { + 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 { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { @@ -14392,7 +14448,7 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14400,7 +14456,7 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t&) const { + void operator()(const asterisk_t &) const { if(this->find_table_name) { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, @@ -14411,7 +14467,7 @@ namespace sqlite_orm { } template - void operator()(const object_t&) const { + void operator()(const object_t &) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14419,7 +14475,7 @@ namespace sqlite_orm { } template - void operator()(const table_rowid_t&) const { + void operator()(const table_rowid_t &) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14427,7 +14483,7 @@ namespace sqlite_orm { } template - void operator()(const table_oid_t&) const { + void operator()(const table_oid_t &) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14435,7 +14491,7 @@ namespace sqlite_orm { } template - void operator()(const table__rowid_t&) const { + void operator()(const table__rowid_t &) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14449,6 +14505,7 @@ namespace sqlite_orm { // #include "column_names_getter.h" + #include // std::system_error #include // std::string #include // std::vector @@ -14458,6 +14515,7 @@ namespace sqlite_orm { // #include "select_constraints.h" + namespace sqlite_orm { namespace internal { @@ -14555,6 +14613,7 @@ namespace sqlite_orm { // #include "order_by_serializator.h" + #include // std::string #include // std::vector #include // std::stringstream @@ -14572,17 +14631,17 @@ namespace sqlite_orm { return serializer(t, context); } - template - struct order_by_serializator, void> { - using statement_type = order_by_t; + template + struct order_by_serializator, void> { + using statement_type = order_by_t; template std::string operator()(const statement_type& orderBy, const C& context) const { std::stringstream ss; auto newContext = context; + newContext.replace_bindable_with_question = !is_bindable_v; newContext.skip_table_name = false; - auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; + ss << serialize(orderBy.expression, newContext); if(!orderBy._collate_argument.empty()) { ss << " COLLATE " << orderBy._collate_argument; } @@ -14609,16 +14668,16 @@ namespace sqlite_orm { std::string entryString; { std::stringstream ss; - ss << entry.name << " "; + ss << entry.name; if(!entry._collate_argument.empty()) { - ss << "COLLATE " << entry._collate_argument << " "; + ss << " COLLATE " << entry._collate_argument << " "; } switch(entry.asc_desc) { case 1: - ss << "ASC"; + ss << " ASC"; break; case -1: - ss << "DESC"; + ss << " DESC"; break; } entryString = ss.str(); @@ -14651,6 +14710,7 @@ namespace sqlite_orm { // #include "index.h" + namespace sqlite_orm { namespace internal { @@ -14668,7 +14728,7 @@ namespace sqlite_orm { * Serializer for bindable types. */ template - struct statement_serializator>> { + struct statement_serializator> { using statement_type = T; template @@ -14739,23 +14799,6 @@ namespace sqlite_orm { } }; -#if __cplusplus >= 201703L // use of C++17 or higher - /** - * Constant which gets never replaced in a bindable context. - * Used together with order_by(1_nth_col). - */ - template - struct statement_serializator, void> { - using statement_type = positional_ordinal; - - template - std::string operator()(const statement_type& /*expression*/, const C& /*context*/) { - static_assert(N > 0, "Column number must be greater than 0."); - return std::to_string(N); - } - }; -#endif - template struct statement_serializator, void> { using statement_type = filtered_aggregate_function; @@ -17088,6 +17131,7 @@ namespace sqlite_orm { // #include "index.h" + namespace sqlite_orm { namespace internal { @@ -17928,9 +17972,9 @@ namespace sqlite_orm { } res = decltype(res)::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, tImpl, {}); - res = decltype(res)::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, tImpl, {}); + res = decltype(res)::old_columns_removed; #endif } @@ -18803,35 +18847,42 @@ __pragma(pop_macro("min")) #include // std::optional #endif // SQLITE_ORM_OPTIONAL_SUPPORTED - // #include "conditions.h" +// #include "conditions.h" - // #include "operators.h" +// #include "operators.h" - // #include "select_constraints.h" +// #include "select_constraints.h" - // #include "prepared_statement.h" +// #include "prepared_statement.h" - // #include "optional_container.h" +// #include "optional_container.h" - // #include "core_functions.h" +// #include "core_functions.h" - // #include "function.h" +// #include "function.h" - // #include "ast/excluded.h" +// #include "ast/excluded.h" - // #include "ast/upsert_clause.h" +// #include "ast/upsert_clause.h" - // #include "ast/where.h" +// #include "ast/where.h" - // #include "ast/into.h" +// #include "ast/into.h" + +// #include "ast/group_by.h" - // #include "ast/group_by.h" - namespace sqlite_orm { +namespace sqlite_orm { namespace internal { template + struct node_tuple; + + template + using node_tuple_t = typename node_tuple::type; + + template struct node_tuple { using type = std::tuple; }; @@ -18842,55 +18893,49 @@ __pragma(pop_macro("min")) }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using type = typename node_tuple>::type; - }; + struct node_tuple, void> : node_tuple> {}; template struct node_tuple, void> { - using args_tuple = typename node_tuple>::type; - using expression_tuple = typename node_tuple::type; + using args_tuple = node_tuple_t>; + using expression_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template - struct node_tuple, std::tuple>, void> { - using type = typename node_tuple>::type; - }; + struct node_tuple, std::tuple>, void> + : node_tuple> {}; template struct node_tuple, void> { - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = where_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; + + template + struct node_tuple, match_if_not> : node_tuple {}; + + template + struct node_tuple, match_if> : node_tuple {}; template struct node_tuple::value>::type> { using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; + using left_node_tuple = node_tuple_t; + using right_node_tuple = node_tuple_t; using type = typename conc_tuple::type; }; @@ -18899,30 +18944,27 @@ __pragma(pop_macro("min")) using node_type = binary_operator; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_node_tuple = typename node_tuple::type; - using right_node_tuple = typename node_tuple::type; + using left_node_tuple = node_tuple_t; + using right_node_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = columns_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = dynamic_in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = in_t; - using left_tuple = typename node_tuple::type; - using right_tuple = typename conc_tuple::type...>::type; + using left_tuple = node_tuple_t; + using right_tuple = typename conc_tuple...>::type; using type = typename conc_tuple::type; }; @@ -18931,266 +18973,188 @@ __pragma(pop_macro("min")) using node_type = T; using left_type = typename node_type::left_type; using right_type = typename node_type::right_type; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = select_t; - using columns_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; + using columns_tuple = node_tuple_t; + using args_tuple = typename conc_tuple...>::type; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = insert_raw_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = replace_raw_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using node_type = into_t; - using type = std::tuple<>; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = values_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = std::tuple; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = get_all_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = get_all_pointer_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template struct node_tuple, void> { - using node_type = get_all_optional_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template struct node_tuple, Wargs...>, void> { - using node_type = update_all_t, Wargs...>; - using set_tuple = typename conc_tuple::type...>::type; - using conditions_tuple = typename conc_tuple::type...>::type; + using set_tuple = typename conc_tuple...>::type; + using conditions_tuple = typename conc_tuple...>::type; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = remove_all_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using node_type = having_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = cast_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = exists_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = optional_container; - using type = typename node_tuple::type; - }; - - template<> - struct node_tuple, void> { - using node_type = optional_container; - using type = std::tuple<>; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = like_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; - using escape_tuple = typename node_tuple::type; + using arg_tuple = node_tuple_t; + using pattern_tuple = node_tuple_t; + using escape_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = glob_t; - using arg_tuple = typename node_tuple::type; - using pattern_tuple = typename node_tuple::type; + using arg_tuple = node_tuple_t; + using pattern_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = between_t; - using expression_tuple = typename node_tuple::type; - using lower_tuple = typename node_tuple::type; - using upper_tuple = typename node_tuple::type; + using expression_tuple = node_tuple_t; + using lower_tuple = node_tuple_t; + using upper_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template - struct node_tuple, void> { - using node_type = named_collate; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = is_null_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = is_not_null_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = negated_condition_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = built_in_function_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = built_in_aggregate_function_t; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template struct node_tuple, void> { - using node_type = filtered_aggregate_function; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = function_call; - using type = typename conc_tuple::type...>::type; + using type = typename conc_tuple...>::type; }; template - struct node_tuple, void> { - using node_type = left_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = on_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; // note: not strictly necessary as there's no binding support for USING; // we provide it nevertheless, in line with on_t. template - struct node_tuple, void> { - using node_type = using_t; - using type = typename node_tuple>::type; - }; + struct node_tuple, void> : node_tuple> {}; template - struct node_tuple, void> { - using node_type = join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = left_outer_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = inner_join_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = simple_case_t; - using case_tuple = typename node_tuple::type; - using args_tuple = typename conc_tuple::type...>::type; - using else_tuple = typename node_tuple::type; + using case_tuple = node_tuple_t; + using args_tuple = typename conc_tuple...>::type; + using else_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template struct node_tuple, void> { - using node_type = std::pair; - using left_tuple = typename node_tuple::type; - using right_tuple = typename node_tuple::type; + using left_tuple = node_tuple_t; + using right_tuple = node_tuple_t; using type = typename conc_tuple::type; }; template - struct node_tuple, void> { - using node_type = as_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, void> { - using node_type = limit_t; - using type = typename node_tuple::type; - }; + struct node_tuple, void> : node_tuple {}; template struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; + using type = typename conc_tuple, node_tuple_t>::type; }; template struct node_tuple, void> { - using node_type = limit_t; - using type = typename conc_tuple::type, typename node_tuple::type>::type; + using type = typename conc_tuple, node_tuple_t>::type; }; } } @@ -19206,6 +19170,7 @@ __pragma(pop_macro("min")) // #include "expression_object_type.h" + namespace sqlite_orm { template @@ -19322,7 +19287,7 @@ namespace sqlite_orm { const auto& get(const internal::prepared_statement_t& statement) { using statement_type = typename std::decay::type; using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; + using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; using result_tupe = typename std::tuple_element(N), bind_tuple>::type; const result_tupe* result = nullptr; @@ -19345,7 +19310,7 @@ namespace sqlite_orm { auto& get(internal::prepared_statement_t& statement) { using statement_type = typename std::decay::type; using expression_type = typename statement_type::expression_type; - using node_tuple = typename internal::node_tuple::type; + using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; using result_tupe = typename std::tuple_element(N), bind_tuple>::type; result_tupe* result = nullptr; @@ -19372,6 +19337,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { SQLITE_ORM_INLINE_VAR constexpr const char carray_pvt_name[] = "carray"; From 1403365f6ff3173f626c1cbcfdd7b3129414896e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 22 Mar 2022 23:32:45 +0200 Subject: [PATCH 12/20] Updated sqlite_orm.h --- include/sqlite_orm/sqlite_orm.h | 221 ++++++++------------------------ 1 file changed, 56 insertions(+), 165 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 3218f5b0c..e183872de 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -39,13 +39,11 @@ __pragma(push_macro("min")) // #include "cxx_polyfill.h" - #include -// #include "start_macros.h" - + // #include "start_macros.h" -namespace sqlite_orm { + namespace sqlite_orm { namespace internal { namespace polyfill { #if __cplusplus < 201703L // before C++17 @@ -136,7 +134,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -346,7 +343,6 @@ namespace sqlite_orm { // #include "../static_magic.h" - #include // std::false_type, std::true_type, std::integral_constant namespace sqlite_orm { @@ -386,7 +382,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { // got from here http://stackoverflow.com/questions/25958259/how-do-i-find-out-if-a-tuple-contains-a-type @@ -799,15 +794,12 @@ namespace sqlite_orm { // #include "table_type.h" - #include // std::enable_if, std::is_member_pointer, std::is_member_function_pointer // #include "member_traits/getter_traits.h" - // #include "getters.h" - namespace sqlite_orm { namespace internal { @@ -850,7 +842,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -958,10 +949,8 @@ namespace sqlite_orm { // #include "member_traits/setter_traits.h" - // #include "setters.h" - namespace sqlite_orm { namespace internal { @@ -986,7 +975,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1034,12 +1022,10 @@ namespace sqlite_orm { // #include "member_traits/is_getter.h" - #include // std::false_type, std::true_type // #include "getters.h" - namespace sqlite_orm { namespace internal { @@ -1087,12 +1073,10 @@ namespace sqlite_orm { // #include "member_traits/is_setter.h" - #include // #include "setters.h" - namespace sqlite_orm { namespace internal { @@ -1120,7 +1104,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1170,7 +1153,6 @@ namespace sqlite_orm { // #include "type_printer.h" - namespace sqlite_orm { namespace internal { @@ -1754,7 +1736,6 @@ namespace sqlite_orm { // #include "serializator_context.h" - namespace sqlite_orm { namespace internal { @@ -1812,7 +1793,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -1846,7 +1826,6 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED // #include "tags.h" - namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1860,7 +1839,6 @@ namespace sqlite_orm { // #include "serialize_result_type.h" - #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED #include // string_view #else @@ -1877,7 +1855,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -2164,12 +2141,10 @@ namespace sqlite_orm { // #include "member_traits/member_traits.h" - #include // std::enable_if // #include "is_field_member_pointer.h" - #include // std::false_type, std::true_type, std::is_member_pointer, std::is_member_function_pointer namespace sqlite_orm { @@ -2190,12 +2165,10 @@ namespace sqlite_orm { // #include "field_member_traits.h" - #include // std::enable_if // #include "is_field_member_pointer.h" - namespace sqlite_orm { namespace internal { @@ -2216,7 +2189,6 @@ namespace sqlite_orm { // #include "setter_traits.h" - namespace sqlite_orm { namespace internal { @@ -2243,7 +2215,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -2544,7 +2515,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -2700,7 +2670,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -2740,7 +2709,6 @@ namespace sqlite_orm { // #include "expression.h" // #include "operators.h" - namespace sqlite_orm { namespace internal { @@ -2815,7 +2783,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -4220,7 +4187,6 @@ namespace sqlite_orm { // #include "conditions.h" - namespace sqlite_orm { namespace internal { @@ -4332,7 +4298,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -4376,7 +4341,6 @@ namespace sqlite_orm { // #include "tuple_helper/count_tuple.h" - namespace sqlite_orm { using int64 = sqlite_int64; @@ -6452,10 +6416,8 @@ namespace sqlite_orm { // #include "ast/where.h" - // #include "../serialize_result_type.h" - namespace sqlite_orm { namespace internal { @@ -6503,7 +6465,6 @@ namespace sqlite_orm { // #include "ast/group_by.h" - #include // std::tuple, std::make_tuple #include // std::true_type, std::false_type, std::forward @@ -6584,7 +6545,6 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { @@ -7052,7 +7012,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) @@ -7085,7 +7044,7 @@ namespace sqlite_orm { partial_trigger_t(T trigger_base, S... statements) : statements(std::make_tuple(std::forward(statements)...)), base(std::move(trigger_base)) {} - partial_trigger_t &end() { + partial_trigger_t& end() { return *this; } }; @@ -7115,7 +7074,7 @@ namespace sqlite_orm { */ elements_type elements; - trigger_t(const std::string &name, T trigger_base, elements_type statements) : + trigger_t(const std::string& name, T trigger_base, elements_type statements) : name(name), base(std::move(trigger_base)), elements(std::move(statements)) {} }; @@ -7150,7 +7109,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; } @@ -7309,7 +7268,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) { return {move(name), std::move(part.base), std::move(part.statements)}; } @@ -7373,7 +7332,6 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" - #include // std::integral_constant #ifdef __cpp_lib_concepts #include @@ -7383,7 +7341,6 @@ namespace sqlite_orm { // #include "cxx_polyfill.h" - namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7613,7 +7570,6 @@ namespace sqlite_orm { #endif } - namespace sqlite_orm { /** @@ -7803,7 +7759,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { /** @@ -8137,7 +8092,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::string #include // std::unique_ptr #include // std::array @@ -8202,7 +8156,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -8637,7 +8590,6 @@ namespace sqlite_orm { // #include "indexed_column.h" - #include // std::string namespace sqlite_orm { @@ -8720,7 +8672,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -8764,7 +8715,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { namespace internal { @@ -8879,7 +8829,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" - namespace sqlite_orm { namespace internal { @@ -9257,7 +9206,6 @@ namespace sqlite_orm { // #include "function.h" - #include #include // std::string #include // std::tuple @@ -9268,7 +9216,6 @@ namespace sqlite_orm { // #include "cxx_polyfill.h" - namespace sqlite_orm { struct arg_values; @@ -9282,13 +9229,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; user_defined_function_base(decltype(name) name_, decltype(argumentsCount) argumentsCount_, @@ -9335,7 +9282,7 @@ namespace sqlite_orm { struct SFINAE {}; template - static char test(SFINAE *); + static char test(SFINAE*); template static int test(...); @@ -9353,13 +9300,13 @@ namespace sqlite_orm { struct SFINAE {}; template - static char test(SFINAE *); + static char test(SFINAE*); template static int test(...); template - static char test2(SFINAE *); + static char test2(SFINAE*); template static int test2(...); @@ -9458,7 +9405,7 @@ namespace sqlite_orm { 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"); @@ -9532,7 +9479,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -9856,7 +9802,6 @@ namespace sqlite_orm { // #include "dbstat.h" - #include // std::string namespace sqlite_orm { @@ -9876,7 +9821,6 @@ namespace sqlite_orm { #endif // SQLITE_ENABLE_DBSTAT_VTAB } - namespace sqlite_orm { namespace internal { @@ -10251,12 +10195,10 @@ namespace sqlite_orm { // #include "field_value_holder.h" - #include // std::enable_if // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -10279,7 +10221,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -10674,22 +10615,18 @@ namespace sqlite_orm { // #include "row_extractor_builder.h" - // #include "row_extractor.h" // #include "mapped_row_extractor.h" - #include // #include "object_from_column_builder.h" - #include // #include "row_extractor.h" - namespace sqlite_orm { namespace internal { @@ -10726,7 +10663,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -10759,7 +10695,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -10839,7 +10774,6 @@ namespace sqlite_orm { // #include "view.h" - #include // std::shared_ptr #include // std::string #include // std::forward, std::move @@ -10854,7 +10788,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include // std::shared_ptr, std::unique_ptr, std::make_shared #include #include // std::decay @@ -10871,7 +10804,6 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" - namespace sqlite_orm { namespace internal { @@ -10975,7 +10907,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -10991,7 +10922,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::iterator_traits #include // std::string @@ -11000,13 +10930,11 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include // std::string // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -11081,7 +11009,6 @@ namespace sqlite_orm { // #include "values.h" - #include // std::vector #include #include // std::tuple @@ -11123,7 +11050,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -11876,7 +11802,6 @@ namespace sqlite_orm { // #include "ast/excluded.h" - namespace sqlite_orm { namespace internal { @@ -11896,7 +11821,6 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" - #include // std::tuple, std::make_tuple #include // std::false_type, std::true_type, std::forward @@ -11962,7 +11886,6 @@ namespace sqlite_orm { // #include "ast/into.h" - #include // std::true_type, std::false_type namespace sqlite_orm { @@ -11990,12 +11913,10 @@ namespace sqlite_orm { // #include "ast/exists.h" - #include // std::move // #include "tags.h" - namespace sqlite_orm { namespace internal { @@ -12024,7 +11945,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -12676,8 +12596,7 @@ namespace sqlite_orm { using node_type = order_by_t; template - void operator()(const node_type& /*node*/, const L& /*l*/) const { - } + void operator()(const node_type& /*node*/, const L& /*l*/) const {} }; template @@ -12697,7 +12616,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -12767,7 +12685,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include // std::function, std::bind #include #include // std::string @@ -12782,7 +12699,6 @@ namespace sqlite_orm { // #include "pragma.h" - #include // std::string #include #include // std::function @@ -12799,7 +12715,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -12956,7 +12871,6 @@ namespace sqlite_orm { // #include "limit_accesor.h" - #include #include // std::map #include // std::function @@ -12964,7 +12878,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13098,12 +13011,10 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13127,7 +13038,7 @@ namespace sqlite_orm { connection(std::move(connection_)), commit_func(std::move(commit_func_)), rollback_func(std::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) { @@ -13144,7 +13055,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 @@ -13189,7 +13100,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::system_error #include // std::string @@ -13199,7 +13109,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13269,7 +13178,6 @@ namespace sqlite_orm { // #include "values_to_tuple.h" - #include #include // std::get, std::tuple_element @@ -13277,19 +13185,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 { @@ -13326,18 +13232,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]; @@ -13366,27 +13272,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; @@ -13419,11 +13325,10 @@ namespace sqlite_orm { private: int argsCount = 0; - sqlite3_value **values = nullptr; + sqlite3_value** values = nullptr; }; } - namespace sqlite_orm { namespace internal { @@ -13435,7 +13340,7 @@ namespace sqlite_orm { template struct values_to_tuple { - void extract(sqlite3_value **values, T &tuple, int argsCount) const { + void extract(sqlite3_value** values, T& tuple, int argsCount) const { using element_type = typename std::tuple_element::type; std::get(tuple) = row_extractor().extract(values[I]); @@ -13445,14 +13350,14 @@ namespace sqlite_orm { template struct values_to_tuple { - void extract(sqlite3_value **values, T &tuple, int argsCount) const { + void extract(sqlite3_value** values, T& tuple, int argsCount) const { //.. } }; template<> struct values_to_tuple, 0> { - void extract(sqlite3_value **values, std::tuple &tuple, int argsCount) const { + void extract(sqlite3_value** values, std::tuple& tuple, int argsCount) const { std::get<0>(tuple) = arg_values(argsCount, values); } }; @@ -13461,7 +13366,6 @@ namespace sqlite_orm { // #include "arg_values.h" - namespace sqlite_orm { namespace internal { @@ -14174,13 +14078,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 { @@ -14331,7 +14233,6 @@ namespace sqlite_orm { // #include "statement_serializator.h" - #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -14381,7 +14282,6 @@ namespace sqlite_orm { // #include "table_name_collector.h" - #include // std::set #include // std::string #include // std::function @@ -14397,7 +14297,6 @@ namespace sqlite_orm { // #include "core_functions.h" - namespace sqlite_orm { namespace internal { @@ -14414,7 +14313,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 {}; } @@ -14426,19 +14325,19 @@ namespace sqlite_orm { } template - void operator()(const column_pointer &) const { + void operator()(const column_pointer&) const { if(this->find_table_name) { table_names.insert({this->find_table_name(typeid(T)), ""}); } } template - void operator()(const alias_column_t &a) const { + 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 { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); if(!tableName.empty()) { @@ -14448,7 +14347,7 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t &) const { + void operator()(const asterisk_t&) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14456,7 +14355,7 @@ namespace sqlite_orm { } template = true> - void operator()(const asterisk_t &) const { + void operator()(const asterisk_t&) const { if(this->find_table_name) { // note: not all alias classes have a nested A::type static_assert(polyfill::is_detected_v, @@ -14467,7 +14366,7 @@ namespace sqlite_orm { } template - void operator()(const object_t &) const { + void operator()(const object_t&) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14475,7 +14374,7 @@ namespace sqlite_orm { } template - void operator()(const table_rowid_t &) const { + void operator()(const table_rowid_t&) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14483,7 +14382,7 @@ namespace sqlite_orm { } template - void operator()(const table_oid_t &) const { + void operator()(const table_oid_t&) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14491,7 +14390,7 @@ namespace sqlite_orm { } template - void operator()(const table__rowid_t &) const { + void operator()(const table__rowid_t&) const { if(this->find_table_name) { auto tableName = this->find_table_name(typeid(T)); table_names.insert(std::make_pair(move(tableName), "")); @@ -14505,7 +14404,6 @@ namespace sqlite_orm { // #include "column_names_getter.h" - #include // std::system_error #include // std::string #include // std::vector @@ -14515,7 +14413,6 @@ namespace sqlite_orm { // #include "select_constraints.h" - namespace sqlite_orm { namespace internal { @@ -14613,7 +14510,6 @@ namespace sqlite_orm { // #include "order_by_serializator.h" - #include // std::string #include // std::vector #include // std::stringstream @@ -14710,7 +14606,6 @@ namespace sqlite_orm { // #include "index.h" - namespace sqlite_orm { namespace internal { @@ -17131,7 +17026,6 @@ namespace sqlite_orm { // #include "index.h" - namespace sqlite_orm { namespace internal { @@ -17972,9 +17866,9 @@ namespace sqlite_orm { } res = decltype(res)::old_columns_removed; #else - // extra table columns than storage columns - this->backup_table(db, tImpl, {}); - res = decltype(res)::old_columns_removed; + // extra table columns than storage columns + this->backup_table(db, tImpl, {}); + res = decltype(res)::old_columns_removed; #endif } @@ -18847,32 +18741,31 @@ __pragma(pop_macro("min")) #include // std::optional #endif // SQLITE_ORM_OPTIONAL_SUPPORTED -// #include "conditions.h" + // #include "conditions.h" -// #include "operators.h" + // #include "operators.h" -// #include "select_constraints.h" + // #include "select_constraints.h" -// #include "prepared_statement.h" + // #include "prepared_statement.h" -// #include "optional_container.h" + // #include "optional_container.h" -// #include "core_functions.h" + // #include "core_functions.h" -// #include "function.h" + // #include "function.h" -// #include "ast/excluded.h" + // #include "ast/excluded.h" -// #include "ast/upsert_clause.h" + // #include "ast/upsert_clause.h" -// #include "ast/where.h" + // #include "ast/where.h" -// #include "ast/into.h" + // #include "ast/into.h" -// #include "ast/group_by.h" + // #include "ast/group_by.h" - -namespace sqlite_orm { + namespace sqlite_orm { namespace internal { @@ -19170,7 +19063,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template @@ -19337,7 +19229,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { SQLITE_ORM_INLINE_VAR constexpr const char carray_pvt_name[] = "carray"; From b8a3ccd73ca6c41cd607d4097b44b77670cf2228 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 23 Mar 2022 09:13:59 +0200 Subject: [PATCH 13/20] Corrected formatting --- dev/ast_iterator.h | 3 +- dev/get_prepared_statement.h | 4 +- tests/CMakeLists.txt | 1 - .../conditions.cpp | 2 +- tests/static_tests/node_tuple.cpp | 41 +++++++++---------- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index afec7eebd..6e7e886b6 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -669,8 +669,7 @@ namespace sqlite_orm { using node_type = order_by_t; template - void operator()(const node_type& /*node*/, const L& /*l*/) const { - } + void operator()(const node_type& /*node*/, const L& /*l*/) const {} }; template diff --git a/dev/get_prepared_statement.h b/dev/get_prepared_statement.h index 7dff509c9..ce6547637 100644 --- a/dev/get_prepared_statement.h +++ b/dev/get_prepared_statement.h @@ -125,7 +125,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element(N), bind_tuple>::type; + using result_tupe = std::tuple_element_t(N), bind_tuple>; const result_tupe* result = nullptr; auto index = -1; internal::iterate_ast(statement.expression, [&result, &index](auto& node) { @@ -148,7 +148,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element(N), bind_tuple>::type; + using result_tupe = std::tuple_element_t(N), bind_tuple>; result_tupe* result = nullptr; auto index = -1; internal::iterate_ast(statement.expression, [&result, &index](auto& node) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 022027c84..6e429997e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -70,7 +70,6 @@ add_executable(unit_tests constraints/unique.cpp constraints/foreign_key.cpp constraints/check.cpp - conditions.cpp table_tests.cpp statement_serializator_tests/column_constraints/generated.cpp statement_serializator_tests/column_constraints/default.cpp diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp index 0bbe1da52..9ef4b1af7 100644 --- a/tests/statement_serializator_tests/conditions.cpp +++ b/tests/statement_serializator_tests/conditions.cpp @@ -14,7 +14,7 @@ TEST_CASE("statement_serializator conditions") { SECTION("expression") { context.replace_bindable_with_question = true; value = serialize(order_by(c(1) == 0), context); - expected = "ORDER BY (? == ?)"; + expected = "ORDER BY (? = ?)"; } SECTION("literal") { context.replace_bindable_with_question = true; diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 52026586e..5afddf08c 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -353,11 +353,11 @@ TEST_CASE("Node tuple") { using Union = decltype(un); using Tuple = node_tuple_t; using Expected = tuple; + decltype(&User::name), + const char*, + decltype(&User::id), + std::string, + decltype(&User::name)>; static_assert(is_same::value, "union_all"); } SECTION("except") { @@ -366,21 +366,20 @@ TEST_CASE("Node tuple") { using Union = decltype(un); using Tuple = node_tuple_t; using Expected = tuple; + decltype(&User::name), + decltype(&User::id), + long, + decltype(&User::id), + decltype(&User::name), + decltype(&User::id), + long>; static_assert(is_same::value, "except"); } SECTION("intersect") { auto un = intersect(select(&User::name), select(&User::name, where(is_equal(&User::name, "Anny")))); using Union = decltype(un); using Tuple = node_tuple_t; - using Expected = - tuple; + using Expected = tuple; static_assert(is_same::value, "intersect"); } } @@ -489,9 +488,8 @@ TEST_CASE("Node tuple") { auto getAll = get_all(where(is_equal(&User::id, 1) or is_equal(std::string("Alex"), &User::name))); using GetAll = decltype(getAll); using Tuple = node_tuple_t; - static_assert( - is_same>::value, - "get_all(where(is_equal(5.0, &User::id)))"); + static_assert(is_same>::value, + "get_all(where(is_equal(5.0, &User::id)))"); } } SECTION("having_t") { @@ -535,7 +533,7 @@ TEST_CASE("Node tuple") { static_assert(is_same>::value, "escape_tuple"); using Tuple = NodeTuple::type; static_assert(std::tuple_size::value == 2, "like(&User::name, \"S%\") size"); - using Tuple0 = std::tuple_element<0, Tuple>::type; + using Tuple0 = std::tuple_element_t<0, Tuple>; static_assert(is_same::value, "like(&User::name, \"S%\") type 0"); static_assert(is_same>::value, "like(&User::name, \"S%\")"); @@ -569,8 +567,7 @@ TEST_CASE("Node tuple") { auto gl = glob(&User::name, "H*"); using Glob = decltype(gl); using Tuple = node_tuple_t; - static_assert(is_same>::value, - "glob(&User::name, \"H*\")"); + static_assert(is_same>::value, "glob(&User::name, \"H*\")"); } SECTION("between_t") { auto bet = between(&User::id, 10, 20); @@ -684,7 +681,7 @@ TEST_CASE("Node tuple") { auto f = upper("hi"); using Fun = decltype(f); using Tuple = node_tuple_t; - using ArgType = std::tuple_element<0, Fun::args_type>::type; + using ArgType = std::tuple_element_t<0, Fun::args_type>; static_assert(is_same::value, "upper arg[0]"); using Expected = tuple; static_assert(is_same::value, "upper"); @@ -866,7 +863,7 @@ TEST_CASE("Node tuple") { STATIC_REQUIRE(is_tuple::value); STATIC_REQUIRE(std::tuple_size::value == 1); - using Arg0 = std::tuple_element<0, ArgsType>::type; + using Arg0 = std::tuple_element_t<0, ArgsType>; STATIC_REQUIRE(is_pair::value); using Arg0First = Arg0::first_type; STATIC_REQUIRE(is_same::value); From 9e5e7fb85072b8cd80a5f6b84532573d89f94f8e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 23 Mar 2022 09:15:00 +0200 Subject: [PATCH 14/20] Updated sqlite_orm.h --- include/sqlite_orm/sqlite_orm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index f44c17fc1..08066fe0e 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -19181,7 +19181,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element(N), bind_tuple>::type; + using result_tupe = std::tuple_element_t(N), bind_tuple>; const result_tupe* result = nullptr; auto index = -1; internal::iterate_ast(statement.expression, [&result, &index](auto& node) { @@ -19204,7 +19204,7 @@ namespace sqlite_orm { using expression_type = typename statement_type::expression_type; using node_tuple = internal::node_tuple_t; using bind_tuple = typename internal::bindable_filter::type; - using result_tupe = typename std::tuple_element(N), bind_tuple>::type; + using result_tupe = std::tuple_element_t(N), bind_tuple>; result_tupe* result = nullptr; auto index = -1; internal::iterate_ast(statement.expression, [&result, &index](auto& node) { From abe53b451139163e4da2679e9b98e2d6d1410df8 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 24 Mar 2022 17:37:59 +0200 Subject: [PATCH 15/20] Ability to order and group by column alias --- dev/alias.h | 48 ++++++++++- dev/ast_iterator.h | 23 +++--- dev/node_tuple.h | 9 ++- dev/order_by_serializator.h | 1 - include/sqlite_orm/sqlite_orm.h | 81 +++++++++++++++---- tests/ast_iterator_tests.cpp | 19 ++++- .../conditions.cpp | 20 ++++- tests/static_tests/node_tuple.cpp | 13 ++- 8 files changed, 174 insertions(+), 40 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index b2073dbab..a6cee2be4 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -7,7 +7,7 @@ namespace sqlite_orm { /** - * This is base class for every class which is used as a custom table alias. + * 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 {}; @@ -16,7 +16,7 @@ namespace sqlite_orm { /** * This is a common built-in class used for custom single character table aliases. - * Also you can use language aliases `alias_a`, `alias_b` etc. instead + * For convenience there exist type aliases `alias_a`, `alias_b`, ... */ template struct table_alias : alias_tag { @@ -37,7 +37,7 @@ namespace sqlite_orm { column_type column; - alias_column_t(){}; + alias_column_t() {} alias_column_t(column_type column_) : column(std::move(column_)) {} }; @@ -72,6 +72,29 @@ namespace sqlite_orm { expression_type expression; }; + /** + * This is a common built-in class used for numeric column identifiers, + * as described in the documentation of the ORDER BY Clause https://sqlite.org/lang_select.html#the_order_by_clause. + * For convenience there exist type aliases `colalias_1`, `colalias_2`, ... + */ + template + struct numeric_column_alias : alias_tag { + static std::string get() { + return std::to_string(K); + } + }; + + /** + * 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 + struct column_alias : alias_tag { + static std::string get() { + return std::string(1u, A); + } + }; + template struct alias_holder { using type = T; @@ -151,4 +174,23 @@ namespace sqlite_orm { using alias_y = internal::table_alias; template using alias_z = internal::table_alias; + + using colalias_1 = internal::numeric_column_alias<1u>; + using colalias_2 = internal::numeric_column_alias<2u>; + using colalias_3 = internal::numeric_column_alias<3u>; + using colalias_4 = internal::numeric_column_alias<4u>; + using colalias_5 = internal::numeric_column_alias<5u>; + using colalias_6 = internal::numeric_column_alias<6u>; + using colalias_7 = internal::numeric_column_alias<7u>; + using colalias_8 = internal::numeric_column_alias<8u>; + using colalias_9 = internal::numeric_column_alias<9u>; + using colalias_a = internal::column_alias<'a'>; + using colalias_b = internal::column_alias<'b'>; + using colalias_c = internal::column_alias<'c'>; + using colalias_d = internal::column_alias<'d'>; + using colalias_e = internal::column_alias<'e'>; + using colalias_f = internal::column_alias<'f'>; + using colalias_g = internal::column_alias<'g'>; + using colalias_h = internal::column_alias<'h'>; + using colalias_i = internal::column_alias<'i'>; } diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 6e7e886b6..62759f1a4 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -654,22 +654,25 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, match_if_not> { - using node_type = order_by_t; + /** + * Column alias + */ + template + struct ast_iterator, void> { + using node_type = alias_holder; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.expression, l); - } + void operator()(const node_type& /*node*/, const L& /*l*/) const {} }; - template - struct ast_iterator, match_if> { - using node_type = order_by_t; + template + struct ast_iterator, void> { + using node_type = order_by_t; template - void operator()(const node_type& /*node*/, const L& /*l*/) const {} + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.expression, l); + } }; template diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 55c5d0b2a..8e94c74f7 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -71,11 +71,14 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; - template - struct node_tuple, match_if_not> : node_tuple {}; + /** + * Column alias + */ + template + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, match_if> : node_tuple {}; + struct node_tuple, void> : node_tuple {}; template struct node_tuple::value>::type> { diff --git a/dev/order_by_serializator.h b/dev/order_by_serializator.h index aa5af6b38..93eee47fb 100644 --- a/dev/order_by_serializator.h +++ b/dev/order_by_serializator.h @@ -25,7 +25,6 @@ namespace sqlite_orm { std::string operator()(const statement_type& orderBy, const C& context) const { std::stringstream ss; auto newContext = context; - newContext.replace_bindable_with_question = !is_bindable_v; newContext.skip_table_name = false; ss << serialize(orderBy.expression, newContext); if(!orderBy._collate_argument.empty()) { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 08066fe0e..bf5313c8e 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -4038,7 +4038,7 @@ namespace sqlite_orm { namespace sqlite_orm { /** - * This is base class for every class which is used as a custom table alias. + * 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 {}; @@ -4047,7 +4047,7 @@ namespace sqlite_orm { /** * This is a common built-in class used for custom single character table aliases. - * Also you can use language aliases `alias_a`, `alias_b` etc. instead + * For convenience there exist type aliases `alias_a`, `alias_b`, ... */ template struct table_alias : alias_tag { @@ -4068,7 +4068,7 @@ namespace sqlite_orm { column_type column; - alias_column_t(){}; + alias_column_t() {} alias_column_t(column_type column_) : column(std::move(column_)) {} }; @@ -4103,6 +4103,29 @@ namespace sqlite_orm { expression_type expression; }; + /** + * This is a common built-in class used for numeric column identifiers, + * as described in the documentation of the ORDER BY Clause https://sqlite.org/lang_select.html#the_order_by_clause. + * For convenience there exist type aliases `colalias_1`, `colalias_2`, ... + */ + template + struct numeric_column_alias : alias_tag { + static std::string get() { + return std::to_string(K); + } + }; + + /** + * 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 + struct column_alias : alias_tag { + static std::string get() { + return std::string(1u, A); + } + }; + template struct alias_holder { using type = T; @@ -4182,6 +4205,25 @@ namespace sqlite_orm { using alias_y = internal::table_alias; template using alias_z = internal::table_alias; + + using colalias_1 = internal::numeric_column_alias<1u>; + using colalias_2 = internal::numeric_column_alias<2u>; + using colalias_3 = internal::numeric_column_alias<3u>; + using colalias_4 = internal::numeric_column_alias<4u>; + using colalias_5 = internal::numeric_column_alias<5u>; + using colalias_6 = internal::numeric_column_alias<6u>; + using colalias_7 = internal::numeric_column_alias<7u>; + using colalias_8 = internal::numeric_column_alias<8u>; + using colalias_9 = internal::numeric_column_alias<9u>; + using colalias_a = internal::column_alias<'a'>; + using colalias_b = internal::column_alias<'b'>; + using colalias_c = internal::column_alias<'c'>; + using colalias_d = internal::column_alias<'d'>; + using colalias_e = internal::column_alias<'e'>; + using colalias_f = internal::column_alias<'f'>; + using colalias_g = internal::column_alias<'g'>; + using colalias_h = internal::column_alias<'h'>; + using colalias_i = internal::column_alias<'i'>; } #pragma once @@ -12581,22 +12623,25 @@ namespace sqlite_orm { } }; - template - struct ast_iterator, match_if_not> { - using node_type = order_by_t; + /** + * Column alias + */ + template + struct ast_iterator, void> { + using node_type = alias_holder; template - void operator()(const node_type& node, const L& l) const { - iterate_ast(node.expression, l); - } + void operator()(const node_type& /*node*/, const L& /*l*/) const {} }; - template - struct ast_iterator, match_if> { - using node_type = order_by_t; + template + struct ast_iterator, void> { + using node_type = order_by_t; template - void operator()(const node_type& /*node*/, const L& /*l*/) const {} + void operator()(const node_type& node, const L& l) const { + iterate_ast(node.expression, l); + } }; template @@ -14535,7 +14580,6 @@ namespace sqlite_orm { std::string operator()(const statement_type& orderBy, const C& context) const { std::stringstream ss; auto newContext = context; - newContext.replace_bindable_with_question = !is_bindable_v; newContext.skip_table_name = false; ss << serialize(orderBy.expression, newContext); if(!orderBy._collate_argument.empty()) { @@ -18816,11 +18860,14 @@ __pragma(pop_macro("min")) template struct node_tuple, void> : node_tuple {}; - template - struct node_tuple, match_if_not> : node_tuple {}; + /** + * Column alias + */ + template + struct node_tuple, void> : node_tuple {}; template - struct node_tuple, match_if> : node_tuple {}; + struct node_tuple, void> : node_tuple {}; template struct node_tuple::value>::type> { diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 35970d6c5..3fbbe5951 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -162,8 +162,23 @@ TEST_CASE("ast_iterator") { expected.push_back(typeid(int)); internal::iterate_ast(node, lambda); } - SECTION("literal") { - auto node = order_by(1); + SECTION("bindable") { + int n = 42; + auto node = order_by(n); + expected.push_back(typeid(int)); + internal::iterate_ast(node, lambda); + } + SECTION("numeric column alias") { + auto node = order_by(get()); + internal::iterate_ast(node, lambda); + } + SECTION("sole column alias") { + auto node = order_by(get()); + internal::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); } } diff --git a/tests/statement_serializator_tests/conditions.cpp b/tests/statement_serializator_tests/conditions.cpp index 9ef4b1af7..07f249791 100644 --- a/tests/statement_serializator_tests/conditions.cpp +++ b/tests/statement_serializator_tests/conditions.cpp @@ -16,11 +16,27 @@ TEST_CASE("statement_serializator conditions") { value = serialize(order_by(c(1) == 0), context); expected = "ORDER BY (? = ?)"; } - SECTION("literal") { + SECTION("bindable") { context.replace_bindable_with_question = true; - value = serialize(order_by(1), context); + int n = 42; + value = serialize(order_by(n), context); + expected = "ORDER BY ?"; + } + SECTION("numeric column alias") { + context.replace_bindable_with_question = true; + value = serialize(order_by(get()), context); expected = "ORDER BY 1"; } + SECTION("sole column alias") { + context.replace_bindable_with_question = true; + value = serialize(order_by(get()), context); + expected = "ORDER BY a"; + } + SECTION("column alias in expression") { + context.replace_bindable_with_question = true; + value = serialize(order_by(get() > c(1)), context); + expected = "ORDER BY (a > ?)"; + } } REQUIRE(value == expected); } diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 5afddf08c..246144ce7 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -559,8 +559,17 @@ TEST_CASE("Node tuple") { STATIC_REQUIRE(is_same, tuple>::value); } - SECTION("literal") { - STATIC_REQUIRE(is_same, tuple<>>::value); + SECTION("bindable") { + STATIC_REQUIRE(is_same, tuple>::value); + } + SECTION("numeric column alias") { + STATIC_REQUIRE(is_same()))>, tuple<>>::value); + } + SECTION("sole column alias") { + STATIC_REQUIRE(is_same()))>, tuple<>>::value); + } + SECTION("column alias in expression") { + STATIC_REQUIRE(is_same() > c(1)))>, tuple>::value); } } SECTION("glob_t") { From 13cae940ffdf4578b4d198a5ed0ff6a4c6e25f99 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 24 Mar 2022 18:33:18 +0200 Subject: [PATCH 16/20] Examples for ordering by numeric and custom column alias --- examples/column_aliases.cpp | 76 +++++++++++++++++++++++++++++++++++++ examples/core_functions.cpp | 4 +- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 examples/column_aliases.cpp diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp new file mode 100644 index 000000000..8d1f88112 --- /dev/null +++ b/examples/column_aliases.cpp @@ -0,0 +1,76 @@ +#include +#include +#include + +using std::cout; +using std::endl; +using std::system_error; +using namespace sqlite_orm; + +void marvel_hero_ordered_by_o_pos() { + struct MarvelHero { + int id = 0; + std::string name; + std::string abilities; + short points = 0; + }; + + auto storage = make_storage("", + make_table("marvel", + make_column("id", &MarvelHero::id, primary_key()), + make_column("name", &MarvelHero::name), + make_column("abilities", &MarvelHero::abilities), + make_column("points", &MarvelHero::points))); + storage.sync_schema(); + + // insert values + storage.transaction([&storage] { + storage.insert(MarvelHero{-1, "Tony Stark", "Iron man, playboy, billionaire, philanthropist", 5}); + storage.insert(MarvelHero{-1, "Thor", "Storm god", -10}); + storage.insert(MarvelHero{-1, "Vision", "Min Stone", 4}); + storage.insert(MarvelHero{-1, "Captain America", "Vibranium shield", -3}); + storage.insert(MarvelHero{-1, "Hulk", "Strength", -15}); + storage.insert(MarvelHero{-1, "Star Lord", "Humor", 19}); + storage.insert(MarvelHero{-1, "Peter Parker", "Spiderman", 16}); + storage.insert(MarvelHero{-1, "Clint Barton", "Hawkeye", -11}); + storage.insert(MarvelHero{-1, "Natasha Romanoff", "Black widow", 8}); + storage.insert(MarvelHero{-1, "Groot", "I am Groot!", 2}); + + return true; + }); + + { + // 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(greater_than(get(), 0)), + order_by(get())); + for(auto& row: rows) { + cout << get<0>(row) << '\t' << get<1>(row) << '\n'; + } + } + cout << endl; + { + // SELECT name, instr(abilities, 'o') + // FROM marvel + // ORDER BY 2 + auto rows = storage.select(columns(&MarvelHero::name, as(instr(&MarvelHero::abilities, "o"))), + order_by(get())); + for(auto& row: rows) { + cout << get<0>(row) << '\t' << get<1>(row) << '\n'; + } + } + cout << endl; +} + +int main() { + try { + marvel_hero_ordered_by_o_pos(); + } catch(const system_error& e) { + cout << "[" << e.code() << "] " << e.what(); + } + + return 0; +} diff --git a/examples/core_functions.cpp b/examples/core_functions.cpp index 9239a8c82..864d92dbf 100644 --- a/examples/core_functions.cpp +++ b/examples/core_functions.cpp @@ -1109,8 +1109,10 @@ int main(int, char** argv) { // SELECT name, instr(abilities, 'o') o_pos // FROM marvel // WHERE o_pos > 0 + // ORDER BY o_pos auto rows = storage.select(columns(&MarvelHero::name, as(instr(&MarvelHero::abilities, "o"))), - where(greater_than(get(), 0))); + where(greater_than(get(), 0)), + order_by(get())); for(auto& row: rows) { cout << get<0>(row) << '\t' << get<1>(row) << endl; } From 43a642d8bfe880859674ab5f495929365533af04 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Thu, 24 Mar 2022 18:42:52 +0200 Subject: [PATCH 17/20] Updated comment of `order_by` --- dev/conditions.h | 8 +++----- include/sqlite_orm/sqlite_orm.h | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/dev/conditions.h b/dev/conditions.h index 30ece62b0..2308cbc63 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1173,14 +1173,12 @@ namespace sqlite_orm { } /** - * ORDER BY column or literal value (including a column number) - * - * Note that a bindable will be serialized as a literal value. - * Only integral numbers make sense and SQLite will understand them as a positional column ordinal. + * ORDER BY column or expression * * Examples: * storage.select(&User::name, order_by(&User::id)) - * storage.select(&User::name, order_by(1)) + * storage.select(&User::name, order_by(get())) + * storage.select(as(&User::name), order_by(get())) */ template internal::order_by_t order_by(O o) { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 0c4bbda60..2f5c34b03 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3942,14 +3942,12 @@ namespace sqlite_orm { } /** - * ORDER BY column or literal value (including a column number) - * - * Note that a bindable will be serialized as a literal value. - * Only integral numbers make sense and SQLite will understand them as a positional column ordinal. + * ORDER BY column or expression * * Examples: * storage.select(&User::name, order_by(&User::id)) - * storage.select(&User::name, order_by(1)) + * storage.select(&User::name, order_by(get())) + * storage.select(as(&User::name), order_by(get())) */ template internal::order_by_t order_by(O o) { From a7414bd849725789d8b844540089895c9354218b Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 30 Mar 2022 21:08:32 +0300 Subject: [PATCH 18/20] Overloaded `order_by()` for integral numeric types `order_by(1)` --- dev/ast_iterator.h | 11 +- dev/conditions.h | 18 +- dev/literal.h | 19 ++ dev/node_tuple.h | 6 + dev/order_by_serializer.h | 10 +- dev/statement_serializer.h | 19 ++ dev/type_printer.h | 2 +- examples/column_aliases.cpp | 11 + include/sqlite_orm/sqlite_orm.h | 80 ++++++- tests/ast_iterator_tests.cpp | 14 +- .../statement_serializer_tests/bindables.cpp | 215 ++++++++++-------- .../statement_serializer_tests/conditions.cpp | 28 ++- tests/static_tests/is_bindable.cpp | 1 + tests/static_tests/node_tuple.cpp | 18 +- 14 files changed, 329 insertions(+), 123 deletions(-) create mode 100644 dev/literal.h diff --git a/dev/ast_iterator.h b/dev/ast_iterator.h index 62759f1a4..d260655f4 100644 --- a/dev/ast_iterator.h +++ b/dev/ast_iterator.h @@ -655,11 +655,14 @@ namespace sqlite_orm { }; /** - * Column alias + * Column alias or literal */ - template - struct ast_iterator, void> { - using node_type = alias_holder; + template + struct ast_iterator< + T, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using node_type = T; template void operator()(const node_type& /*node*/, const L& /*l*/) const {} diff --git a/dev/conditions.h b/dev/conditions.h index c484ba67c..495dfd77c 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -6,6 +6,7 @@ #include // std::tuple, std::tuple_size #include // std::stringstream +#include "cxx_polyfill.h" #include "type_traits.h" #include "collate_argument.h" #include "constraints.h" @@ -13,6 +14,8 @@ #include "serializer_context.h" #include "tags.h" #include "expression.h" +#include "type_printer.h" +#include "literal.h" namespace sqlite_orm { @@ -1173,18 +1176,29 @@ namespace sqlite_orm { } /** - * ORDER BY column or expression + * ORDER BY column, column alias or expression * * Examples: * storage.select(&User::name, order_by(&User::id)) * storage.select(&User::name, order_by(get())) * storage.select(as(&User::name), order_by(get())) */ - template + template> = true> internal::order_by_t order_by(O o) { return {std::move(o)}; } + /** + * ORDER BY positional ordinal + * + * Examples: + * storage.select(&User::name, order_by(1)) + */ + template> = true> + internal::order_by_t> order_by(O o) { + return {{std::move(o)}}; + } + /** * ORDER BY column1, column2 * Example: storage.get_all(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc()) diff --git a/dev/literal.h b/dev/literal.h new file mode 100644 index 000000000..52683eb9b --- /dev/null +++ b/dev/literal.h @@ -0,0 +1,19 @@ +#pragma once + +#include // std::move + +namespace sqlite_orm { + namespace internal { + + /* + * Protect an otherwise bindable element so that it is always serialized as a literal value. + */ + template + struct literal_holder { + using type = T; + + T value; + }; + + } +} diff --git a/dev/node_tuple.h b/dev/node_tuple.h index 8e94c74f7..3cfff1c1f 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -77,6 +77,12 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; + /** + * Literal + */ + template + struct node_tuple, void> : node_tuple {}; + template struct node_tuple, void> : node_tuple {}; diff --git a/dev/order_by_serializer.h b/dev/order_by_serializer.h index 9314faefd..05f9748e0 100644 --- a/dev/order_by_serializer.h +++ b/dev/order_by_serializer.h @@ -27,7 +27,7 @@ namespace sqlite_orm { auto newContext = context; newContext.skip_table_name = false; auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; + ss << columnName; if(!orderBy._collate_argument.empty()) { ss << " COLLATE " << orderBy._collate_argument; } @@ -54,16 +54,16 @@ namespace sqlite_orm { std::string entryString; { std::stringstream ss; - ss << entry.name << " "; + ss << entry.name; if(!entry._collate_argument.empty()) { - ss << "COLLATE " << entry._collate_argument << " "; + ss << " COLLATE " << entry._collate_argument; } switch(entry.asc_desc) { case 1: - ss << "ASC"; + ss << " ASC"; break; case -1: - ss << "DESC"; + ss << " DESC"; break; } entryString = ss.str(); diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 0ebd37647..e2c6f71e9 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -29,6 +29,7 @@ #include "pointer_value.h" #include "type_printer.h" #include "field_printer.h" +#include "literal.h" #include "table_name_collector.h" #include "column_names_getter.h" #include "order_by_serializer.h" @@ -126,6 +127,24 @@ namespace sqlite_orm { } }; + /** + * Serializer for literal values. + */ + template + struct statement_serializer> { + using statement_type = T; + + template + std::string operator()(const T& literal, const Ctx& context) const { + static_assert(is_bindable_v>, "A literal value must be also bindable"); + + Ctx literalCtx = context; + literalCtx.replace_bindable_with_question = false; + statement_serializer> serializer{}; + return serializer(literal.value, literalCtx); + } + }; + template struct statement_serializer, void> { using statement_type = filtered_aggregate_function; diff --git a/dev/type_printer.h b/dev/type_printer.h index 2ae90f87b..2c3c93d2c 100644 --- a/dev/type_printer.h +++ b/dev/type_printer.h @@ -13,7 +13,7 @@ namespace sqlite_orm { * This class accepts c++ type and transfers it to sqlite name (int -> INTEGER, std::string -> TEXT) */ template - struct type_printer; + struct type_printer {}; struct integer_printer { inline const std::string& print() { diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index 8d1f88112..186381a32 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -63,6 +63,17 @@ void marvel_hero_ordered_by_o_pos() { } } cout << endl; + { + // 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)); + for(auto& row: rows) { + cout << get<0>(row) << '\t' << get<1>(row) << '\n'; + } + } + cout << endl; } int main() { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 6387c5698..cee8d1854 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -702,7 +702,7 @@ namespace sqlite_orm { * This class accepts c++ type and transfers it to sqlite name (int -> INTEGER, std::string -> TEXT) */ template - struct type_printer; + struct type_printer {}; struct integer_printer { inline const std::string& print() { @@ -2592,6 +2592,8 @@ namespace sqlite_orm { #include // std::tuple, std::tuple_size #include // std::stringstream +// #include "cxx_polyfill.h" + // #include "type_traits.h" // #include "collate_argument.h" @@ -2750,6 +2752,28 @@ namespace sqlite_orm { } } +// #include "type_printer.h" + +// #include "literal.h" + +#include // std::move + +namespace sqlite_orm { + namespace internal { + + /* + * Protect an otherwise bindable element so that it is always serialized as a literal value. + */ + template + struct literal_holder { + using type = T; + + T value; + }; + + } +} + namespace sqlite_orm { namespace internal { @@ -3909,18 +3933,29 @@ namespace sqlite_orm { } /** - * ORDER BY column or expression + * ORDER BY column, column alias or expression * * Examples: * storage.select(&User::name, order_by(&User::id)) * storage.select(&User::name, order_by(get())) * storage.select(as(&User::name), order_by(get())) */ - template + template> = true> internal::order_by_t order_by(O o) { return {std::move(o)}; } + /** + * ORDER BY positional ordinal + * + * Examples: + * storage.select(&User::name, order_by(1)) + */ + template> = true> + internal::order_by_t> order_by(O o) { + return {{std::move(o)}}; + } + /** * ORDER BY column1, column2 * Example: storage.get_all(multi_order_by(order_by(&Singer::name).asc(), order_by(&Singer::gender).desc()) @@ -12509,11 +12544,14 @@ namespace sqlite_orm { }; /** - * Column alias + * Column alias or literal */ - template - struct ast_iterator, void> { - using node_type = alias_holder; + template + struct ast_iterator< + T, + std::enable_if_t, + polyfill::is_specialization_of>>> { + using node_type = T; template void operator()(const node_type& /*node*/, const L& /*l*/) const {} @@ -14226,6 +14264,8 @@ namespace sqlite_orm { // #include "field_printer.h" +// #include "literal.h" + // #include "table_name_collector.h" #include // std::set @@ -14483,7 +14523,7 @@ namespace sqlite_orm { auto newContext = context; newContext.skip_table_name = false; auto columnName = serialize(orderBy.expression, newContext); - ss << columnName << " "; + ss << columnName; if(!orderBy._collate_argument.empty()) { ss << " COLLATE " << orderBy._collate_argument; } @@ -14640,6 +14680,24 @@ namespace sqlite_orm { } }; + /** + * Serializer for literal values. + */ + template + struct statement_serializer> { + using statement_type = T; + + template + std::string operator()(const T& literal, const Ctx& context) const { + static_assert(is_bindable_v>, "A literal value must be also bindable"); + + Ctx literalCtx = context; + literalCtx.replace_bindable_with_question = false; + statement_serializer> serializer{}; + return serializer(literal.value, literalCtx); + } + }; + template struct statement_serializer, void> { using statement_type = filtered_aggregate_function; @@ -18698,6 +18756,12 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; + /** + * Literal + */ + template + struct node_tuple, void> : node_tuple {}; + template struct node_tuple, void> : node_tuple {}; diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 3fbbe5951..38aed7e5f 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -13,6 +13,11 @@ TEST_CASE("ast_iterator") { auto lambda = [&typeIndexes](auto &value) { typeIndexes.push_back(typeid(value)); }; + SECTION("bindables") { + auto node = select(1); + expected.push_back(typeid(int)); + internal::iterate_ast(node, lambda); + } SECTION("aggregate functions") { SECTION("avg") { auto node = avg(&User::id); @@ -163,9 +168,12 @@ TEST_CASE("ast_iterator") { internal::iterate_ast(node, lambda); } SECTION("bindable") { - int n = 42; - auto node = order_by(n); - expected.push_back(typeid(int)); + auto node = order_by(""); + expected.push_back(typeid(const char *)); + internal::iterate_ast(node, lambda); + } + SECTION("positional ordinal") { + auto node = order_by(1); internal::iterate_ast(node, lambda); } SECTION("numeric column alias") { diff --git a/tests/statement_serializer_tests/bindables.cpp b/tests/statement_serializer_tests/bindables.cpp index 0ac25bcf6..2706455eb 100644 --- a/tests/statement_serializer_tests/bindables.cpp +++ b/tests/statement_serializer_tests/bindables.cpp @@ -1,26 +1,80 @@ #include #include #include +#include // std::fill_n #include #include using std::array; +using std::index_sequence; +using std::index_sequence_for; +using std::make_index_sequence; using std::nullptr_t; using std::shared_ptr; using std::string; using std::tuple; +using std::tuple_element_t; +using std::tuple_size; using std::unique_ptr; using std::vector; +using std::wstring; using namespace sqlite_orm; -inline void require_string(const std::string& value, const std::string& expected) { +template +constexpr T get_default() { + return T{}; +} + +template<> +constexpr auto get_default() -> const char* { + return ""; +} + +template<> +constexpr auto get_default() -> const wchar_t* { + return L""; +} + +template<> +constexpr auto get_default>() -> internal::literal_holder { + return {""}; +} + +template<> +constexpr auto get_default>() -> internal::literal_holder { + return {L""}; +} + +template +constexpr Tpl make_default_tuple(index_sequence) { + return {get_default>()...}; +} + +template +constexpr Tpl make_default_tuple() { + return make_default_tuple(make_index_sequence::value>{}); +} + +template +array single_value_array(const char* s) { + array a; + std::fill_n(a.data(), a.size(), s); + return a; +} + +template +struct wrap_in_literal { + using type = internal::literal_holder; +}; + +inline void require_string(const string& value, const string& expected) { REQUIRE(value == expected); } template void require_strings(const array& values, const array& expected, - std::index_sequence) { + index_sequence) { for(size_t i = 0; i < sizeof...(Idx); ++i) { require_string(values[i], expected[i]); } @@ -28,7 +82,7 @@ void require_strings(const array& values, template void test_tuple(const tuple& t, const Ctx& ctx, const array& expected) { - require_strings({internal::serialize(get(t), ctx)...}, expected, std::index_sequence_for{}); + require_strings({internal::serialize(get(t), ctx)...}, expected, index_sequence_for{}); } struct Custom {}; @@ -87,66 +141,54 @@ TEST_CASE("bindables") { #endif >; - Tuple t{false, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0.f, - 0., - 0., - "", - nullptr -#ifndef SQLITE_ORM_OMITS_CODECVT - , - L"" -#endif -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - , - std::nullopt -#endif - }; - array::value> e{"0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "0", - "''", - "null" + constexpr Tuple t = make_default_tuple(); + + array::value> e{"0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "''", + "null" #ifndef SQLITE_ORM_OMITS_CODECVT - , - "''" + , + "''" #endif #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - , - "null" + , + "null" #endif }; - test_tuple(t, context, e); + SECTION("dump") { + context.replace_bindable_with_question = false; + test_tuple(t, context, e); + } + SECTION("parametrized") { + context.replace_bindable_with_question = true; + test_tuple(t, context, single_value_array::value>("?")); + } + SECTION("non-bindable literals") { + context.replace_bindable_with_question = true; + constexpr auto t = make_default_tuple::type>(); + test_tuple(t, context, e); + } } SECTION("bindable_types") { using Tuple = tuple, #endif unique_ptr, @@ -164,57 +206,50 @@ TEST_CASE("bindables") { #endif StringVeneer, Custom, - std::unique_ptr>; + unique_ptr>; - Tuple t{"", -#ifndef SQLITE_ORM_OMITS_CODECVT - L"", - L"", -#endif - nullptr, - nullptr, - vector{}, -#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - std::nullopt, - std::nullopt, -#endif -#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - "", -#ifndef SQLITE_ORM_OMITS_CODECVT - L"", -#endif -#endif - "", - Custom{}, - nullptr}; - array::value> e{"''", + Tuple t = make_default_tuple(); + + array::value> e{"''", #ifndef SQLITE_ORM_OMITS_CODECVT - "''", - "''", + "''", + "''", #endif - "null", - "null", - "x''", + "null", + "null", + "x''", #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED - "null", - "null", + "null", + "null", #endif #ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED - "''", + "''", #ifndef SQLITE_ORM_OMITS_CODECVT - "''", + "''", #endif #endif - "''", - "custom", - "null"}; + "''", + "custom", + "null"}; - test_tuple(t, context, e); + SECTION("dump") { + context.replace_bindable_with_question = false; + test_tuple(t, context, e); + } + SECTION("parametrized") { + context.replace_bindable_with_question = true; + test_tuple(t, context, single_value_array::value>("?")); + } + SECTION("non-bindable literals") { + context.replace_bindable_with_question = true; + auto t = make_default_tuple::type>(); + test_tuple(t, context, e); + } } SECTION("bindable_pointer") { - string value; - decltype(value) expected; + string value, expected; + context.replace_bindable_with_question = false; SECTION("null by itself") { auto v = statically_bindable_pointer(nullptr); diff --git a/tests/statement_serializer_tests/conditions.cpp b/tests/statement_serializer_tests/conditions.cpp index 82a021aae..cdee7dacf 100644 --- a/tests/statement_serializer_tests/conditions.cpp +++ b/tests/statement_serializer_tests/conditions.cpp @@ -4,6 +4,8 @@ using namespace sqlite_orm; TEST_CASE("statement_serializer conditions") { + std::string value, expected; + SECTION("using") { struct User { int64 id; @@ -16,14 +18,28 @@ TEST_CASE("statement_serializer conditions") { internal::serializer_context ctx{storage}; SECTION("using column") { - auto ast = using_(&User::id); - auto value = serialize(ast, ctx); - REQUIRE(value == R"(USING ("id"))"); + auto expression = using_(&User::id); + value = serialize(expression, ctx); + expected = R"(USING ("id"))"; } SECTION("using explicit column") { - auto ast = using_(column(&User::id)); - auto value = serialize(ast, ctx); - REQUIRE(value == R"(USING ("id"))"); + auto expression = using_(column(&User::id)); + value = serialize(expression, ctx); + expected = R"(USING ("id"))"; + } + } + SECTION("order by") { + auto storage = internal::storage_impl<>{}; + using storage_impl = decltype(storage); + + internal::serializer_context ctx{storage}; + + SECTION("positional ordinal") { + auto expression = order_by(1); + value = serialize(expression, ctx); + expected = "ORDER BY 1"; } } + + REQUIRE(value == expected); } diff --git a/tests/static_tests/is_bindable.cpp b/tests/static_tests/is_bindable.cpp index 926eff477..c9aa931f3 100644 --- a/tests/static_tests/is_bindable.cpp +++ b/tests/static_tests/is_bindable.cpp @@ -70,6 +70,7 @@ TEST_CASE("is_bindable") { STATIC_REQUIRE(is_bindable_v>); STATIC_REQUIRE(!is_bindable_v); + STATIC_REQUIRE(!is_bindable_v>); STATIC_REQUIRE(!is_bindable_v); STATIC_REQUIRE(!is_bindable_v>); { diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 246144ce7..20701d172 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -28,20 +28,27 @@ TEST_CASE("Node tuple") { std::string name; }; - SECTION("simple") { + SECTION("bindables") { SECTION("int") { using Tuple = node_tuple_t; using Expected = tuple; - static_assert(is_same::value, "int"); + static_assert(is_same::value, "bindable int"); STATIC_REQUIRE(is_same::type, tuple>::value); } SECTION("float") { using Tuple = node_tuple_t; using Expected = tuple; - static_assert(is_same::value, "float"); + static_assert(is_same::value, "bindable float"); STATIC_REQUIRE(is_same::type, tuple>::value); } } + SECTION("non-bindable literals") { + using namespace internal; + using Tuple = node_tuple_t>; + using Expected = tuple<>; + static_assert(is_same::value, "literal int"); + STATIC_REQUIRE(is_same::type, tuple<>>::value); + } SECTION("binary_condition") { using namespace internal; SECTION("5 < 6.0f") { @@ -560,7 +567,10 @@ TEST_CASE("Node tuple") { tuple>::value); } SECTION("bindable") { - STATIC_REQUIRE(is_same, tuple>::value); + STATIC_REQUIRE(is_same, tuple>::value); + } + SECTION("positional ordinal") { + STATIC_REQUIRE(is_same, tuple<>>::value); } SECTION("numeric column alias") { STATIC_REQUIRE(is_same()))>, tuple<>>::value); From 776bc0a35bbd4fb68b8fd7b0f31f2a3b859e3bd4 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 30 Mar 2022 21:08:53 +0300 Subject: [PATCH 19/20] Removed numeric column alias --- dev/alias.h | 21 --------------------- dev/conditions.h | 1 - examples/column_aliases.cpp | 11 ----------- include/sqlite_orm/sqlite_orm.h | 30 ++++-------------------------- tests/ast_iterator_tests.cpp | 4 ---- tests/static_tests/node_tuple.cpp | 3 --- 6 files changed, 4 insertions(+), 66 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index a6cee2be4..819c26925 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -72,18 +72,6 @@ namespace sqlite_orm { expression_type expression; }; - /** - * This is a common built-in class used for numeric column identifiers, - * as described in the documentation of the ORDER BY Clause https://sqlite.org/lang_select.html#the_order_by_clause. - * For convenience there exist type aliases `colalias_1`, `colalias_2`, ... - */ - template - struct numeric_column_alias : alias_tag { - static std::string get() { - return std::to_string(K); - } - }; - /** * This is a common built-in class used for custom single-character column aliases. * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... @@ -175,15 +163,6 @@ namespace sqlite_orm { template using alias_z = internal::table_alias; - using colalias_1 = internal::numeric_column_alias<1u>; - using colalias_2 = internal::numeric_column_alias<2u>; - using colalias_3 = internal::numeric_column_alias<3u>; - using colalias_4 = internal::numeric_column_alias<4u>; - using colalias_5 = internal::numeric_column_alias<5u>; - using colalias_6 = internal::numeric_column_alias<6u>; - using colalias_7 = internal::numeric_column_alias<7u>; - using colalias_8 = internal::numeric_column_alias<8u>; - using colalias_9 = internal::numeric_column_alias<9u>; using colalias_a = internal::column_alias<'a'>; using colalias_b = internal::column_alias<'b'>; using colalias_c = internal::column_alias<'c'>; diff --git a/dev/conditions.h b/dev/conditions.h index 495dfd77c..92f6bf16c 100644 --- a/dev/conditions.h +++ b/dev/conditions.h @@ -1180,7 +1180,6 @@ namespace sqlite_orm { * * Examples: * storage.select(&User::name, order_by(&User::id)) - * storage.select(&User::name, order_by(get())) * storage.select(as(&User::name), order_by(get())) */ template> = true> diff --git a/examples/column_aliases.cpp b/examples/column_aliases.cpp index 186381a32..671809829 100644 --- a/examples/column_aliases.cpp +++ b/examples/column_aliases.cpp @@ -52,17 +52,6 @@ void marvel_hero_ordered_by_o_pos() { } } cout << endl; - { - // SELECT name, instr(abilities, 'o') - // FROM marvel - // ORDER BY 2 - auto rows = storage.select(columns(&MarvelHero::name, as(instr(&MarvelHero::abilities, "o"))), - order_by(get())); - for(auto& row: rows) { - cout << get<0>(row) << '\t' << get<1>(row) << '\n'; - } - } - cout << endl; { // SELECT name, instr(abilities, 'o') // FROM marvel diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index cee8d1854..8595b6fdb 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3937,7 +3937,6 @@ namespace sqlite_orm { * * Examples: * storage.select(&User::name, order_by(&User::id)) - * storage.select(&User::name, order_by(get())) * storage.select(as(&User::name), order_by(get())) */ template> = true> @@ -4103,18 +4102,6 @@ namespace sqlite_orm { expression_type expression; }; - /** - * This is a common built-in class used for numeric column identifiers, - * as described in the documentation of the ORDER BY Clause https://sqlite.org/lang_select.html#the_order_by_clause. - * For convenience there exist type aliases `colalias_1`, `colalias_2`, ... - */ - template - struct numeric_column_alias : alias_tag { - static std::string get() { - return std::to_string(K); - } - }; - /** * This is a common built-in class used for custom single-character column aliases. * For convenience there exist type aliases `colalias_a`, `colalias_b`, ... @@ -4206,15 +4193,6 @@ namespace sqlite_orm { template using alias_z = internal::table_alias; - using colalias_1 = internal::numeric_column_alias<1u>; - using colalias_2 = internal::numeric_column_alias<2u>; - using colalias_3 = internal::numeric_column_alias<3u>; - using colalias_4 = internal::numeric_column_alias<4u>; - using colalias_5 = internal::numeric_column_alias<5u>; - using colalias_6 = internal::numeric_column_alias<6u>; - using colalias_7 = internal::numeric_column_alias<7u>; - using colalias_8 = internal::numeric_column_alias<8u>; - using colalias_9 = internal::numeric_column_alias<9u>; using colalias_a = internal::column_alias<'a'>; using colalias_b = internal::column_alias<'b'>; using colalias_c = internal::column_alias<'c'>; @@ -14550,16 +14528,16 @@ namespace sqlite_orm { std::string entryString; { std::stringstream ss; - ss << entry.name << " "; + ss << entry.name; if(!entry._collate_argument.empty()) { - ss << "COLLATE " << entry._collate_argument << " "; + ss << " COLLATE " << entry._collate_argument; } switch(entry.asc_desc) { case 1: - ss << "ASC"; + ss << " ASC"; break; case -1: - ss << "DESC"; + ss << " DESC"; break; } entryString = ss.str(); diff --git a/tests/ast_iterator_tests.cpp b/tests/ast_iterator_tests.cpp index 38aed7e5f..746cfd852 100644 --- a/tests/ast_iterator_tests.cpp +++ b/tests/ast_iterator_tests.cpp @@ -176,10 +176,6 @@ TEST_CASE("ast_iterator") { auto node = order_by(1); internal::iterate_ast(node, lambda); } - SECTION("numeric column alias") { - auto node = order_by(get()); - internal::iterate_ast(node, lambda); - } SECTION("sole column alias") { auto node = order_by(get()); internal::iterate_ast(node, lambda); diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 20701d172..98c0a0ea2 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -572,9 +572,6 @@ TEST_CASE("Node tuple") { SECTION("positional ordinal") { STATIC_REQUIRE(is_same, tuple<>>::value); } - SECTION("numeric column alias") { - STATIC_REQUIRE(is_same()))>, tuple<>>::value); - } SECTION("sole column alias") { STATIC_REQUIRE(is_same()))>, tuple<>>::value); } From f4c905261a20d775520fe1e22cee112e844b98d0 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 30 Mar 2022 22:29:20 +0300 Subject: [PATCH 20/20] Fixed bindable unit tests for C++17 and later --- tests/statement_serializer_tests/bindables.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/statement_serializer_tests/bindables.cpp b/tests/statement_serializer_tests/bindables.cpp index 2706455eb..922cdab2e 100644 --- a/tests/statement_serializer_tests/bindables.cpp +++ b/tests/statement_serializer_tests/bindables.cpp @@ -45,6 +45,18 @@ constexpr auto get_default>() -> intern return {L""}; } +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +template<> +constexpr auto get_default() -> std::nullopt_t { + return std::nullopt; +} + +template<> +constexpr auto get_default>() -> internal::literal_holder { + return {std::nullopt}; +} +#endif + template constexpr Tpl make_default_tuple(index_sequence) { return {get_default>()...};