From 92e670118a63327f0b9190044158d66a02ea93cf Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 13 Jan 2015 21:53:29 +0100 Subject: [PATCH] Started to add common table expressions and 'with' --- include/sqlpp11/column.h | 6 +- include/sqlpp11/count.h | 2 + include/sqlpp11/cte.h | 61 ++++++++++ include/sqlpp11/extra_tables.h | 4 +- include/sqlpp11/join.h | 2 + include/sqlpp11/parameter.h | 6 +- include/sqlpp11/result_field_methods.h | 6 +- include/sqlpp11/select.h | 2 + include/sqlpp11/statement.h | 33 +++++- include/sqlpp11/table.h | 4 +- include/sqlpp11/table_alias.h | 4 +- include/sqlpp11/type_traits.h | 10 ++ include/sqlpp11/union.h | 3 +- include/sqlpp11/with.h | 158 +++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/WithTest.cpp | 40 +++++++ 16 files changed, 329 insertions(+), 13 deletions(-) create mode 100644 include/sqlpp11/cte.h create mode 100644 include/sqlpp11/with.h create mode 100644 tests/WithTest.cpp diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 82d34183..83468e5b 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -54,11 +54,13 @@ namespace sqlpp struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = detail::type_set<>; + using _provided_ctes = detail::type_set<>; + using _required_tables = detail::type_set; using _provided_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set
; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = typename std::conditional::value, detail::type_set, detail::type_set<>>::type; diff --git a/include/sqlpp11/count.h b/include/sqlpp11/count.h index ffe74bc4..1403aa8b 100644 --- a/include/sqlpp11/count.h +++ b/include/sqlpp11/count.h @@ -41,6 +41,8 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { + using _required_ctes = required_ctes_of; + using _provided_ctes = detail::type_set<>; using _required_tables = required_tables_of; using _provided_tables = provided_tables_of; using _provided_outer_tables = provided_outer_tables_of; diff --git a/include/sqlpp11/cte.h b/include/sqlpp11/cte.h new file mode 100644 index 00000000..af31e09a --- /dev/null +++ b/include/sqlpp11/cte.h @@ -0,0 +1,61 @@ +/* + * 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_CTE_H +#define SQLPP_CTE_H + +#include +#include +#include +#include +#include +#include +#include + +namespace sqlpp +{ + template + struct pre_cte_t + { + template + auto as(Statement statement) + -> cte + { + // FIXME: Need to check stuff here. + return { statement }; + } + }; + + template + auto cte(const AliasProvider&) + -> pre_cte_t + { + return {}; + } + +} + +#endif diff --git a/include/sqlpp11/extra_tables.h b/include/sqlpp11/extra_tables.h index 884e1946..cd4e1068 100644 --- a/include/sqlpp11/extra_tables.h +++ b/include/sqlpp11/extra_tables.h @@ -54,11 +54,13 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = detail::make_joined_set_t...>; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; using _provided_tables = detail::type_set<>; using _extra_tables = detail::type_set; + using _parameters = std::tuple<>; using _tags = detail::type_set<>; }; diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 99dbcdd0..e4dcb97f 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -68,6 +68,8 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { + using _required_ctes = detail::make_joined_set_t, required_ctes_of>; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::make_joined_set_t, required_tables_of>; using _provided_tables = detail::make_joined_set_t, provided_tables_of>; using _provided_outer_tables = typename JoinType::template _provided_outer_tables; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index b5daaabc..542a5cb1 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -40,11 +40,13 @@ namespace sqlpp using _traits = make_traits; struct _recursive_traits { - using _parameters = std::tuple; + using _required_ctes = detail::type_set<>; + using _provided_ctes = detail::type_set<>; + using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple; using _tags = detail::type_set; }; diff --git a/include/sqlpp11/result_field_methods.h b/include/sqlpp11/result_field_methods.h index 5829ba91..4ab50af9 100644 --- a/include/sqlpp11/result_field_methods.h +++ b/include/sqlpp11/result_field_methods.h @@ -83,11 +83,13 @@ namespace sqlpp struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = detail::type_set<>; + using _provided_ctes = detail::type_set<>; + using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = typename std::conditional::value, detail::type_set, detail::type_set<>>::type; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index b663c7d4..89506245 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -69,6 +70,7 @@ namespace sqlpp template using blank_select_t = statement_t struct statement_t; + struct assert_no_unknown_ctes_t + { + using type = std::false_type; + + template + static void _() + { + static_assert(wrong_t::value, "one clause requires common table expressions which are otherwise not known in the statement"); + } + }; + struct assert_no_unknown_tables_t { using type = std::false_type; @@ -84,6 +95,8 @@ namespace sqlpp template using _new_statement_t = typename _policies_update_t::type; + using _all_required_ctes = detail::make_joined_set_t...>; + using _all_provided_ctes = detail::make_joined_set_t...>; using _all_required_tables = detail::make_joined_set_t...>; using _all_provided_tables = detail::make_joined_set_t...>; using _all_provided_outer_tables = detail::make_joined_set_t...>; @@ -100,6 +113,12 @@ namespace sqlpp _all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*() >; + // 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; struct _result_methods_t: public _result_type_provider::template _result_methods_t<_statement_t> @@ -111,7 +130,9 @@ namespace sqlpp // - the select is complete (leaks no tables) static constexpr bool _can_be_used_as_table() { - return is_select_column_list_t<_result_type_provider>::value and _required_tables::size::value == 0 + return is_select_column_list_t<_result_type_provider>::value + and _required_tables::size::value == 0 + and _required_ctes::size::value == 0 ? true : false; } @@ -133,6 +154,8 @@ namespace sqlpp struct _recursive_traits { + using _required_ctes = statement_policies_t::_required_ctes; + using _provided_ctes = detail::type_set<>; using _required_tables = statement_policies_t::_required_tables; using _provided_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; @@ -143,6 +166,8 @@ namespace sqlpp detail::type_set<>>::type; }; + using _cte_check = typename std::conditional<_required_ctes::size::value == 0, + consistent_t, assert_no_unknown_ctes_t>::type; using _table_check = typename std::conditional<_required_tables::size::value == 0, consistent_t, assert_no_unknown_tables_t>::type; using _parameter_check = typename std::conditional::value == 0, @@ -161,10 +186,12 @@ namespace sqlpp using _run_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check>; + typename _policies_t::_table_check, + typename _policies_t::_cte_check>; using _prepare_check = detail::get_first_if::_consistency_check..., - typename _policies_t::_table_check>; + typename _policies_t::_table_check, + typename _policies_t::_cte_check>; using _result_type_provider = typename _policies_t::_result_type_provider; template diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index b7bd5065..e5e6549c 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -48,11 +48,13 @@ namespace sqlpp struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = detail::type_set<>; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set
; using _provided_outer_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = detail::type_set<>; }; diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index e7befef0..4985a875 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -44,11 +44,13 @@ namespace sqlpp struct _recursive_traits { - using _parameters = std::tuple<>; + using _required_ctes = required_ctes_of
; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set; using _provided_outer_tables = detail::type_set<>; using _extra_tables = detail::type_set<>; + using _parameters = std::tuple<>; using _tags = detail::type_set<>; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 04ffc42a..4cf352ec 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -183,6 +183,12 @@ namespace sqlpp template using cpp_value_type_of = typename value_type_of::_cpp_value_type; + template + using required_ctes_of = typename T::_recursive_traits::_required_ctes; + + template + using provided_ctes_of = typename T::_recursive_traits::_provided_ctes; + template using required_tables_of = typename T::_recursive_traits::_required_tables; @@ -217,6 +223,8 @@ namespace sqlpp template struct make_recursive_traits { + using _required_ctes = detail::make_joined_set_t...>; + using _provided_ctes = detail::make_joined_set_t...>; using _required_tables = detail::make_joined_set_t...>; using _provided_tables = detail::make_joined_set_t...>; using _provided_outer_tables = detail::make_joined_set_t...>; @@ -228,6 +236,8 @@ namespace sqlpp template struct recursive_tags { + using _required_ctes = detail::type_set<>; + using _provided_ctes = detail::type_set<>; using _required_tables = detail::type_set<>; using _provided_tables = detail::type_set<>; using _provided_outer_tables = detail::type_set<>; diff --git a/include/sqlpp11/union.h b/include/sqlpp11/union.h index 615321dc..56559421 100644 --- a/include/sqlpp11/union.h +++ b/include/sqlpp11/union.h @@ -83,7 +83,7 @@ namespace sqlpp template struct union_statement_impl { - using type = statement_t; + using type = statement_t; }; template @@ -208,6 +208,7 @@ namespace sqlpp auto union_distinct(Rhs rhs) const -> _new_statement_t<_check, union_t, Rhs>> { +#warning: make sure that Rhs is a select, not a uninon static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_result_row_t::value, "argument of a union has to be a (complete) select statement"); static_assert(has_result_row_t>::value, "left hand side argument of a union has to be a (complete) select statement"); diff --git a/include/sqlpp11/with.h b/include/sqlpp11/with.h new file mode 100644 index 00000000..4811c8d7 --- /dev/null +++ b/include/sqlpp11/with.h @@ -0,0 +1,158 @@ +/* + * 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_WITH_H +#define SQLPP_WITH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sqlpp +{ + template + struct with_data_t + { + with_data_t(Expressions... expressions): + _expressions(expressions...) + {} + + with_data_t(const with_data_t&) = default; + with_data_t(with_data_t&&) = default; + with_data_t& operator=(const with_data_t&) = default; + with_data_t& operator=(with_data_t&&) = default; + ~with_data_t() = default; + + std::tuple _expressions; + interpretable_list_t _dynamic_expressions; + }; + + template + struct with_t + { + using _traits = make_traits; + using _recursive_traits = make_recursive_traits; + + using _is_dynamic = is_database; + + // Data + using _data_t = with_data_t; + + // Member implementation with data and methods + template + struct _impl_t + { + public: + _data_t _data; + }; + + // Base template to be inherited by the statement + template + struct _base_t + { + using _data_t = with_data_t; + + _impl_t where; + _impl_t& operator()() { return where; } + const _impl_t& operator()() const { return where; } + + template + static auto _get_member(T t) -> decltype(t.where) + { + return t.where; + } + +#warning: Need real checks here + using _consistency_check = consistent_t; + }; + }; + + + struct no_with_t + { + using _traits = make_traits; + using _recursive_traits = make_recursive_traits<>; + + // Data + using _data_t = no_data_t; + + // Member implementation with data and methods + template + struct _impl_t + { + _data_t _data; + }; + + // Base template to be inherited by the statement + template + struct _base_t + { + using _data_t = no_data_t; + + _impl_t no_with; + _impl_t& operator()() { return no_with; } + const _impl_t& operator()() const { return no_with; } + + template + static auto _get_member(T t) -> decltype(t.no_with) + { + return t.no_with; + } + + using _consistency_check = consistent_t; + + }; + }; + + template + struct blank_with_t + { + with_data_t _data; + + template + auto operator()(Statement statement) + -> new_statement_t> + { + // FIXME need checks here, e.g. if there is recursion + return { statement, _data }; + } + }; + + template + auto with(Expressions... cte) + -> blank_with_t + { + return { {cte...} }; + } +} + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f3127acf..74505083 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,7 @@ endmacro () #build_and_run(Minimalistic) #build_and_run(ResultTest) build_and_run(UnionTest) +build_and_run(WithTest) # if you want to use the generator, you can do something like this: #find_package(PythonInterp REQUIRED) diff --git a/tests/WithTest.cpp b/tests/WithTest.cpp new file mode 100644 index 00000000..6932966e --- /dev/null +++ b/tests/WithTest.cpp @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#include "Sample.h" +#include "MockDb.h" +#include +#include +#include + +MockDb db; +MockDb::_serializer_context_t printer; + +int main() +{ + // to be done + + return 0; +}