From 73097e989f063871eb876a1aa15ede0a6e30860c Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 11 Feb 2015 19:06:16 +0100 Subject: [PATCH] Mapping ctes to cte_references when used in from, helping with serialization --- include/sqlpp11/cte.h | 52 +++++++++++++++++++++++++---------- include/sqlpp11/from.h | 11 ++++---- include/sqlpp11/table_ref.h | 55 +++++++++++++++++++++++++++++++++++++ include/sqlpp11/with.h | 3 ++ tests/WithTest.cpp | 5 ++++ 5 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 include/sqlpp11/table_ref.h diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h index 76aa337e..d1c3432f 100644 --- a/include/sqlpp11/cte.h +++ b/include/sqlpp11/cte.h @@ -27,6 +27,7 @@ #ifndef SQLPP_CTE_H #define SQLPP_CTE_H +#include #include #include #include @@ -40,9 +41,25 @@ namespace sqlpp { - template + template struct cte_t; + template + struct cte_ref_t; + + template + auto from_table(cte_t t) -> cte_ref_t + { + return cte_ref_t{}; + } + + template + struct from_table_impl> + { + using type = cte_ref_t; + }; + + template struct cte_column_spec_t { @@ -64,13 +81,19 @@ namespace sqlpp template struct make_cte_impl> { - using type = cte_t; + using type = cte_t; }; template using make_cte_t = typename make_cte_impl>::type; - template + template + struct cte_union_is_recursive + { + static constexpr bool value = Lhs or detail::is_element_of>::value; + }; + + template struct cte_t: public member_t, column_t>>... { using _traits = make_traits; // FIXME: is table? really? @@ -86,6 +109,7 @@ namespace sqlpp using _tags = detail::type_set<>; }; using _alias_t = typename AliasProvider::_alias_t; + constexpr static bool _is_recursive = Recursive; using _column_tuple_t = std::tuple>...>; @@ -94,7 +118,7 @@ namespace sqlpp template auto union_distinct(Rhs rhs) const - -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type + -> typename std::conditional<_check::value, cte_t::value, union_data_t, FieldSpecs...>, bad_statement>::type { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); @@ -108,7 +132,7 @@ namespace sqlpp template auto union_all(Rhs rhs) const - -> typename std::conditional<_check::value, cte_t, FieldSpecs...>, bad_statement>::type + -> typename std::conditional<_check::value, cte_t::value, union_data_t, FieldSpecs...>, bad_statement>::type { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); @@ -127,7 +151,7 @@ namespace sqlpp template auto _union_impl(const std::true_type&, Rhs rhs) const - -> cte_t, FieldSpecs...> + -> cte_t::value, union_data_t, FieldSpecs...> { return union_data_t{_statement, rhs}; } @@ -144,11 +168,11 @@ namespace sqlpp Statement _statement; }; - template - struct serializer_t> + template + struct serializer_t> { using _serialize_check = serialize_check_of; - using T = cte_t; + using T = cte_t; static Context& _(const T& t, Context& context) { @@ -165,9 +189,9 @@ namespace sqlpp // AliasProviderName AS (ColumnNames) (select/union) // The result row of the select should not have dynamic parts template - struct pre_cte_t + struct cte_ref_t { - using _traits = make_traits; // FIXME: is table? really? + using _traits = make_traits; // FIXME: is table? really? struct _recursive_traits { using _required_ctes = detail::make_type_set_t; @@ -195,10 +219,10 @@ namespace sqlpp }; template - struct serializer_t> + struct serializer_t> { using _serialize_check = consistent_t; - using T = pre_cte_t; + using T = cte_ref_t; static Context& _(const T& t, Context& context) { @@ -209,7 +233,7 @@ namespace sqlpp template auto cte(const AliasProvider&) - -> pre_cte_t + -> cte_ref_t { return {}; } diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index bbe7d939..37f5b68a 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -27,6 +27,7 @@ #ifndef SQLPP_FROM_H #define SQLPP_FROM_H +#include #include #include #include @@ -90,7 +91,7 @@ namespace sqlpp template void _add_impl(Table table, const std::true_type&) { - return _data._dynamic_tables.emplace_back(table); + return _data._dynamic_tables.emplace_back(from_table(table)); } template @@ -164,7 +165,7 @@ namespace sqlpp template auto from(Tables... tables) const - -> _new_statement_t<_check, from_t> + -> _new_statement_t<_check, from_t...>> { static_assert(_check::value, "at least one argument is not a table or join in from()"); static_assert(sizeof...(Tables), "at least one table or join argument required in from()"); @@ -173,7 +174,7 @@ namespace sqlpp template auto dynamic_from(Tables... tables) const - -> _new_statement_t<_check, from_t<_database_t, Tables...>> + -> _new_statement_t<_check, from_t<_database_t, from_table_t...>> { static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement"); static_assert(_check::value, "at least one argument is not a table or join in from()"); @@ -187,7 +188,7 @@ namespace sqlpp template auto _from_impl(const std::true_type&, Tables... tables) const - -> _new_statement_t> + -> _new_statement_t...>> { static_assert(required_tables_of>::size::value == 0, "at least one table depends on another table in from()"); @@ -197,7 +198,7 @@ namespace sqlpp static_assert(_number_of_tables == _unique_tables::size::value, "at least one duplicate table detected in from()"); static_assert(_number_of_tables == _unique_table_names::size::value, "at least one duplicate table name detected in from()"); - return { static_cast&>(*this), from_data_t{tables...} }; + return { static_cast&>(*this), from_data_t...>{from_table(tables)...} }; } }; diff --git a/include/sqlpp11/table_ref.h b/include/sqlpp11/table_ref.h new file mode 100644 index 00000000..58211093 --- /dev/null +++ b/include/sqlpp11/table_ref.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013-2014, 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. + */ + +#ifndef SQLPP_TABLE_REF_H +#define SQLPP_TABLE_REF_H + +#include + +namespace sqlpp +{ + template + auto from_table(T t) -> T + { + return t; + } + + template + struct from_table_impl + { + using type = T; + }; + template + using from_table_t = typename from_table_impl::type; + + template + auto table_ref(T t) -> T + { + return t; + } +} + +#endif diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h index fe3d7bda..7f696567 100644 --- a/include/sqlpp11/with.h +++ b/include/sqlpp11/with.h @@ -176,6 +176,7 @@ namespace sqlpp if (T::_is_recursive::value) context << "RECURSIVE "; interpret_tuple(t._expressions, ',', context); + context << ' '; return context; } }; @@ -184,6 +185,8 @@ namespace sqlpp auto with(Expressions... cte) -> blank_with_t { + static_assert(logic::all_t::value...>::value, "at least one expression in with is not a common table expression"); + static_assert(logic::none_t::value...>::value, "at least one expression in with is an incomplete common table expression"); return { {cte...} }; } } diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp index f6bd4006..1ee5cd14 100644 --- a/tests/WithTest.cpp +++ b/tests/WithTest.cpp @@ -43,5 +43,10 @@ int main() auto y0 = cte(sqlpp::y).as(select(all_of(t)).from(t)); auto y = y0.union_all(select(all_of(y0)).from(y0).where(false)); + std::cout << serialize(y, printer).str() << std::endl; printer.reset(); + std::cout << serialize(from_table(y), printer).str() << std::endl; + + db(with(y)(select(y.alpha).from(y).where(true))); + return 0; }