0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 12:51:13 +08:00

Implement CTE alias (allowing self-join)

This commit is contained in:
Roland Bock 2024-10-25 07:31:56 +02:00
parent 982812abcc
commit 980daac517
2 changed files with 59 additions and 10 deletions

View File

@ -134,6 +134,40 @@ namespace sqlpp
using type = member_t<FieldSpec, column_t<cte_ref_t<NameTagProvider>, FieldSpec>>; using type = member_t<FieldSpec, column_t<cte_ref_t<NameTagProvider>, FieldSpec>>;
}; };
#warning: Need to document that you need to be a bit careful with aliased CTEs as we use cte_ref in columns, from, and join.
template <typename NameTagProvider, typename NewNameTagProvider, typename... FieldSpecs>
struct cte_as_t : public cte_member<NewNameTagProvider, FieldSpecs>::type...,
public enable_join<cte_as_t<NameTagProvider, NewNameTagProvider, FieldSpecs...>>
{
};
template <typename NameTagProvider, typename NewNameTagProvider, typename... ColumnSpecs>
struct is_table<cte_as_t<NameTagProvider, NewNameTagProvider, ColumnSpecs...>> : public std::true_type
{
};
template <typename NameTagProvider, typename NewNameTagProvider, typename... ColumnSpecs>
struct name_tag_of<cte_as_t<NameTagProvider, NewNameTagProvider, ColumnSpecs...>> : public name_tag_of<NewNameTagProvider>
{
};
template <typename NameTagProvider, typename NewNameTagProvider, typename... ColumnSpecs>
struct provided_tables_of<cte_as_t<NameTagProvider, NewNameTagProvider, ColumnSpecs...>>
{
using type = sqlpp::detail::type_vector<cte_ref_t<NewNameTagProvider>>;
};
template <typename NameTagProvider, typename NewNameTagProvider, typename... ColumnSpecs>
struct provided_static_tables_of<cte_as_t<NameTagProvider, NewNameTagProvider, ColumnSpecs...>> : public provided_tables_of<cte_as_t<NameTagProvider, NewNameTagProvider, ColumnSpecs...>>
{
};
template <typename Context, typename NameTagProvider, typename NewNameTagProvider, typename... ColumnSpecs>
auto to_sql_string(Context& context, const cte_as_t<NameTagProvider, NewNameTagProvider, ColumnSpecs...>&) -> std::string
{
return name_to_sql_string(context, name_tag_of_t<NameTagProvider>::name) + " AS " + name_to_sql_string(context, name_tag_of_t<NewNameTagProvider>::name);
}
template <typename NameTagProvider, typename Statement, typename... FieldSpecs> template <typename NameTagProvider, typename Statement, typename... FieldSpecs>
struct cte_t : public cte_member<NameTagProvider, FieldSpecs>::type..., struct cte_t : public cte_member<NameTagProvider, FieldSpecs>::type...,
public enable_join<cte_t<NameTagProvider, Statement, FieldSpecs...>> public enable_join<cte_t<NameTagProvider, Statement, FieldSpecs...>>
@ -151,6 +185,13 @@ namespace sqlpp
using _result_row_t = result_row_t<void, FieldSpecs...>; using _result_row_t = result_row_t<void, FieldSpecs...>;
template <typename NewNameTagProvider>
constexpr auto as(const NewNameTagProvider& /*unused*/) const
-> cte_as_t<NameTagProvider, NewNameTagProvider, FieldSpecs...>
{
return {};
}
template <typename Rhs> template <typename Rhs>
auto union_distinct(Rhs rhs) const auto union_distinct(Rhs rhs) const
-> union_cte_impl_t<check_cte_union_t<Rhs>, -> union_cte_impl_t<check_cte_union_t<Rhs>,
@ -205,7 +246,7 @@ namespace sqlpp
Statement _statement; Statement _statement;
}; };
#warning: is table? really? #warning: is table? really? cte_ref needs to be a table, not sure about cte_t
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs> template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct is_table<cte_t<NameTagProvider, Statement, ColumnSpecs...>> : public std::true_type struct is_table<cte_t<NameTagProvider, Statement, ColumnSpecs...>> : public std::true_type
{ {
@ -219,13 +260,12 @@ namespace sqlpp
template <typename Context, typename NameTagProvider, typename Statement, typename... ColumnSpecs> template <typename Context, typename NameTagProvider, typename Statement, typename... ColumnSpecs>
auto to_sql_string(Context& context, const cte_t<NameTagProvider, Statement, ColumnSpecs...>& t) -> std::string auto to_sql_string(Context& context, const cte_t<NameTagProvider, Statement, ColumnSpecs...>& t) -> std::string
{ {
return name_to_sql_string(context, name_tag_of_t<NameTagProvider>::name) + " AS (" + return name_to_sql_string(context, name_tag_of_t<NameTagProvider>::name) + " AS (" +
to_sql_string(context, t._statement) + ")"; to_sql_string(context, t._statement) + ")";
} }
// The cte_t is displayed as NameTagProviderName except within the with: // The cte_ref_t represents the cte as table in FROM.
// - the with needs the // The cte_t needs to be provided by WITH.
// NameTagProviderName AS (ColumnNames) (select/union)
template <typename NameTagProvider> template <typename NameTagProvider>
struct cte_ref_t struct cte_ref_t
{ {
@ -247,10 +287,13 @@ namespace sqlpp
} }
}; };
#warning: is table? really?
template<typename NameTagProvider> template<typename NameTagProvider>
struct is_table<cte_ref_t<NameTagProvider>> : public std::true_type{}; struct is_table<cte_ref_t<NameTagProvider>> : public std::true_type{};
template<typename NameTagProvider>
struct name_tag_of<cte_ref_t<NameTagProvider>> : public name_tag_of<NameTagProvider>
{};
template<typename NameTagProvider> template<typename NameTagProvider>
struct provided_tables_of<cte_ref_t<NameTagProvider>> struct provided_tables_of<cte_ref_t<NameTagProvider>>
{ {
@ -262,9 +305,6 @@ namespace sqlpp
{ {
}; };
template<typename NameTagProvider>
struct name_tag_of<cte_ref_t<NameTagProvider>> : public name_tag_of<NameTagProvider>{};
template <typename Context, typename NameTagProvider> template <typename Context, typename NameTagProvider>
auto to_sql_string(Context& context, const cte_ref_t<NameTagProvider>&) -> std::string auto to_sql_string(Context& context, const cte_ref_t<NameTagProvider>&) -> std::string
{ {

View File

@ -36,6 +36,9 @@ int main()
const auto cFoo = foo.as(sqlpp::alias::c); const auto cFoo = foo.as(sqlpp::alias::c);
const auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally()); const auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally());
const auto xa = x.as(sqlpp::alias::a);
const auto xb = x.as(sqlpp::alias::b);
const auto y = cte(sqlpp::alias::y).as(select(foo.id).from(foo).unconditionally());
// Single table // Single table
SQLPP_COMPARE(from(foo), " FROM tab_foo"); SQLPP_COMPARE(from(foo), " FROM tab_foo");
@ -53,7 +56,13 @@ int main()
// CTE // CTE
SQLPP_COMPARE(from(x), " FROM x"); SQLPP_COMPARE(from(x), " FROM x");
SQLPP_COMPARE(from(foo.join(x).on(x.id == foo.id)), " FROM tab_foo INNER JOIN x ON x.id = tab_foo.id");
SQLPP_COMPARE(from(x.join(foo).on(x.id == foo.id)), " FROM x INNER JOIN tab_foo ON x.id = tab_foo.id"); SQLPP_COMPARE(from(x.join(foo).on(x.id == foo.id)), " FROM x INNER JOIN tab_foo ON x.id = tab_foo.id");
SQLPP_COMPARE(from(x.join(y).on(x.id == y.id)), " FROM x INNER JOIN y ON x.id = y.id");
#warning: Some of these should go into CTE tests
SQLPP_COMPARE(xa, "x AS a");
SQLPP_COMPARE(xa.id == xb.id, "a.id = b.id");
SQLPP_COMPARE(from(xa.join(xb).on(xa.id == xb.id)), " FROM x AS a INNER JOIN x AS b ON a.id = b.id");
#warning add tests for dynamic joins #warning add tests for dynamic joins