From cc768208707c10bba7dae76780cbb76015e3b52c Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 9 Feb 2014 18:14:52 +0100 Subject: [PATCH 1/8] Migrated insert and remove back to composite design --- include/sqlpp11/insert.h | 127 ++++++++++++++------- include/sqlpp11/remove.h | 125 +++++++++++++++----- include/sqlpp11/type_traits.h | 1 + include/sqlpp11/vendor/insert_value_list.h | 74 ++---------- include/sqlpp11/vendor/noop.h | 1 + include/sqlpp11/vendor/single_table.h | 15 --- include/sqlpp11/vendor/using.h | 28 +---- include/sqlpp11/vendor/where.h | 40 +------ tests/CMakeLists.txt | 10 +- tests/InsertTest.cpp | 1 + tests/RemoveTest.cpp | 1 - 11 files changed, 210 insertions(+), 213 deletions(-) diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index e0c0f6b0..5aac9e34 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -34,49 +34,48 @@ #include #include #include -#include -#include #include namespace sqlpp { - namespace detail - { - template< - typename Table, - typename InsertValueList - > - struct check_insert_t - { - static_assert(Table::_table_set::template is_superset_of::value, "inserted columns do not match the table in insert_into"); - //static_assert(not (vendor::is_noop::value and vendor::is_noop::value) , "calling set() or default_values()"); - static constexpr bool value = true; - }; - } - - template - struct insert_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... + // INSERT + template + struct insert_t { - template - using _policy_update_t = insert_t...>; + static_assert(Table::_table_set::template is_superset_of::value, "inserted columns do not match the table in insert_into"); using _database_t = Database; - using _parameter_tuple_t = std::tuple; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + + template + struct _policies_update_impl + { + using type = insert_t...>; + }; + + template + using _policies_update_t = typename _policies_update_impl::type; + + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; + // Constructors insert_t() {} - static_assert(detail::check_insert_t::value, "invalid insert_into"); - - template - insert_t(insert_t i, Whatever whatever): - vendor::policy_t(i, whatever)... + template + insert_t(X x, Table table): + _table(table), + _insert_value_list(x._insert_value_list) {} - template - insert_t(Insert i, Whatever whatever): - vendor::policy_t(i, whatever)... + template + insert_t(X x, InsertValueList insert_value_list): + _table(x._table), + _insert_value_list(insert_value_list) {} insert_t(const insert_t&) = default; @@ -85,6 +84,56 @@ namespace sqlpp insert_t& operator=(insert_t&&) = default; ~insert_t() = default; + // type update functions + auto default_values() + -> _policies_update_t + { + static_assert(is_noop_t::value, "cannot combine default_values() with other methods"); + return { *this, vendor::insert_default_values_t{} }; + } + + template + auto columns(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot combine columns() with other methods"); + return { *this, vendor::column_list_t(args...) }; + } + + template + auto set(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot combine set() with other methods"); + return { *this, vendor::insert_list_t(args...) }; + } + + template + auto dynamic_set(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot combine dynamic_set() with other methods"); + static_assert(_is_dynamic::value, "dynamic_set must not be called in a static statement"); + return { *this, vendor::insert_list_t<_database_t, Args...>(args...) }; + } + + // value adding methods + template + void add_set(Args... args) + { + static_assert(is_insert_list_t::value, "cannot call add_set() before dynamic_set()"); + static_assert(is_dynamic_t::value, "cannot call add_set() before dynamic_set()"); + return _insert_value_list.add_set(*this, args...); + } + + template + void add_values(Args... args) + { + static_assert(is_column_list_t::value, "cannot call add_set() before columns()"); + return _insert_value_list.add_columns(args...); + } + + // run and prepare static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -99,7 +148,6 @@ namespace sqlpp std::size_t _run(Db& db) const { 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); } @@ -107,9 +155,11 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_insert_t { - static_assert(detail::check_insert_t::value, "Cannot prepare this insert expression"); return {{}, db.prepare_insert(*this)}; } + + InsertValueList _insert_value_list; + Table _table; }; namespace vendor @@ -122,28 +172,25 @@ namespace sqlpp static Context& _(const T& t, Context& context) { context << "INSERT INTO "; - interpret(t._single_table(), context); - interpret(t._insert_value_list(), context); + interpret(t._table, context); + interpret(t._insert_value_list, context); return context; } }; } - template - using blank_insert_t = insert_t; - template constexpr auto insert_into(Table table) - -> insert_t, vendor::no_insert_value_list_t> + -> insert_t> { - return { blank_insert_t(), vendor::single_table_t{table} }; + return { insert_t(), vendor::single_table_t{table} }; } template constexpr auto dynamic_insert_into(const Database&, Table table) - -> insert_t, vendor::no_insert_value_list_t> + -> insert_t> { - return { blank_insert_t(), vendor::single_table_t{table} }; + return { insert_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index d95fd883..d9213f7c 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include namespace sqlpp @@ -50,27 +48,52 @@ namespace sqlpp }; } - template - struct remove_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... + // REMOVE + template + struct remove_t { - template - using _policy_update_t = remove_t...>; - using _database_t = Database; - using _parameter_tuple_t = std::tuple; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + + template + struct _policies_update_impl + { + using type = remove_t...>; + }; + + template + using _policies_update_t = typename _policies_update_impl::type; + + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; + // Constructors remove_t() {} - template - remove_t(remove_t r, Whatever whatever): - vendor::policy_t(r, whatever)... + template + remove_t(X x, Table table): + _table(table), + _using(x._using), + _where(x._where) {} - template - remove_t(Remove r, Whatever whatever): - vendor::policy_t(r, whatever)... + template + remove_t(X x, Using using_): + _table(x._table), + _using(using_), + _where(x._where) + {} + + template + remove_t(X x, Where where): + _table(x._table), + _using(x._using), + _where(where) {} remove_t(const remove_t&) = default; @@ -79,6 +102,55 @@ namespace sqlpp remove_t& operator=(remove_t&&) = default; ~remove_t() = default; + // type update functions + template + auto using_(Args... args) + -> _policies_update_t> + { + return { *this, vendor::using_t(args...) }; + } + + template + auto dynamic_using(Args... args) + -> _policies_update_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_using must not be called in a static statement"); + return { *this, vendor::using_t<_database_t, Args...>(args...) }; + } + + template + auto where(Args... args) + -> _policies_update_t> + { + return { *this, vendor::where_t(args...) }; + } + + template + auto dynamic_where(Args... args) + -> _policies_update_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); + return { *this, vendor::where_t<_database_t, Args...>(args...) }; + } + + // value adding methods + template + void add_using(Args... args) + { + static_assert(is_using_t::value, "cannot call add_using() before dynamic_using()"); + static_assert(is_dynamic_t::value, "cannot call add_using() before dynamic_using()"); + return _using.add_using(args...); + } + + template + void add_where(Args... args) + { + static_assert(is_where_t::value, "cannot call add_where() before dynamic_where()"); + static_assert(is_dynamic_t::value, "cannot call add_where() before dynamic_where()"); + return _where.add_where(*this, args...); + } + + // run and prepare static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -93,7 +165,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 remove expression"); + //static_assert(detail::check_remove_t::value, "Cannot run this remove expression"); return db.remove(*this); } @@ -101,9 +173,13 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_remove_t { - static_assert(detail::check_remove_t::value, "Cannot run this remove expression"); + //static_assert(detail::check_remove_t::value, "Cannot run this remove expression"); return {{}, db.prepare_remove(*this)}; } + + Table _table; + Using _using; + Where _where; }; namespace vendor @@ -116,29 +192,26 @@ namespace sqlpp static Context& _(const T& t, Context& context) { context << "DELETE FROM"; - interpret(t._single_table(), context); - interpret(t._using(), context); - interpret(t._where(), context); + interpret(t._table, context); + interpret(t._using, context); + interpret(t._where, context); return context; } }; } - template - using blank_remove_t = remove_t; - template constexpr auto remove_from(Table table) - -> remove_t, vendor::no_using_t, vendor::no_where_t> + -> remove_t> { - return { blank_remove_t(), vendor::single_table_t{table} }; + return { remove_t(), vendor::single_table_t{table} }; } template constexpr auto dynamic_remove_from(const Database&, Table table) - -> remove_t, vendor::no_using_t, vendor::no_where_t> + -> remove_t> { - return { blank_remove_t(), vendor::single_table_t{table} }; + return { remove_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 83f74895..52f7f90b 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -93,6 +93,7 @@ namespace sqlpp SQLPP_IS_COLUMN_TRAIT_GENERATOR(require_insert); SQLPP_IS_COLUMN_TRAIT_GENERATOR(can_be_null); + SQLPP_TYPE_TRAIT_GENERATOR(is_noop); SQLPP_TYPE_TRAIT_GENERATOR(is_table); SQLPP_TYPE_TRAIT_GENERATOR(is_join); SQLPP_TYPE_TRAIT_GENERATOR(is_pseudo_table); diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index ac6586cb..22668b6a 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -32,8 +32,6 @@ #include #include #include -#include -#include namespace sqlpp { @@ -42,10 +40,8 @@ namespace sqlpp // COLUMN AND VALUE LIST struct insert_default_values_t { - using _is_insert_list = std::true_type; using _table_set = ::sqlpp::detail::type_set<>; using _is_dynamic = std::false_type; - const insert_default_values_t& _insert_value_list() const { return *this; } }; template @@ -82,8 +78,8 @@ namespace sqlpp insert_list_t& operator=(insert_list_t&&) = default; ~insert_list_t() = default; - template - void add_set(Assignment assignment) + template + void add_set(const Insert&, 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"); @@ -92,7 +88,6 @@ namespace sqlpp } - 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) @@ -139,72 +134,23 @@ 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; }; struct no_insert_value_list_t { + using _is_noop = std::true_type; using _table_set = ::sqlpp::detail::type_set<>; - const no_insert_value_list_t& _insert_value_list() const { return *this; } + + template + void add_values(Base base, Args...) + { + static_assert(wrong_t::value, "cannot call add_values() without calling columns() first"); + } + }; - // CRTP Wrappers - template - struct crtp_wrapper_t - { - }; - - template - struct crtp_wrapper_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 diff --git a/include/sqlpp11/vendor/noop.h b/include/sqlpp11/vendor/noop.h index fc057cef..6cd7114c 100644 --- a/include/sqlpp11/vendor/noop.h +++ b/include/sqlpp11/vendor/noop.h @@ -35,6 +35,7 @@ namespace sqlpp { struct noop { + using is_noop = std::true_type; }; template diff --git a/include/sqlpp11/vendor/single_table.h b/include/sqlpp11/vendor/single_table.h index 2a728ea8..53387b6a 100644 --- a/include/sqlpp11/vendor/single_table.h +++ b/include/sqlpp11/vendor/single_table.h @@ -28,8 +28,6 @@ #define SQLPP_VENDOR_SINGLE_TABLE_H #include -#include -#include #include namespace sqlpp @@ -54,7 +52,6 @@ namespace sqlpp single_table_t& operator=(single_table_t&&) = default; ~single_table_t() = default; - const single_table_t& _single_table() const { return *this; } using _table_set = typename Table::_table_set; Table _table; }; @@ -62,20 +59,8 @@ namespace sqlpp struct no_single_table_t { using _table_set = ::sqlpp::detail::type_set<>; - const no_single_table_t& _single_table() const { return *this; } }; - // CRTP Wrappers - template - struct crtp_wrapper_t> - { - }; - - template - struct crtp_wrapper_t - { - }; - // Interpreters template struct interpreter_t> diff --git a/include/sqlpp11/vendor/using.h b/include/sqlpp11/vendor/using.h index 1ad27720..49ab7d9d 100644 --- a/include/sqlpp11/vendor/using.h +++ b/include/sqlpp11/vendor/using.h @@ -71,41 +71,15 @@ namespace sqlpp _dynamic_tables.emplace_back(table); } - const using_t& _using() const { return *this; } _parameter_tuple_t _tables; vendor::interpretable_list_t _dynamic_tables; }; struct no_using_t { - const no_using_t& _using() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrapper - template - struct crtp_wrapper_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> diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 78b34db6..3cac506e 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include namespace sqlpp @@ -63,15 +61,14 @@ namespace sqlpp where_t& operator=(where_t&&) = default; ~where_t() = default; - template - void add_where(E expr) + template + void add_where(const Statement&, Expression expression) { 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); + static_assert(is_expression_t::value, "invalid expression argument in add_where()"); + _dynamic_expressions.emplace_back(expression); } - const where_t& _where() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; @@ -92,41 +89,14 @@ namespace sqlpp where_t& operator=(where_t&&) = default; ~where_t() = default; - const where_t& _where() const { return *this; } bool _condition; }; struct no_where_t { - using _is_where = std::true_type; - const no_where_t& _where() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - template - struct crtp_wrapper_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> diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b2a56c15..b8b3879a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,13 +6,13 @@ macro (build_and_run arg) add_test(${arg} ${arg}) endmacro () -build_and_run(InterpretTest) +#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(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 6238d729..29a3e7c5 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -57,6 +57,7 @@ int main() static_assert(sqlpp::is_regular::value, "type requirement"); } + interpret(insert_into(t).default_values(), printer).flush(); 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(); diff --git a/tests/RemoveTest.cpp b/tests/RemoveTest.cpp index 398943e6..c1f221b0 100644 --- a/tests/RemoveTest.cpp +++ b/tests/RemoveTest.cpp @@ -25,7 +25,6 @@ #include #include -#include #include "Sample.h" #include "MockDb.h" #include "is_regular.h" From 22c43358f2edb7e8830c8100252bb3b8620ac01f Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 9 Feb 2014 23:30:30 +0100 Subject: [PATCH 2/8] All statements back to composite design The point is that even though the CRTP code looked nice, it was too hard to comprehend. --- include/sqlpp11/insert.h | 2 +- include/sqlpp11/remove.h | 4 + include/sqlpp11/select.h | 470 +++++++++++++++++--- include/sqlpp11/select_flags.h | 1 - include/sqlpp11/select_fwd.h | 37 -- include/sqlpp11/update.h | 125 ++++-- include/sqlpp11/vendor/from.h | 27 +- include/sqlpp11/vendor/group_by.h | 32 +- include/sqlpp11/vendor/having.h | 29 +- include/sqlpp11/vendor/limit.h | 44 +- include/sqlpp11/vendor/offset.h | 44 +- include/sqlpp11/vendor/order_by.h | 34 +- include/sqlpp11/vendor/select_column_list.h | 34 +- include/sqlpp11/vendor/select_flag_list.h | 32 +- include/sqlpp11/vendor/update_list.h | 31 +- tests/CMakeLists.txt | 10 +- tests/SelectTest.cpp | 4 +- 17 files changed, 543 insertions(+), 417 deletions(-) delete mode 100644 include/sqlpp11/select_fwd.h diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index 5aac9e34..f55b092f 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -130,7 +130,7 @@ namespace sqlpp void add_values(Args... args) { static_assert(is_column_list_t::value, "cannot call add_set() before columns()"); - return _insert_value_list.add_columns(args...); + return _insert_value_list.add_values(args...); } // run and prepare diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index d9213f7c..b74983b6 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -107,6 +107,7 @@ namespace sqlpp auto using_(Args... args) -> _policies_update_t> { + static_assert(is_noop_t::value, "cannot call using_()/dynamic_using() twice"); return { *this, vendor::using_t(args...) }; } @@ -114,6 +115,7 @@ namespace sqlpp auto dynamic_using(Args... args) -> _policies_update_t> { + static_assert(is_noop_t::value, "cannot call using_()/dynamic_using() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_using must not be called in a static statement"); return { *this, vendor::using_t<_database_t, Args...>(args...) }; } @@ -122,6 +124,7 @@ namespace sqlpp auto where(Args... args) -> _policies_update_t> { + static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); return { *this, vendor::where_t(args...) }; } @@ -129,6 +132,7 @@ namespace sqlpp auto dynamic_where(Args... args) -> _policies_update_t> { + static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); return { *this, vendor::where_t<_database_t, Args...>(args...) }; } diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 27408cff..22bd0f24 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -55,74 +55,179 @@ namespace sqlpp namespace detail { template< - typename FlagList, typename ColumnList, - typename From, - typename Where, - typename GroupBy, - typename Having, - typename OrderBy, - typename Limit, - typename Offset + typename From > struct select_helper_t { - using _column_list_t = ColumnList; - using _from_t = ColumnList; - + static_assert(is_noop_t::value or sqlpp::is_select_column_list_t::value, "Yikes"); + static_assert(is_noop_t::value or sqlpp::is_from_t::value, "Yikes"); 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 - { - //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>..., - public detail::select_helper_t::_value_type::template operators> + template + struct select_t: public detail::select_helper_t::_value_type::template operators> { - template - using _policy_update_t = select_t...>; - using _database_t = Database; - using _parameter_tuple_t = std::tuple; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + + template + struct _policies_update_impl + { + using type = select_t...>; + }; + + template + using _policies_update_t = typename _policies_update_impl::type; + + 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 _column_list_t = ColumnList; 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; - using _value_type = typename detail::select_helper_t::_value_type; + using _value_type = typename detail::select_helper_t::_value_type; using _name_t = typename _column_list_t::_name_t; + // Constructors select_t() {} - template - select_t(select_t r, Whatever whatever): - vendor::policy_t(r, whatever)... + template + select_t(X x, FlagList flag_list): + _flag_list(flag_list), + _column_list(x._column_list), + _from(x._from), + _where(x._where), + _group_by(x._group_by), + _having(x._having), + _order_by(x._order_by), + _limit(x._limit), + _offset(x._offset) {} - template - select_t(Remove r, Whatever whatever): - vendor::policy_t(r, whatever)... + template + select_t(X x, ColumnList column_list): + _flag_list(x._flag_list), + _column_list(column_list), + _from(x._from), + _where(x._where), + _group_by(x._group_by), + _having(x._having), + _order_by(x._order_by), + _limit(x._limit), + _offset(x._offset) + {} + + template + select_t(X x, From from): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(from), + _where(x._where), + _group_by(x._group_by), + _having(x._having), + _order_by(x._order_by), + _limit(x._limit), + _offset(x._offset) + {} + + template + select_t(X x, Where where): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(x._from), + _where(where), + _group_by(x._group_by), + _having(x._having), + _order_by(x._order_by), + _limit(x._limit), + _offset(x._offset) + {} + + template + select_t(X x, GroupBy group_by): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(x._from), + _where(x._where), + _group_by(group_by), + _having(x._having), + _order_by(x._order_by), + _limit(x._limit), + _offset(x._offset) + {} + + template + select_t(X x, Having having): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(x._from), + _where(x._where), + _group_by(x._group_by), + _having(having), + _order_by(x._order_by), + _limit(x._limit), + _offset(x._offset) + {} + + template + select_t(X x, OrderBy order_by): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(x._from), + _where(x._where), + _group_by(x._group_by), + _having(x._having), + _order_by(order_by), + _limit(x._limit), + _offset(x._offset) + {} + + template + select_t(X x, Limit limit): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(x._from), + _where(x._where), + _group_by(x._group_by), + _having(x._having), + _order_by(x._order_by), + _limit(limit), + _offset(x._offset) + {} + + template + select_t(X x, Offset offset): + _flag_list(x._flag_list), + _column_list(x._column_list), + _from(x._from), + _where(x._where), + _group_by(x._group_by), + _having(x._having), + _order_by(x._order_by), + _limit(x._limit), + _offset(offset) {} select_t(const select_t& r) = default; @@ -131,7 +236,230 @@ namespace sqlpp select_t& operator=(select_t&& r) = default; ~select_t() = default; - // Indicators + // type update functions + template + auto flags(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "flags()/dynamic_flags() must not be called twice"); + return { *this, vendor::select_flag_list_t(args...) }; + } + + template + auto dynamic_flags(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "flags()/dynamic_flags() must not be called twice"); + static_assert(_is_dynamic::value, "dynamic_flags must not be called in a static statement"); + return { *this, vendor::select_flag_list_t<_database_t, Args...>(args...) }; + } + + template + auto columns(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "columns()/dynamic_columns() must not be called twice"); + return { *this, vendor::select_column_list_t(args...) }; + } + + template + auto dynamic_columns(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "columns()/dynamic_columns() must not be called twice"); + static_assert(_is_dynamic::value, "dynamic_columns must not be called in a static statement"); + return { *this, vendor::select_column_list_t<_database_t, Args...>(args...) }; + } + + template + auto from(Args... args) + -> _policies_update_t> + { + return { *this, vendor::from_t(args...) }; + } + + template + auto dynamic_from(Args... args) + -> _policies_update_t> + { + static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement"); + return { *this, vendor::from_t<_database_t, Args...>(args...) }; + } + + template + auto where(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); + return { *this, vendor::where_t(args...) }; + } + + template + auto dynamic_where(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); + return { *this, vendor::where_t<_database_t, Args...>(args...) }; + } + + template + auto group_by(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call group_by()/dynamic_group_by() twice"); + return { *this, vendor::group_by_t(args...) }; + } + + template + auto dynamic_group_by(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call group_by()/dynamic_group_by() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_group_by must not be called in a static statement"); + return { *this, vendor::group_by_t<_database_t, Args...>(args...) }; + } + + template + auto having(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call having()/dynamic_having() twice"); + return { *this, vendor::having_t(args...) }; + } + + template + auto dynamic_having(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call having()/dynamic_having() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_having must not be called in a static statement"); + return { *this, vendor::having_t<_database_t, Args...>(args...) }; + } + + template + auto order_by(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call order_by()/dynamic_order_by() twice"); + return { *this, vendor::order_by_t(args...) }; + } + + template + auto dynamic_order_by(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call order_by()/dynamic_order_by() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_order_by must not be called in a static statement"); + return { *this, vendor::order_by_t<_database_t, Args...>(args...) }; + } + + template + auto limit(Arg arg) + -> _policies_update_t::type>> + { + static_assert(is_noop_t::value, "cannot call limit()/dynamic_limit() twice"); + return { *this, vendor::limit_t::type>({arg}) }; + } + + auto dynamic_limit() + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call limit()/dynamic_limit() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_limit must not be called in a static statement"); + return { *this, vendor::dynamic_limit_t<_database_t>() }; + } + + template + auto offset(Arg arg) + -> _policies_update_t::type>> + { + static_assert(is_noop_t::value, "cannot call offset()/dynamic_offset() twice"); + return { *this, vendor::offset_t::type>({arg}) }; + } + + auto dynamic_offset() + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call offset()/dynamic_offset() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_offset must not be called in a static statement"); + return { *this, vendor::dynamic_offset_t<_database_t>() }; + } + + // value adding methods + template + void add_flag(Args... args) + { + static_assert(is_select_flag_list_t::value, "cannot call add_flag() before dynamic_flags()"); + static_assert(is_dynamic_t::value, "cannot call add_flag() before dynamic_flags()"); + return _flag_list.add_flag(*this, args...); + } + + template + void add_column(Args... args) + { + static_assert(is_select_column_list_t::value, "cannot call add_column() before dynamic_columns()"); + static_assert(is_dynamic_t::value, "cannot call add_column() before dynamic_columns()"); + return _column_list.add_column(*this, args...); + } + + template + void add_from(Args... args) + { + static_assert(is_from_t::value, "cannot call add_from() before dynamic_from()"); + static_assert(is_dynamic_t::value, "cannot call add_using() before dynamic_from()"); + return _from.add_from(*this, args...); + } + + template + void add_where(Args... args) + { + static_assert(is_where_t::value, "cannot call add_where() before dynamic_where()"); + static_assert(is_dynamic_t::value, "cannot call add_where() before dynamic_where()"); + return _where.add_where(*this, args...); + } + + template + void add_group_by(Args... args) + { + static_assert(is_group_by_t::value, "cannot call add_group_by() before dynamic_group_by()"); + static_assert(is_dynamic_t::value, "cannot call add_group_by() before dynamic_group_by()"); + return _group_by.add_group_by(*this, args...); + } + + template + void add_having(Args... args) + { + static_assert(is_having_t::value, "cannot call add_having() before dynamic_having()"); + static_assert(is_dynamic_t::value, "cannot call add_having() before dynamic_having()"); + return _having.add_having(*this, args...); + } + + template + void add_order_by(Args... args) + { + static_assert(is_order_by_t::value, "cannot call add_order_by() before dynamic_order_by()"); + static_assert(is_dynamic_t::value, "cannot call add_order_by() before dynamic_order_by()"); + return _order_by.add_order_by(*this, args...); + } + + template + void set_limit(Arg arg) + { + static_assert(is_limit_t::value, "cannot call add_limit() before dynamic_limit()"); + static_assert(is_dynamic_t::value, "cannot call add_limit() before dynamic_limit()"); + return _limit.set_limit(arg); + } + + template + void set_offset(Arg arg) + { + static_assert(is_offset_t::value, "cannot call add_offset() before dynamic_offset()"); + static_assert(is_dynamic_t::value, "cannot call add_offset() before dynamic_offset()"); + return _offset.set_offset(arg); + } + + // PseudoTable template struct _pseudo_table_t { @@ -166,12 +494,25 @@ namespace sqlpp return _result_row_t::static_size() + get_dynamic_names().size(); } + 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; + }; + // Execute template auto _run(Db& db) const -> result_t { - static_assert(detail::select_helper_t::template can_run_t::value, "Cannot execute select statement"); + static_assert(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"); return {db.select(*this), get_dynamic_names()}; } @@ -181,10 +522,20 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_select_t { - static_assert(detail::select_helper_t::template can_run_t::value, "Cannot prepare select statement"); + static_assert(can_run_t::value, "Cannot prepare select statement"); return {{}, get_dynamic_names(), db.prepare_select(*this)}; } + + FlagList _flag_list; + ColumnList _column_list; + From _from; + Where _where; + GroupBy _group_by; + Having _having; + OrderBy _order_by; + Limit _limit; + Offset _offset; }; namespace vendor @@ -198,15 +549,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; } @@ -233,32 +584,29 @@ namespace sqlpp decltype(std::tuple_cat(as_tuple::_(std::declval())...))>; } - - blank_select_t select() // FIXME: These should be constexpr + select_t select() // FIXME: These should be constexpr { - return { blank_select_t() }; + return { select_t() }; } template auto select(Columns... columns) - -> vendor::update_policies_t, - vendor::no_select_column_list_t, - detail::make_select_column_list_t> + -> select_t> { - return { blank_select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; + return { select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; } template - blank_select_t dynamic_select(const Database&) + select_t dynamic_select(const Database&) { - return { blank_select_t() }; + return { select_t() }; } template auto dynamic_select(const Database&, Columns... columns) - -> vendor::update_policies_t, vendor::no_select_column_list_t, detail::make_select_column_list_t> + -> select_t> { - return { blank_select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; + return { select_t(), detail::make_select_column_list_t(std::tuple_cat(detail::as_tuple::_(columns)...)) }; } } diff --git a/include/sqlpp11/select_flags.h b/include/sqlpp11/select_flags.h index 3bcce768..f59a6ae4 100644 --- a/include/sqlpp11/select_flags.h +++ b/include/sqlpp11/select_flags.h @@ -27,7 +27,6 @@ #ifndef SQLPP_SELECT_FLAGS_H #define SQLPP_SELECT_FLAGS_H -#include #include #include #include diff --git a/include/sqlpp11/select_fwd.h b/include/sqlpp11/select_fwd.h deleted file mode 100644 index a9a5c9dd..00000000 --- a/include/sqlpp11/select_fwd.h +++ /dev/null @@ -1,37 +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_SELECT_FWD_H -#define SQLPP_SELECT_FWD_H - -#include - -namespace sqlpp -{ - template - struct select_t; -} -#endif diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index d50f7a9a..215c5006 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -44,7 +44,7 @@ namespace sqlpp { template< typename Table, - typename Assignments, + typename UpdateList, typename Where > struct check_update_t @@ -53,27 +53,50 @@ namespace sqlpp }; } - template - struct update_t: public vendor::policy_t..., public vendor::crtp_wrapper_t, Policies>... + template + struct update_t { - template - using _policy_update_t = update_t...>; - using _database_t = Database; - using _parameter_tuple_t = std::tuple; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + + template + struct _policies_update_impl + { + using type = update_t...>; + }; + + template + using _policies_update_t = typename _policies_update_impl::type; + + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; update_t() {} - template - update_t(update_t r, Whatever whatever): - vendor::policy_t(r, whatever)... + // Constructors + template + update_t(X x, Table table): + _table(table), + _update_list(x._update_list), + _where(x._where) {} - template - update_t(Remove r, Whatever whatever): - vendor::policy_t(r, whatever)... + template + update_t(X x, UpdateList update_list): + _table(x._table), + _update_list(update_list), + _where(x._where) + {} + + template + update_t(X x, Where where): + _table(x._table), + _update_list(x._update_list), + _where(where) {} update_t(const update_t&) = default; @@ -82,6 +105,59 @@ namespace sqlpp update_t& operator=(update_t&&) = default; ~update_t() = default; + // type update functions + template + auto set(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call set()/dynamic_set() twice"); + return { *this, vendor::update_list_t(args...) }; + } + + template + auto dynamic_set(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call set()/dynamic_set() twice"); + static_assert(_is_dynamic::value, "dynamic_set must not be called in a static statement"); + return { *this, vendor::update_list_t<_database_t, Args...>(args...) }; + } + + template + auto where(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); + return { *this, vendor::where_t(args...) }; + } + + template + auto dynamic_where(Args... args) + -> _policies_update_t> + { + static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); + static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); + return { *this, vendor::where_t<_database_t, Args...>(args...) }; + } + + // value adding methods + template + void add_set(Args... args) + { + static_assert(is_update_list_t::value, "cannot call add_set() before dynamic_set()"); + static_assert(is_dynamic_t::value, "cannot call add_set() before dynamic_set()"); + return _update_list.add_set(*this, args...); + } + + template + void add_where(Args... args) + { + static_assert(is_where_t::value, "cannot call add_where() before dynamic_where()"); + static_assert(is_dynamic_t::value, "cannot call add_where() before dynamic_where()"); + return _where.add_where(*this, args...); + } + + // run and prepare static constexpr size_t _get_static_no_of_parameters() { return _parameter_list_t::size::value; @@ -96,7 +172,6 @@ namespace sqlpp std::size_t _run(Db& db) const { 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); } @@ -104,9 +179,12 @@ namespace sqlpp auto _prepare(Db& db) const -> prepared_update_t { - static_assert(detail::check_update_t::value, "Cannot run this update expression"); return {{}, db.prepare_update(*this)}; } + + Table _table; + UpdateList _update_list; + Where _where; }; namespace vendor @@ -119,29 +197,26 @@ namespace sqlpp static Context& _(const T& t, Context& context) { context << "UPDATE "; - interpret(t._single_table(), context); - interpret(t._update_list(), context); - interpret(t._where(), context); + interpret(t._table, context); + interpret(t._update_list, context); + interpret(t._where, context); return context; } }; } - template - using blank_update_t = update_t; - template constexpr auto update(Table table) - -> update_t, vendor::no_update_list_t, vendor::no_where_t> + -> update_t> { - return { blank_update_t(), vendor::single_table_t{table} }; + return { update_t(), vendor::single_table_t{table} }; } template constexpr auto dynamic_update(const Database&, Table table) - -> update_t, vendor::no_update_list_t, vendor::no_where_t> + -> update_t> { - return { blank_update_t(), vendor::single_table_t{table} }; + return { update_t(), vendor::single_table_t{table} }; } } diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index c01f24e7..4211098d 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -27,7 +27,6 @@ #ifndef SQLPP_FROM_H #define SQLPP_FROM_H -#include #include #include #include @@ -66,22 +65,21 @@ namespace sqlpp from_t& operator=(from_t&&) = default; ~from_t() = default; - template - void add_from(Table table) + template + void add_from(const Select&, 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); } - const from_t& _from() const { return *this; } std::tuple _tables; vendor::interpretable_list_t _dynamic_tables; }; struct no_from_t { - const no_from_t& _from() const { return *this; } + using _is_noop = std::true_type; }; // CRTP Wrappers @@ -90,25 +88,6 @@ namespace sqlpp { }; - 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> diff --git a/include/sqlpp11/vendor/group_by.h b/include/sqlpp11/vendor/group_by.h index d5e90eb8..1a0de458 100644 --- a/include/sqlpp11/vendor/group_by.h +++ b/include/sqlpp11/vendor/group_by.h @@ -64,8 +64,8 @@ namespace sqlpp group_by_t& operator=(group_by_t&&) = default; ~group_by_t() = default; - template - void add_group_by(Expression expression) + template + void add_group_by(const Statement&, Expression expression) { static_assert(is_table_t::value, "from arguments require to be tables or joins"); _dynamic_expressions.emplace_back(expression); @@ -78,35 +78,9 @@ namespace sqlpp struct no_group_by_t { - using _is_group_by = std::true_type; - const no_group_by_t& _group_by() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - template - struct crtp_wrapper_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> diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index 63698dad..e412e762 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -69,42 +69,15 @@ namespace sqlpp _dynamic_expressions.emplace_back(expr); } - const having_t& _having() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; struct no_having_t { - using _is_having = std::true_type; - const no_having_t& _having() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - template - struct crtp_wrapper_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> diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index fbdaee20..f73b36bf 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -52,7 +52,6 @@ namespace sqlpp limit_t& operator=(limit_t&&) = default; ~limit_t() = default; - const limit_t& _limit() const { return *this; } Limit _value; }; @@ -88,56 +87,15 @@ namespace sqlpp _initialized = true; } - const dynamic_limit_t& _limit() const { return *this; } - bool _initialized = false; interpretable_t _value; }; struct no_limit_t { - using _is_limit = std::true_type; - const no_limit_t& _limit() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - 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::type>> - { - typename wrap_operand::type value = {arg}; - return { static_cast(*this), limit_t::type>(value) }; - } - - 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>(args...) }; - } - }; - // Interpreters template struct interpreter_t> diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index e5ca8d10..18a90c65 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -52,8 +52,6 @@ namespace sqlpp offset_t& operator=(offset_t&&) = default; ~offset_t() = default; - const offset_t& _offset() const { return *this; } - Offset _value; }; @@ -89,55 +87,15 @@ namespace sqlpp _initialized = true; } - const dynamic_offset_t& _offset() const { return *this; } bool _initialized = false; interpretable_t _value; }; struct no_offset_t { - using _is_offset = std::true_type; - const no_offset_t& _offset() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - 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::type>> - { - typename wrap_operand::type value = {arg}; - return { static_cast(*this), offset_t::type>(value) }; - } - - 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::type>(args...) }; - } - }; - // Interpreters template struct interpreter_t> diff --git a/include/sqlpp11/vendor/order_by.h b/include/sqlpp11/vendor/order_by.h index 63ee7421..0233f03b 100644 --- a/include/sqlpp11/vendor/order_by.h +++ b/include/sqlpp11/vendor/order_by.h @@ -28,7 +28,6 @@ #define SQLPP_ORDER_BY_H #include -#include #include #include #include @@ -63,49 +62,22 @@ namespace sqlpp order_by_t& operator=(order_by_t&&) = default; ~order_by_t() = default; - template - void add_order_by(Expression expressions) + template + void add_order_by(const Statement&, Expression expressions) { static_assert(is_sort_order_t::value, "order_by arguments require to be sort-order expressions"); _dynamic_expressions.push_back(expressions); } - const order_by_t& _order_by() const { return *this; } _parameter_tuple_t _expressions; vendor::interpretable_list_t _dynamic_expressions; }; struct no_order_by_t { - using _is_order_by = std::true_type; - const no_order_by_t& _order_by() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - template - struct crtp_wrapper_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> diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index 30bf75c4..255644b5 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -29,7 +29,6 @@ #include #include -#include #include #include #include @@ -184,8 +183,8 @@ namespace sqlpp select_column_list_t& operator=(select_column_list_t&&) = default; ~select_column_list_t() = default; - template - void add_column(Expr namedExpr) + template + void add_column(const Select&, 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"); @@ -199,7 +198,7 @@ namespace sqlpp struct no_select_column_list_t { - using _is_select_column_list = std::true_type; + using _is_noop = 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; @@ -210,35 +209,8 @@ namespace sqlpp { 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; } }; - // CRTP Wrappers - template - struct crtp_wrapper_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> diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index dc6b4b8e..fe68a9f7 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -28,7 +28,6 @@ #define SQLPP_VENDOR_SELECT_FLAG_LIST_H #include -#include #include #include #include @@ -63,8 +62,8 @@ namespace sqlpp select_flag_list_t& operator=(select_flag_list_t&&) = default; ~select_flag_list_t() = default; - template - void add_flag(Flag flag) + template + void add_flag(const Select&, Flag flag) { static_assert(is_select_flag_t::value, "flag arguments require to be select flags"); _dynamic_flags.emplace_back(flag); @@ -77,34 +76,9 @@ namespace sqlpp struct no_select_flag_list_t { - using _is_select_flag_list = std::true_type; - const no_select_flag_list_t& _flag_list() const { return *this; } + using _is_noop = std::true_type; }; - // CRTP Wrappers - template - struct crtp_wrapper_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 diff --git a/include/sqlpp11/vendor/update_list.h b/include/sqlpp11/vendor/update_list.h index 8d620c27..3637f3c5 100644 --- a/include/sqlpp11/vendor/update_list.h +++ b/include/sqlpp11/vendor/update_list.h @@ -62,8 +62,8 @@ namespace sqlpp update_list_t& operator=(update_list_t&&) = default; ~update_list_t() = default; - template - void add_set(Assignment assignment) + template + void add_set(const Update&, 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"); @@ -77,35 +77,10 @@ namespace sqlpp struct no_update_list_t { - using _is_update_list = std::true_type; + using _is_noop = 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> diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b8b3879a..b2a56c15 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,13 +6,13 @@ macro (build_and_run arg) add_test(${arg} ${arg}) endmacro () -#build_and_run(InterpretTest) +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(UpdateTest) +build_and_run(SelectTest) +build_and_run(FunctionTest) +build_and_run(PreparedTest) find_package(PythonInterp REQUIRED) diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 4f030c75..5c9c7b2b 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -23,6 +23,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include "Sample.h" #include "MockDb.h" #include "is_regular.h" @@ -31,7 +32,6 @@ #include #include -#include DbMock db = {}; DbMock::_context_t printer(std::cerr); @@ -175,6 +175,8 @@ int main() // Test a select of a single numeric table column { using T = decltype(select(t.alpha).from(t)); + static_assert(sqlpp::is_select_column_list_t::value, "Must not be noop"); + static_assert(sqlpp::is_from_t::value, "Must not be noop"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_expression_t::value, "type requirement"); static_assert(sqlpp::is_named_expression_t::value, "type requirement"); From 82bcd63efde287526d24566e25b0f68255588fd3 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 9 Feb 2014 23:45:17 +0100 Subject: [PATCH 3/8] Removed the dreaded crtp_wrapper and the policy_wrapper --- include/sqlpp11/select.h | 2 - include/sqlpp11/update.h | 2 - include/sqlpp11/vendor/crtp_wrapper.h | 57 ------------------- include/sqlpp11/vendor/from.h | 7 --- include/sqlpp11/vendor/group_by.h | 1 - include/sqlpp11/vendor/having.h | 1 - include/sqlpp11/vendor/limit.h | 1 - include/sqlpp11/vendor/offset.h | 1 - include/sqlpp11/vendor/order_by.h | 1 - include/sqlpp11/vendor/policy.h | 62 --------------------- include/sqlpp11/vendor/select_column_list.h | 1 - include/sqlpp11/vendor/select_flag_list.h | 1 - include/sqlpp11/vendor/using.h | 1 - 13 files changed, 138 deletions(-) delete mode 100644 include/sqlpp11/vendor/crtp_wrapper.h delete mode 100644 include/sqlpp11/vendor/policy.h diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 22bd0f24..cf1db690 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -44,8 +44,6 @@ #include #include #include -#include -#include #include #include diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 215c5006..63ba4cd5 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include namespace sqlpp diff --git a/include/sqlpp11/vendor/crtp_wrapper.h b/include/sqlpp11/vendor/crtp_wrapper.h deleted file mode 100644 index 47ef265a..00000000 --- a/include/sqlpp11/vendor/crtp_wrapper.h +++ /dev/null @@ -1,57 +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_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 4211098d..7c513848 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { @@ -82,12 +81,6 @@ namespace sqlpp using _is_noop = std::true_type; }; - // CRTP Wrappers - template - struct crtp_wrapper_t> - { - }; - // Interpreters template struct interpreter_t> diff --git a/include/sqlpp11/vendor/group_by.h b/include/sqlpp11/vendor/group_by.h index 1a0de458..9e405787 100644 --- a/include/sqlpp11/vendor/group_by.h +++ b/include/sqlpp11/vendor/group_by.h @@ -33,7 +33,6 @@ #include #include #include -#include #include namespace sqlpp diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index e412e762..ca4e6410 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -32,7 +32,6 @@ #include #include #include -#include #include namespace sqlpp diff --git a/include/sqlpp11/vendor/limit.h b/include/sqlpp11/vendor/limit.h index f73b36bf..3c4e03c3 100644 --- a/include/sqlpp11/vendor/limit.h +++ b/include/sqlpp11/vendor/limit.h @@ -29,7 +29,6 @@ #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/vendor/offset.h b/include/sqlpp11/vendor/offset.h index 18a90c65..f92ff306 100644 --- a/include/sqlpp11/vendor/offset.h +++ b/include/sqlpp11/vendor/offset.h @@ -29,7 +29,6 @@ #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/vendor/order_by.h b/include/sqlpp11/vendor/order_by.h index 0233f03b..61eeb7ed 100644 --- a/include/sqlpp11/vendor/order_by.h +++ b/include/sqlpp11/vendor/order_by.h @@ -32,7 +32,6 @@ #include #include #include -#include #include namespace sqlpp diff --git a/include/sqlpp11/vendor/policy.h b/include/sqlpp11/vendor/policy.h deleted file mode 100644 index 45edeeac..00000000 --- a/include/sqlpp11/vendor/policy.h +++ /dev/null @@ -1,62 +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_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/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index 255644b5..7442e313 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -37,7 +37,6 @@ #include #include #include -#include #include namespace sqlpp diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index fe68a9f7..c999b003 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -33,7 +33,6 @@ #include #include #include -#include namespace sqlpp { diff --git a/include/sqlpp11/vendor/using.h b/include/sqlpp11/vendor/using.h index 49ab7d9d..bb8ef152 100644 --- a/include/sqlpp11/vendor/using.h +++ b/include/sqlpp11/vendor/using.h @@ -32,7 +32,6 @@ #include #include #include -#include namespace sqlpp { From e4c7b5235fac7cca3eea456c2b37907641ac42c3 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 10 Feb 2014 09:46:31 +0100 Subject: [PATCH 4/8] Added several checks for correct types in insert columns/values --- include/sqlpp11/any.h | 4 +++- include/sqlpp11/default_value.h | 1 + include/sqlpp11/null.h | 1 + include/sqlpp11/parameter.h | 2 ++ include/sqlpp11/tvin.h | 3 +++ include/sqlpp11/vendor/assignment.h | 1 + include/sqlpp11/vendor/insert_value.h | 3 +++ include/sqlpp11/vendor/insert_value_list.h | 5 ++++- include/sqlpp11/vendor/wrap_operand.h | 5 +++++ tests/InsertTest.cpp | 1 + tests/UpdateTest.cpp | 3 +++ 11 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index 004a4cfd..e4c9ceef 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -27,8 +27,8 @@ #ifndef SQLPP_ANY_H #define SQLPP_ANY_H -#include #include +#include namespace sqlpp { @@ -57,6 +57,8 @@ namespace sqlpp }; }; + using _table_set = ::sqlpp::detail::type_set<>; // FIXME: Can selects leak tables here? + any_t(Select select): _select(select) {} diff --git a/include/sqlpp11/default_value.h b/include/sqlpp11/default_value.h index 78eb71c5..b4125efe 100644 --- a/include/sqlpp11/default_value.h +++ b/include/sqlpp11/default_value.h @@ -35,6 +35,7 @@ namespace sqlpp { static constexpr bool _is_expression = true; using _value_type = no_value_t; + using _table_set = ::sqlpp::detail::type_set<>; static constexpr bool _is_trivial() { return false; } }; diff --git a/include/sqlpp11/null.h b/include/sqlpp11/null.h index c07a3001..643511a8 100644 --- a/include/sqlpp11/null.h +++ b/include/sqlpp11/null.h @@ -35,6 +35,7 @@ namespace sqlpp { static constexpr bool _is_expression = true; using _value_type = no_value_t; + using _table_set = ::sqlpp::detail::type_set<>; static constexpr bool _is_trivial() { return false; } }; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 3f33b808..875e738a 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -28,6 +28,7 @@ #define SQLPP_PARAMETER_H #include +#include namespace sqlpp { @@ -38,6 +39,7 @@ namespace sqlpp using _is_parameter = std::true_type; using _is_expression_t = std::true_type; using _instance_t = typename NameType::_name_t::template _member_t; + using _table_set = sqlpp::detail::type_set<>; parameter_t() {} diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index a3462d08..2b98c3ef 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -39,6 +39,7 @@ namespace sqlpp { using _operand_t = Operand; using _value_type = typename _operand_t::_value_type; + using _table_set = typename _operand_t::_table_set; tvin_t(Operand operand): _value(operand) @@ -74,6 +75,7 @@ namespace sqlpp template struct tvin_wrap_t { + using _table_set = typename T::_table_set; static constexpr bool _is_trivial() { return false; @@ -94,6 +96,7 @@ namespace sqlpp template struct tvin_wrap_t> { + using _table_set = typename T::_table_set; bool _is_trivial() const { return _value._is_trivial(); diff --git a/include/sqlpp11/vendor/assignment.h b/include/sqlpp11/vendor/assignment.h index 5d2cfc67..d4e0f660 100644 --- a/include/sqlpp11/vendor/assignment.h +++ b/include/sqlpp11/vendor/assignment.h @@ -44,6 +44,7 @@ namespace sqlpp using _column_t = Lhs; using value_type = Rhs; using _parameter_tuple_t = std::tuple<_column_t, Rhs>; + using _table_set = typename Lhs::_table_set::template join::type; static_assert(not std::is_same::value or can_be_null_t<_column_t>::value, "column cannot be null"); diff --git a/include/sqlpp11/vendor/insert_value.h b/include/sqlpp11/vendor/insert_value.h index 88559474..440c88ec 100644 --- a/include/sqlpp11/vendor/insert_value.h +++ b/include/sqlpp11/vendor/insert_value.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace sqlpp { @@ -43,6 +44,7 @@ namespace sqlpp struct type_if { using type = Type; + using _table_set = typename Type::_table_set; }; template @@ -50,6 +52,7 @@ namespace sqlpp { struct type { + using _table_set = sqlpp::detail::type_set<>; }; }; } diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 22668b6a..31ea1db6 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -63,7 +63,10 @@ namespace sqlpp static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); - using _table_set = typename ::sqlpp::detail::make_joined_set::type; + using _table_set = typename ::sqlpp::detail::make_joined_set< + typename Assignments::_column_t::_table_set..., + typename Assignments::value_type::_table_set... + >::type; static_assert(_is_dynamic::value ? (_table_set::size::value < 2) : (_table_set::size::value == 1), "set() contains assignments for tables from several columns"); insert_list_t(Assignments... assignment): diff --git a/include/sqlpp11/vendor/wrap_operand.h b/include/sqlpp11/vendor/wrap_operand.h index 106a6349..97d9cd8a 100644 --- a/include/sqlpp11/vendor/wrap_operand.h +++ b/include/sqlpp11/vendor/wrap_operand.h @@ -29,6 +29,7 @@ #include #include +#include namespace sqlpp { @@ -47,6 +48,7 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = sqlpp::detail::boolean; using _value_t = bool; + using _table_set = ::sqlpp::detail::type_set<>; bool _is_trivial() const { return _t == false; } @@ -71,6 +73,7 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = ::sqlpp::detail::integral; using _value_t = T; + using _table_set = ::sqlpp::detail::type_set<>; bool _is_trivial() const { return _t == 0; } @@ -96,6 +99,7 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = ::sqlpp::detail::floating_point; using _value_t = T; + using _table_set = ::sqlpp::detail::type_set<>; bool _is_trivial() const { return _t == 0; } @@ -119,6 +123,7 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = ::sqlpp::detail::text; using _value_t = std::string; + using _table_set = ::sqlpp::detail::type_set<>; bool _is_trivial() const { return _t.empty(); } diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index 29a3e7c5..93d7e6c7 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -35,6 +35,7 @@ DbMock::_context_t printer(std::cerr); int main() { test::TabBar t; + test::TabFoo f; auto x = t.alpha = 7; auto y = t.beta = "kaesekuchen"; diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index a4f07fe4..93dbf7f0 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -35,6 +35,7 @@ DbMock::_context_t printer(std::cerr); int main() { test::TabBar t; + test::TabFoo f; auto x = t.alpha = 7; auto y = t.beta = "kaesekuchen"; @@ -58,6 +59,8 @@ int main() interpret(update(t), printer).flush(); interpret(update(t).set(t.gamma = false), printer).flush(); interpret(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush(); +#warning make this fail! + interpret(update(t).set(t.beta = f.delta).where(t.beta != "transparent"), printer).flush(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); u.add_set(t.gamma = false); interpret(u, printer).flush(); From 54687c5e69274fd80f2ce4da13b3fcff083b05e2 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 10 Feb 2014 17:56:16 +0100 Subject: [PATCH 5/8] Added a bunch of static asserts to prevent misuse of insert and update There are quite a few more to be inserted --- include/sqlpp11/insert.h | 11 ++--- include/sqlpp11/remove.h | 8 ++-- include/sqlpp11/select.h | 36 ++++++++--------- include/sqlpp11/update.h | 10 +++-- include/sqlpp11/vendor/insert_value_list.h | 47 ++++++++++++++-------- include/sqlpp11/vendor/update_list.h | 9 ++++- tests/InsertTest.cpp | 3 ++ tests/UpdateTest.cpp | 4 +- 8 files changed, 77 insertions(+), 51 deletions(-) diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index f55b092f..e1ee5593 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -45,10 +45,11 @@ namespace sqlpp > struct insert_t { - static_assert(Table::_table_set::template is_superset_of::value, "inserted columns do not match the table in insert_into"); + static_assert(Table::_table_set::template is_superset_of::value, "columns do not match the table they are to be inserted into"); using _database_t = Database; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _table_set = typename Table::_table_set; template struct _policies_update_impl @@ -97,7 +98,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot combine columns() with other methods"); - return { *this, vendor::column_list_t(args...) }; + return { *this, vendor::column_list_t{args...} }; } template @@ -105,7 +106,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot combine set() with other methods"); - return { *this, vendor::insert_list_t(args...) }; + return { *this, vendor::insert_list_t{args...} }; } template @@ -114,7 +115,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot combine dynamic_set() with other methods"); static_assert(_is_dynamic::value, "dynamic_set must not be called in a static statement"); - return { *this, vendor::insert_list_t<_database_t, Args...>(args...) }; + return { *this, vendor::insert_list_t<_database_t, Args...>{args...} }; } // value adding methods @@ -129,7 +130,7 @@ namespace sqlpp template void add_values(Args... args) { - static_assert(is_column_list_t::value, "cannot call add_set() before columns()"); + static_assert(is_column_list_t::value, "cannot call add_values() before columns()"); return _insert_value_list.add_values(args...); } diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index b74983b6..a0673934 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -108,7 +108,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call using_()/dynamic_using() twice"); - return { *this, vendor::using_t(args...) }; + return { *this, vendor::using_t{args...} }; } template @@ -117,7 +117,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call using_()/dynamic_using() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_using must not be called in a static statement"); - return { *this, vendor::using_t<_database_t, Args...>(args...) }; + return { *this, vendor::using_t<_database_t, Args...>{args...} }; } template @@ -125,7 +125,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); - return { *this, vendor::where_t(args...) }; + return { *this, vendor::where_t{args...} }; } template @@ -134,7 +134,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); - return { *this, vendor::where_t<_database_t, Args...>(args...) }; + return { *this, vendor::where_t<_database_t, Args...>{args...} }; } // value adding methods diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index cf1db690..2f01e1d9 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -240,7 +240,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "flags()/dynamic_flags() must not be called twice"); - return { *this, vendor::select_flag_list_t(args...) }; + return { *this, vendor::select_flag_list_t{args...} }; } template @@ -249,7 +249,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "flags()/dynamic_flags() must not be called twice"); static_assert(_is_dynamic::value, "dynamic_flags must not be called in a static statement"); - return { *this, vendor::select_flag_list_t<_database_t, Args...>(args...) }; + return { *this, vendor::select_flag_list_t<_database_t, Args...>{args...} }; } template @@ -257,7 +257,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "columns()/dynamic_columns() must not be called twice"); - return { *this, vendor::select_column_list_t(args...) }; + return { *this, vendor::select_column_list_t{args...} }; } template @@ -266,14 +266,14 @@ namespace sqlpp { static_assert(is_noop_t::value, "columns()/dynamic_columns() must not be called twice"); static_assert(_is_dynamic::value, "dynamic_columns must not be called in a static statement"); - return { *this, vendor::select_column_list_t<_database_t, Args...>(args...) }; + return { *this, vendor::select_column_list_t<_database_t, Args...>{args...} }; } template auto from(Args... args) -> _policies_update_t> { - return { *this, vendor::from_t(args...) }; + return { *this, vendor::from_t{args...} }; } template @@ -281,7 +281,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(not std::is_same<_database_t, void>::value, "dynamic_from must not be called in a static statement"); - return { *this, vendor::from_t<_database_t, Args...>(args...) }; + return { *this, vendor::from_t<_database_t, Args...>{args...} }; } template @@ -289,7 +289,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); - return { *this, vendor::where_t(args...) }; + return { *this, vendor::where_t{args...} }; } template @@ -298,7 +298,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); - return { *this, vendor::where_t<_database_t, Args...>(args...) }; + return { *this, vendor::where_t<_database_t, Args...>{args...} }; } template @@ -306,7 +306,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call group_by()/dynamic_group_by() twice"); - return { *this, vendor::group_by_t(args...) }; + return { *this, vendor::group_by_t{args...} }; } template @@ -315,7 +315,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call group_by()/dynamic_group_by() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_group_by must not be called in a static statement"); - return { *this, vendor::group_by_t<_database_t, Args...>(args...) }; + return { *this, vendor::group_by_t<_database_t, Args...>{args...} }; } template @@ -323,7 +323,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call having()/dynamic_having() twice"); - return { *this, vendor::having_t(args...) }; + return { *this, vendor::having_t{args...} }; } template @@ -332,7 +332,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call having()/dynamic_having() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_having must not be called in a static statement"); - return { *this, vendor::having_t<_database_t, Args...>(args...) }; + return { *this, vendor::having_t<_database_t, Args...>{args...} }; } template @@ -340,7 +340,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call order_by()/dynamic_order_by() twice"); - return { *this, vendor::order_by_t(args...) }; + return { *this, vendor::order_by_t{args...} }; } template @@ -349,7 +349,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call order_by()/dynamic_order_by() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_order_by must not be called in a static statement"); - return { *this, vendor::order_by_t<_database_t, Args...>(args...) }; + return { *this, vendor::order_by_t<_database_t, Args...>{args...} }; } template @@ -357,7 +357,7 @@ namespace sqlpp -> _policies_update_t::type>> { static_assert(is_noop_t::value, "cannot call limit()/dynamic_limit() twice"); - return { *this, vendor::limit_t::type>({arg}) }; + return { *this, vendor::limit_t::type>{{arg}} }; } auto dynamic_limit() @@ -365,7 +365,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call limit()/dynamic_limit() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_limit must not be called in a static statement"); - return { *this, vendor::dynamic_limit_t<_database_t>() }; + return { *this, vendor::dynamic_limit_t<_database_t>{} }; } template @@ -373,7 +373,7 @@ namespace sqlpp -> _policies_update_t::type>> { static_assert(is_noop_t::value, "cannot call offset()/dynamic_offset() twice"); - return { *this, vendor::offset_t::type>({arg}) }; + return { *this, vendor::offset_t::type>{{arg}} }; } auto dynamic_offset() @@ -381,7 +381,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call offset()/dynamic_offset() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_offset must not be called in a static statement"); - return { *this, vendor::dynamic_offset_t<_database_t>() }; + return { *this, vendor::dynamic_offset_t<_database_t>{} }; } // value adding methods diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 63ba4cd5..e92ba792 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -57,6 +57,8 @@ namespace sqlpp typename Where = vendor::no_where_t> struct update_t { + static_assert(Table::_table_set::template is_superset_of::value, "updated columns do not match the table"); + using _database_t = Database; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; @@ -109,7 +111,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call set()/dynamic_set() twice"); - return { *this, vendor::update_list_t(args...) }; + return { *this, vendor::update_list_t{args...} }; } template @@ -118,7 +120,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call set()/dynamic_set() twice"); static_assert(_is_dynamic::value, "dynamic_set must not be called in a static statement"); - return { *this, vendor::update_list_t<_database_t, Args...>(args...) }; + return { *this, vendor::update_list_t<_database_t, Args...>{args...} }; } template @@ -126,7 +128,7 @@ namespace sqlpp -> _policies_update_t> { static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); - return { *this, vendor::where_t(args...) }; + return { *this, vendor::where_t{args...} }; } template @@ -135,7 +137,7 @@ namespace sqlpp { static_assert(is_noop_t::value, "cannot call where()/dynamic_where() twice"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_where must not be called in a static statement"); - return { *this, vendor::where_t<_database_t, Args...>(args...) }; + return { *this, vendor::where_t<_database_t, Args...>{args...} }; } // value adding methods diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 31ea1db6..5fb1239c 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -63,11 +63,11 @@ namespace sqlpp static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); - using _table_set = typename ::sqlpp::detail::make_joined_set< - typename Assignments::_column_t::_table_set..., - typename Assignments::value_type::_table_set... - >::type; - static_assert(_is_dynamic::value ? (_table_set::size::value < 2) : (_table_set::size::value == 1), "set() contains assignments for tables from several columns"); + using _column_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _value_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _table_set = typename ::sqlpp::detail::make_joined_set<_column_table_set, _value_table_set>::type; + static_assert(sizeof...(Assignments) ? (_column_table_set::size::value == 1) : true, "set() contains assignments for tables from several columns"); + static_assert(_value_table_set::template is_subset_of<_column_table_set>::value, "set() contains values from foreign tables"); insert_list_t(Assignments... assignment): _assignments(assignment...), @@ -84,8 +84,12 @@ namespace sqlpp template void add_set(const Insert&, 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"); + static_assert(is_assignment_t::value, "add_set() arguments require to be assigments"); + static_assert(not must_not_insert_t::value, "add_set() argument must not be used in insert"); + using _column_table_set = typename Assignment::_column_t::_table_set; + using _value_table_set = typename Assignment::value_type::_table_set; + static_assert(_value_table_set::template is_subset_of::value, "add_set() contains a column from a foreign table"); + static_assert(_column_table_set::template is_subset_of::value, "add_set() contains a value from a foreign table"); _dynamic_columns.emplace_back(simple_column_t{assignment._lhs}); _dynamic_values.emplace_back(assignment._rhs); } @@ -127,9 +131,14 @@ namespace sqlpp column_list_t& operator=(column_list_t&&) = default; ~column_list_t() = default; - void add_values(vendor::insert_value_t... values) + template + void add_values(Assignments... assignments) { - _insert_values.emplace_back(values...); + static_assert(::sqlpp::detail::and_t::value, "add_values() arguments have to be assignments"); + using _arg_value_tuple = std::tuple...>; + using _args_correct = std::is_same<_arg_value_tuple, _value_tuple_t>; + static_assert(_args_correct::value, "add_values() arguments do not match columns() arguments"); + add_values_impl(_args_correct{}, assignments...); // dispatch to prevent error messages due to incorrect arguments } bool empty() const @@ -139,19 +148,25 @@ namespace sqlpp std::tuple...> _columns; std::vector<_value_tuple_t> _insert_values; + + private: + template + void add_values_impl(const std::true_type&, Assignments... assignments) + { + _insert_values.emplace_back(vendor::insert_value_t{assignments}...); + } + + template + void add_values_impl(const std::false_type&, Assignments... assignments) + { + } + }; struct no_insert_value_list_t { using _is_noop = std::true_type; using _table_set = ::sqlpp::detail::type_set<>; - - template - void add_values(Base base, Args...) - { - static_assert(wrong_t::value, "cannot call add_values() without calling columns() first"); - } - }; // Interpreters diff --git a/include/sqlpp11/vendor/update_list.h b/include/sqlpp11/vendor/update_list.h index 3637f3c5..eab8b785 100644 --- a/include/sqlpp11/vendor/update_list.h +++ b/include/sqlpp11/vendor/update_list.h @@ -52,6 +52,12 @@ namespace sqlpp static_assert(not ::sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + using _column_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _value_table_set = typename ::sqlpp::detail::make_joined_set::type; + using _table_set = typename ::sqlpp::detail::make_joined_set<_column_table_set, _value_table_set>::type; + static_assert(sizeof...(Assignments) ? (_column_table_set::size::value == 1) : true, "set() contains assignments for tables from several columns"); + static_assert(_value_table_set::template is_subset_of<_column_table_set>::value, "set() contains values from foreign tables"); + update_list_t(Assignments... assignments): _assignments(assignments...) {} @@ -70,7 +76,6 @@ namespace sqlpp _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; }; @@ -78,7 +83,7 @@ namespace sqlpp struct no_update_list_t { using _is_noop = std::true_type; - const no_update_list_t& _update_list() const { return *this; } + using _table_set = ::sqlpp::detail::type_set<>; }; // Interpreters diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index 93d7e6c7..9a343a0c 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -61,6 +61,9 @@ int main() interpret(insert_into(t).default_values(), printer).flush(); interpret(insert_into(t), printer).flush(); interpret(insert_into(t).set(t.beta = "kirschauflauf"), printer).flush(); + interpret(insert_into(t).columns(t.beta), printer).flush(); + auto multi_insert = insert_into(t).columns(t.beta); + multi_insert.add_values(t.beta = "cheesecake"); auto i = dynamic_insert_into(db, t).dynamic_set(); i.add_set(t.beta = "kirschauflauf"); interpret(i, printer).flush(); diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index 93dbf7f0..cdc35a6f 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -59,8 +59,8 @@ int main() interpret(update(t), printer).flush(); interpret(update(t).set(t.gamma = false), printer).flush(); interpret(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush(); -#warning make this fail! - interpret(update(t).set(t.beta = f.delta).where(t.beta != "transparent"), printer).flush(); +#warning make this fail + interpret(update(t).set(t.beta = "opaque").where(t.beta != f.delta), printer).flush(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); u.add_set(t.gamma = false); interpret(u, printer).flush(); From 7c928ae6d0f42a16ac5209e764e843bd50197c08 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 10 Feb 2014 19:55:48 +0100 Subject: [PATCH 6/8] Added table sets to several more expressions --- include/sqlpp11/functions.h | 3 +++ include/sqlpp11/select.h | 1 + include/sqlpp11/update.h | 1 + include/sqlpp11/vendor/concat.h | 1 + include/sqlpp11/vendor/expression.h | 4 ++++ include/sqlpp11/vendor/in.h | 1 + include/sqlpp11/vendor/like.h | 1 + include/sqlpp11/vendor/where.h | 3 +++ tests/UpdateTest.cpp | 3 +-- 9 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index 43a69a98..9aabf960 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.h @@ -47,6 +47,7 @@ namespace sqlpp template auto value(T t) -> typename operand_t::type { + using _table_set = ::sqlpp::detail::type_set<>; static_assert(not is_value_t::value, "value() is to be called with non-sql-type like int, or string"); return { t }; } @@ -55,6 +56,7 @@ namespace sqlpp struct verbatim_t: public ValueType::template operators> { using _value_type = ValueType; + using _table_set = ::sqlpp::detail::type_set<>; verbatim_t(std::string verbatim): _verbatim(verbatim) {} verbatim_t(const verbatim_t&) = default; @@ -100,6 +102,7 @@ namespace sqlpp struct value_list_t // to be used in .in() method { using _container_t = Container; + using _table_set = ::sqlpp::detail::type_set<>;// FIXME: Could it be something else? using _value_type = typename operand_t::type::_value_type; value_list_t(_container_t container): diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 2f01e1d9..0afcb168 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -96,6 +96,7 @@ namespace sqlpp using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; + using _table_set = ::sqlpp::detail::type_set<>; using _column_list_t = ColumnList; using _result_row_t = typename _column_list_t::_result_row_t; diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index e92ba792..a26a34aa 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -58,6 +58,7 @@ namespace sqlpp struct update_t { static_assert(Table::_table_set::template is_superset_of::value, "updated columns do not match the table"); + static_assert(Table::_table_set::template is_superset_of::value, "where condition does not match updated table"); using _database_t = Database; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; diff --git a/include/sqlpp11/vendor/concat.h b/include/sqlpp11/vendor/concat.h index 232e92d2..91bb5d80 100644 --- a/include/sqlpp11/vendor/concat.h +++ b/include/sqlpp11/vendor/concat.h @@ -40,6 +40,7 @@ namespace sqlpp { static_assert(sizeof...(Args) > 0, "concat requires two arguments at least"); static_assert(sqlpp::detail::and_t::value, "at least one non-text argument detected in concat()"); + using _table_set = typename ::sqlpp::detail::make_joined_set::type; struct _value_type: public First::_value_type::_base_value_type { diff --git a/include/sqlpp11/vendor/expression.h b/include/sqlpp11/vendor/expression.h index 20de7a16..48c71c5a 100644 --- a/include/sqlpp11/vendor/expression.h +++ b/include/sqlpp11/vendor/expression.h @@ -44,6 +44,7 @@ namespace sqlpp { using _value_type = ::sqlpp::detail::boolean; using _parameter_tuple_t = std::tuple; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; equal_t(Lhs lhs, Rhs rhs): _lhs(lhs), @@ -88,6 +89,7 @@ namespace sqlpp { using _value_type = ::sqlpp::detail::boolean; using _parameter_tuple_t = std::tuple; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; not_equal_t(Lhs lhs, Rhs rhs): _lhs(lhs), @@ -132,6 +134,7 @@ namespace sqlpp { using _value_type = ::sqlpp::detail::boolean; using _parameter_tuple_t = std::tuple; + using _table_set = typename Lhs::_table_set; logical_not_t(Lhs l): _lhs(l) @@ -168,6 +171,7 @@ namespace sqlpp using _rhs_t = Rhs; using _value_type = typename O::_value_type; using _parameter_tuple_t = std::tuple<_lhs_t, _rhs_t>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; binary_expression_t(_lhs_t lhs, _rhs_t rhs): _lhs(lhs), diff --git a/include/sqlpp11/vendor/in.h b/include/sqlpp11/vendor/in.h index 993a3288..557de680 100644 --- a/include/sqlpp11/vendor/in.h +++ b/include/sqlpp11/vendor/in.h @@ -56,6 +56,7 @@ namespace sqlpp T in; }; }; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; in_t(Operand operand, Args... args): _operand(operand), diff --git a/include/sqlpp11/vendor/like.h b/include/sqlpp11/vendor/like.h index 6ad5d9a9..b9b0f562 100644 --- a/include/sqlpp11/vendor/like.h +++ b/include/sqlpp11/vendor/like.h @@ -41,6 +41,7 @@ namespace sqlpp static_assert(is_text_t::value, "Operand for like() has to be a text"); static_assert(is_text_t::value, "Pattern for like() has to be a text"); using _parameter_tuple_t = std::tuple; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; struct _value_type: public boolean { diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 3cac506e..7cff9e35 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -51,6 +51,8 @@ namespace sqlpp using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; + where_t(Expressions... expressions): _expressions(expressions...) {} @@ -95,6 +97,7 @@ namespace sqlpp struct no_where_t { using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; }; // Interpreters diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index cdc35a6f..e77f65a9 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -59,8 +59,7 @@ int main() interpret(update(t), printer).flush(); interpret(update(t).set(t.gamma = false), printer).flush(); interpret(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush(); -#warning make this fail - interpret(update(t).set(t.beta = "opaque").where(t.beta != f.delta), printer).flush(); + interpret(update(t).set(t.beta = "opaque").where(t.beta != t.beta), printer).flush(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); u.add_set(t.gamma = false); interpret(u, printer).flush(); From fb092583cc20719cb92656991353ce573e120abc Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 11 Feb 2014 10:17:02 +0100 Subject: [PATCH 7/8] Made wrong_t<...> a true std::false_type again. I am sure this would shoot me in the foot some day otherwise --- include/sqlpp11/vendor/wrong.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/include/sqlpp11/vendor/wrong.h b/include/sqlpp11/vendor/wrong.h index 5694fd6a..896f1e46 100644 --- a/include/sqlpp11/vendor/wrong.h +++ b/include/sqlpp11/vendor/wrong.h @@ -33,14 +33,19 @@ namespace sqlpp { namespace vendor { - // A template that always returns false - // To be used with static assert, for instance, to ensure it - // fires only when the template is instantiated. - template - struct wrong_t - { - static constexpr bool value = false; - }; + namespace detail + { + // A template that always returns false + // To be used with static assert, for instance, to ensure it + // fires only when the template is instantiated. + template + struct wrong + { + using type = std::false_type; + }; + } + template + using wrong_t = typename detail::wrong::type; } } #endif From 9e8979c6f008c6909022207a2a735128f1ec49d9 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 13 Feb 2014 08:44:09 +0100 Subject: [PATCH 8/8] Fixed a bunch of small errors and shorted compile error messages --- include/sqlpp11/column.h | 8 ++ include/sqlpp11/select.h | 2 +- include/sqlpp11/text.h | 6 + include/sqlpp11/vendor/insert_value_list.h | 4 +- include/sqlpp11/vendor/where.h | 4 +- include/sqlpp11/vendor/wrap_operand.h | 122 +++++++++++++++------ tests/CMakeLists.txt | 1 + tests/InsertTest.cpp | 5 +- tests/SelectTest.cpp | 6 +- tests/sample.sql | 3 +- 10 files changed, 116 insertions(+), 45 deletions(-) diff --git a/include/sqlpp11/column.h b/include/sqlpp11/column.h index 95c334bb..06193dab 100644 --- a/include/sqlpp11/column.h +++ b/include/sqlpp11/column.h @@ -84,6 +84,14 @@ namespace sqlpp return { *this, {t} }; } + template + auto operator =(T t) const + -> typename std::enable_if::type>::value and not std::is_same::value), + vendor::assignment_t::type>>::type + { + static_assert(sqlpp::vendor::wrong_t::value, "invalid assignment operand"); + } + auto operator =(sqlpp::null_t) const ->vendor::assignment_t { diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 0afcb168..aa5e5983 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -475,7 +475,7 @@ namespace sqlpp const _dynamic_names_t& get_dynamic_names() const { - return _column_list_t::_dynamic_columns._dynamic_expression_names; + return _column_list._dynamic_columns._dynamic_expression_names; } static constexpr size_t _get_static_no_of_parameters() diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index f7d535ea..33ad3f75 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -179,6 +179,12 @@ namespace sqlpp return { *static_cast(this), {t} }; } + template + auto operator +=(T t) const -> decltype(std::declval() = std::declval() + t) + { + return *static_cast(this) = operator +(t); + } + template vendor::like_t::type> like(T t) const { diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 5fb1239c..9959c823 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -157,9 +157,7 @@ namespace sqlpp } template - void add_values_impl(const std::false_type&, Assignments... assignments) - { - } + void add_values_impl(const std::false_type&, Assignments... assignments); }; diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 7cff9e35..e61feef5 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -47,7 +47,8 @@ namespace sqlpp using _parameter_tuple_t = std::tuple; 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()"); + static_assert(not sqlpp::detail::or_t::value, "at least one argument is an assignment in where()"); + static_assert(sqlpp::detail::and_t::value, "at least one argument is not valid expression in where()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; @@ -80,6 +81,7 @@ namespace sqlpp { using _is_where = std::true_type; using _is_dynamic = std::false_type; + using _table_set = ::sqlpp::detail::type_set<>; where_t(bool condition): _condition(condition) diff --git a/include/sqlpp11/vendor/wrap_operand.h b/include/sqlpp11/vendor/wrap_operand.h index 97d9cd8a..1dfce4a2 100644 --- a/include/sqlpp11/vendor/wrap_operand.h +++ b/include/sqlpp11/vendor/wrap_operand.h @@ -50,6 +50,20 @@ namespace sqlpp using _value_t = bool; using _table_set = ::sqlpp::detail::type_set<>; + boolean_operand(): + _t{} + {} + + boolean_operand(_value_t t): + _t(t) + {} + + boolean_operand(const boolean_operand&) = default; + boolean_operand(boolean_operand&&) = default; + boolean_operand& operator=(const boolean_operand&) = default; + boolean_operand& operator=(boolean_operand&&) = default; + ~boolean_operand() = default; + bool _is_trivial() const { return _t == false; } _value_t _t; @@ -67,23 +81,36 @@ namespace sqlpp } }; - template - struct integral_operand + struct integral_operand + { + static constexpr bool _is_expression = true; + using _value_type = ::sqlpp::detail::integral; + using _value_t = int64_t; + using _table_set = ::sqlpp::detail::type_set<>; + + integral_operand(): + _t{} + {} + + integral_operand(_value_t t): + _t(t) + {} + + integral_operand(const integral_operand&) = default; + integral_operand(integral_operand&&) = default; + integral_operand& operator=(const integral_operand&) = default; + integral_operand& operator=(integral_operand&&) = default; + ~integral_operand() = default; + + bool _is_trivial() const { return _t == 0; } + + _value_t _t; + }; + + template + struct interpreter_t { - static constexpr bool _is_expression = true; - using _value_type = ::sqlpp::detail::integral; - using _value_t = T; - using _table_set = ::sqlpp::detail::type_set<>; - - bool _is_trivial() const { return _t == 0; } - - _value_t _t; - }; - - template - struct interpreter_t> - { - using Operand = integral_operand; + using Operand = integral_operand; static Context& _(const Operand& t, Context& context) { @@ -93,23 +120,36 @@ namespace sqlpp }; - template - struct floating_point_operand + struct floating_point_operand + { + static constexpr bool _is_expression = true; + using _value_type = ::sqlpp::detail::floating_point; + using _value_t = double; + using _table_set = ::sqlpp::detail::type_set<>; + + floating_point_operand(): + _t{} + {} + + floating_point_operand(_value_t t): + _t(t) + {} + + floating_point_operand(const floating_point_operand&) = default; + floating_point_operand(floating_point_operand&&) = default; + floating_point_operand& operator=(const floating_point_operand&) = default; + floating_point_operand& operator=(floating_point_operand&&) = default; + ~floating_point_operand() = default; + + bool _is_trivial() const { return _t == 0; } + + _value_t _t; + }; + + template + struct interpreter_t { - static constexpr bool _is_expression = true; - using _value_type = ::sqlpp::detail::floating_point; - using _value_t = T; - using _table_set = ::sqlpp::detail::type_set<>; - - bool _is_trivial() const { return _t == 0; } - - _value_t _t; - }; - - template - struct interpreter_t> - { - using Operand = floating_point_operand; + using Operand = floating_point_operand; static Context& _(const Operand& t, Context& context) { @@ -125,6 +165,20 @@ namespace sqlpp using _value_t = std::string; using _table_set = ::sqlpp::detail::type_set<>; + text_operand(): + _t{} + {} + + text_operand(_value_t t): + _t(t) + {} + + text_operand(const text_operand&) = default; + text_operand(text_operand&&) = default; + text_operand& operator=(const text_operand&) = default; + text_operand& operator=(text_operand&&) = default; + ~text_operand() = default; + bool _is_trivial() const { return _t.empty(); } _value_t _t; @@ -157,13 +211,13 @@ namespace sqlpp template struct wrap_operand::value>::type> { - using type = integral_operand; + using type = integral_operand; }; template struct wrap_operand::value>::type> { - using type = floating_point_operand; + using type = floating_point_operand; }; template diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b2a56c15..8d04a9e3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,5 +19,6 @@ find_package(PythonInterp REQUIRED) add_custom_command( OUTPUT ${CMAKE_CURRENT_LIST_DIR}/Sample.h COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/ddl2cpp ${CMAKE_CURRENT_LIST_DIR}/sample.sql Sample test + DEPENDS ${CMAKE_CURRENT_LIST_DIR}/sample.sql ) diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index 9a343a0c..55e5bbc7 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -62,8 +62,9 @@ int main() interpret(insert_into(t), printer).flush(); interpret(insert_into(t).set(t.beta = "kirschauflauf"), printer).flush(); interpret(insert_into(t).columns(t.beta), printer).flush(); - auto multi_insert = insert_into(t).columns(t.beta); - multi_insert.add_values(t.beta = "cheesecake"); + auto multi_insert = insert_into(t).columns(t.beta, t.delta); + multi_insert.add_values(t.beta = "cheesecake", t.delta = 1); + multi_insert.add_values(t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); auto i = dynamic_insert_into(db, t).dynamic_set(); i.add_set(t.beta = "kirschauflauf"); interpret(i, printer).flush(); diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 5c9c7b2b..c41c4d85 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -273,7 +273,7 @@ int main() // Test that select(all_of(tab)) is expanded in select { auto a = select(all_of(t)); - auto b = select(t.alpha, t.beta, t.gamma); + auto b = select(t.alpha, t.beta, t.gamma, t.delta); //auto c = select(t); static_assert(std::is_same::value, "all_of(t) has to be expanded by select()"); //static_assert(std::is_same::value, "t has to be expanded by select()"); @@ -282,14 +282,14 @@ int main() // Test that select(all_of(tab)) is expanded in multi_column { auto a = multi_column(alias::a, all_of(t)); - auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma); + auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma, t.delta); static_assert(std::is_same::value, "all_of(t) has to be expanded by multi_column"); } // Test that select(tab) is expanded in multi_column { auto a = multi_column(alias::a, all_of(t)); - auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma); + auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma, t.delta); static_assert(std::is_same::value, "t has to be expanded by multi_column"); } diff --git a/tests/sample.sql b/tests/sample.sql index 4fa7e01c..75f48445 100644 --- a/tests/sample.sql +++ b/tests/sample.sql @@ -35,6 +35,7 @@ CREATE TABLE tab_bar ( alpha bigint AUTO_INCREMENT, beta varchar(255) NULL DEFAULT "", - gamma bool NOT NULL + gamma bool NOT NULL, + delta int );