mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 04:47:18 +08:00
Fix serialize tests for WITH RECURSIVE
This commit is contained in:
parent
10eaa1f97a
commit
aa6ea6c4f0
@ -40,7 +40,6 @@ namespace sqlpp
|
||||
public enable_join<table_as_t<TableSpec, NameTag>>
|
||||
{
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _required_ctes = required_ctes_of<TableSpec>;
|
||||
|
||||
static_assert(required_tables_of_t<TableSpec>::empty(), "table aliases must not depend on external tables");
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace sqlpp
|
||||
struct cte_union_t
|
||||
{
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _required_ctes = detail::make_joined_set_t<required_ctes_of<Lhs>, required_ctes_of<Rhs>>;
|
||||
using _required_ctes = detail::type_vector_cat_t<required_ctes_of_t<Lhs>, required_ctes_of_t<Rhs>>;
|
||||
using _parameters = detail::type_vector_cat_t<parameters_of<Lhs>, parameters_of<Rhs>>;
|
||||
|
||||
cte_union_t(Lhs lhs, Rhs rhs) : _lhs(lhs), _rhs(rhs)
|
||||
@ -58,6 +58,21 @@ namespace sqlpp
|
||||
Rhs _rhs;
|
||||
};
|
||||
|
||||
template <typename Flag, typename Lhs, typename Rhs>
|
||||
struct required_ctes_of<cte_union_t<Flag, Lhs, Rhs>>
|
||||
{
|
||||
using type = detail::type_vector_cat_t<required_ctes_of_t<Lhs>, required_ctes_of_t<Rhs>>;
|
||||
};
|
||||
|
||||
template <typename Flag, typename Lhs, typename Rhs>
|
||||
struct required_static_ctes_of<cte_union_t<Flag, Lhs, Rhs>>
|
||||
{
|
||||
using type = typename std::conditional<
|
||||
is_dynamic<Rhs>::value,
|
||||
provided_static_ctes_of_t<Lhs>,
|
||||
detail::type_vector_cat_t<provided_static_ctes_of_t<Lhs>, provided_static_ctes_of_t<Rhs>>>::type;
|
||||
};
|
||||
|
||||
// Interpreters
|
||||
template <typename Context, typename Flag, typename Lhs, typename Rhs>
|
||||
auto to_sql_string(Context& context, const cte_union_t<Flag, Lhs, Rhs>& t) -> std::string
|
||||
@ -169,7 +184,7 @@ namespace sqlpp
|
||||
public enable_join<cte_t<NameTagProvider, Statement, FieldSpecs...>>
|
||||
{
|
||||
#warning: Need to test this.
|
||||
constexpr static bool _is_recursive = required_ctes_of<Statement>::template count<cte_ref_t<NameTagProvider>>();
|
||||
constexpr static bool _is_recursive = required_ctes_of_t<Statement>::template contains<cte_ref_t<NameTagProvider>>::value;
|
||||
|
||||
using _column_tuple_t = std::tuple<column_t<cte_ref_t<NameTagProvider>, FieldSpecs>...>;
|
||||
|
||||
@ -252,6 +267,17 @@ namespace sqlpp
|
||||
{
|
||||
};
|
||||
|
||||
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
|
||||
struct provided_ctes_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
|
||||
{
|
||||
using type = detail::type_vector<cte_ref_t<NameTagProvider>>;
|
||||
};
|
||||
|
||||
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
|
||||
struct provided_static_ctes_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>> : public provided_ctes_of<cte_t<NameTagProvider, Statement, 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
|
||||
{
|
||||
@ -269,7 +295,7 @@ namespace sqlpp
|
||||
{
|
||||
static_assert(required_tables_of_t<Statement>::empty(),
|
||||
"common table expression must not use unknown tables");
|
||||
static_assert(not required_ctes_of<Statement>::template count<NameTagProvider>(),
|
||||
static_assert(not required_ctes_of_t<Statement>::template contains<NameTagProvider>::value,
|
||||
"common table expression must not self-reference in the first part, use union_all/union_distinct "
|
||||
"for recursion");
|
||||
|
||||
@ -295,6 +321,17 @@ namespace sqlpp
|
||||
{
|
||||
};
|
||||
|
||||
template<typename NameTagProvider>
|
||||
struct required_ctes_of<cte_ref_t<NameTagProvider>>
|
||||
{
|
||||
using type = sqlpp::detail::type_vector<cte_ref_t<NameTagProvider>>;
|
||||
};
|
||||
|
||||
template<typename NameTagProvider>
|
||||
struct required_static_ctes_of<cte_ref_t<NameTagProvider>> : public required_ctes_of<cte_ref_t<NameTagProvider>>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename Context, typename NameTagProvider>
|
||||
auto to_sql_string(Context& context, const cte_ref_t<NameTagProvider>&) -> std::string
|
||||
{
|
||||
|
@ -75,14 +75,16 @@ namespace sqlpp
|
||||
template <typename Needle, typename Replacement>
|
||||
using _new_statement_t = typename _policies_update_t<Needle, Replacement>::type;
|
||||
|
||||
using _all_required_ctes = detail::make_joined_set_t<required_ctes_of<Policies>...>;
|
||||
using _all_provided_ctes = detail::make_joined_set_t<provided_ctes_of<Policies>...>;
|
||||
using _all_required_ctes = detail::type_vector_cat_t<required_ctes_of_t<Policies>...>;
|
||||
using _all_provided_ctes = detail::type_vector_cat_t<provided_ctes_of_t<Policies>...>;
|
||||
using _all_required_tables = detail::type_vector_cat_t<required_tables_of_t<Policies>...>;
|
||||
using _all_provided_tables = detail::type_vector_cat_t<provided_tables_of_t<Policies>...>;
|
||||
using _all_provided_optional_tables = detail::type_vector_cat_t<provided_optional_tables_of_t<Policies>...>;
|
||||
#warning: provided_aggregates_of needs to be replaced with type_vector, too
|
||||
using _all_provided_aggregates = detail::make_joined_set_t<provided_aggregates_of<Policies>...>;
|
||||
|
||||
using _required_tables_of = detail::copy_if_t<_all_required_tables, _all_provided_tables::template contains_not>;
|
||||
using _required_ctes_of = detail::copy_if_t<_all_required_ctes, _all_provided_ctes::template contains_not>;
|
||||
|
||||
template <typename Expression>
|
||||
static constexpr bool _no_unknown_tables = _all_provided_tables::template contains_all<required_tables_of_t<Expression>>::value;
|
||||
@ -110,12 +112,6 @@ namespace sqlpp
|
||||
template <template <typename> class Predicate>
|
||||
using any_t = logic::any<Predicate<Policies>::value...>;
|
||||
|
||||
// The tables not covered by the from.
|
||||
//using _required_tables = detail::make_difference_set_t<_all_required_tables, _all_provided_tables>;
|
||||
|
||||
// The common table expressions not covered by the with.
|
||||
using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>;
|
||||
|
||||
using _result_type_provider = detail::get_last_if_t<is_result_clause, noop, Policies...>;
|
||||
|
||||
struct _result_methods_t : public _result_type_provider::template _result_methods_t<_statement_t>
|
||||
@ -127,9 +123,8 @@ namespace sqlpp
|
||||
// - the select is complete (leaks no table requirements or cte requirements)
|
||||
static constexpr bool _can_be_used_as_table()
|
||||
{
|
||||
#warning: reactivate
|
||||
return has_result_row<_statement_t>::value and /*_required_tables::size::value == 0 and*/
|
||||
_required_ctes::size::value == 0;
|
||||
return has_result_row<_statement_t>::value and _required_tables_of::empty() == 0 and
|
||||
_required_ctes_of::empty();
|
||||
}
|
||||
|
||||
using _value_type =
|
||||
@ -149,10 +144,9 @@ namespace sqlpp
|
||||
// required_tables and _required_ctes are defined above
|
||||
|
||||
using _cte_check =
|
||||
typename std::conditional<_required_ctes::size::value == 0, consistent_t, assert_no_unknown_ctes_t>::type;
|
||||
#warning: reactivate
|
||||
using _table_check = consistent_t;
|
||||
//typename std::conditional<_required_tables::size::value == 0, consistent_t, assert_no_unknown_tables_t>::type;
|
||||
typename std::conditional<_required_ctes_of::empty() == 0, 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::
|
||||
conditional<_parameters::empty(), consistent_t, assert_no_parameters_t>::type;
|
||||
};
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sqlpp11/core/type_traits/nodes_of.h>
|
||||
#include <sqlpp11/core/type_traits/optional.h>
|
||||
#include <sqlpp11/core/type_traits/value_type.h>
|
||||
#include <sqlpp11/core/type_traits/ctes_of.h>
|
||||
#include <sqlpp11/core/type_traits/tables_of.h>
|
||||
|
||||
namespace sqlpp
|
||||
@ -288,8 +289,6 @@ namespace sqlpp
|
||||
template <typename T> \
|
||||
using trait##_of = typename detail::trait##_of_impl<T>::type;
|
||||
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(required_ctes)
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_ctes)
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates)
|
||||
|
||||
template <typename T>
|
||||
|
107
include/sqlpp11/core/type_traits/ctes_of.h
Normal file
107
include/sqlpp11/core/type_traits/ctes_of.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024, Roland Bock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sqlpp11/core/type_traits/nodes_of.h>
|
||||
#include <sqlpp11/core/detail/type_vector.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
// required_ctes_of determines the type_vector of ctes referenced by columns within within T.
|
||||
// column_t or other structs that might reference a table shall specialize this template to indicate their table
|
||||
// requirement.
|
||||
// Dynamic parts of a query shall wrap their required ctes in dynamic_t.
|
||||
template<typename T>
|
||||
struct required_ctes_of
|
||||
{
|
||||
using type = typename required_ctes_of<nodes_of_t<T>>::type;
|
||||
};
|
||||
|
||||
template<typename... T>
|
||||
struct required_ctes_of<detail::type_vector<T...>>
|
||||
{
|
||||
using type = detail::type_vector_cat_t<typename required_ctes_of<T>::type...>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using required_ctes_of_t = typename required_ctes_of<T>::type;
|
||||
|
||||
template<typename T>
|
||||
struct required_static_ctes_of
|
||||
{
|
||||
using type = typename required_static_ctes_of<nodes_of_t<T>>::type;
|
||||
};
|
||||
|
||||
template<typename... T>
|
||||
struct required_static_ctes_of<detail::type_vector<T...>>
|
||||
{
|
||||
using type = detail::type_vector_cat_t<typename required_static_ctes_of<T>::type...>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using required_static_ctes_of_t = typename required_static_ctes_of<T>::type;
|
||||
|
||||
#warning: need type tests...
|
||||
//static_assert(required_ctes_of_t<int>::size::value == 0, "");
|
||||
|
||||
// provided_ctes_of determines the type_vector of ctes provided by the query clause, e.g. by FROM.
|
||||
// Provided ctes can be wrapped in dynamic_t if they are provided through a dynamic join.
|
||||
// table_t, cte_ref_t, or other structs that might provide a table in a query need to specialize this template.
|
||||
template <typename T>
|
||||
struct provided_ctes_of
|
||||
{
|
||||
using type = typename provided_ctes_of<nodes_of_t<T>>::type;
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
struct provided_ctes_of<detail::type_vector<T...>>
|
||||
{
|
||||
using type = detail::type_vector_cat_t<typename provided_ctes_of<T>::type...>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using provided_ctes_of_t = typename provided_ctes_of<T>::type;
|
||||
|
||||
template <typename T>
|
||||
struct provided_static_ctes_of
|
||||
{
|
||||
using type = typename provided_static_ctes_of<nodes_of_t<T>>::type;
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
struct provided_static_ctes_of<detail::type_vector<T...>>
|
||||
{
|
||||
using type = detail::type_vector_cat_t<typename provided_static_ctes_of<T>::type...>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using provided_static_ctes_of_t = typename provided_static_ctes_of<T>::type;
|
||||
|
||||
static_assert(provided_ctes_of_t<int>::empty(), "");
|
||||
|
||||
} // namespace sqlpp
|
||||
|
@ -53,8 +53,36 @@ int main(int, char* [])
|
||||
{
|
||||
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));
|
||||
#warning: Remove debug code.
|
||||
/*
|
||||
using Lhs = sqlpp::statement_t<sqlpp::no_with_t, sqlpp::select_t, sqlpp::no_select_flag_list_t,
|
||||
sqlpp::select_column_list_t<sqlpp::expression_as<sqlpp::value_t<int>, sqlpp::alias::a_t>>,
|
||||
sqlpp::no_from_t, sqlpp::no_where_t<true>, sqlpp::no_group_by_t, sqlpp::no_having_t,
|
||||
sqlpp::no_order_by_t, sqlpp::no_limit_t, sqlpp::no_offset_t, sqlpp::no_union_t,
|
||||
sqlpp::no_for_update_t>;
|
||||
using Rhs = sqlpp::statement_t<
|
||||
sqlpp::no_with_t, sqlpp::select_t, sqlpp::no_select_flag_list_t,
|
||||
sqlpp::select_column_list_t<sqlpp::expression_as<
|
||||
sqlpp::arithmetic_expression<
|
||||
sqlpp::column_t<sqlpp::cte_ref_t<sqlpp::alias::x_t>,
|
||||
sqlpp::field_spec_t<sqlpp::alias::a_t::_sqlpp_name_tag, sqlpp::integral>>,
|
||||
sqlpp::plus, int>,
|
||||
sqlpp::alias::a_t>>,
|
||||
sqlpp::from_t<sqlpp::cte_ref_t<sqlpp::alias::x_t>>,
|
||||
sqlpp::where_t<sqlpp::comparison_expression<
|
||||
sqlpp::column_t<sqlpp::cte_ref_t<sqlpp::alias::x_t>,
|
||||
sqlpp::field_spec_t<sqlpp::alias::a_t::_sqlpp_name_tag, sqlpp::integral>>,
|
||||
sqlpp::less, int>>,
|
||||
sqlpp::no_group_by_t, sqlpp::no_having_t, sqlpp::no_order_by_t, sqlpp::no_limit_t, sqlpp::no_offset_t,
|
||||
sqlpp::no_union_t, sqlpp::no_for_update_t>;
|
||||
//sqlpp::required_ctes_of_t<Rhs>::hansi;
|
||||
using U = sqlpp::cte_union_t<
|
||||
sqlpp::all_t, Lhs, Rhs>;
|
||||
|
||||
using X = typename std::decay<decltype(x)>::type;
|
||||
//X::hansi;
|
||||
static_assert(X::_is_recursive, "");
|
||||
*/
|
||||
#warning: Need to test that recursive CTEs are detected as being recursive.
|
||||
SQLPP_COMPARE(with(x), "WITH RECURSIVE x AS (SELECT 0 AS a UNION ALL SELECT (x.a + 1) AS a FROM x WHERE x.a < 10) ");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user