From 9c4832df0fac7e632a6ed01203a1a0c9bc50c0c4 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 7 Feb 2014 21:25:23 +0100 Subject: [PATCH 01/12] Switched remove to policy based design. A lot of sweating to figure out how to do it, but now it looks MUCH cleaner and it is probably a lot easier to extend :-) --- include/sqlpp11/remove.h | 154 ++++++++----------------- include/sqlpp11/vendor/crtp_wrapper.h | 57 +++++++++ include/sqlpp11/vendor/from.h | 85 +++++++++++--- include/sqlpp11/vendor/interpreter.h | 4 +- include/sqlpp11/vendor/policy.h | 62 ++++++++++ include/sqlpp11/vendor/policy_update.h | 59 ++++++++++ include/sqlpp11/vendor/using.h | 85 +++++++++++--- include/sqlpp11/vendor/where.h | 75 ++++++++++-- tests/CMakeLists.txt | 12 +- tests/InterpretTest.cpp | 6 +- 10 files changed, 447 insertions(+), 152 deletions(-) create mode 100644 include/sqlpp11/vendor/crtp_wrapper.h create mode 100644 include/sqlpp11/vendor/policy.h create mode 100644 include/sqlpp11/vendor/policy_update.h diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index 270ef9d9..68c2397d 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -31,107 +31,53 @@ #include #include #include +#include #include #include +#include +#include +#include namespace sqlpp { - template< - typename Database, - typename Table, - typename Using = vendor::noop, - typename Where = vendor::noop - > - struct remove_t; + namespace detail + { + template + struct check_remove_t + { + static_assert(is_where_t::value, "cannot run remove without having a where condition, use .where(true) to remove all rows"); + static constexpr bool value = true; + }; + } - template< - typename Database, - typename Table, - typename Using, - typename Where - > - struct remove_t + template + struct remove_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... { - static_assert(vendor::is_noop::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(vendor::is_noop::value or is_using_t::value, "invalid 'Using' argument"); - static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'Where' argument"); + template + using _policy_update_t = remove_t...>; - template - using set_using_t = remove_t; - template - using set_where_t = remove_t; - - using _parameter_tuple_t = std::tuple; + using _database_t = Database; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - template - auto using_(Tab... tab) - -> set_using_t> - { - static_assert(vendor::is_noop::value, "cannot call using() twice"); - static_assert(vendor::is_noop::value, "cannot call using() after where()"); - return { - _table, - {std::tuple{tab...}}, - _where - }; - } + remove_t() + {} - template - auto dynamic_using_(Tab... tab) - -> set_using_t> - { - static_assert(vendor::is_noop::value, "cannot call using() twice"); - static_assert(vendor::is_noop::value, "cannot call using() after where()"); - return { - _table, - {std::tuple{tab...}}, - _where - }; - } + template + remove_t(remove_t r, Whatever whatever): + vendor::policy_t(r, whatever)... + {} - template - remove_t& add_using_(Tab table) - { - static_assert(is_dynamic_t::value, "cannot call add_using() in a non-dynamic using"); - _using.add(table); + template + remove_t(Remove r, Whatever whatever): + vendor::policy_t(r, whatever)... + {} - return *this; - } - - template - auto where(Expr... expr) - -> set_where_t> - { - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _using, - {std::tuple{expr...}}, - }; - } - - template - auto dynamic_where(Expr... expr) - -> set_where_t> - { - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _using, - {std::tuple{expr...}}, - }; - } - - template - remove_t& add_where(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_where() in a non-dynamic where"); - - _where.add(expr); - - return *this; - } + remove_t(const remove_t& r) = default; + remove_t(remove_t&& r) = default; + remove_t& operator=(const remove_t& r) = default; + remove_t& operator=(remove_t&& r) = default; + ~remove_t() = default; static constexpr size_t _get_static_no_of_parameters() { @@ -147,33 +93,30 @@ namespace sqlpp std::size_t _run(Db& db) const { static_assert(_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead"); - static_assert(is_where_t::value, "cannot run update without having a where condition, use .where(true) to remove all rows"); + static_assert(detail::check_remove_t::value, "Cannot run this expression"); return db.remove(*this); } template auto _prepare(Db& db) const - -> prepared_remove_t + -> prepared_remove_t { + static_assert(detail::check_remove_t::value, "Cannot run this expression"); return {{}, db.prepare_remove(*this)}; } - - Table _table; - Using _using; - Where _where; }; namespace vendor { - template - struct interpreter_t> + template + struct interpreter_t> { - using T = remove_t; + using T = remove_t; static Context& _(const T& t, Context& context) { - context << "DELETE FROM "; - interpret(t._table, context); + context << "DELETE"; + interpret(t._from, context); interpret(t._using, context); interpret(t._where, context); return context; @@ -181,16 +124,19 @@ namespace sqlpp }; } + template + using blank_remove_t = remove_t; + template - constexpr remove_t remove_from(Table table) + constexpr remove_t, vendor::no_using_t, vendor::no_where_t> remove_from(Table table) { - return {table}; + return { blank_remove_t(), vendor::from_t{table} }; } - template - constexpr remove_t dynamic_remove_from(const Db&, Table table) + template + constexpr remove_t, vendor::no_using_t, vendor::no_where_t> dynamic_remove_from(const Database&, Table table) { - return {table}; + return { blank_remove_t(), vendor::from_t{table} }; } } diff --git a/include/sqlpp11/vendor/crtp_wrapper.h b/include/sqlpp11/vendor/crtp_wrapper.h new file mode 100644 index 00000000..47ef265a --- /dev/null +++ b/include/sqlpp11/vendor/crtp_wrapper.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 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_VENDOR_CRTP_WRAPPER_H +#define SQLPP_VENDOR_CRTP_WRAPPER_H + +#include + +namespace sqlpp +{ + namespace vendor + { + template + struct get_database_impl; + + template class Statement, typename Database, typename... Policies> + struct get_database_impl> + { + using type = Database; + }; + + template + using get_database_t = typename get_database_impl::type; + + template + struct crtp_wrapper_t + { + static_assert(wrong_t::value, "missing crtp policy specialization"); + }; + } + +} + +#endif diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index 11e8c999..0de1e217 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -32,56 +32,113 @@ #include #include #include +#include +#include namespace sqlpp { namespace vendor { - template + // FROM + template struct from_t { using _is_from = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - // ensure one argument at least - static_assert(_is_dynamic::value or sizeof...(TableOrJoin), "at least one table or join argument required in from()"); + static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table or join argument required in from()"); - // check for duplicate arguments - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in from()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in from()"); - // check for invalid arguments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a table or join in from()"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a table or join in from()"); // FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance + from_t(Tables... tables): + _tables(tables...) + {} + + from_t(const from_t&) = default; + from_t(from_t&&) = default; + from_t& operator=(const from_t&) = default; + from_t& operator=(from_t&&) = default; + ~from_t() = default; + template - void add(Table table) + void add_from(Table table) { + static_assert(_is_dynamic::value, "add_from can only be called for dynamic_from"); static_assert(is_table_t
::value, "from arguments require to be tables or joins"); _dynamic_tables.emplace_back(table); } - std::tuple _tables; + from_t& _from = *this; + std::tuple _tables; vendor::interpretable_list_t _dynamic_tables; }; - template - struct interpreter_t> + struct no_from_t + { + using _is_from = std::true_type; + no_from_t& _from = *this; + }; + + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = from_t; + }; + + template + struct crtp_wrapper_t + { + template + auto from(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), from_t(args...) }; + } + + template + auto dynamic_from(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_from must not be called in a static statement"); + return { static_cast(*this), from_t, Args...>(args...) }; + } + }; + + + // Interpreters + template + struct interpreter_t> + { + using T = from_t; static Context& _(const T& t, Context& context) { - if (sizeof...(TableOrJoin) == 0 and t._dynamic_tables.empty()) + if (sizeof...(Tables) == 0 and t._dynamic_tables.empty()) return context; context << " FROM "; interpret_tuple(t._tables, ',', context); - if (sizeof...(TableOrJoin) and not t._dynamic_tables.empty()) + if (sizeof...(Tables) and not t._dynamic_tables.empty()) context << ','; interpret_list(t._dynamic_tables, ',', context); return context; } }; + + template + struct interpreter_t + { + using T = no_from_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/interpreter.h b/include/sqlpp11/vendor/interpreter.h index 547d7ebd..43b4b625 100644 --- a/include/sqlpp11/vendor/interpreter.h +++ b/include/sqlpp11/vendor/interpreter.h @@ -24,8 +24,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_VENDOR_INTERPRET_H -#define SQLPP_VENDOR_INTERPRET_H +#ifndef SQLPP_VENDOR_INTERPRETER_H +#define SQLPP_VENDOR_INTERPRETER_H #include diff --git a/include/sqlpp11/vendor/policy.h b/include/sqlpp11/vendor/policy.h new file mode 100644 index 00000000..45edeeac --- /dev/null +++ b/include/sqlpp11/vendor/policy.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, 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_VENDOR_POLICY_H +#define SQLPP_VENDOR_POLICY_H + +#include + +namespace sqlpp +{ + namespace vendor + { + template + struct policy_t: public PolicyImpl + { + policy_t() + {} + + template + policy_t(const Whatever&, policy_t policy): + PolicyImpl(policy) + {} + + template + policy_t(const Whatever&, PolicyImpl impl): + PolicyImpl(impl) + {} + + template + policy_t(Derived derived, const Whatever&): + PolicyImpl(derived) + {} + }; + + } + +} + +#endif diff --git a/include/sqlpp11/vendor/policy_update.h b/include/sqlpp11/vendor/policy_update.h new file mode 100644 index 00000000..62f8fbcc --- /dev/null +++ b/include/sqlpp11/vendor/policy_update.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 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_VENDOR_POLICY_UPDATE_H +#define SQLPP_VENDOR_POLICY_UPDATE_H + +#include + +namespace sqlpp +{ + namespace vendor + { + template + struct policy_update_impl + { + template + using _policy_t = typename std::conditional::value, Replacement, T>::type; + }; + + template + using policy_update_t = typename policy_update_impl::template _policy_t; + + template + struct update_policies_impl + { + using type = typename Original::template _policy_update_t; + }; + + template + using update_policies_t = typename update_policies_impl::type; + + } + +} + +#endif diff --git a/include/sqlpp11/vendor/using.h b/include/sqlpp11/vendor/using.h index 7f98b821..0cd2222f 100644 --- a/include/sqlpp11/vendor/using.h +++ b/include/sqlpp11/vendor/using.h @@ -31,55 +31,110 @@ #include #include #include +#include +#include namespace sqlpp { namespace vendor { - template + // USING + template struct using_t { using _is_using = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - static_assert(_is_dynamic::value or sizeof...(Table), "at least one table argument required in using()"); + static_assert(_is_dynamic::value or sizeof...(Tables), "at least one table argument required in using()"); - // check for duplicate arguments - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in using()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in using()"); - // check for invalid arguments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an table in using()"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an table in using()"); + + using_t(Tables... tables): + _tables(tables...) + {} + + using_t(const using_t&) = default; + using_t(using_t&&) = default; + using_t& operator=(const using_t&) = default; + using_t& operator=(using_t&&) = default; + ~using_t() = default; - template - void add(T table) + template + void add_using(Table table) { - static_assert(is_table_t::value, "using() arguments require to be tables"); + static_assert(_is_dynamic::value, "add_using can only be called for dynamic_using"); + static_assert(is_table_t
::value, "using() arguments require to be tables"); _dynamic_tables.emplace_back(table); } + using_t& _using = *this; _parameter_tuple_t _tables; vendor::interpretable_list_t _dynamic_tables; }; - template - struct interpreter_t> + struct no_using_t + { + no_using_t& _using = *this; + }; + + // CRTP Wrapper + template + struct crtp_wrapper_t> { - using T = using_t; + }; + + template + struct crtp_wrapper_t + { + template + auto using_(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), using_t(args...) }; + } + + template + auto dynamic_using(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_using must not be called in a static statement"); + return { static_cast(*this), using_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = using_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Table) == 0 and t._dynamic_tables.empty()) + if (sizeof...(Tables) == 0 and t._dynamic_tables.empty()) return context; context << " USING "; interpret_tuple(t._tables, ',', context); - if (sizeof...(Table) and not t._dynamic_tables.empty()) + if (sizeof...(Tables) and not t._dynamic_tables.empty()) context << ','; interpret_list(t._dynamic_tables, ',', context); return context; } }; + + template + struct interpreter_t + { + using T = no_using_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 72de65fa..bba16b33 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -40,41 +40,85 @@ namespace sqlpp { namespace vendor { - template + // WHERE + template struct where_t { using _is_where = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in where()"); - static_assert(sqlpp::detail::and_t::value, "at least one argument is not an expression in where()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in where()"); + static_assert(sqlpp::detail::and_t::value, "at least one argument is not an expression in where()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; + where_t(Expressions... expressions): + _expressions(expressions...) + {} + + where_t(const where_t&) = default; + where_t(where_t&&) = default; + where_t& operator=(const where_t&) = default; + where_t& operator=(where_t&&) = default; + ~where_t() = default; + template - void add(E expr) + void add_where(E expr) { + static_assert(_is_dynamic::value, "add_where can only be called for dynamic_where"); static_assert(is_expression_t::value, "invalid expression argument in add_where()"); _dynamic_expressions.emplace_back(expr); } + where_t& _where = *this; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; - template - struct interpreter_t> + struct no_where_t + { + no_where_t& _where = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = where_t; + }; + + template + struct crtp_wrapper_t + { + template + auto where(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), where_t(args...) }; + } + + template + auto dynamic_where(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_where must not be called in a static statement"); + return { static_cast(*this), where_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = where_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " WHERE "; interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); return context; @@ -104,6 +148,17 @@ namespace sqlpp } }; + template + struct interpreter_t + { + using T = no_where_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b2a56c15..ef9f5c96 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,12 +7,12 @@ macro (build_and_run arg) endmacro () build_and_run(InterpretTest) -build_and_run(InsertTest) -build_and_run(RemoveTest) -build_and_run(UpdateTest) -build_and_run(SelectTest) -build_and_run(FunctionTest) -build_and_run(PreparedTest) +#build_and_run(InsertTest) +#build_and_run(RemoveTest) +#build_and_run(UpdateTest) +#build_and_run(SelectTest) +#build_and_run(FunctionTest) +#build_and_run(PreparedTest) find_package(PythonInterp REQUIRED) diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 8f523298..58efc51a 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -43,6 +43,7 @@ int main() test::TabFoo f; test::TabBar t; + /* interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush(); interpret(insert_into(t).columns(t.gamma, t.beta).add_values(t.gamma = true, t.beta = "cheesecake"), printer).flush(); interpret(insert_into(t).columns(t.gamma, t.beta) @@ -90,10 +91,13 @@ int main() interpret(update(t), printer).flush(); interpret(update(t).set(t.gamma = true), printer).flush(); interpret(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).flush(); + */ interpret(remove_from(t), printer).flush(); + interpret(remove_from(t).using_(t), printer).flush(); interpret(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); interpret(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); + /* // functions sqlpp::interpret(sqlpp::value(7), printer).flush(); // FIXME: Why is the namespace specifier required? @@ -136,6 +140,6 @@ int main() interpret(select(all_of(t)).from(t).where(true), printer).flush(); interpret(select(all_of(t)).from(t).where(false), printer).flush(); - +*/ return 0; } From 62b828ef8f675a1c9f3df73f2e772290d7870837 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 7 Feb 2014 22:52:02 +0100 Subject: [PATCH 02/12] Migrated select components to support policy based select --- include/sqlpp11/select.h | 161 ++++++++------------ include/sqlpp11/select_fwd.h | 22 +-- include/sqlpp11/vendor/from.h | 4 +- include/sqlpp11/vendor/group_by.h | 90 ++++++++--- include/sqlpp11/vendor/having.h | 72 +++++++-- include/sqlpp11/vendor/limit.h | 114 +++++++++++--- include/sqlpp11/vendor/offset.h | 101 ++++++++++-- include/sqlpp11/vendor/order_by.h | 89 ++++++++--- include/sqlpp11/vendor/select_column_list.h | 101 ++++++++---- include/sqlpp11/vendor/select_flag_list.h | 92 ++++++++--- include/sqlpp11/vendor/where.h | 30 ++-- 11 files changed, 604 insertions(+), 272 deletions(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index cd68ec59..fb22fe58 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -28,7 +28,6 @@ #define SQLPP_SELECT_H #include -#include #include #include @@ -45,74 +44,69 @@ #include #include #include +#include +#include +#include + #include #include -#include - namespace sqlpp { - template< - typename Database, - typename FlagList, - typename ColumnList, - typename From, - typename Where, - typename GroupBy, - typename Having, - typename OrderBy, - typename Limit, - typename Offset - > - struct select_t - : public ColumnList::_value_type::template operators> - { - using _Database = Database; - using _From = From; + namespace detail + { + template< + typename FlagList, + typename ColumnList, + typename From, + typename Where, + typename GroupBy, + typename Having, + typename OrderBy, + typename Limit, + typename Offset + > + struct check_select_t + { + //static_assert(is_where_t::value, "cannot select remove without having a where condition, use .where(true) to remove all rows"); + static constexpr bool value = true; + }; + } - static_assert(is_select_flag_list_t::value, "invalid list of select flags"); - static_assert(is_select_column_list_t::value, "invalid list of select expressions"); - static_assert(vendor::is_noop::value or is_from_t::value, "invalid 'from' argument"); - static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'where' argument"); - static_assert(vendor::is_noop::value or is_group_by_t::value, "invalid 'group by' arguments"); - static_assert(vendor::is_noop::value or is_having_t::value, "invalid 'having' arguments"); - static_assert(vendor::is_noop::value or is_order_by_t::value, "invalid 'order by' arguments"); - static_assert(vendor::is_noop::value or is_limit_t::value, "invalid 'limit' arguments"); - static_assert(vendor::is_noop::value or is_offset_t::value, "invalid 'offset' arguments"); + template + struct select_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... + { + template + using _policy_update_t = select_t...>; + + using _database_t = Database; + using _parameter_tuple_t = std::tuple; + using _parameter_list_t = typename make_parameter_list_t::type; + + select_t() + {} + + template + select_t(select_t r, Whatever whatever): + vendor::policy_t(r, whatever)... + {} + + template + select_t(Remove r, Whatever whatever): + vendor::policy_t(r, whatever)... + {} + + select_t(const select_t& r) = default; + select_t(select_t&& r) = default; + select_t& operator=(const select_t& r) = default; + select_t& operator=(select_t&& r) = default; + ~select_t() = default; using _is_select = std::true_type; using _requires_braces = std::true_type; - template - using set_flag_list_t = select_t; - template - using set_column_list_t = select_t; - template - using set_from_t = select_t; - template - using set_where_t = select_t; - template - using set_group_by_t = select_t; - template - using set_having_t = select_t; - template - using set_order_by_t = select_t; - template - using set_limit_t = select_t; - template - using set_offset_t = select_t; - + /* using _result_row_t = typename ColumnList::_result_row_t; using _dynamic_names_t = typename ColumnList::_dynamic_names_t; using _parameter_tuple_t = std::tuple; @@ -640,58 +634,21 @@ namespace sqlpp return {{}, get_dynamic_names(), db.prepare_select(*this)}; } - - FlagList _flags; - ColumnList _columns; - From _from; - Where _where; - GroupBy _group_by; - Having _having; - OrderBy _order_by; - Limit _limit; - Offset _offset; +*/ }; namespace vendor { - template - struct interpreter_t> + template + struct interpreter_t> { - using T = select_t; + using T = select_t; static Context& _(const T& t, Context& context) { context << "SELECT "; + /* interpret(t._flags, context); interpret(t._columns, context); interpret(t._from, context); @@ -701,6 +658,7 @@ namespace sqlpp interpret(t._order_by, context); interpret(t._limit, context); interpret(t._offset, context); + */ return context; } @@ -708,6 +666,8 @@ namespace sqlpp } + /* + // construct select flag list namespace detail { @@ -751,6 +711,7 @@ namespace sqlpp {}, {}, {}, {}, {}, {}, {} }; } + */ } #endif diff --git a/include/sqlpp11/select_fwd.h b/include/sqlpp11/select_fwd.h index dc432e57..a9a5c9dd 100644 --- a/include/sqlpp11/select_fwd.h +++ b/include/sqlpp11/select_fwd.h @@ -31,27 +31,7 @@ namespace sqlpp { - namespace vendor - { - struct noop; - } - // select flags - struct all_t; - struct distinct_t; - struct straight_join_t; - - template< - typename Db, - typename Flags = vendor::noop, - typename ExpressionList = vendor::noop, - typename From = vendor::noop, - typename Where = vendor::noop, - typename GroupBy = vendor::noop, - typename Having = vendor::noop, - typename OrderBy = vendor::noop, - typename Limit = vendor::noop, - typename Offset = vendor::noop - > + template struct select_t; } #endif diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index 0de1e217..f0a816cd 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -83,7 +83,6 @@ namespace sqlpp no_from_t& _from = *this; }; - // CRTP Wrappers template struct crtp_wrapper_t> @@ -109,7 +108,6 @@ namespace sqlpp } }; - // Interpreters template struct interpreter_t> @@ -139,8 +137,8 @@ namespace sqlpp return context; } }; - } + } } #endif diff --git a/include/sqlpp11/vendor/group_by.h b/include/sqlpp11/vendor/group_by.h index ca8e2e5e..bdb7b169 100644 --- a/include/sqlpp11/vendor/group_by.h +++ b/include/sqlpp11/vendor/group_by.h @@ -32,57 +32,111 @@ #include #include #include +#include +#include #include namespace sqlpp { namespace vendor { - template + // GROUP BY + template struct group_by_t { using _is_group_by = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - // ensure one argument at least - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression (e.g. a column) required in group_by()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression (e.g. a column) required in group_by()"); - // check for duplicate expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); - // check for invalid expressions - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in group_by()"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in group_by()"); - template - void add(E expr) + group_by_t(Expressions... expressions): + _expressions(expressions...) + {} + + group_by_t(const group_by_t&) = default; + group_by_t(group_by_t&&) = default; + group_by_t& operator=(const group_by_t&) = default; + group_by_t& operator=(group_by_t&&) = default; + ~group_by_t() = default; + + template + void add_group_by(Expression expression) { - static_assert(is_table_t::value, "from arguments require to be tables or joins"); - _dynamic_expressions.emplace_back(expr); + static_assert(is_table_t::value, "from arguments require to be tables or joins"); + _dynamic_expressions.emplace_back(expression); } + group_by_t& _group_by = *this; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; - }; - template - struct interpreter_t> + struct no_group_by_t + { + using _is_group_by = std::true_type; + no_group_by_t& _group_by = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = group_by_t; + }; + + template + struct crtp_wrapper_t + { + template + auto group_by(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), group_by_t(args...) }; + } + + template + auto dynamic_group_by(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_group_by must not be called in a static statement"); + return { static_cast(*this), group_by_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = group_by_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " GROUP BY "; interpret_tuple(t._expressions, ',', context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << ','; interpret_list(t._dynamic_expressions, ',', context); return context; } }; + + template + struct interpreter_t + { + using T = no_group_by_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index e9a474df..116e1e2a 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -31,52 +31,100 @@ #include #include #include +#include +#include #include namespace sqlpp { namespace vendor { - template + // HAVING + template struct having_t { using _is_having = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in having()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in having()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in having()"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in having()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; - template - void add(E expr) + template + void add(Expression expr) { - static_assert(is_expression_t::value, "invalid expression argument in add_having()"); + static_assert(is_expression_t::value, "invalid expression argument in add_having()"); _dynamic_expressions.emplace_back(expr); } + having_t& _having = *this; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; - template - struct interpreter_t> + struct no_having_t + { + using _is_having = std::true_type; + no_having_t& _having = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = having_t; + }; + + template + struct crtp_wrapper_t + { + template + auto having(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), having_t(args...) }; + } + + template + auto dynamic_having(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_having must not be called in a static statement"); + return { static_cast(*this), having_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = having_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " HAVING "; interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); return context; } }; + + template + struct interpreter_t + { + using T = no_having_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index fdee2700..d3b175a5 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -27,21 +27,106 @@ #ifndef SQLPP_LIMIT_H #define SQLPP_LIMIT_H -#include -#include #include +#include +#include namespace sqlpp { namespace vendor { + // LIMIT template struct limit_t { using _is_limit = std::true_type; static_assert(is_integral_t::value, "limit requires an integral value or integral parameter"); - Limit _limit; + limit_t(size_t value): + _value(value) + {} + + limit_t(const limit_t&) = default; + limit_t(limit_t&&) = default; + limit_t& operator=(const limit_t&) = default; + limit_t& operator=(limit_t&&) = default; + ~limit_t() = default; + + limit_t& _limit = *this; + Limit _value; + }; + + struct dynamic_limit_t + { + using _is_limit = std::true_type; + using _is_dynamic = std::true_type; + + dynamic_limit_t(size_t value): + _value(value) + {} + + dynamic_limit_t(const dynamic_limit_t&) = default; + dynamic_limit_t(dynamic_limit_t&&) = default; + dynamic_limit_t& operator=(const dynamic_limit_t&) = default; + dynamic_limit_t& operator=(dynamic_limit_t&&) = default; + ~dynamic_limit_t() = default; + + void set_limit(std::size_t limit) + { + _value = limit; + } + + dynamic_limit_t& _limit = *this; + std::size_t _value; // FIXME: This should be a serializable! + }; + + struct no_limit_t + { + using _is_limit = std::true_type; + no_limit_t& _limit = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> + { + }; + + template + struct crtp_wrapper_t + { + }; + + template + struct crtp_wrapper_t + { + template + auto limit(Arg arg) + -> vendor::update_policies_t> + { + return { static_cast(*this), limit_t(arg) }; + } + + auto dynamic_limit(size_t arg) + -> vendor::update_policies_t + { + static_assert(not std::is_same, void>::value, "dynamic_limit must not be called in a static statement"); + return { static_cast(*this), dynamic_limit_t(arg) }; + } + }; + + // Interpreters + template + struct interpreter_t + { + using T = dynamic_limit_t; + + static Context& _(const T& t, Context& context) + { + if (t._value > 0) + context << " LIMIT " << t._limit; + return context; + } }; template @@ -52,38 +137,23 @@ namespace sqlpp static Context& _(const T& t, Context& context) { context << " LIMIT "; - interpret(t._limit, context); + interpret(t._value, context); return context; } }; - struct dynamic_limit_t - { - using _is_limit = std::true_type; - using _is_dynamic = std::true_type; - - void set(std::size_t limit) - { - _limit = limit; - } - - std::size_t _limit; - }; - template - struct interpreter_t + struct interpreter_t { - using T = dynamic_limit_t; + using T = no_limit_t; static Context& _(const T& t, Context& context) { - if (t._limit > 0) - context << " LIMIT " << t._limit; return context; } }; - } + } } #endif diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index a7af759a..7f4df82b 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -28,20 +28,94 @@ #define SQLPP_OFFSET_H #include +#include +#include namespace sqlpp { namespace vendor { + // OFFSET template struct offset_t { using _is_offset = std::true_type; static_assert(is_integral_t::value, "offset requires an integral value or integral parameter"); - Offset _offset; + offset_t(size_t value): + _value(value) + {} + + offset_t(const offset_t&) = default; + offset_t(offset_t&&) = default; + offset_t& operator=(const offset_t&) = default; + offset_t& operator=(offset_t&&) = default; + ~offset_t() = default; + + offset_t& _offset = *this; + Offset _value; }; + struct dynamic_offset_t + { + using _is_offset = std::true_type; + using _is_dynamic = std::true_type; + + dynamic_offset_t(size_t value): + _value(value) + {} + + dynamic_offset_t(const dynamic_offset_t&) = default; + dynamic_offset_t(dynamic_offset_t&&) = default; + dynamic_offset_t& operator=(const dynamic_offset_t&) = default; + dynamic_offset_t& operator=(dynamic_offset_t&&) = default; + ~dynamic_offset_t() = default; + + void set_offset(std::size_t offset) + { + _value = offset; + } + + dynamic_offset_t& _offset = *this; + std::size_t _value; // FIXME: This should be a serializable! + }; + + struct no_offset_t + { + using _is_offset = std::true_type; + no_offset_t& _offset = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> + { + }; + + template + struct crtp_wrapper_t + { + }; + + template + struct crtp_wrapper_t + { + template + auto offset(Arg arg) + -> vendor::update_policies_t> + { + return { static_cast(*this), offset_t(arg) }; + } + + auto dynamic_offset(size_t arg) + -> vendor::update_policies_t + { + static_assert(not std::is_same, void>::value, "dynamic_offset must not be called in a static statement"); + return { static_cast(*this), dynamic_offset_t(arg) }; + } + }; + + // Interpreters template struct interpreter_t> { @@ -55,19 +129,6 @@ namespace sqlpp } }; - struct dynamic_offset_t - { - using _is_offset = std::true_type; - using _is_dynamic = std::true_type; - - void set(std::size_t offset) - { - _offset = offset; - } - - std::size_t _offset; - }; - template struct interpreter_t { @@ -75,12 +136,22 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - if (t._offset > 0) + if (t._value > 0) context << " OFFSET " << t._offset; return context; } }; + template + struct interpreter_t + { + using T = no_offset_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/order_by.h b/include/sqlpp11/vendor/order_by.h index fd58485f..9c6f32ed 100644 --- a/include/sqlpp11/vendor/order_by.h +++ b/include/sqlpp11/vendor/order_by.h @@ -32,55 +32,110 @@ #include #include #include +#include +#include +#include namespace sqlpp { namespace vendor { - template + template struct order_by_t { using _is_order_by = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; - // check for at least one order expression - static_assert(_is_dynamic::value or sizeof...(Expr), "at least one sort-order expression required in order_by()"); + static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one sort-order expression required in order_by()"); - // check for duplicate order expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in order_by()"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in order_by()"); - // check for invalid order expressions - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a sort order expression in order_by()"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a sort order expression in order_by()"); - template - void add(E expr) + order_by_t(Expressions... expressions): + _expressions(expressions...) + {} + + order_by_t(const order_by_t&) = default; + order_by_t(order_by_t&&) = default; + order_by_t& operator=(const order_by_t&) = default; + order_by_t& operator=(order_by_t&&) = default; + ~order_by_t() = default; + + template + void add_order_by(Expression expressions) { - static_assert(is_sort_order_t::value, "order_by arguments require to be sort-order expressions"); - _dynamic_expressions.push_back(expr); + static_assert(is_sort_order_t::value, "order_by arguments require to be sort-order expressions"); + _dynamic_expressions.push_back(expressions); } + order_by_t& _order_by = *this; _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; - template - struct interpreter_t> + struct no_order_by_t + { + using _is_order_by = std::true_type; + no_order_by_t& _order_by = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = order_by_t; + }; + + template + struct crtp_wrapper_t + { + template + auto order_by(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), order_by_t(args...) }; + } + + template + auto dynamic_order_by(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_order_by must not be called in a static statement"); + return { static_cast(*this), order_by_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = order_by_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expr) == 0 and t._dynamic_expressions.empty()) + if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; context << " ORDER BY "; interpret_tuple(t._expressions, ',', context); - if (sizeof...(Expr) and not t._dynamic_expressions.empty()) + if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) context << ','; interpret_list(t._dynamic_expressions, ',', context); return context; } }; + + template + struct interpreter_t + { + using T = no_order_by_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index ce421e8f..7872ac62 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include namespace sqlpp @@ -130,69 +132,103 @@ namespace sqlpp }; - template + // SELECT COLUMNS + template struct select_column_list_t - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid template argument for select_column_list"); - }; - - template - struct select_column_list_t> { using _is_select_column_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using size = std::tuple_size<_parameter_tuple_t>; - // check for duplicate select expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected"); - // check for invalid select expressions template using is_valid_expression_t = std::integral_constant::value or is_multi_column_t::value>; - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a named expression"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a named expression"); - // check for duplicate select expression names - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate name detected"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate name detected"); - // provide type information for sub-selects that are used as expressions struct _column_type {}; - struct _value_type: ::sqlpp::detail::get_first_argument_if_unique::_value_type + struct _value_type: ::sqlpp::detail::get_first_argument_if_unique::_value_type { - using _is_expression = typename std::conditional::type; - using _is_named_expression = typename std::conditional::type; + using _is_expression = typename std::conditional::type; + using _is_named_expression = typename std::conditional::type; using _is_alias = std::false_type; }; - using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique::_name_t; + using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique::_name_t; using _result_row_t = typename std::conditional<_is_dynamic::value, - dynamic_result_row_t...>, - result_row_t...>>::type; + dynamic_result_row_t...>, + result_row_t...>>::type; using _dynamic_names_t = typename dynamic_select_column_list::_names_t; template - using _pseudo_table_t = select_pseudo_table_t; + using _pseudo_table_t = select_pseudo_table_t; template - using _dynamic_t = select_column_list_t>; + using _dynamic_t = select_column_list_t>; + + select_column_list_t(Columns... columns): + _columns(columns...) + {} + + select_column_list_t(const select_column_list_t&) = default; + select_column_list_t(select_column_list_t&&) = default; + select_column_list_t& operator=(const select_column_list_t&) = default; + select_column_list_t& operator=(select_column_list_t&&) = default; + ~select_column_list_t() = default; template - void add(Expr namedExpr) + void add_column(Expr namedExpr) { static_assert(is_named_expression_t::value, "select() arguments require to be named expressions"); static_assert(_is_dynamic::value, "cannot add columns to a non-dynamic column list"); _dynamic_columns.push_back(namedExpr); } + select_column_list_t& _column_list = *this; _parameter_tuple_t _columns; dynamic_select_column_list _dynamic_columns; }; - template - struct interpreter_t> + struct no_select_column_list_t + { + using _is_select_column_list = std::true_type; + no_select_column_list_t& _column_list = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = select_column_list_t; + }; + + template + struct crtp_wrapper_t + { + template + auto columns(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), select_column_list_t(args...) }; + } + + template + auto dynamic_columns(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_columns must not be called in a static statement"); + return { static_cast(*this), select_column_list_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = select_column_list_t; static Context& _(const T& t, Context& context) { @@ -206,6 +242,17 @@ namespace sqlpp return context; } }; + + template + struct interpreter_t + { + using T = no_select_column_list_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index a167e4fc..48860aa7 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -27,58 +27,95 @@ #ifndef SQLPP_VENDOR_SELECT_FLAG_LIST_H #define SQLPP_VENDOR_SELECT_FLAG_LIST_H +#include #include #include #include #include #include -#include +#include +#include namespace sqlpp { namespace vendor { - template + // SELECT FLAGS + template struct select_flag_list_t - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for select_flag_list"); - }; - - // select_flag_list_t - template - struct select_flag_list_t> { using _is_select_flag_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; + using _parameter_tuple_t = std::tuple; using size = std::tuple_size<_parameter_tuple_t>; - // check for duplicate order expressions - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); - // check for invalid order expressions - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a select flag in select flag list"); + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a select flag in select flag list"); - template - void add(E expr) + select_flag_list_t(Flags... flags): + _flags(flags...) + {} + + select_flag_list_t(const select_flag_list_t&) = default; + select_flag_list_t(select_flag_list_t&&) = default; + select_flag_list_t& operator=(const select_flag_list_t&) = default; + select_flag_list_t& operator=(select_flag_list_t&&) = default; + ~select_flag_list_t() = default; + + template + void add_flag(Flag flag) { - static_assert(is_select_flag_t::value, "flag arguments require to be select flags"); - _dynamic_flags.emplace_back(expr); + static_assert(is_select_flag_t::value, "flag arguments require to be select flags"); + _dynamic_flags.emplace_back(flag); } + select_flag_list_t& _flag_list = *this; _parameter_tuple_t _flags; vendor::interpretable_list_t _dynamic_flags; }; - template - struct interpreter_t>> + struct no_select_flag_list_t + { + using _is_select_flag_list = std::true_type; + no_select_flag_list_t& _flag_list = *this; + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = select_flag_list_t>; + }; + + template + struct crtp_wrapper_t + { + template + auto flags(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), select_flag_list_t(args...) }; + } + + template + auto dynamic_flags(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_flags must not be called in a static statement"); + return { static_cast(*this), select_flag_list_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t> + { + using T = select_flag_list_t; static Context& _(const T& t, Context& context) { interpret_tuple(t._flags, ' ', context); - if (sizeof...(Flag)) + if (sizeof...(Flags)) context << ' '; interpret_list(t._dynamic_flags, ',', context); if (not t._dynamic_flags.empty()) @@ -86,6 +123,17 @@ namespace sqlpp return context; } }; + + template + struct interpreter_t + { + using T = no_select_flag_list_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; } } diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index bba16b33..b1805212 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -27,14 +27,14 @@ #ifndef SQLPP_WHERE_H #define SQLPP_WHERE_H -#include -#include -#include #include -#include +#include +#include #include #include -#include +#include +#include +#include namespace sqlpp { @@ -76,8 +76,18 @@ namespace sqlpp vendor::interpretable_list_t _dynamic_expressions; }; + template<> + struct where_t + { + using _is_where = std::true_type; + using _is_dynamic = std::false_type; + + std::tuple _condition; + }; + struct no_where_t { + using _is_where = std::true_type; no_where_t& _where = *this; }; @@ -125,16 +135,6 @@ namespace sqlpp } }; - template<> - struct where_t - { - using _is_where = std::true_type; - using _is_dynamic = std::false_type; - using _parameter_tuple_t = std::tuple<>; - - std::tuple _condition; - }; - template struct interpreter_t> { From 0a744455ecc6bd672274fe0b4d676cfa4df47788 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 7 Feb 2014 23:43:26 +0100 Subject: [PATCH 03/12] basic select methods work again I've let go of the select(flags, columns) monster methods, these are now separated --- include/sqlpp11/select.h | 518 ++------------------------------ include/sqlpp11/vendor/having.h | 10 + include/sqlpp11/vendor/limit.h | 66 ++-- include/sqlpp11/vendor/offset.h | 66 ++-- tests/InterpretTest.cpp | 19 +- 5 files changed, 122 insertions(+), 557 deletions(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index fb22fe58..af251d69 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -120,459 +120,6 @@ namespace sqlpp using _name_t = typename ColumnList::_name_t; - // The standard constructors, assigment operators and destructor - constexpr select_t(FlagList flag_list, ColumnList column_list, From from, - Where where, GroupBy group_by, Having having, - OrderBy order_by, Limit limit, Offset offset): - _flags(flag_list), - _columns(column_list), - _from(from), - _where(where), - _group_by(group_by), - _having(having), - _order_by(order_by), - _limit(limit), - _offset(offset) - { - } - - select_t(const select_t& rhs) = default; - select_t(select_t&& rhs) = default; - select_t& operator=(const select_t& rhs) = default; - select_t& operator=(select_t&& rhs) = default; - ~select_t() = default; - - // select functions - template - auto flags(Flag... flag) - -> set_flag_list_t>> - { - static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time"); - static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); - return { - {std::tuple{flag...}}, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - auto dynamic_flags(Flag... flag) - -> set_flag_list_t>> - { - static_assert(not std::is_same::value, "cannot call dynamic_flags() in a non-dynamic select"); - static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time"); - static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); - return { - {std::tuple{flag...}}, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - select_t& add_flag(Flag flag) - { - static_assert(is_dynamic_t::value, "cannot call add_flag() in a non-dynamic column list"); - - _flags.add(flag); - - return *this; - } - - template - auto columns(Column... column) - -> set_column_list_t>> - { - static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); - return { - _flags, - {std::tuple{column...}}, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - auto dynamic_columns(Column... column) - -> set_column_list_t>> - { - static_assert(not std::is_same::value, "cannot call dynamic_columns() in a non-dynamic select"); - static_assert(not ColumnList::size::value, "cannot call dynamic_columns() after specifying them the first time"); - return { - _flags, - {std::tuple{column...}}, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - select_t& add_column(NamedExpr namedExpr) - { - static_assert(is_dynamic_t::value, "cannot call add_column() in a non-dynamic column list"); - - _columns.add(namedExpr); - - return *this; - } - - template - auto from(Table... table) - -> set_from_t> - { - static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); - static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); - return { - _flags, - _columns, - {std::tuple{table...}}, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - auto dynamic_from(Table... table) - -> set_from_t> - { - static_assert(not std::is_same::value, "cannot call dynamic_from() in a non-dynamic select"); - static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); - static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); - return { - _flags, - _columns, - {std::tuple{table...}}, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset - }; - } - - template - select_t& add_from(Table table) - { - static_assert(not vendor::is_noop::value, "cannot call add_from() without having selected anything"); - static_assert(is_dynamic_t::value, "cannot call add_from() in a non-dynamic from"); - - _from.add(table); - - return *this; - } - - template - auto where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call where() without a from()"); - static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); - return { - _flags, - _columns, - _from, - {std::tuple{expr...}}, - _group_by, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - auto dynamic_where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call dynamic_where() without a from()"); - static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); - return { - _flags, - _columns, - _from, - {std::tuple{expr...}}, - _group_by, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - select_t& add_where(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_where() with a non-dynamic where"); - - _where.add(expr); - - return *this; - } - - template - auto group_by(Col... column) - -> set_group_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call group_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - {std::tuple{column...}}, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - auto dynamic_group_by(Col... column) - -> set_group_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call group_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - {std::tuple{column...}}, - _having, - _order_by, - _limit, - _offset, - }; - } - - template - select_t& add_group_by(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_group_by() in a non-dynamic group_by"); - - _group_by.add(expr); - - return *this; - } - - template - auto having(Expr... expr) - -> set_having_t> - { - static_assert(not vendor::is_noop::value, "cannot call having() without a group_by"); - static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - {std::tuple{expr...}}, - _order_by, - _limit, - _offset, - }; - } - - template - auto dynamic_having(Expr... expr) - -> set_having_t> - { - static_assert(not vendor::is_noop::value, "cannot call having() without a group_by"); - static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - {std::tuple{expr...}}, - _order_by, - _limit, - _offset, - }; - } - - template - select_t& add_having(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_having() in a non-dynamic having"); - - _having.add(expr); - - return *this; - } - - template - auto order_by(OrderExpr... expr) - -> set_order_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call order_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - {std::tuple{expr...}}, - _limit, - _offset, - }; - } - - template - auto dynamic_order_by(OrderExpr... expr) - -> set_order_by_t> - { - static_assert(not vendor::is_noop::value, "cannot call order_by() without a from()"); - static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - {std::tuple{expr...}}, - _limit, - _offset, - }; - } - - template - select_t& add_order_by(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_order_by() in a non-dynamic order_by"); - - _order_by.add(expr); - - return *this; - } - - template - auto limit(Expr limit) - -> set_limit_t::type>> - { - static_assert(not vendor::is_noop::value, "cannot call limit() without a from()"); - static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - {limit}, - _offset, - }; - } - - auto dynamic_limit(std::size_t limit = 0) - ->set_limit_t - { - static_assert(not vendor::is_noop::value, "cannot call limit() without a from()"); - static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - {limit}, - _offset, - }; - } - - select_t& set_limit(std::size_t limit) - { - static_assert(is_dynamic_t::value, "cannot call set_limit() in a non-dynamic limit"); - - _limit.set(limit); - - return *this; - } - - template - auto offset(Expr offset) - -> set_offset_t::type>> - { - static_assert(not vendor::is_noop::value, "cannot call offset() without a limit"); - static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - {offset}, - }; - } - - auto dynamic_offset(std::size_t offset = 0) - -> set_offset_t - { - static_assert(not vendor::is_noop::value, "cannot call offset() without a limit"); - static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); - return { - _flags, - _columns, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - {offset}, - }; - } - - select_t& set_offset(std::size_t offset) - { - static_assert(is_dynamic_t::value, "cannot call set_offset() in a non-dynamic limit"); - - _offset.set(offset); - - return *this; - } - template struct _pseudo_table_t { @@ -648,9 +195,8 @@ namespace sqlpp { context << "SELECT "; - /* - interpret(t._flags, context); - interpret(t._columns, context); + interpret(t._flag_list, context); + interpret(t._column_list, context); interpret(t._from, context); interpret(t._where, context); interpret(t._group_by, context); @@ -658,60 +204,48 @@ namespace sqlpp interpret(t._order_by, context); interpret(t._limit, context); interpret(t._offset, context); - */ return context; } }; } + template + using blank_select_t = select_t; - /* - - // construct select flag list - namespace detail + blank_select_t select() // FIXME: These should be constexpr { - template - using make_select_flag_list_t = - vendor::select_flag_list_t()...))>; + return { blank_select_t() }; } - // construct select expression list - namespace detail - { - template - using make_select_column_list_t = - vendor::select_column_list_t()...))>; - } - - auto select() - -> select_t>, vendor::select_column_list_t>> + template + auto select(Columns... columns) + -> vendor::update_policies_t, vendor::no_select_column_list_t, vendor::select_column_list_t> { - return { {}, vendor::select_column_list_t>{}, {}, {}, {}, {}, {}, {}, {} }; + return { blank_select_t(), vendor::select_column_list_t(columns...) }; } - template - auto select(NamedExpr... namedExpr) - -> select_t, detail::make_select_column_list_t> + template + blank_select_t dynamic_select() { - return { - { detail::make_flag_tuple(namedExpr...) }, - { detail::make_expression_tuple(namedExpr...) }, - {}, {}, {}, {}, {}, {}, {} - }; + return { blank_select_t() }; } - template - auto dynamic_select(const Db& db, NamedExpr... namedExpr) - -> select_t, detail::make_select_column_list_t> + template + auto dynamic_select(Columns... columns) + -> vendor::update_policies_t, vendor::no_select_column_list_t, vendor::select_column_list_t> { - return { - { detail::make_flag_tuple(namedExpr...) }, - { detail::make_expression_tuple(namedExpr...) }, - {}, {}, {}, {}, {}, {}, {} - }; + return { blank_select_t(), vendor::select_column_list_t(columns...) }; } - */ } #endif diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index 116e1e2a..cc5de0ac 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -52,6 +52,16 @@ namespace sqlpp using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; + having_t(Expressions... expressions): + _expressions(expressions...) + {} + + having_t(const having_t&) = default; + having_t(having_t&&) = default; + having_t& operator=(const having_t&) = default; + having_t& operator=(having_t&&) = default; + ~having_t() = default; + template void add(Expression expr) { diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index d3b175a5..be74b7c5 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -56,29 +56,30 @@ namespace sqlpp Limit _value; }; - struct dynamic_limit_t - { - using _is_limit = std::true_type; - using _is_dynamic = std::true_type; - - dynamic_limit_t(size_t value): - _value(value) - {} - - dynamic_limit_t(const dynamic_limit_t&) = default; - dynamic_limit_t(dynamic_limit_t&&) = default; - dynamic_limit_t& operator=(const dynamic_limit_t&) = default; - dynamic_limit_t& operator=(dynamic_limit_t&&) = default; - ~dynamic_limit_t() = default; - - void set_limit(std::size_t limit) + template + struct dynamic_limit_t { - _value = limit; - } + using _is_limit = std::true_type; + using _is_dynamic = std::true_type; - dynamic_limit_t& _limit = *this; - std::size_t _value; // FIXME: This should be a serializable! - }; + dynamic_limit_t(size_t value): + _value(value) + {} + + dynamic_limit_t(const dynamic_limit_t&) = default; + dynamic_limit_t(dynamic_limit_t&&) = default; + dynamic_limit_t& operator=(const dynamic_limit_t&) = default; + dynamic_limit_t& operator=(dynamic_limit_t&&) = default; + ~dynamic_limit_t() = default; + + void set_limit(std::size_t limit) + { + _value = limit; + } + + dynamic_limit_t& _limit = *this; + std::size_t _value; // FIXME: This should be a serializable! + }; struct no_limit_t { @@ -92,14 +93,20 @@ namespace sqlpp { }; - template - struct crtp_wrapper_t + template + struct crtp_wrapper_t> { }; template struct crtp_wrapper_t { + template + struct delayed_get_database_t + { + using type = get_database_t; + }; + template auto limit(Arg arg) -> vendor::update_policies_t> @@ -107,19 +114,20 @@ namespace sqlpp return { static_cast(*this), limit_t(arg) }; } - auto dynamic_limit(size_t arg) - -> vendor::update_policies_t + template + auto dynamic_limit(Arg arg) + -> vendor::update_policies_t::type>> { static_assert(not std::is_same, void>::value, "dynamic_limit must not be called in a static statement"); - return { static_cast(*this), dynamic_limit_t(arg) }; + return { static_cast(*this), dynamic_limit_t::type>(arg) }; } }; // Interpreters - template - struct interpreter_t + template + struct interpreter_t> { - using T = dynamic_limit_t; + using T = dynamic_limit_t; static Context& _(const T& t, Context& context) { diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index 7f4df82b..5af2ee84 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -56,29 +56,30 @@ namespace sqlpp Offset _value; }; - struct dynamic_offset_t - { - using _is_offset = std::true_type; - using _is_dynamic = std::true_type; - - dynamic_offset_t(size_t value): - _value(value) - {} - - dynamic_offset_t(const dynamic_offset_t&) = default; - dynamic_offset_t(dynamic_offset_t&&) = default; - dynamic_offset_t& operator=(const dynamic_offset_t&) = default; - dynamic_offset_t& operator=(dynamic_offset_t&&) = default; - ~dynamic_offset_t() = default; - - void set_offset(std::size_t offset) + template + struct dynamic_offset_t { - _value = offset; - } + using _is_offset = std::true_type; + using _is_dynamic = std::true_type; - dynamic_offset_t& _offset = *this; - std::size_t _value; // FIXME: This should be a serializable! - }; + dynamic_offset_t(size_t value): + _value(value) + {} + + dynamic_offset_t(const dynamic_offset_t&) = default; + dynamic_offset_t(dynamic_offset_t&&) = default; + dynamic_offset_t& operator=(const dynamic_offset_t&) = default; + dynamic_offset_t& operator=(dynamic_offset_t&&) = default; + ~dynamic_offset_t() = default; + + void set_offset(std::size_t offset) + { + _value = offset; + } + + dynamic_offset_t& _offset = *this; + std::size_t _value; // FIXME: This should be a serializable! + }; struct no_offset_t { @@ -92,14 +93,20 @@ namespace sqlpp { }; - template - struct crtp_wrapper_t + template + struct crtp_wrapper_t> { }; template struct crtp_wrapper_t { + template + struct delayed_get_database_t + { + using type = get_database_t; + }; + template auto offset(Arg arg) -> vendor::update_policies_t> @@ -107,11 +114,12 @@ namespace sqlpp return { static_cast(*this), offset_t(arg) }; } - auto dynamic_offset(size_t arg) - -> vendor::update_policies_t + template + auto dynamic_offset(Arg arg) + -> vendor::update_policies_t::type>> { static_assert(not std::is_same, void>::value, "dynamic_offset must not be called in a static statement"); - return { static_cast(*this), dynamic_offset_t(arg) }; + return { static_cast(*this), dynamic_offset_t>(arg) }; } }; @@ -129,10 +137,10 @@ namespace sqlpp } }; - template - struct interpreter_t + template + struct interpreter_t> { - using T = dynamic_offset_t; + using T = dynamic_offset_t; static Context& _(const T& t, Context& context) { diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 58efc51a..3646635e 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -69,15 +69,20 @@ int main() interpret(t.gamma != sqlpp::tvin(false), printer).flush(); interpret(t.alpha == 7, printer).flush(); interpret(t.beta + "kaesekuchen", printer).flush(); + */ - interpret(select(sqlpp::distinct, t.alpha, t.beta), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush(); - interpret(select(sqlpp::distinct, t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush(); + interpret(sqlpp::select(), printer).flush(); + interpret(sqlpp::select().flags(sqlpp::distinct), printer).flush(); + interpret(select(t.alpha, t.beta).flags(sqlpp::distinct), printer).flush(); + interpret(select(t.alpha, t.beta), printer).flush(); + interpret(select(t.alpha, t.beta).from(t), printer).flush(); + interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3), printer).flush(); + interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).flush(); + interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).flush(); + interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush(); + interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush(); + /* interpret(parameter(sqlpp::bigint(), t.alpha), printer).flush(); interpret(parameter(t.alpha), printer).flush(); interpret(t.alpha == parameter(t.alpha), printer).flush(); From c5ef725106c6de399fc17fa8edbdb635d0c37539 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 7 Feb 2014 23:51:21 +0100 Subject: [PATCH 04/12] Removed the dreaded make_expression_tuple and make_flag_tuple --- .../sqlpp11/detail/make_expression_tuple.h | 64 ----------------- include/sqlpp11/detail/make_flag_tuple.h | 70 ------------------- include/sqlpp11/multi_column.h | 5 +- include/sqlpp11/select.h | 4 -- 4 files changed, 2 insertions(+), 141 deletions(-) delete mode 100644 include/sqlpp11/detail/make_expression_tuple.h delete mode 100644 include/sqlpp11/detail/make_flag_tuple.h diff --git a/include/sqlpp11/detail/make_expression_tuple.h b/include/sqlpp11/detail/make_expression_tuple.h deleted file mode 100644 index ab9478fd..00000000 --- a/include/sqlpp11/detail/make_expression_tuple.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013, 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_DETAIL_MAKE_EXPRESSION_TUPLE_H -#define SQLPP_DETAIL_MAKE_EXPRESSION_TUPLE_H - -namespace sqlpp -{ - namespace detail - { - template - auto make_single_expression_tuple(Expr expr) - -> typename std::enable_if::value, decltype(std::make_tuple(expr))>::type - { - return std::make_tuple(expr); - }; - - template - auto make_single_expression_tuple(Expr expr) - -> typename std::enable_if::value, std::tuple<>>::type - { - return {}; - }; - - template - auto make_single_expression_tuple(std::tuple t) - -> std::tuple - { - return t; - }; - - template - auto make_expression_tuple(Expr... expr) - -> decltype(std::tuple_cat(make_single_expression_tuple(expr)...)) - { - return std::tuple_cat(make_single_expression_tuple(expr)...); - }; - - } -} -#endif diff --git a/include/sqlpp11/detail/make_flag_tuple.h b/include/sqlpp11/detail/make_flag_tuple.h deleted file mode 100644 index 7c9efad0..00000000 --- a/include/sqlpp11/detail/make_flag_tuple.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013, 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_DETAIL_MAKE_FLAG_TUPLE_H -#define SQLPP_DETAIL_MAKE_FLAG_TUPLE_H - -namespace sqlpp -{ - namespace detail - { - // accept select flags - template - auto make_single_flag_tuple(Expr expr) -> typename std::enable_if::value, decltype(std::make_tuple(expr))>::type - { - return std::make_tuple(expr); - }; - - // ignore named expressions - template - auto make_single_flag_tuple(Expr expr) -> typename std::enable_if::value, std::tuple<>>::type - { - return {}; - }; - - // ignore tables - template - auto make_single_flag_tuple(Tab tab) -> typename std::enable_if::value, std::tuple<>>::type - { - return {}; - }; - - // ignore tuples of expressions - template - auto make_single_flag_tuple(std::tuple t) -> std::tuple<> - { - return {}; - }; - - template - auto make_flag_tuple(Expr... expr) -> decltype(std::tuple_cat(make_single_flag_tuple(expr)...)) - { - return std::tuple_cat(make_single_flag_tuple(expr)...); - }; - - } -} -#endif diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index 8cf50469..199bcfa8 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -28,7 +28,6 @@ #define SQLPP_MULTI_COLUMN_H #include -#include #include namespace sqlpp @@ -74,13 +73,13 @@ namespace sqlpp { template using make_multi_column_t = - multi_column_t()...))>; + multi_column_t>; } template detail::make_multi_column_t multi_column(const AliasProvider& aliasProvider, NamedExpr... namedExpr) { - return { detail::make_expression_tuple(namedExpr...)}; + return { std::tuple(namedExpr...)}; } } diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index af251d69..0da74235 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -48,10 +48,6 @@ #include #include - -#include -#include - namespace sqlpp { namespace detail From 3a875e794bcab60cee80e84c21b045a8477d287f Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 00:35:59 +0100 Subject: [PATCH 05/12] More reasonable dynamic limit and offset --- include/sqlpp11/vendor/limit.h | 52 ++++++++++++++++++++----------- include/sqlpp11/vendor/offset.h | 55 +++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 38 deletions(-) diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index be74b7c5..1a8426a2 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -42,7 +42,7 @@ namespace sqlpp using _is_limit = std::true_type; static_assert(is_integral_t::value, "limit requires an integral value or integral parameter"); - limit_t(size_t value): + limit_t(Limit value): _value(value) {} @@ -62,9 +62,17 @@ namespace sqlpp using _is_limit = std::true_type; using _is_dynamic = std::true_type; - dynamic_limit_t(size_t value): - _value(value) - {} + dynamic_limit_t(): + _value(noop()) + { + } + + template + dynamic_limit_t(Limit value): + _initialized(true), + _value(typename wrap_operand::type(value)) + { + } dynamic_limit_t(const dynamic_limit_t&) = default; dynamic_limit_t(dynamic_limit_t&&) = default; @@ -72,13 +80,19 @@ namespace sqlpp dynamic_limit_t& operator=(dynamic_limit_t&&) = default; ~dynamic_limit_t() = default; - void set_limit(std::size_t limit) - { - _value = limit; - } + template + void set_limit(Limit value) + { + using arg_t = typename wrap_operand::type; + _value = arg_t(value); + _initialized = true; + } +#warning this is stupid! Will get dangling references when copying dynamic_limit_t& _limit = *this; - std::size_t _value; // FIXME: This should be a serializable! + + bool _initialized = false; + interpretable_t _value; }; struct no_limit_t @@ -101,7 +115,7 @@ namespace sqlpp template struct crtp_wrapper_t { - template + template struct delayed_get_database_t { using type = get_database_t; @@ -109,17 +123,19 @@ namespace sqlpp template auto limit(Arg arg) - -> vendor::update_policies_t> + -> vendor::update_policies_t::type>> { - return { static_cast(*this), limit_t(arg) }; + typename wrap_operand::type value = {arg}; + return { static_cast(*this), limit_t::type>(value) }; } - template - auto dynamic_limit(Arg arg) - -> vendor::update_policies_t::type>> + template + auto dynamic_limit(Args... args) + -> vendor::update_policies_t::type>> { + static_assert(sizeof...(Args) < 2, "dynamic_limit must be called with zero or one arguments"); static_assert(not std::is_same, void>::value, "dynamic_limit must not be called in a static statement"); - return { static_cast(*this), dynamic_limit_t::type>(arg) }; + return { static_cast(*this), dynamic_limit_t::type>(args...) }; } }; @@ -131,8 +147,8 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - if (t._value > 0) - context << " LIMIT " << t._limit; + if (t._initialized) + interpret(t._value, context); return context; } }; diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index 5af2ee84..c8f1f119 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -42,7 +42,7 @@ namespace sqlpp using _is_offset = std::true_type; static_assert(is_integral_t::value, "offset requires an integral value or integral parameter"); - offset_t(size_t value): + offset_t(Offset value): _value(value) {} @@ -53,6 +53,7 @@ namespace sqlpp ~offset_t() = default; offset_t& _offset = *this; + Offset _value; }; @@ -62,9 +63,17 @@ namespace sqlpp using _is_offset = std::true_type; using _is_dynamic = std::true_type; - dynamic_offset_t(size_t value): - _value(value) - {} + dynamic_offset_t(): + _value(noop()) + { + } + + template + dynamic_offset_t(Offset value): + _initialized(true), + _value(typename wrap_operand::type(value)) + { + } dynamic_offset_t(const dynamic_offset_t&) = default; dynamic_offset_t(dynamic_offset_t&&) = default; @@ -72,13 +81,17 @@ namespace sqlpp dynamic_offset_t& operator=(dynamic_offset_t&&) = default; ~dynamic_offset_t() = default; - void set_offset(std::size_t offset) - { - _value = offset; - } + template + void set_offset(Offset value) + { + using arg_t = typename wrap_operand::type; + _value = arg_t(value); + _initialized = true; + } dynamic_offset_t& _offset = *this; - std::size_t _value; // FIXME: This should be a serializable! + bool _initialized = false; + interpretable_t _value; }; struct no_offset_t @@ -88,8 +101,8 @@ namespace sqlpp }; // CRTP Wrappers - template - struct crtp_wrapper_t> + template + struct crtp_wrapper_t> { }; @@ -101,7 +114,7 @@ namespace sqlpp template struct crtp_wrapper_t { - template + template struct delayed_get_database_t { using type = get_database_t; @@ -109,17 +122,19 @@ namespace sqlpp template auto offset(Arg arg) - -> vendor::update_policies_t> + -> vendor::update_policies_t::type>> { - return { static_cast(*this), offset_t(arg) }; + typename wrap_operand::type value = {arg}; + return { static_cast(*this), offset_t::type>(value) }; } - template - auto dynamic_offset(Arg arg) - -> vendor::update_policies_t::type>> + template + auto dynamic_offset(Args... args) + -> vendor::update_policies_t::type>> { + static_assert(sizeof...(Args) < 2, "dynamic_offset must be called with zero or one arguments"); static_assert(not std::is_same, void>::value, "dynamic_offset must not be called in a static statement"); - return { static_cast(*this), dynamic_offset_t>(arg) }; + return { static_cast(*this), dynamic_offset_t::type>(args...) }; } }; @@ -132,7 +147,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { context << " OFFSET "; - interpret(t._offset, context); + interpret(t._value, context); return context; } }; @@ -144,7 +159,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - if (t._value > 0) + if (t._initialized) context << " OFFSET " << t._offset; return context; } From f7aa56b7dcb0e84a366ffdf2fb7a04b35dc2fcdb Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 00:43:20 +0100 Subject: [PATCH 06/12] Fixed possible dangling references problem --- include/sqlpp11/remove.h | 6 +++--- include/sqlpp11/select.h | 18 +++++++++--------- include/sqlpp11/vendor/from.h | 4 ++-- include/sqlpp11/vendor/group_by.h | 4 ++-- include/sqlpp11/vendor/having.h | 4 ++-- include/sqlpp11/vendor/limit.h | 7 +++---- include/sqlpp11/vendor/offset.h | 6 +++--- include/sqlpp11/vendor/order_by.h | 4 ++-- include/sqlpp11/vendor/select_column_list.h | 4 ++-- include/sqlpp11/vendor/select_flag_list.h | 4 ++-- include/sqlpp11/vendor/using.h | 4 ++-- include/sqlpp11/vendor/where.h | 4 ++-- 12 files changed, 34 insertions(+), 35 deletions(-) diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index 68c2397d..d7601bc8 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -116,9 +116,9 @@ namespace sqlpp static Context& _(const T& t, Context& context) { context << "DELETE"; - interpret(t._from, context); - interpret(t._using, context); - interpret(t._where, context); + interpret(t._from(), context); + interpret(t._using(), context); + interpret(t._where(), context); return context; } }; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 0da74235..07dadf0a 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -191,15 +191,15 @@ namespace sqlpp { context << "SELECT "; - interpret(t._flag_list, context); - interpret(t._column_list, context); - interpret(t._from, context); - interpret(t._where, context); - interpret(t._group_by, context); - interpret(t._having, context); - interpret(t._order_by, context); - interpret(t._limit, context); - interpret(t._offset, context); + interpret(t._flag_list(), context); + interpret(t._column_list(), context); + interpret(t._from(), context); + interpret(t._where(), context); + interpret(t._group_by(), context); + interpret(t._having(), context); + interpret(t._order_by(), context); + interpret(t._limit(), context); + interpret(t._offset(), context); return context; } diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index f0a816cd..8cdfa710 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -72,7 +72,7 @@ namespace sqlpp _dynamic_tables.emplace_back(table); } - from_t& _from = *this; + const from_t& _from() const { return *this; } std::tuple _tables; vendor::interpretable_list_t _dynamic_tables; }; @@ -80,7 +80,7 @@ namespace sqlpp struct no_from_t { using _is_from = std::true_type; - no_from_t& _from = *this; + const no_from_t& _from() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/group_by.h b/include/sqlpp11/vendor/group_by.h index bdb7b169..d5e90eb8 100644 --- a/include/sqlpp11/vendor/group_by.h +++ b/include/sqlpp11/vendor/group_by.h @@ -71,7 +71,7 @@ namespace sqlpp _dynamic_expressions.emplace_back(expression); } - group_by_t& _group_by = *this; + const group_by_t& _group_by() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; @@ -79,7 +79,7 @@ namespace sqlpp struct no_group_by_t { using _is_group_by = std::true_type; - no_group_by_t& _group_by = *this; + const no_group_by_t& _group_by() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index cc5de0ac..63698dad 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -69,7 +69,7 @@ namespace sqlpp _dynamic_expressions.emplace_back(expr); } - having_t& _having = *this; + const having_t& _having() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; @@ -77,7 +77,7 @@ namespace sqlpp struct no_having_t { using _is_having = std::true_type; - no_having_t& _having = *this; + const no_having_t& _having() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index 1a8426a2..bdae95fc 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -52,7 +52,7 @@ namespace sqlpp limit_t& operator=(limit_t&&) = default; ~limit_t() = default; - limit_t& _limit = *this; + const limit_t& _limit() const { return *this; } Limit _value; }; @@ -88,8 +88,7 @@ namespace sqlpp _initialized = true; } -#warning this is stupid! Will get dangling references when copying - dynamic_limit_t& _limit = *this; + const dynamic_limit_t& _limit() const { return *this; } bool _initialized = false; interpretable_t _value; @@ -98,7 +97,7 @@ namespace sqlpp struct no_limit_t { using _is_limit = std::true_type; - no_limit_t& _limit = *this; + const no_limit_t& _limit() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index c8f1f119..1c839887 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -52,7 +52,7 @@ namespace sqlpp offset_t& operator=(offset_t&&) = default; ~offset_t() = default; - offset_t& _offset = *this; + const offset_t& _offset() const { return *this; } Offset _value; }; @@ -89,7 +89,7 @@ namespace sqlpp _initialized = true; } - dynamic_offset_t& _offset = *this; + const dynamic_offset_t& _offset() const { return *this; } bool _initialized = false; interpretable_t _value; }; @@ -97,7 +97,7 @@ namespace sqlpp struct no_offset_t { using _is_offset = std::true_type; - no_offset_t& _offset = *this; + const no_offset_t& _offset() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/order_by.h b/include/sqlpp11/vendor/order_by.h index 9c6f32ed..63ee7421 100644 --- a/include/sqlpp11/vendor/order_by.h +++ b/include/sqlpp11/vendor/order_by.h @@ -70,7 +70,7 @@ namespace sqlpp _dynamic_expressions.push_back(expressions); } - order_by_t& _order_by = *this; + const order_by_t& _order_by() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; @@ -78,7 +78,7 @@ namespace sqlpp struct no_order_by_t { using _is_order_by = std::true_type; - no_order_by_t& _order_by = *this; + const no_order_by_t& _order_by() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index 7872ac62..ea90f17b 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -188,7 +188,7 @@ namespace sqlpp _dynamic_columns.push_back(namedExpr); } - select_column_list_t& _column_list = *this; + const select_column_list_t& _column_list() const { return *this; } _parameter_tuple_t _columns; dynamic_select_column_list _dynamic_columns; }; @@ -196,7 +196,7 @@ namespace sqlpp struct no_select_column_list_t { using _is_select_column_list = std::true_type; - no_select_column_list_t& _column_list = *this; + const no_select_column_list_t& _column_list() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index 48860aa7..dc6b4b8e 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -70,7 +70,7 @@ namespace sqlpp _dynamic_flags.emplace_back(flag); } - select_flag_list_t& _flag_list = *this; + const select_flag_list_t& _flag_list() const { return *this; } _parameter_tuple_t _flags; vendor::interpretable_list_t _dynamic_flags; }; @@ -78,7 +78,7 @@ namespace sqlpp struct no_select_flag_list_t { using _is_select_flag_list = std::true_type; - no_select_flag_list_t& _flag_list = *this; + const no_select_flag_list_t& _flag_list() const { return *this; } }; // CRTP Wrappers diff --git a/include/sqlpp11/vendor/using.h b/include/sqlpp11/vendor/using.h index 0cd2222f..1ad27720 100644 --- a/include/sqlpp11/vendor/using.h +++ b/include/sqlpp11/vendor/using.h @@ -71,14 +71,14 @@ namespace sqlpp _dynamic_tables.emplace_back(table); } - using_t& _using = *this; + const using_t& _using() const { return *this; } _parameter_tuple_t _tables; vendor::interpretable_list_t _dynamic_tables; }; struct no_using_t { - no_using_t& _using = *this; + const no_using_t& _using() const { return *this; } }; // CRTP Wrapper diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index b1805212..89ceeece 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -71,7 +71,7 @@ namespace sqlpp _dynamic_expressions.emplace_back(expr); } - where_t& _where = *this; + const where_t& _where() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; @@ -88,7 +88,7 @@ namespace sqlpp struct no_where_t { using _is_where = std::true_type; - no_where_t& _where = *this; + const no_where_t& _where() const { return *this; } }; // CRTP Wrappers From b82a0295cf7c87cb8b3618b8e9c84ce1957c0266 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 16:29:21 +0100 Subject: [PATCH 07/12] Fixed all_of use in select --- include/sqlpp11/multi_column.h | 1 + include/sqlpp11/select.h | 114 +++++++++++++------- include/sqlpp11/vendor/select_column_list.h | 15 +++ include/sqlpp11/vendor/where.h | 15 ++- tests/InterpretTest.cpp | 28 ++++- 5 files changed, 126 insertions(+), 47 deletions(-) diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index 199bcfa8..61d1f5f2 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -71,6 +71,7 @@ namespace sqlpp namespace detail { +#warning need to handle all_of here. template using make_multi_column_t = multi_column_t>; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 07dadf0a..98795f71 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -63,13 +63,26 @@ namespace sqlpp typename Limit, typename Offset > - struct check_select_t + struct select_helper_t { - //static_assert(is_where_t::value, "cannot select remove without having a where condition, use .where(true) to remove all rows"); - static constexpr bool value = true; + using _column_list_t = ColumnList; + using _from_t = ColumnList; + template + struct can_run_t + { + //static_assert(is_where_t::value, "cannot select remove without having a where condition, use .where(true) to remove all rows"); + //static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); + //static_assert(is_from_t::value, "cannot run select without a from()"); + //static_assert(is_where_t::value, "cannot run select without having a where condition, use .where(true) to select all rows"); + // FIXME: Check for missing aliases (if references are used) + // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. + + static constexpr bool value = true; + }; }; } + // SELECT template struct select_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... { @@ -80,6 +93,17 @@ namespace sqlpp using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; + using _column_list_t = typename detail::select_helper_t::_column_list_t; + using _result_row_t = typename _column_list_t::_result_row_t; + using _dynamic_names_t = typename _column_list_t::_dynamic_names_t; + + using _is_select = std::true_type; + using _requires_braces = std::true_type; + + // FIXME: introduce checks whether this select could really be used as a value + using _value_type = typename _column_list_t::_value_type; + using _name_t = typename _column_list_t::_name_t; + select_t() {} @@ -99,27 +123,11 @@ namespace sqlpp select_t& operator=(select_t&& r) = default; ~select_t() = default; - using _is_select = std::true_type; - using _requires_braces = std::true_type; - - /* - using _result_row_t = typename ColumnList::_result_row_t; - using _dynamic_names_t = typename ColumnList::_dynamic_names_t; - using _parameter_tuple_t = std::tuple; - using _parameter_list_t = typename make_parameter_list_t::type; - // Indicators - using _value_type = typename std::conditional< - vendor::is_noop::value, - no_value_t, // If there is no from, the select is not complete (this logic is a bit simple, but better than nothing) - typename ColumnList::_value_type>::type; - - using _name_t = typename ColumnList::_name_t; - template struct _pseudo_table_t { - using table = typename ColumnList::template _pseudo_table_t; + using table = typename _column_list_t::template _pseudo_table_t; using alias = typename table::template _alias_t; }; @@ -130,9 +138,9 @@ namespace sqlpp *this).as(aliasProvider); } - const typename ColumnList::_dynamic_names_t& get_dynamic_names() const + const _dynamic_names_t& get_dynamic_names() const { - return _columns._dynamic_columns._dynamic_expression_names; + return _column_list_t::_dynamic_columns._dynamic_expression_names; } static constexpr size_t _get_static_no_of_parameters() @@ -155,13 +163,8 @@ namespace sqlpp auto _run(Db& db) const -> result_t { - static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); - static_assert(is_from_t::value, "cannot run select without a from()"); - static_assert(is_where_t::value, "cannot run select without having a where condition, use .where(true) to select all rows"); + static_assert(detail::select_helper_t::template can_run_t::value, "Cannot execute select statement"); static_assert(_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); - // FIXME: Check for missing aliases (if references are used) - // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. - return {db.select(*this), get_dynamic_names()}; } @@ -170,14 +173,10 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_select_t { - static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); - static_assert(is_from_t::value, "cannot run select without a from()"); - // FIXME: Check for missing aliases (if references are used) - // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. + static_assert(detail::select_helper_t::template can_run_t::value, "Cannot prepare select statement"); return {{}, get_dynamic_names(), db.prepare_select(*this)}; } -*/ }; namespace vendor @@ -218,6 +217,39 @@ namespace sqlpp vendor::no_limit_t, vendor::no_offset_t>; + template + struct as_tuple + { + static std::tuple _(T t) { return { t }; }; + }; + + template + struct as_tuple> + { + static std::tuple _(std::tuple t) { return t; } + }; + + template class Target, typename First, typename T> + struct copy_tuple_args_impl + { + static_assert(vendor::wrong_t::value, "copy_tuple_args must be called with a tuple"); + }; + + template class Target, typename First, typename... Args> + struct copy_tuple_args_impl> + { + using type = Target; + }; + + template class Target, typename First, typename T> + using copy_tuple_args_t = typename copy_tuple_args_impl::type; + + template + using make_select_column_list_t = + copy_tuple_args_t::_(std::declval())...))>; + + blank_select_t select() // FIXME: These should be constexpr { return { blank_select_t() }; @@ -225,22 +257,24 @@ namespace sqlpp template auto select(Columns... columns) - -> vendor::update_policies_t, vendor::no_select_column_list_t, vendor::select_column_list_t> + -> vendor::update_policies_t, + vendor::no_select_column_list_t, + make_select_column_list_t> { - return { blank_select_t(), vendor::select_column_list_t(columns...) }; + return { blank_select_t(), make_select_column_list_t(std::tuple_cat(as_tuple::_(columns)...)) }; } template - blank_select_t dynamic_select() + blank_select_t dynamic_select(const Database&) { - return { blank_select_t() }; + return { blank_select_t() }; } template - auto dynamic_select(Columns... columns) - -> vendor::update_policies_t, vendor::no_select_column_list_t, vendor::select_column_list_t> + auto dynamic_select(const Database&, Columns... columns) + -> vendor::update_policies_t, vendor::no_select_column_list_t, make_select_column_list_t> { - return { blank_select_t(), vendor::select_column_list_t(columns...) }; + return { blank_select_t(), make_select_column_list_t(std::tuple_cat(as_tuple::_(columns)...)) }; } } diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index ea90f17b..30bf75c4 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -170,6 +170,10 @@ namespace sqlpp template using _dynamic_t = select_column_list_t>; + select_column_list_t(std::tuple columns): + _columns(columns) + {} + select_column_list_t(Columns... columns): _columns(columns...) {} @@ -196,6 +200,17 @@ namespace sqlpp struct no_select_column_list_t { using _is_select_column_list = std::true_type; + using _result_row_t = ::sqlpp::result_row_t<>; + using _dynamic_names_t = typename dynamic_select_column_list::_names_t; + using _value_type = no_value_t; + struct _name_t {}; + + template + struct _pseudo_table_t + { + static_assert(wrong_t::value, "Cannot use a select as a table when no columns have been selected yet"); + }; + const no_select_column_list_t& _column_list() const { return *this; } }; diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 89ceeece..78b34db6 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -82,7 +82,18 @@ namespace sqlpp using _is_where = std::true_type; using _is_dynamic = std::false_type; - std::tuple _condition; + where_t(bool condition): + _condition(condition) + {} + + where_t(const where_t&) = default; + where_t(where_t&&) = default; + where_t& operator=(const where_t&) = default; + where_t& operator=(where_t&&) = default; + ~where_t() = default; + + const where_t& _where() const { return *this; } + bool _condition; }; struct no_where_t @@ -142,7 +153,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - if (not std::get<0>(t._condition)) + if (not t._condition) context << " WHERE NULL"; return context; } diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 3646635e..098710cc 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -131,20 +131,38 @@ int main() interpret(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).flush(); // multi_column + */ interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); // dynamic select - interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta).add_column(t.gamma), printer).flush(); - interpret(dynamic_select(db).dynamic_flags().add_flag(sqlpp::distinct).dynamic_columns().add_column(t.gamma).add_column(t.beta), printer).flush(); - interpret(dynamic_select(db).dynamic_flags(sqlpp::distinct).add_flag(sqlpp::all).dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); + { + auto s = dynamic_select(db).dynamic_flags().dynamic_columns(); + s.add_column(t.beta); + s.add_column(t.gamma); + interpret(s, printer).flush(); + } + { + auto s = dynamic_select(db).dynamic_flags().dynamic_columns(); + s.add_flag(sqlpp::distinct); + s.add_column(t.beta); + s.add_column(t.gamma); + interpret(s, printer).flush(); + } + { + auto s = dynamic_select(db).dynamic_flags(sqlpp::distinct).dynamic_columns(t.alpha); + s.add_flag(sqlpp::all); + s.add_column(t.beta); + s.add_column(t.gamma); + interpret(s, printer).flush(); + } + /* // distinct aggregate interpret(count(sqlpp::distinct, t.alpha % 7), printer).flush(); interpret(avg(sqlpp::distinct, t.alpha - 7), printer).flush(); interpret(sum(sqlpp::distinct, t.alpha + 7), printer).flush(); - +*/ interpret(select(all_of(t)).from(t).where(true), printer).flush(); interpret(select(all_of(t)).from(t).where(false), printer).flush(); -*/ return 0; } From 5b67061fca68fa12d77723d46078543dcf994571 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 17:12:40 +0100 Subject: [PATCH 08/12] Fixed multi_column to handle all_of again --- include/sqlpp11/detail/copy_tuple_args.h | 67 ++++++++++++++++++++++++ include/sqlpp11/multi_column.h | 49 ++++++++++------- include/sqlpp11/select.h | 48 +++++------------ tests/InterpretTest.cpp | 1 + 4 files changed, 112 insertions(+), 53 deletions(-) create mode 100644 include/sqlpp11/detail/copy_tuple_args.h diff --git a/include/sqlpp11/detail/copy_tuple_args.h b/include/sqlpp11/detail/copy_tuple_args.h new file mode 100644 index 00000000..caac57d8 --- /dev/null +++ b/include/sqlpp11/detail/copy_tuple_args.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013, 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_DETAIL_COPY_TUPLE_ARGS_H +#define SQLPP_DETAIL_COPY_TUPLE_ARGS_H + +#include + +namespace sqlpp +{ + namespace detail + { + template + struct as_tuple + { + static std::tuple _(T t) { return { t }; }; + }; + + template + struct as_tuple> + { + static std::tuple _(std::tuple t) { return t; } + }; + + template class Target, typename First, typename T> + struct copy_tuple_args_impl + { + static_assert(vendor::wrong_t::value, "copy_tuple_args must be called with a tuple"); + }; + + template class Target, typename First, typename... Args> + struct copy_tuple_args_impl> + { + using type = Target; + }; + + template class Target, typename First, typename T> + using copy_tuple_args_t = typename copy_tuple_args_impl::type; + + } +} + + +#endif diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index 61d1f5f2..c60ee57d 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -30,36 +30,47 @@ #include #include +#include + namespace sqlpp { - template + template struct multi_column_t { - static_assert(vendor::wrong_t::value, "invalid argument for multicolumn_t"); - }; - - template - struct multi_column_t> - { - static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); + static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); using _name_t = typename AliasProvider::_name_t; + multi_column_t(std::tuple columns): + _columns(columns) + {} + + multi_column_t(Columns... columns): + _columns(columns...) + {} + + multi_column_t(const multi_column_t&) = default; + multi_column_t(multi_column_t&&) = default; + multi_column_t& operator=(const multi_column_t&) = default; + multi_column_t& operator=(multi_column_t&&) = default; + ~multi_column_t() = default; + + struct _value_type: public no_value_t { using _is_named_expression = std::true_type; }; using _is_multi_column = std::true_type; - std::tuple _columns; + std::tuple _columns; }; namespace vendor { - template - struct interpreter_t> + template + struct interpreter_t> { - using T = multi_column_t; + using T = multi_column_t; static Context& _(const T& t, Context& context) { @@ -71,18 +82,20 @@ namespace sqlpp namespace detail { -#warning need to handle all_of here. - template + template using make_multi_column_t = - multi_column_t>; + detail::copy_tuple_args_t::_(std::declval())...))>; } - template - detail::make_multi_column_t multi_column(const AliasProvider& aliasProvider, NamedExpr... namedExpr) + template + auto multi_column(const AliasProvider&, Columns... columns) + -> detail::make_multi_column_t { - return { std::tuple(namedExpr...)}; + return detail::make_multi_column_t(std::tuple_cat(detail::as_tuple::_(columns)...)); } + } #endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 98795f71..7c6ba00d 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -48,6 +48,8 @@ #include #include +#include + namespace sqlpp { namespace detail @@ -217,37 +219,13 @@ namespace sqlpp vendor::no_limit_t, vendor::no_offset_t>; - template - struct as_tuple - { - static std::tuple _(T t) { return { t }; }; - }; - - template - struct as_tuple> - { - static std::tuple _(std::tuple t) { return t; } - }; - - template class Target, typename First, typename T> - struct copy_tuple_args_impl - { - static_assert(vendor::wrong_t::value, "copy_tuple_args must be called with a tuple"); - }; - - template class Target, typename First, typename... Args> - struct copy_tuple_args_impl> - { - using type = Target; - }; - - template class Target, typename First, typename T> - using copy_tuple_args_t = typename copy_tuple_args_impl::type; - - template - using make_select_column_list_t = - copy_tuple_args_t::_(std::declval())...))>; + namespace detail + { + template + using make_select_column_list_t = + copy_tuple_args_t::_(std::declval())...))>; + } blank_select_t select() // FIXME: These should be constexpr @@ -259,9 +237,9 @@ namespace sqlpp auto select(Columns... columns) -> vendor::update_policies_t, vendor::no_select_column_list_t, - make_select_column_list_t> + detail::make_select_column_list_t> { - return { blank_select_t(), make_select_column_list_t(std::tuple_cat(as_tuple::_(columns)...)) }; + return { blank_select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; } template @@ -272,9 +250,9 @@ namespace sqlpp template auto dynamic_select(const Database&, Columns... columns) - -> vendor::update_policies_t, vendor::no_select_column_list_t, make_select_column_list_t> + -> vendor::update_policies_t, vendor::no_select_column_list_t, detail::make_select_column_list_t> { - return { blank_select_t(), make_select_column_list_t(std::tuple_cat(as_tuple::_(columns)...)) }; + return { blank_select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; } } diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 098710cc..f8a7e208 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -133,6 +133,7 @@ int main() // multi_column */ interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); + interpret(multi_column(t, all_of(t)), printer).flush(); // dynamic select { From 68750aac80954de6a220e0730eb7565daa585ce7 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 21:06:23 +0100 Subject: [PATCH 09/12] Refactored insert to use policies Much cleaner now. --- include/sqlpp11/insert.h | 183 +++++--------- include/sqlpp11/remove.h | 32 +-- include/sqlpp11/vendor/insert_list.h | 141 ----------- include/sqlpp11/vendor/insert_value_list.h | 225 +++++++++++++++--- .../vendor/{column_list.h => single_table.h} | 69 ++++-- tests/InterpretTest.cpp | 23 +- 6 files changed, 323 insertions(+), 350 deletions(-) delete mode 100644 include/sqlpp11/vendor/insert_list.h rename include/sqlpp11/vendor/{column_list.h => single_table.h} (52%) diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index 918b3892..f46459be 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -31,114 +31,56 @@ #include #include #include -#include #include -#include -#include +#include #include +#include +#include +#include namespace sqlpp { + namespace detail + { + template< + typename Table, + typename InsertValueList, + > + struct check_insert_t + { + //static_assert(not (vendor::is_noop::value and vendor::is_noop::value) , "calling set() or default_values()"); + static constexpr bool value = true; + }; + } - template< - typename Database = void, - typename Table = vendor::noop, - typename InsertList = vendor::noop, - typename ColumnList = vendor::noop, - typename ValueList = vendor::insert_value_list_t - > - struct insert_t + template + struct insert_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... { - static_assert(vendor::is_noop
::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(vendor::is_noop::value or is_insert_list_t::value, "invalid 'InsertList' argument"); - static_assert(vendor::is_noop::value or is_column_list_t::value, "invalid 'ColumnList' argument"); - static_assert(vendor::is_noop::value or is_insert_value_list_t::value, "invalid 'ValueList' argument"); + template + using _policy_update_t = insert_t...>; - using use_default_values_t = insert_t; - template - using set_insert_list_t = insert_t; - template - using set_column_value_list_t = insert_t; - - using _parameter_tuple_t = std::tuple; + using _database_t = Database; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - auto default_values() - -> use_default_values_t - { - static_assert(std::is_same::value, "cannot call default_values() after set() or default_values()"); - static_assert(vendor::is_noop::value, "cannot call default_values() after columns()"); - static_assert(Table::_required_insert_columns::size::value == 0, "cannot use default_values, because some columns are configured to require values"); - return { - _table, - {}, - _column_list, - _value_list, - }; - } + insert_t() + {} - template - auto set(Assignment... assignment) - -> set_insert_list_t> - { - static_assert(std::is_same::value, "cannot call set() after set() or default_values()"); - static_assert(vendor::is_noop::value, "cannot call set() after columns()"); - // FIXME: Need to check if all required columns are set - return { - _table, - vendor::insert_list_t{assignment...}, - _column_list, - _value_list, - }; - } + template + insert_t(insert_t i, Whatever whatever): + vendor::policy_t(i, whatever)... + {} - template - auto dynamic_set(Assignment... assignment) - -> set_insert_list_t> - { - static_assert(std::is_same::value, "cannot call set() after set() or default_values()"); - static_assert(vendor::is_noop::value, "cannot call set() after columns()"); - return { - _table, - vendor::insert_list_t{assignment...}, - _column_list, - _value_list, - }; - } + template + insert_t(Insert i, Whatever whatever): + vendor::policy_t(i, whatever)... + {} - template - insert_t add_set(Assignment assignment) - { - static_assert(is_dynamic_t::value, "cannot call add_set() in a non-dynamic set"); - - _insert_list.add(assignment); - - return *this; - } - - template - auto columns(Column... columns) - -> set_column_value_list_t, vendor::insert_value_list_t...>> - { - static_assert(vendor::is_noop::value, "cannot call columns() twice"); - static_assert(vendor::is_noop::value, "cannot call columns() after set() or dynamic_set()"); - // FIXME: Need to check if all required columns are set - - return { - _table, - _insert_list, - {std::tuple...>{{columns}...}}, - vendor::insert_value_list_t...>{}, - }; - } - - template - insert_t& add_values(Value... values) - { - static_assert(is_insert_value_list_t::value, "cannot call add_values() before columns()"); - _value_list.add(typename ValueList::_value_tuple_t{values...}); - return *this; - }; + insert_t(const insert_t&) = default; + insert_t(insert_t&&) = default; + insert_t& operator=(const insert_t&) = default; + insert_t& operator=(insert_t&&) = default; + ~insert_t() = default; static constexpr size_t _get_static_no_of_parameters() { @@ -153,8 +95,8 @@ namespace sqlpp template std::size_t _run(Db& db) const { - static_assert(not (vendor::is_noop::value and vendor::is_noop::value) , "calling set() or default_values()"); static_assert(_get_static_no_of_parameters() == 0, "cannot run insert directly with parameters, use prepare instead"); + static_assert(detail::check_insert_t::value, "Cannot run this insert expression"); return db.insert(*this); } @@ -162,60 +104,43 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_insert_t { - constexpr bool calledSet = not vendor::is_noop::value; - constexpr bool requireSet = Table::_required_insert_columns::size::value > 0; - static_assert(calledSet or not requireSet, "calling set() required for given table"); - + static_assert(detail::check_insert_t::value, "Cannot prepare this insert expression"); return {{}, db.prepare_insert(*this)}; } - - Table _table; - InsertList _insert_list; - ColumnList _column_list; - ValueList _value_list; }; namespace vendor { - template - struct interpreter_t> + template + struct interpreter_t> { - using T = insert_t; + using T = insert_t; static Context& _(const T& t, Context& context) { - if (not vendor::is_noop::value) - { - context << "INSERT INTO "; - interpret(t._table, context); - interpret(t._insert_list, context); - } - else if (not t._value_list.empty()) - { - context << "INSERT INTO "; - interpret(t._table, context); - interpret(t._column_list, context); - interpret(t._value_list, context); - } - else - { - context << "# empty insert"; - } + context << "INSERT INTO "; + interpret(t._single_table(), context); + interpret(t._insert_value_list(), context); return context; } }; } + template + using blank_insert_t = insert_t; + template - insert_t insert_into(Table table) + constexpr auto insert_into(Table table) + -> insert_t, vendor::no_insert_value_list_t> { - return {table}; + return { blank_insert_t(), vendor::single_table_t{table} }; } template - insert_t dynamic_insert_into(const Database& db, Table table) + constexpr auto dynamic_insert_into(const Database&, Table table) + -> insert_t, vendor::no_insert_value_list_t> { - return {table}; + return { blank_insert_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index d7601bc8..5d097838 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -42,7 +42,7 @@ namespace sqlpp { namespace detail { - template + template struct check_remove_t { static_assert(is_where_t::value, "cannot run remove without having a where condition, use .where(true) to remove all rows"); @@ -73,10 +73,10 @@ namespace sqlpp vendor::policy_t(r, whatever)... {} - remove_t(const remove_t& r) = default; - remove_t(remove_t&& r) = default; - remove_t& operator=(const remove_t& r) = default; - remove_t& operator=(remove_t&& r) = default; + remove_t(const remove_t&) = default; + remove_t(remove_t&&) = default; + remove_t& operator=(const remove_t&) = default; + remove_t& operator=(remove_t&&) = default; ~remove_t() = default; static constexpr size_t _get_static_no_of_parameters() @@ -93,7 +93,7 @@ namespace sqlpp std::size_t _run(Db& db) const { static_assert(_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead"); - static_assert(detail::check_remove_t::value, "Cannot run this expression"); + static_assert(detail::check_remove_t::value, "Cannot run this remove expression"); return db.remove(*this); } @@ -101,7 +101,7 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_remove_t { - static_assert(detail::check_remove_t::value, "Cannot run this expression"); + static_assert(detail::check_remove_t::value, "Cannot run this remove expression"); return {{}, db.prepare_remove(*this)}; } }; @@ -115,8 +115,8 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - context << "DELETE"; - interpret(t._from(), context); + context << "DELETE FROM"; + interpret(t._single_table(), context); interpret(t._using(), context); interpret(t._where(), context); return context; @@ -125,18 +125,20 @@ namespace sqlpp } template - using blank_remove_t = remove_t; + using blank_remove_t = remove_t; template - constexpr remove_t, vendor::no_using_t, vendor::no_where_t> remove_from(Table table) + constexpr auto remove_from(Table table) + -> remove_t, vendor::no_using_t, vendor::no_where_t> { - return { blank_remove_t(), vendor::from_t{table} }; + return { blank_remove_t(), vendor::single_table_t{table} }; } template - constexpr remove_t, vendor::no_using_t, vendor::no_where_t> dynamic_remove_from(const Database&, Table table) + constexpr auto dynamic_remove_from(const Database&, Table table) + -> remove_t, vendor::no_using_t, vendor::no_where_t> { - return { blank_remove_t(), vendor::from_t{table} }; + return { blank_remove_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/vendor/insert_list.h b/include/sqlpp11/vendor/insert_list.h deleted file mode 100644 index 2d30390f..00000000 --- a/include/sqlpp11/vendor/insert_list.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013, 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_INSERT_LIST_H -#define SQLPP_INSERT_LIST_H - -#include -#include -#include -#include -#include - -namespace sqlpp -{ - namespace vendor - { - struct insert_default_values_t - { - using _is_insert_list = std::true_type; - using _is_dynamic = std::false_type; - }; - - template - struct interpreter_t - { - using T = insert_default_values_t; - - static Context& _(const T& t, Context& context) - { - context << " DEFAULT VALUES"; - return context; - } - }; - - template - struct insert_list_t - { - using _is_insert_list = std::true_type; - using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - using _parameter_tuple_t = std::tuple; - template class Target> - using copy_assignments_t = Target; // FIXME: Nice idea to copy variadic template arguments? - template class Target, template class Wrap> - using copy_wrapped_assignments_t = Target...>; - - // check for at least one order expression - static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()"); - - // check for duplicate assignments - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - - // check for invalid assignments - static_assert(sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); - - // check for prohibited assignments - static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); - - insert_list_t(Assignments... assignment): - _assignments(assignment...), - _columns({assignment._lhs}...), - _values(assignment._rhs...) - {} - - insert_list_t(const insert_list_t&) = default; - insert_list_t(insert_list_t&&) = default; - insert_list_t& operator=(const insert_list_t&) = default; - insert_list_t& operator=(insert_list_t&&) = default; - ~insert_list_t() = default; - - template - void add(Assignment assignment) - { - static_assert(is_assignment_t::value, "set() arguments require to be assigments"); - static_assert(not must_not_insert_t::value, "set() argument must not be used in insert"); - _dynamic_columns.emplace_back(simple_column_t{assignment._lhs}); - _dynamic_values.emplace_back(assignment._rhs); - } - - - std::tuple...> _columns; - std::tuple _values; - std::tuple _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments) - typename vendor::interpretable_list_t _dynamic_columns; - typename vendor::interpretable_list_t _dynamic_values; - }; - - template - struct interpreter_t> - { - using T = insert_list_t; - - static Context& _(const T& t, Context& context) - { - if (sizeof...(Assignments) + t._dynamic_columns.size() == 0) - { - interpret(insert_default_values_t(), context); - } - else - { - context << " ("; - interpret_tuple(t._columns, ",", context); - if (sizeof...(Assignments) and not t._dynamic_columns.empty()) - context << ','; - interpret_list(t._dynamic_columns, ',', context); - context << ") VALUES("; - interpret_tuple(t._values, ",", context); - if (sizeof...(Assignments) and not t._dynamic_values.empty()) - context << ','; - interpret_list(t._dynamic_values, ',', context); - context << ")"; - } - return context; - } - }; - } -} - -#endif diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 76fc1552..5d750be6 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -29,28 +29,102 @@ #include #include -#include #include +#include +#include +#include +#include namespace sqlpp { namespace vendor { - template - struct insert_value_list_t + // COLUMN AND VALUE LIST + struct insert_default_values_t + { + using _is_insert_list = std::true_type; + using _is_dynamic = std::false_type; + const insert_default_values_t& _insert_value_list() const { return *this; } + }; + + template + struct insert_list_t { - using _is_insert_value_list = std::true_type; + using _is_insert_list = std::true_type; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; + template class Target> + using copy_assignments_t = Target; // FIXME: Nice idea to copy variadic template arguments? + template class Target, template class Wrap> + using copy_wrapped_assignments_t = Target...>; - static_assert(sizeof...(InsertValues), "at least one insert value required"); + static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one select expression required in set()"); - // check for invalid arguments - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an insert value"); + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - using _value_tuple_t = std::tuple; + static_assert(sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); - void add(_value_tuple_t value_tuple) + static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + + insert_list_t(Assignments... assignment): + _assignments(assignment...), + _columns({assignment._lhs}...), + _values(assignment._rhs...) + {} + + insert_list_t(const insert_list_t&) = default; + insert_list_t(insert_list_t&&) = default; + insert_list_t& operator=(const insert_list_t&) = default; + insert_list_t& operator=(insert_list_t&&) = default; + ~insert_list_t() = default; + + template + void add_set(Assignment assignment) + { + static_assert(is_assignment_t::value, "set() arguments require to be assigments"); + static_assert(not must_not_insert_t::value, "set() argument must not be used in insert"); + _dynamic_columns.emplace_back(simple_column_t{assignment._lhs}); + _dynamic_values.emplace_back(assignment._rhs); + } + + + const insert_list_t& _insert_value_list() const { return *this; } + std::tuple...> _columns; + std::tuple _values; + std::tuple _assignments; // FIXME: Need to replace _columns and _values by _assignments (connector-container requires assignments) + typename vendor::interpretable_list_t _dynamic_columns; + typename vendor::interpretable_list_t _dynamic_values; + }; + + template + struct column_list_t + { + using _is_column_list = std::true_type; + using _parameter_tuple_t = std::tuple; + + static_assert(sizeof...(Columns), "at least one column required in columns()"); + + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); + + static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a column in columns()"); + + static_assert(not ::sqlpp::detail::or_t::value, "at least one column argument has a must_not_insert flag in its definition"); + + using _value_tuple_t = std::tuple...>; + + column_list_t(Columns... columns): + _columns(simple_column_t{columns}...) + {} + + column_list_t(const column_list_t&) = default; + column_list_t(column_list_t&&) = default; + column_list_t& operator=(const column_list_t&) = default; + column_list_t& operator=(column_list_t&&) = default; + ~column_list_t() = default; + + void add_values(vendor::insert_value_t... values) { - _insert_values.emplace_back(value_tuple); + _insert_values.emplace_back(values...); } bool empty() const @@ -58,33 +132,95 @@ namespace sqlpp return _insert_values.empty(); } + const column_list_t& _insert_value_list() const { return *this; } + std::tuple...> _columns; std::vector<_value_tuple_t> _insert_values; }; - template<> - struct insert_value_list_t + struct no_insert_value_list_t + { + using _is_insert_value_list = std::true_type; + const no_insert_value_list_t& _insert_value_list() const { return *this; } + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t { - using _is_insert_value_list = std::true_type; - - using _value_tuple_t = std::tuple<>; - - void add(_value_tuple_t value_tuple) - { - } - - static constexpr bool empty() - { - return true; - } }; - template - struct interpreter_t> + template + struct crtp_wrapper_t> { - using T = insert_value_list_t; + }; + + template + struct crtp_wrapper_t> + { + }; + + template + struct crtp_wrapper_t + { + template + struct delayed_t + { + using type = Derived; + }; + + template + auto default_values() + -> vendor::update_policies_t::type, no_insert_value_list_t, insert_default_values_t> + { + return { static_cast(*this), insert_default_values_t{} }; + } + + template + auto columns(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), column_list_t(args...) }; + } + + template + auto set(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), insert_list_t(args...) }; + } + + template + auto dynamic_set(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_insert_list must not be called in a static statement"); + return { static_cast(*this), insert_list_t, Args...>(args...) }; + } + }; + + // Interpreters + template + struct interpreter_t + { + using T = insert_default_values_t; static Context& _(const T& t, Context& context) { + context << " DEFAULT VALUES"; + return context; + } + }; + + template + struct interpreter_t> + { + using T = column_list_t; + + static Context& _(const T& t, Context& context) + { + context << " ("; + interpret_tuple(t._columns, ",", context); + context << ")"; context << " VALUES "; bool first = true; for (const auto& row : t._insert_values) @@ -97,20 +233,51 @@ namespace sqlpp interpret_tuple(row, ",", context); context << ')'; } + + return context; + } + }; + + template + struct interpreter_t> + { + using T = insert_list_t; + + static Context& _(const T& t, Context& context) + { + if (sizeof...(Assignments) + t._dynamic_columns.size() == 0) + { + interpret(insert_default_values_t(), context); + } + else + { + context << " ("; + interpret_tuple(t._columns, ",", context); + if (sizeof...(Assignments) and not t._dynamic_columns.empty()) + context << ','; + interpret_list(t._dynamic_columns, ',', context); + context << ") VALUES("; + interpret_tuple(t._values, ",", context); + if (sizeof...(Assignments) and not t._dynamic_values.empty()) + context << ','; + interpret_list(t._dynamic_values, ',', context); + context << ")"; + } return context; } }; template - struct interpreter_t> + struct interpreter_t { - using T = insert_value_list_t; + using T = no_insert_value_list_t; static Context& _(const T& t, Context& context) { return context; } }; + } } diff --git a/include/sqlpp11/vendor/column_list.h b/include/sqlpp11/vendor/single_table.h similarity index 52% rename from include/sqlpp11/vendor/column_list.h rename to include/sqlpp11/vendor/single_table.h index e8bbdb9a..eb77b0cf 100644 --- a/include/sqlpp11/vendor/column_list.h +++ b/include/sqlpp11/vendor/single_table.h @@ -24,53 +24,70 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_COLUMN_LIST_H -#define SQLPP_COLUMN_LIST_H +#ifndef SQLPP_VENDOR_SINGLE_TABLE_H +#define SQLPP_VENDOR_SINGLE_TABLE_H #include -#include -#include -#include +#include +#include +#include // FIXME: REMOVE namespace sqlpp { namespace vendor { - template - struct column_list_t + // A SINGLE TABLE + template + struct single_table_t { - using _is_column_list = std::true_type; - using _parameter_tuple_t = std::tuple; + using _is_single_table = std::true_type; - // check for at least one order column - static_assert(sizeof...(Columns), "at least one column required in columns()"); + static_assert(is_table_t
::value, "argument has to be a table"); - // check for duplicate columns - static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); + single_table_t(Table table): + _table(table) + {} - // check for invalid columns - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a column in columns()"); + single_table_t(const single_table_t&) = default; + single_table_t(single_table_t&&) = default; + single_table_t& operator=(const single_table_t&) = default; + single_table_t& operator=(single_table_t&&) = default; + ~single_table_t() = default; - // check for prohibited columns - static_assert(not ::sqlpp::detail::or_t::value, "at least one column argument has a must_not_insert flag in its definition"); - - std::tuple...> _columns; + const single_table_t& _single_table() const { return *this; } + Table _table; }; - template - struct interpreter_t> + struct no_single_table_t + { + using _is_single_table = std::true_type; + const no_single_table_t& _single_table() const { return *this; } + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> { - using T = column_list_t; + }; + + template + struct crtp_wrapper_t + { + }; + + // Interpreters + template + struct interpreter_t> + { + using T = single_table_t; static Context& _(const T& t, Context& context) { - context << " ("; - interpret_tuple(t._columns, ",", context); - context << ")"; - + interpret(t._table, context); return context; } }; + } } diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index f8a7e208..d5bf6377 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -43,18 +43,19 @@ int main() test::TabFoo f; test::TabBar t; - /* interpret(insert_into(t).columns(t.gamma, t.beta), printer).flush(); - interpret(insert_into(t).columns(t.gamma, t.beta).add_values(t.gamma = true, t.beta = "cheesecake"), printer).flush(); - interpret(insert_into(t).columns(t.gamma, t.beta) - .add_values(t.gamma = true, t.beta = "cheesecake") - .add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee")) - .add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string())) - , printer).flush(); - interpret(insert_into(t).columns(t.gamma, t.beta) - .add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null) - , printer).flush(); + { + auto i = insert_into(t).columns(t.gamma, t.beta); + i.add_values(t.gamma = true, t.beta = "cheesecake"); + interpret(i, printer).flush(); + i.add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee")); + i.add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string())); + interpret(i, printer).flush(); + i.add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null); + interpret(i, printer).flush(); + } + /* interpret(t.alpha = sqlpp::null, printer).flush(); interpret(t.alpha = sqlpp::default_value, printer).flush(); interpret(t.alpha, printer).flush(); @@ -87,12 +88,14 @@ int main() interpret(parameter(t.alpha), printer).flush(); interpret(t.alpha == parameter(t.alpha), printer).flush(); interpret(t.alpha == parameter(t.alpha) and (t.beta + "gimmick").like(parameter(t.beta)), printer).flush(); + */ interpret(insert_into(t), printer).flush(); interpret(insert_into(f).default_values(), printer).flush(); interpret(insert_into(t).set(t.gamma = true), printer).flush(); //interpret(insert_into(t).set(t.gamma = sqlpp::tvin(false)), printer).flush(); cannot test this since gamma cannot be null and a static assert is thrown + /* interpret(update(t), printer).flush(); interpret(update(t).set(t.gamma = true), printer).flush(); interpret(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).flush(); From 3c6e7cb89a9f1b08c1abf5e85aefd2b5be182aec Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 22:24:05 +0100 Subject: [PATCH 10/12] Fixed a bunch of smaller migration errors --- include/sqlpp11/detail/copy_tuple_args.h | 2 +- include/sqlpp11/insert.h | 4 +- include/sqlpp11/remove.h | 2 +- include/sqlpp11/update.h | 184 ++++++++--------------- include/sqlpp11/vendor/field.h | 2 +- include/sqlpp11/vendor/limit.h | 5 +- include/sqlpp11/vendor/offset.h | 5 +- include/sqlpp11/vendor/update_list.h | 62 +++++++- tests/CMakeLists.txt | 12 +- tests/InsertTest.cpp | 2 +- tests/InterpretTest.cpp | 11 +- tests/RemoveTest.cpp | 8 +- tests/SelectTest.cpp | 17 ++- tests/UpdateTest.cpp | 2 +- 14 files changed, 157 insertions(+), 161 deletions(-) diff --git a/include/sqlpp11/detail/copy_tuple_args.h b/include/sqlpp11/detail/copy_tuple_args.h index caac57d8..f41d2443 100644 --- a/include/sqlpp11/detail/copy_tuple_args.h +++ b/include/sqlpp11/detail/copy_tuple_args.h @@ -36,7 +36,7 @@ namespace sqlpp template struct as_tuple { - static std::tuple _(T t) { return { t }; }; + static std::tuple _(T t) { return std::tuple{ t }; }; }; template diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index f46459be..ccd4583b 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -44,7 +44,7 @@ namespace sqlpp { template< typename Table, - typename InsertValueList, + typename InsertValueList > struct check_insert_t { @@ -140,7 +140,7 @@ namespace sqlpp constexpr auto dynamic_insert_into(const Database&, Table table) -> insert_t, vendor::no_insert_value_list_t> { - return { blank_insert_t(), vendor::single_table_t{table} }; + return { blank_insert_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index 5d097838..d95fd883 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -138,7 +138,7 @@ namespace sqlpp constexpr auto dynamic_remove_from(const Database&, Table table) -> remove_t, vendor::no_using_t, vendor::no_where_t> { - return { blank_remove_t(), vendor::single_table_t{table} }; + return { blank_remove_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index bdc2860d..d50f7a9a 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -30,109 +30,57 @@ #include #include #include +#include #include #include #include +#include +#include +#include namespace sqlpp { - template< - typename Database = void, - typename Table = vendor::noop, - typename Assignments = vendor::noop, - typename Where = vendor::noop - > - struct update_t; - - template< - typename Database, - typename Table, - typename Assignments, - typename Where - > - struct update_t + namespace detail + { + template< + typename Table, + typename Assignments, + typename Where + > + struct check_update_t { - static_assert(vendor::is_noop
::value or is_table_t
::value, "invalid 'Table' argument"); - static_assert(vendor::is_noop::value or is_update_list_t::value, "invalid 'Assignments' arguments"); - static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'Where' argument"); + static constexpr bool value = true; + }; + } - template - using set_assignments_t = update_t; - template - using set_where_t = update_t; + template + struct update_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... + { + template + using _policy_update_t = update_t...>; - using _parameter_tuple_t = std::tuple; + using _database_t = Database; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - template - auto set(Assignment... assignment) - -> set_assignments_t> - { - static_assert(vendor::is_noop::value, "cannot call set() twice"); - return { - _table, - {std::tuple{assignment...}}, - _where, - }; - } + update_t() + {} - template - auto dynamic_set(Assignment... assignment) - -> set_assignments_t> - { - static_assert(vendor::is_noop::value, "cannot call set() twice"); - return { - _table, - {std::tuple{assignment...}}, - _where, - }; - } + template + update_t(update_t r, Whatever whatever): + vendor::policy_t(r, whatever)... + {} - template - update_t& add_set(Assignment assignment) - { - static_assert(is_dynamic_t::value, "cannot call add_set() in a non-dynamic set"); + template + update_t(Remove r, Whatever whatever): + vendor::policy_t(r, whatever)... + {} - _assignments.add(assignment); - - return *this; - } - - template - auto where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call where() if set() hasn't been called yet"); - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _assignments, - {std::tuple{expr...}}, - }; - } - - template - auto dynamic_where(Expr... expr) - -> set_where_t> - { - static_assert(not vendor::is_noop::value, "cannot call where() if set() hasn't been called yet"); - static_assert(vendor::is_noop::value, "cannot call where() twice"); - return { - _table, - _assignments, - {std::tuple{expr...}}, - }; - } - - template - update_t& add_where(Expr expr) - { - static_assert(is_dynamic_t::value, "cannot call add_where() in a non-dynamic where"); - - _where.add(expr); - - return *this; - } + update_t(const update_t&) = default; + update_t(update_t&&) = default; + update_t& operator=(const update_t&) = default; + update_t& operator=(update_t&&) = default; + ~update_t() = default; static constexpr size_t _get_static_no_of_parameters() { @@ -147,59 +95,53 @@ namespace sqlpp template std::size_t _run(Db& db) const { - static_assert(not vendor::is_noop::value, "calling set() required before running update"); - static_assert(is_where_t::value, "cannot run update without having a where condition, use .where(true) to update all rows"); static_assert(_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead"); + static_assert(detail::check_update_t::value, "Cannot run this update expression"); return db.update(*this); } template auto _prepare(Db& db) const - -> prepared_update_t + -> prepared_update_t { - static_assert(not vendor::is_noop::value, "calling set() required before running update"); - + static_assert(detail::check_update_t::value, "Cannot run this update expression"); return {{}, db.prepare_update(*this)}; } - - Table _table; - Assignments _assignments; - Where _where; }; namespace vendor { - template - struct interpreter_t> - { - using T = update_t; + template + struct interpreter_t> + { + using T = update_t; - static Context& _(const T& t, Context& context) - { - context << "UPDATE "; - interpret(t._table, context); - interpret(t._assignments, context); - interpret(t._where, context); - return context; - } - }; + static Context& _(const T& t, Context& context) + { + context << "UPDATE "; + interpret(t._single_table(), context); + interpret(t._update_list(), context); + interpret(t._where(), context); + return context; + } + }; } + template + using blank_update_t = update_t; + template - constexpr update_t update(Table table) + constexpr auto update(Table table) + -> update_t, vendor::no_update_list_t, vendor::no_where_t> { - return {table}; + return { blank_update_t(), vendor::single_table_t{table} }; } - template - constexpr update_t dynamic_update(const Db&, Table table) + template + constexpr auto dynamic_update(const Database&, Table table) + -> update_t, vendor::no_update_list_t, vendor::no_where_t> { - return {table}; + return { blank_update_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/vendor/field.h b/include/sqlpp11/vendor/field.h index cf816b77..33dad90e 100644 --- a/include/sqlpp11/vendor/field.h +++ b/include/sqlpp11/vendor/field.h @@ -54,7 +54,7 @@ namespace sqlpp }; template - struct make_field_t_impl>> + struct make_field_t_impl> { using type = multi_field_t::type...>>; }; diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index bdae95fc..fbdaee20 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -84,7 +84,7 @@ namespace sqlpp void set_limit(Limit value) { using arg_t = typename wrap_operand::type; - _value = arg_t(value); + _value = arg_t{value}; _initialized = true; } @@ -147,7 +147,10 @@ namespace sqlpp static Context& _(const T& t, Context& context) { if (t._initialized) + { + context << " LIMIT "; interpret(t._value, context); + } return context; } }; diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index 1c839887..e5ca8d10 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -160,7 +160,10 @@ namespace sqlpp static Context& _(const T& t, Context& context) { if (t._initialized) - context << " OFFSET " << t._offset; + { + context << " OFFSET "; + interpret(t._value, context); + } return context; } }; diff --git a/include/sqlpp11/vendor/update_list.h b/include/sqlpp11/vendor/update_list.h index a58e92fd..8d620c27 100644 --- a/include/sqlpp11/vendor/update_list.h +++ b/include/sqlpp11/vendor/update_list.h @@ -36,6 +36,7 @@ namespace sqlpp { namespace vendor { + // UPDATE ASSIGNMENTS template struct update_list_t { @@ -43,30 +44,69 @@ namespace sqlpp using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; using _parameter_tuple_t = std::tuple; - // check for at least one order expression static_assert(_is_dynamic::value or sizeof...(Assignments), "at least one assignment expression required in set()"); - // check for duplicate assignments static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - // check for invalid assignments static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); - // check for prohibited assignments static_assert(not ::sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + update_list_t(Assignments... assignments): + _assignments(assignments...) + {} + + update_list_t(const update_list_t&) = default; + update_list_t(update_list_t&&) = default; + update_list_t& operator=(const update_list_t&) = default; + update_list_t& operator=(update_list_t&&) = default; + ~update_list_t() = default; + template - void add(Assignment assignment) + void add_set(Assignment assignment) { static_assert(is_assignment_t::value, "set() arguments require to be assigments"); static_assert(not must_not_update_t::value, "set() argument must not be updated"); _dynamic_assignments.emplace_back(assignment); } + const update_list_t& _update_list() const { return *this; } _parameter_tuple_t _assignments; typename vendor::interpretable_list_t _dynamic_assignments; }; + struct no_update_list_t + { + using _is_update_list = std::true_type; + const no_update_list_t& _update_list() const { return *this; } + }; + + // CRTP Wrappers + template + struct crtp_wrapper_t> + { + }; + + template + struct crtp_wrapper_t + { + template + auto set(Args... args) + -> vendor::update_policies_t> + { + return { static_cast(*this), update_list_t(args...) }; + } + + template + auto dynamic_set(Args... args) + -> vendor::update_policies_t, Args...>> + { + static_assert(not std::is_same, void>::value, "dynamic_update_list must not be called in a static statement"); + return { static_cast(*this), update_list_t, Args...>(args...) }; + } + }; + + // Interpreters template struct interpreter_t> { @@ -82,6 +122,18 @@ namespace sqlpp return context; } }; + + template + struct interpreter_t + { + using T = no_update_list_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef9f5c96..b2a56c15 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,12 +7,12 @@ macro (build_and_run arg) endmacro () build_and_run(InterpretTest) -#build_and_run(InsertTest) -#build_and_run(RemoveTest) -#build_and_run(UpdateTest) -#build_and_run(SelectTest) -#build_and_run(FunctionTest) -#build_and_run(PreparedTest) +build_and_run(InsertTest) +build_and_run(RemoveTest) +build_and_run(UpdateTest) +build_and_run(SelectTest) +build_and_run(FunctionTest) +build_and_run(PreparedTest) find_package(PythonInterp REQUIRED) diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index a116d93c..6238d729 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -60,7 +60,7 @@ int main() interpret(insert_into(t), printer).flush(); interpret(insert_into(t).set(t.beta = "kirschauflauf"), printer).flush(); auto i = dynamic_insert_into(db, t).dynamic_set(); - i = i.add_set(t.beta = "kirschauflauf"); + i.add_set(t.beta = "kirschauflauf"); interpret(i, printer).flush(); return 0; diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index d5bf6377..b8f74d3d 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -55,7 +55,6 @@ int main() interpret(i, printer).flush(); } - /* interpret(t.alpha = sqlpp::null, printer).flush(); interpret(t.alpha = sqlpp::default_value, printer).flush(); interpret(t.alpha, printer).flush(); @@ -70,7 +69,6 @@ int main() interpret(t.gamma != sqlpp::tvin(false), printer).flush(); interpret(t.alpha == 7, printer).flush(); interpret(t.beta + "kaesekuchen", printer).flush(); - */ interpret(sqlpp::select(), printer).flush(); interpret(sqlpp::select().flags(sqlpp::distinct), printer).flush(); @@ -83,29 +81,24 @@ int main() interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush(); interpret(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush(); - /* interpret(parameter(sqlpp::bigint(), t.alpha), printer).flush(); interpret(parameter(t.alpha), printer).flush(); interpret(t.alpha == parameter(t.alpha), printer).flush(); interpret(t.alpha == parameter(t.alpha) and (t.beta + "gimmick").like(parameter(t.beta)), printer).flush(); - */ interpret(insert_into(t), printer).flush(); interpret(insert_into(f).default_values(), printer).flush(); interpret(insert_into(t).set(t.gamma = true), printer).flush(); //interpret(insert_into(t).set(t.gamma = sqlpp::tvin(false)), printer).flush(); cannot test this since gamma cannot be null and a static assert is thrown - /* interpret(update(t), printer).flush(); interpret(update(t).set(t.gamma = true), printer).flush(); interpret(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).flush(); - */ interpret(remove_from(t), printer).flush(); interpret(remove_from(t).using_(t), printer).flush(); interpret(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); interpret(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); - /* // functions sqlpp::interpret(sqlpp::value(7), printer).flush(); // FIXME: Why is the namespace specifier required? @@ -134,7 +127,6 @@ int main() interpret(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).flush(); // multi_column - */ interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); interpret(multi_column(t, all_of(t)), printer).flush(); @@ -159,13 +151,12 @@ int main() s.add_column(t.gamma); interpret(s, printer).flush(); } - /* // distinct aggregate interpret(count(sqlpp::distinct, t.alpha % 7), printer).flush(); interpret(avg(sqlpp::distinct, t.alpha - 7), printer).flush(); interpret(sum(sqlpp::distinct, t.alpha + 7), printer).flush(); -*/ + interpret(select(all_of(t)).from(t).where(true), printer).flush(); interpret(select(all_of(t)).from(t).where(false), printer).flush(); return 0; diff --git a/tests/RemoveTest.cpp b/tests/RemoveTest.cpp index 616a2eaf..398943e6 100644 --- a/tests/RemoveTest.cpp +++ b/tests/RemoveTest.cpp @@ -53,16 +53,16 @@ int main() } { - using T = decltype(dynamic_remove_from(db, t).dynamic_using_().dynamic_where()); + using T = decltype(dynamic_remove_from(db, t).dynamic_using().dynamic_where()); static_assert(sqlpp::is_regular::value, "type requirement"); } interpret(remove_from(t), printer).flush(); interpret(remove_from(t).where(t.beta != "transparent"), printer).flush(); interpret(remove_from(t).using_(t), printer).flush(); - auto r = dynamic_remove_from(db, t).dynamic_using_().dynamic_where(); - r = r.add_using_(t); - r = r.add_where(t.beta != "transparent"); + auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where(); + r.add_using(t); + r.add_where(t.beta != "transparent"); interpret(r, printer).flush(); return 0; diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 94b2b790..8ff93911 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -159,6 +159,8 @@ int main() // Test a select of a single column without a from { using T = decltype(select(t.alpha)); // Hint: The current rule is pretty crude (a from is required), but certainly better than nothing +#warning Need to reactivate these tests + /* static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_expression_t::value, "type requirement"); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); @@ -170,6 +172,7 @@ int main() static_assert(not sqlpp::is_alias_t::value, "type requirement"); static_assert(not sqlpp::is_table_t::value, "type requirement"); static_assert(sqlpp::is_regular::value, "type requirement"); + */ } // Test a select of a single numeric table column @@ -297,7 +300,6 @@ int main() auto a = select(m).from(t).as(alias::b).a; static_assert(not sqlpp::is_value_t::value, "a multi_column is not a value"); } - // Test that result sets with identical name/value combinations have identical types { auto a = select(t.alpha); @@ -312,10 +314,10 @@ int main() { auto s = dynamic_select(db, all_of(t)).dynamic_from().dynamic_where().dynamic_limit().dynamic_offset(); - s = s.add_from(t); - s = s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); - s = s.set_limit(30); - s = s.set_limit(3); + s.add_from(t); + s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); + s.set_limit(30); + s.set_limit(3); std::cerr << "------------------------\n"; interpret(s, printer).flush(); std::cerr << "------------------------\n"; @@ -325,7 +327,8 @@ int main() // Test that select can be called with zero columns if it is used with dynamic columns. { - auto s = dynamic_select(db).dynamic_columns().add_column(t.alpha); + auto s = dynamic_select(db).dynamic_columns(); + s.add_column(t.alpha); interpret(s, printer).flush(); } @@ -360,6 +363,7 @@ int main() auto z = select(t.alpha) == 7; auto l = t.as(alias::left); auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); +#if 0 static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); interpret(select(sqlpp::distinct, sqlpp::straight_join, l.alpha, l.beta, select(r.a).from(r)) .from(l, r) @@ -371,6 +375,7 @@ int main() .offset(3) .as(alias::a) , printer).flush(); +#endif return 0; } diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index a46c3dbd..a4f07fe4 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -59,7 +59,7 @@ int main() interpret(update(t).set(t.gamma = false), printer).flush(); interpret(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); - u = u.add_set(t.gamma = false); + u.add_set(t.gamma = false); interpret(u, printer).flush(); return 0; From 88fc0959b5e8fe82b38170f3b9eaad4ce3a5daf7 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 22:50:26 +0100 Subject: [PATCH 11/12] Added value type back to select --- include/sqlpp11/select.h | 3 ++- tests/SelectTest.cpp | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 7c6ba00d..652c12cf 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -86,7 +86,8 @@ namespace sqlpp // SELECT template - struct select_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... + struct select_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>..., + public detail::select_helper_t::_column_list_t::_value_type::template operators> { template using _policy_update_t = select_t...>; diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 8ff93911..9172920c 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -363,9 +363,8 @@ int main() auto z = select(t.alpha) == 7; auto l = t.as(alias::left); auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); -#if 0 static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); - interpret(select(sqlpp::distinct, sqlpp::straight_join, l.alpha, l.beta, select(r.a).from(r)) + interpret(sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r)) .from(l, r) .where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right)) .group_by(l.gamma, r.a) @@ -375,7 +374,6 @@ int main() .offset(3) .as(alias::a) , printer).flush(); -#endif return 0; } From 61ed1d9f37a9938114d6053e3725349b5729cb52 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 8 Feb 2014 23:48:35 +0100 Subject: [PATCH 12/12] Corrected inconsistency in select value_type --- include/sqlpp11/select.h | 11 ++++++++--- include/sqlpp11/vendor/from.h | 1 - tests/SelectTest.cpp | 5 +---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 652c12cf..27408cff 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -69,6 +69,12 @@ namespace sqlpp { using _column_list_t = ColumnList; using _from_t = ColumnList; + + using _value_type = typename std::conditional< + sqlpp::is_from_t::value, + typename ColumnList::_value_type, + no_value_t // If there is no from, the select is not complete (this logic is a bit simple, but better than nothing) + >::type; template struct can_run_t { @@ -87,7 +93,7 @@ namespace sqlpp // SELECT template struct select_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>..., - public detail::select_helper_t::_column_list_t::_value_type::template operators> + public detail::select_helper_t::_value_type::template operators> { template using _policy_update_t = select_t...>; @@ -103,8 +109,7 @@ namespace sqlpp using _is_select = std::true_type; using _requires_braces = std::true_type; - // FIXME: introduce checks whether this select could really be used as a value - using _value_type = typename _column_list_t::_value_type; + using _value_type = typename detail::select_helper_t::_value_type; using _name_t = typename _column_list_t::_name_t; select_t() diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index 8cdfa710..e94a8c5f 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -79,7 +79,6 @@ namespace sqlpp struct no_from_t { - using _is_from = std::true_type; const no_from_t& _from() const { return *this; } }; diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 9172920c..4f030c75 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -159,8 +159,6 @@ int main() // Test a select of a single column without a from { using T = decltype(select(t.alpha)); // Hint: The current rule is pretty crude (a from is required), but certainly better than nothing -#warning Need to reactivate these tests - /* static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_expression_t::value, "type requirement"); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); @@ -172,7 +170,6 @@ int main() static_assert(not sqlpp::is_alias_t::value, "type requirement"); static_assert(not sqlpp::is_table_t::value, "type requirement"); static_assert(sqlpp::is_regular::value, "type requirement"); - */ } // Test a select of a single numeric table column @@ -360,7 +357,7 @@ int main() static_assert(sqlpp::is_named_expression_t::value, "alpha should be a named expression"); static_assert(sqlpp::is_named_expression_t::value, "an alias of alpha should be a named expression"); static_assert(sqlpp::is_alias_t::value, "an alias of alpha should be an alias"); - auto z = select(t.alpha) == 7; + auto z = select(t.alpha).from(t) == 7; auto l = t.as(alias::left); auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool");