From 6128b78f282d923de5ec337c8d177f4e2eeec66f Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 3 Nov 2024 12:21:53 +0100 Subject: [PATCH] More cte tests --- include/sqlpp11/core/clause/cte.h | 7 +++ tests/core/types/clause/cte.cpp | 100 +++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/include/sqlpp11/core/clause/cte.h b/include/sqlpp11/core/clause/cte.h index 1aa8f711..7c5cd6c5 100644 --- a/include/sqlpp11/core/clause/cte.h +++ b/include/sqlpp11/core/clause/cte.h @@ -161,6 +161,13 @@ namespace sqlpp { }; + template + struct required_ctes_of> + { + // An aliased CTE requires the original CTE from the WITH clause. + using type = sqlpp::detail::type_vector>; + }; + template auto to_sql_string(Context& context, const cte_as_t&) -> std::string { diff --git a/tests/core/types/clause/cte.cpp b/tests/core/types/clause/cte.cpp index 5937a7ee..ea2c22de 100644 --- a/tests/core/types/clause/cte.cpp +++ b/tests/core/types/clause/cte.cpp @@ -50,16 +50,23 @@ void test_cte() 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(sqlpp::parameters_of_t::empty(), ""); // 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(std::is_same, sqlpp::detail::type_vector<>>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::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(std::is_same, sqlpp::detail::type_vector<>>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(sqlpp::parameters_of_t::empty(), ""); } // Simple CTE with parameter @@ -70,7 +77,6 @@ void test_cte() 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); @@ -82,16 +88,8 @@ void test_cte() 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(rx) would not compile. - static_assert(not sqlpp::is_cte::value, ""); - static_assert(not sqlpp::is_table::value, ""); + // Neither CTE reference nor alias carry the parameter. 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(), ""); } @@ -100,21 +98,91 @@ void test_cte() auto x = cte(sqlpp::alias::x) .as(select(foo.id).from(foo).unconditionally().union_all(select(bar.id).from(bar).unconditionally())); - auto a = x.as(sqlpp::alias::a); + + using X = decltype(x); + using RX = decltype(make_table_ref(x)); + + // 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(sqlpp::parameters_of_t::empty(), ""); } // Recursive union CTE: X AS SELECT ... UNION ALL SELECT ... FROM X ... { + auto p = sqlpp::parameter(foo.id); auto x_base = cte(sqlpp::alias::x).as(select(sqlpp::value(0).as(sqlpp::alias::a))); - auto x = x_base.union_all(select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < 10)); - auto y = x.as(sqlpp::alias::y); + auto x = x_base.union_all(select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < p)); + + using X = decltype(x); + using RX = decltype(make_table_ref(x)); + using P = decltype(p); + + // CTE is used in WITH and in FROM + static_assert(sqlpp::is_cte::value, ""); + static_assert(sqlpp::is_recursive_cte::value, ""); + static_assert(sqlpp::is_table::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector

>::value, ""); } // A CTE depending on another CTE { - auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally()); - auto y = cte(sqlpp::alias::y).as(select(x.id, sqlpp::value(7).as(sqlpp::alias::a)).from(x).unconditionally()); - auto z = y.as(sqlpp::alias::z); + auto pb = sqlpp::parameter(foo.intN); + auto p = sqlpp::parameter(foo.id); + auto b = cte(sqlpp::alias::b).as(select(foo.id).from(foo).where(foo.id != pb)); + auto x = cte(sqlpp::alias::y).as(select(b.id, sqlpp::value(7).as(sqlpp::alias::a)).from(b).where(b.id > p)); + auto a = x.as(sqlpp::alias::a); + + using RB = decltype(make_table_ref(b)); + using X = decltype(x); + using RX = decltype(make_table_ref(x)); + 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(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector

>::value, ""); + + // Neither CTE reference nor alias carry the dependency. + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + } + + // A recursive CTE depending on another CTE + { + auto pb = sqlpp::parameter(foo.intN); + auto p = sqlpp::parameter(foo.id); + auto b = cte(sqlpp::alias::b).as(select(foo.id.as(sqlpp::alias::a)).from(foo).where(foo.id != pb)); + auto x_base = cte(sqlpp::alias::x).as(select(b.a).from(b).unconditionally()); + auto x = x_base.union_all(select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < p)); + auto a = x.as(sqlpp::alias::a); + + using RB = decltype(make_table_ref(b)); + using X = decltype(x); + using RX = decltype(make_table_ref(x)); + 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(sqlpp::is_recursive_cte::value, ""); + static_assert(sqlpp::is_table::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector

>::value, ""); + + // Neither CTE reference nor alias carry the dependency. + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); } }