mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 12:51:13 +08:00
Add more cte tests
This commit is contained in:
parent
fef1c3e426
commit
dc53fd5acc
@ -33,12 +33,12 @@
|
|||||||
|
|
||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
|
#warning: It would be sufficient to store the NameTag here, not the whole NameTagProvider
|
||||||
template <typename ValueType, typename NameType>
|
template <typename ValueType, typename NameType>
|
||||||
struct parameter_t : public enable_comparison<parameter_t<ValueType, NameType>>
|
struct parameter_t : public enable_comparison<parameter_t<ValueType, NameType>>
|
||||||
{
|
{
|
||||||
using _traits = make_traits<ValueType, tag::is_parameter, tag::is_expression>;
|
using _traits = make_traits<ValueType, tag::is_parameter, tag::is_expression>;
|
||||||
|
|
||||||
using _parameters = detail::type_vector<parameter_t>;
|
|
||||||
using _is_literal_expression = std::true_type;
|
using _is_literal_expression = std::true_type;
|
||||||
|
|
||||||
using _instance_t = member_t<NameType, parameter_value_t<ValueType>>;
|
using _instance_t = member_t<NameType, parameter_value_t<ValueType>>;
|
||||||
@ -52,6 +52,12 @@ namespace sqlpp
|
|||||||
~parameter_t() = default;
|
~parameter_t() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename ValueType, typename NameType>
|
||||||
|
struct parameters_of<parameter_t<ValueType, NameType>>
|
||||||
|
{
|
||||||
|
using type = detail::type_vector<parameter_t<ValueType, NameType>>;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename ValueType, typename NameType>
|
template<typename ValueType, typename NameType>
|
||||||
struct value_type_of<parameter_t<ValueType, NameType>>
|
struct value_type_of<parameter_t<ValueType, NameType>>
|
||||||
{
|
{
|
||||||
|
@ -40,8 +40,6 @@ namespace sqlpp
|
|||||||
template <typename Flag, typename Lhs, typename Rhs>
|
template <typename Flag, typename Lhs, typename Rhs>
|
||||||
struct cte_union_t
|
struct cte_union_t
|
||||||
{
|
{
|
||||||
using _parameters = detail::type_vector_cat_t<parameters_of<Lhs>, parameters_of<Rhs>>;
|
|
||||||
|
|
||||||
cte_union_t(Lhs lhs, Rhs rhs) : _lhs(lhs), _rhs(rhs)
|
cte_union_t(Lhs lhs, Rhs rhs) : _lhs(lhs), _rhs(rhs)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -303,9 +301,6 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename NameTagProvider>
|
|
||||||
struct is_table<cte_ref_t<NameTagProvider>> : public std::true_type{};
|
|
||||||
|
|
||||||
template<typename NameTagProvider>
|
template<typename NameTagProvider>
|
||||||
struct name_tag_of<cte_ref_t<NameTagProvider>> : public name_tag_of<NameTagProvider>
|
struct name_tag_of<cte_ref_t<NameTagProvider>> : public name_tag_of<NameTagProvider>
|
||||||
{};
|
{};
|
||||||
|
@ -62,7 +62,7 @@ namespace sqlpp
|
|||||||
using _nodes = detail::type_vector<>;
|
using _nodes = detail::type_vector<>;
|
||||||
using _provided_ctes =
|
using _provided_ctes =
|
||||||
detail::make_joined_set_t<required_ctes_of<Expressions>...>; // WITH provides common table expressions
|
detail::make_joined_set_t<required_ctes_of<Expressions>...>; // WITH provides common table expressions
|
||||||
using _parameters = detail::type_vector_cat_t<parameters_of<Expressions>...>;
|
using _parameters = detail::type_vector_cat_t<parameters_of_t<Expressions>...>;
|
||||||
|
|
||||||
using _data_t = with_data_t<Expressions...>;
|
using _data_t = with_data_t<Expressions...>;
|
||||||
|
|
||||||
@ -80,6 +80,7 @@ namespace sqlpp
|
|||||||
using _consistency_check = consistent_t;
|
using _consistency_check = consistent_t;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
#warning: Need traits here! And type tests for them
|
||||||
|
|
||||||
struct no_with_t
|
struct no_with_t
|
||||||
{
|
{
|
||||||
|
@ -64,6 +64,7 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#warning: Why would we need this?
|
||||||
template <typename Exp>
|
template <typename Exp>
|
||||||
using make_parameter_list_t = parameter_list_t<parameters_of<Exp>>;
|
using make_parameter_list_t = parameter_list_t<parameters_of_t<Exp>>;
|
||||||
} // namespace sqlpp
|
} // namespace sqlpp
|
||||||
|
@ -69,7 +69,7 @@ namespace sqlpp
|
|||||||
using _nodes = detail::type_vector<Parts...>;
|
using _nodes = detail::type_vector<Parts...>;
|
||||||
|
|
||||||
using _parameter_check =
|
using _parameter_check =
|
||||||
typename std::conditional<parameters_of<custom_query_t>::empty(),
|
typename std::conditional<parameters_of_t<custom_query_t>::empty(),
|
||||||
consistent_t,
|
consistent_t,
|
||||||
assert_no_parameters_t>::type;
|
assert_no_parameters_t>::type;
|
||||||
using _run_check = detail::get_first_if<is_inconsistent_t, consistent_t, _parameter_check>;
|
using _run_check = detail::get_first_if<is_inconsistent_t, consistent_t, _parameter_check>;
|
||||||
|
@ -123,7 +123,7 @@ namespace sqlpp
|
|||||||
// - the select is complete (leaks no table requirements or cte requirements)
|
// - the select is complete (leaks no table requirements or cte requirements)
|
||||||
static constexpr bool _can_be_used_as_table()
|
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();
|
_required_ctes_of::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +140,11 @@ namespace sqlpp
|
|||||||
detail::make_intersect_set_t<required_tables_of_t<_result_type_provider>,
|
detail::make_intersect_set_t<required_tables_of_t<_result_type_provider>,
|
||||||
_all_provided_optional_tables>::size::value != 0>;
|
_all_provided_optional_tables>::size::value != 0>;
|
||||||
*/
|
*/
|
||||||
using _parameters = detail::type_vector_cat_t<parameters_of<Policies>...>;
|
using _parameters = detail::type_vector_cat_t<parameters_of_t<Policies>...>;
|
||||||
// required_tables and _required_ctes are defined above
|
// required_tables and _required_ctes are defined above
|
||||||
|
|
||||||
using _cte_check =
|
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 =
|
using _table_check =
|
||||||
typename std::conditional<_required_tables_of::empty(), consistent_t, assert_no_unknown_tables_t>::type;
|
typename std::conditional<_required_tables_of::empty(), consistent_t, assert_no_unknown_tables_t>::type;
|
||||||
using _parameter_check = typename std::
|
using _parameter_check = typename std::
|
||||||
|
@ -404,26 +404,20 @@ namespace sqlpp
|
|||||||
template <typename KnownAggregates, typename T>
|
template <typename KnownAggregates, typename T>
|
||||||
using is_non_aggregate_expression_t = typename detail::is_non_aggregate_expression_impl<KnownAggregates, T>::type;
|
using is_non_aggregate_expression_t = typename detail::is_non_aggregate_expression_impl<KnownAggregates, T>::type;
|
||||||
|
|
||||||
namespace detail
|
template<typename T>
|
||||||
|
struct parameters_of
|
||||||
{
|
{
|
||||||
template <typename T, typename Leaf = void>
|
using type = typename parameters_of<nodes_of_t<T>>::type;
|
||||||
struct parameters_of_impl
|
|
||||||
{
|
|
||||||
using type = typename parameters_of_impl<nodes_of_t<T>>::type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
struct parameters_of<detail::type_vector<T...>>
|
||||||
|
{
|
||||||
|
using type = detail::type_vector_cat_t<typename parameters_of<T>::type...>;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct parameters_of_impl<T, typename std::enable_if<std::is_class<typename T::_parameters>::value>::type>
|
using parameters_of_t = typename parameters_of<T>::type;
|
||||||
{
|
|
||||||
using type = typename T::_parameters;
|
|
||||||
};
|
|
||||||
template <typename... Nodes>
|
|
||||||
struct parameters_of_impl<type_vector<Nodes...>, void>
|
|
||||||
{
|
|
||||||
using type = detail::type_vector_cat_t<typename parameters_of_impl<Nodes>::type...>;
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
template <typename T>
|
|
||||||
using parameters_of = typename detail::parameters_of_impl<T>::type;
|
|
||||||
|
|
||||||
// Something that can be used as a table
|
// Something that can be used as a table
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -31,21 +31,68 @@ void test_cte()
|
|||||||
const auto foo = test::TabFoo{};
|
const auto foo = test::TabFoo{};
|
||||||
const auto bar = test::TabBar{};
|
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
|
// Simple CTE: X AS SELECT
|
||||||
{
|
{
|
||||||
auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally());
|
auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally());
|
||||||
auto a = x.as(sqlpp::alias::a);
|
auto a = x.as(sqlpp::alias::a);
|
||||||
|
|
||||||
using X = decltype(x);
|
using X = decltype(x);
|
||||||
using R = decltype(make_table_ref(x));
|
using RX = decltype(make_table_ref(x));
|
||||||
using A = decltype(a);
|
using A = decltype(a);
|
||||||
|
using RA = decltype(make_table_ref(a));
|
||||||
|
|
||||||
|
// CTE is used in WITH and in FROM
|
||||||
static_assert(sqlpp::is_cte<X>::value, "");
|
static_assert(sqlpp::is_cte<X>::value, "");
|
||||||
static_assert(not sqlpp::is_recursive_cte<X>::value, "");
|
static_assert(not sqlpp::is_recursive_cte<X>::value, "");
|
||||||
static_assert(sqlpp::is_table<X>::value, "");
|
static_assert(sqlpp::is_table<X>::value, "");
|
||||||
static_assert(sqlpp::required_ctes_of_t<X>::empty(), "");
|
static_assert(sqlpp::required_ctes_of_t<X>::empty(), "");
|
||||||
static_assert(std::is_same<sqlpp::provided_ctes_of_t<X>, sqlpp::detail::type_vector<R>>::value, "");
|
static_assert(std::is_same<sqlpp::provided_ctes_of_t<X>, sqlpp::detail::type_vector<RX>>::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<RX>::value, "");
|
||||||
|
static_assert(not sqlpp::is_table<RX>::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<A>::value, "");
|
||||||
|
static_assert(sqlpp::is_table<A>::value, "");
|
||||||
|
static_assert(std::is_same<A, RA>::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<X>::value, "");
|
||||||
|
static_assert(not sqlpp::is_recursive_cte<X>::value, "");
|
||||||
|
static_assert(sqlpp::is_table<X>::value, "");
|
||||||
|
static_assert(sqlpp::required_ctes_of_t<X>::empty(), "");
|
||||||
|
static_assert(std::is_same<sqlpp::provided_ctes_of_t<X>, sqlpp::detail::type_vector<RX>>::value, "");
|
||||||
|
static_assert(std::is_same<sqlpp::parameters_of_t<X>, sqlpp::detail::type_vector<P>>::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<RX>::value, "");
|
||||||
|
static_assert(not sqlpp::is_table<RX>::value, "");
|
||||||
|
static_assert(sqlpp::parameters_of_t<RX>::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<A>::value, "");
|
||||||
|
static_assert(sqlpp::is_table<A>::value, "");
|
||||||
|
static_assert(std::is_same<A, RA>::value, "");
|
||||||
|
static_assert(sqlpp::parameters_of_t<RA>::empty(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-recursive union CTE: X AS SELECT ... UNION ALL SELECT ...
|
// Non-recursive union CTE: X AS SELECT ... UNION ALL SELECT ...
|
||||||
|
@ -304,6 +304,8 @@ int main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#warning: Test with CTEs
|
||||||
|
|
||||||
int main(int, char* [])
|
int main(int, char* [])
|
||||||
{
|
{
|
||||||
single_table();
|
single_table();
|
||||||
|
Loading…
Reference in New Issue
Block a user