From dc53fd5acc0e875c1346d4bfef6548c164a9f56d Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 3 Nov 2024 11:33:47 +0100 Subject: [PATCH] Add more cte tests --- include/sqlpp11/core/basic/parameter.h | 8 ++- include/sqlpp11/core/clause/cte.h | 5 -- include/sqlpp11/core/clause/with.h | 3 +- .../sqlpp11/core/database/parameter_list.h | 3 +- include/sqlpp11/core/query/custom_query.h | 2 +- include/sqlpp11/core/query/statement.h | 6 +-- include/sqlpp11/core/type_traits.h | 30 +++++------ tests/core/types/clause/cte.cpp | 53 +++++++++++++++++-- tests/core/types/result_row.cpp | 2 + 9 files changed, 79 insertions(+), 33 deletions(-) diff --git a/include/sqlpp11/core/basic/parameter.h b/include/sqlpp11/core/basic/parameter.h index 00b45605..f81e9c69 100644 --- a/include/sqlpp11/core/basic/parameter.h +++ b/include/sqlpp11/core/basic/parameter.h @@ -33,12 +33,12 @@ namespace sqlpp { +#warning: It would be sufficient to store the NameTag here, not the whole NameTagProvider template struct parameter_t : public enable_comparison> { using _traits = make_traits; - using _parameters = detail::type_vector; using _is_literal_expression = std::true_type; using _instance_t = member_t>; @@ -52,6 +52,12 @@ namespace sqlpp ~parameter_t() = default; }; + template + struct parameters_of> + { + using type = detail::type_vector>; + }; + template struct value_type_of> { diff --git a/include/sqlpp11/core/clause/cte.h b/include/sqlpp11/core/clause/cte.h index 07bc94fe..1aa8f711 100644 --- a/include/sqlpp11/core/clause/cte.h +++ b/include/sqlpp11/core/clause/cte.h @@ -40,8 +40,6 @@ namespace sqlpp template struct cte_union_t { - using _parameters = detail::type_vector_cat_t, parameters_of>; - cte_union_t(Lhs lhs, Rhs rhs) : _lhs(lhs), _rhs(rhs) { } @@ -303,9 +301,6 @@ namespace sqlpp } }; - template - struct is_table> : public std::true_type{}; - template struct name_tag_of> : public name_tag_of {}; diff --git a/include/sqlpp11/core/clause/with.h b/include/sqlpp11/core/clause/with.h index 2c2a43a3..41c202d7 100644 --- a/include/sqlpp11/core/clause/with.h +++ b/include/sqlpp11/core/clause/with.h @@ -62,7 +62,7 @@ namespace sqlpp using _nodes = detail::type_vector<>; using _provided_ctes = detail::make_joined_set_t...>; // WITH provides common table expressions - using _parameters = detail::type_vector_cat_t...>; + using _parameters = detail::type_vector_cat_t...>; using _data_t = with_data_t; @@ -80,6 +80,7 @@ namespace sqlpp using _consistency_check = consistent_t; }; }; +#warning: Need traits here! And type tests for them struct no_with_t { diff --git a/include/sqlpp11/core/database/parameter_list.h b/include/sqlpp11/core/database/parameter_list.h index fbfd16b1..78ddb22a 100644 --- a/include/sqlpp11/core/database/parameter_list.h +++ b/include/sqlpp11/core/database/parameter_list.h @@ -64,6 +64,7 @@ namespace sqlpp } }; +#warning: Why would we need this? template - using make_parameter_list_t = parameter_list_t>; + using make_parameter_list_t = parameter_list_t>; } // namespace sqlpp diff --git a/include/sqlpp11/core/query/custom_query.h b/include/sqlpp11/core/query/custom_query.h index 1303350d..6d89dd61 100644 --- a/include/sqlpp11/core/query/custom_query.h +++ b/include/sqlpp11/core/query/custom_query.h @@ -69,7 +69,7 @@ namespace sqlpp using _nodes = detail::type_vector; using _parameter_check = - typename std::conditional::empty(), + typename std::conditional::empty(), consistent_t, assert_no_parameters_t>::type; using _run_check = detail::get_first_if; diff --git a/include/sqlpp11/core/query/statement.h b/include/sqlpp11/core/query/statement.h index 91a72c90..cdb15043 100644 --- a/include/sqlpp11/core/query/statement.h +++ b/include/sqlpp11/core/query/statement.h @@ -123,7 +123,7 @@ namespace sqlpp // - the select is complete (leaks no table requirements or cte requirements) static constexpr bool _can_be_used_as_table() { - return has_result_row<_statement_t>::value and _required_tables_of::empty() == 0 and + return has_result_row<_statement_t>::value and _required_tables_of::empty() and _required_ctes_of::empty(); } @@ -140,11 +140,11 @@ namespace sqlpp detail::make_intersect_set_t, _all_provided_optional_tables>::size::value != 0>; */ - using _parameters = detail::type_vector_cat_t...>; + using _parameters = detail::type_vector_cat_t...>; // required_tables and _required_ctes are defined above using _cte_check = - typename std::conditional<_required_ctes_of::empty() == 0, consistent_t, assert_no_unknown_ctes_t>::type; + typename std::conditional<_required_ctes_of::empty(), consistent_t, assert_no_unknown_ctes_t>::type; using _table_check = typename std::conditional<_required_tables_of::empty(), consistent_t, assert_no_unknown_tables_t>::type; using _parameter_check = typename std:: diff --git a/include/sqlpp11/core/type_traits.h b/include/sqlpp11/core/type_traits.h index 2a2bbc0a..ac397526 100644 --- a/include/sqlpp11/core/type_traits.h +++ b/include/sqlpp11/core/type_traits.h @@ -404,26 +404,20 @@ namespace sqlpp template using is_non_aggregate_expression_t = typename detail::is_non_aggregate_expression_impl::type; - namespace detail + template + struct parameters_of { - template - struct parameters_of_impl - { - using type = typename parameters_of_impl>::type; - }; - template - struct parameters_of_impl::value>::type> - { - using type = typename T::_parameters; - }; - template - struct parameters_of_impl, void> - { - using type = detail::type_vector_cat_t::type...>; - }; - } // namespace detail + using type = typename parameters_of>::type; + }; + + template + struct parameters_of> + { + using type = detail::type_vector_cat_t::type...>; + }; + template - using parameters_of = typename detail::parameters_of_impl::type; + using parameters_of_t = typename parameters_of::type; // Something that can be used as a table template diff --git a/tests/core/types/clause/cte.cpp b/tests/core/types/clause/cte.cpp index 8d73fc75..12ad97cd 100644 --- a/tests/core/types/clause/cte.cpp +++ b/tests/core/types/clause/cte.cpp @@ -31,21 +31,68 @@ void test_cte() const auto foo = test::TabFoo{}; const auto bar = test::TabBar{}; -#warning: add more tests +#warning: add more tests, including parameters and dynamic parts +#warning: Can we union dynamically? + // Simple CTE: X AS SELECT { auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally()); auto a = x.as(sqlpp::alias::a); using X = decltype(x); - using R = decltype(make_table_ref(x)); + using RX = decltype(make_table_ref(x)); using A = decltype(a); + using RA = decltype(make_table_ref(a)); + // CTE is used in WITH and in FROM static_assert(sqlpp::is_cte::value, ""); static_assert(not sqlpp::is_recursive_cte::value, ""); static_assert(sqlpp::is_table::value, ""); static_assert(sqlpp::required_ctes_of_t::empty(), ""); - static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + + // CTE reference is what is stored in from_t or join_t. + // While it refers to a CTE, it cannot be used as a CTE or table, i.e. with(rx) or from(ra) would not compile. + static_assert(not sqlpp::is_cte::value, ""); + static_assert(not sqlpp::is_table::value, ""); + + // CTEs can be aliased (e.g. x AS a). This alias can be used as a table in FROM, but not as a CTE in WITH. + static_assert(not sqlpp::is_cte::value, ""); + static_assert(sqlpp::is_table::value, ""); + static_assert(std::is_same::value, ""); + } + + // Simple CTE with parameter + { + auto p = sqlpp::parameter(foo.id); + auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).where(foo.id > p)); + auto a = x.as(sqlpp::alias::a); + + using X = decltype(x); + using RX = decltype(make_table_ref(x)); + using A = decltype(a); + using RA = decltype(make_table_ref(a)); + using P = decltype(p); + + // CTE is used in WITH and in FROM + static_assert(sqlpp::is_cte::value, ""); + static_assert(not sqlpp::is_recursive_cte::value, ""); + static_assert(sqlpp::is_table::value, ""); + static_assert(sqlpp::required_ctes_of_t::empty(), ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector

>::value, ""); + + // CTE reference is what is stored in from_t or join_t. + // While it refers to a CTE, it cannot be used as a CTE or table, i.e. with(rx) or from(ra) would not compile. + static_assert(not sqlpp::is_cte::value, ""); + static_assert(not sqlpp::is_table::value, ""); + static_assert(sqlpp::parameters_of_t::empty(), ""); + + // CTEs can be aliased (e.g. x AS a). This alias can be used as a table in FROM, but not as a CTE in WITH. + static_assert(not sqlpp::is_cte::value, ""); + static_assert(sqlpp::is_table::value, ""); + static_assert(std::is_same::value, ""); + static_assert(sqlpp::parameters_of_t::empty(), ""); } // Non-recursive union CTE: X AS SELECT ... UNION ALL SELECT ... diff --git a/tests/core/types/result_row.cpp b/tests/core/types/result_row.cpp index 02d56d60..69a29738 100644 --- a/tests/core/types/result_row.cpp +++ b/tests/core/types/result_row.cpp @@ -304,6 +304,8 @@ int main() } } +#warning: Test with CTEs + int main(int, char* []) { single_table();