0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 04:47:18 +08:00

Add support for dynamic union in CTEs

This commit is contained in:
Roland Bock 2024-11-04 07:21:29 +01:00
parent 6128b78f28
commit 7cdcf0f172
2 changed files with 59 additions and 14 deletions

View File

@ -68,6 +68,15 @@ namespace sqlpp
return to_sql_string(context, t._lhs) + " UNION " + to_sql_string(context, Flag{}) + to_sql_string(context, t._rhs);
}
template <typename Context, typename Flag, typename Lhs, typename Rhs>
auto to_sql_string(Context& context, const cte_union_t<Flag, Lhs, dynamic_t<Rhs>>& t) -> std::string
{
if (t._rhs._condition){
return to_sql_string(context, t._lhs) + " UNION " + to_sql_string(context, Flag{}) + to_sql_string(context, t._rhs._expr);
}
return to_sql_string(context, t._lhs);
}
template <typename NameTagProvider, typename Statement, typename... FieldSpecs>
struct cte_t;
@ -116,14 +125,14 @@ namespace sqlpp
using union_cte_impl_t = typename union_cte_impl<Check, Union>::type;
SQLPP_PORTABLE_STATIC_ASSERT(assert_cte_union_args_are_statements_t, "argument for union() must be a statement");
template <typename... T>
template <typename T>
struct check_cte_union
{
using type = static_combined_check_t<
static_check_t<logic::all<is_statement_t<T>::value...>::value, assert_cte_union_args_are_statements_t>>;
static_check_t<is_statement_t<T>::value, assert_cte_union_args_are_statements_t>>;
};
template <typename... T>
using check_cte_union_t = typename check_cte_union<T...>::type;
template <typename T>
using check_cte_union_t = typename check_cte_union<remove_dynamic_t<T>>::type;
// cte_member is a helper to add column data members to `cte_t`.
template <typename NameTagProvider, typename FieldSpec>
@ -194,14 +203,15 @@ namespace sqlpp
-> union_cte_impl_t<check_cte_union_t<Rhs>,
cte_t<NameTagProvider, cte_union_t<distinct_t, Statement, Rhs>, FieldSpecs...>>
{
static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<Rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row<Rhs>::value, "argument of a clause/union.has to be a (complete) select statement");
using _rhs = remove_dynamic_t<Rhs>;
static_assert(is_statement_t<_rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<_rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row<_rhs>::value, "argument of a clause/union.has to be a (complete) select statement");
static_assert(std::is_same<_result_row_t, get_result_row_t<Rhs>>::value,
static_assert(std::is_same<_result_row_t, get_result_row_t<_rhs>>::value,
"both select statements in a clause/union.have to have the same result columns (type and name)");
return _union_impl<void, distinct_t>(check_cte_union_t<Rhs>{}, rhs);
return _union_impl<distinct_t>(check_cte_union_t<Rhs>{}, rhs);
}
template <typename Rhs>
@ -209,11 +219,12 @@ namespace sqlpp
-> union_cte_impl_t<check_cte_union_t<Rhs>,
cte_t<NameTagProvider, cte_union_t<all_t, Statement, Rhs>, FieldSpecs...>>
{
static_assert(is_statement_t<Rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<Rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row<Rhs>::value, "argument of a clause/union.has to be a (complete) select statement");
using _rhs = remove_dynamic_t<Rhs>;
static_assert(is_statement_t<_rhs>::value, "argument of union call has to be a statement");
static_assert(has_policy_t<_rhs, is_select_t>::value, "argument of union call has to be a select");
static_assert(has_result_row<_rhs>::value, "argument of a clause/union.has to be a (complete) select statement");
static_assert(std::is_same<_result_row_t, get_result_row_t<Rhs>>::value,
static_assert(std::is_same<_result_row_t, get_result_row_t<_rhs>>::value,
"both select statements in a clause/union.have to have the same result columns (type and name)");
return _union_impl<all_t>(check_cte_union_t<Rhs>{}, rhs);
@ -272,6 +283,18 @@ namespace sqlpp
using type = Statement;
};
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct provided_tables_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
{
using type = sqlpp::detail::type_vector<cte_ref_t<NameTagProvider>>;
};
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct provided_static_tables_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>> : public provided_tables_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
{
};
#warning: Should enough if with_t provides ctes?
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct provided_ctes_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
{

View File

@ -63,7 +63,7 @@ int main(int, char* [])
SQLPP_COMPARE(all_of(a), "a.id");
}
// Recursive union CTE: X AS SELECT ... UNION ALL SELECT ... FROM X ...
// Recursive CTE: X AS SELECT ... UNION ALL SELECT ... FROM X ...
{
const auto x_base = cte(sqlpp::alias::x).as(select(sqlpp::value(0).as(sqlpp::alias::a)));
const auto x = x_base.union_all(select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < 10));
@ -91,5 +91,27 @@ int main(int, char* [])
SQLPP_COMPARE(all_of(z), "z.id, z.a");
}
// Dynamically recursive CTE: X AS SELECT ... UNION ALL SELECT ... FROM X ...
{
const auto x_base = cte(sqlpp::alias::x).as(select(sqlpp::value(0).as(sqlpp::alias::a)));
auto x = x_base.union_all(dynamic(true, select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < 10)));
SQLPP_COMPARE(x, "x AS (SELECT 0 AS a UNION ALL SELECT (x.a + 1) AS a FROM x WHERE x.a < 10)");
x = x_base.union_all(dynamic(false, select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < 10)));
SQLPP_COMPARE(x, "x AS (SELECT 0 AS a)");
}
// Dynamically recursive CTE: X AS SELECT ... UNION DISTINCT SELECT ... FROM X ...
{
const auto x_base = cte(sqlpp::alias::x).as(select(sqlpp::value(0).as(sqlpp::alias::a)));
auto x = x_base.union_distinct(dynamic(true, select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < 10)));
SQLPP_COMPARE(x, "x AS (SELECT 0 AS a UNION DISTINCT SELECT (x.a + 1) AS a FROM x WHERE x.a < 10)");
x = x_base.union_distinct(dynamic(false, select((x_base.a + 1).as(sqlpp::alias::a)).from(x_base).where(x_base.a < 10)));
SQLPP_COMPARE(x, "x AS (SELECT 0 AS a)");
}
return 0;
}