From f8e0e9047759eb67f43b61dadf8cabb500312264 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 9 Jun 2014 14:06:04 +0200 Subject: [PATCH] Fixed serializability of statements --- include/sqlpp11/insert.h | 22 +++++ include/sqlpp11/remove.h | 80 +++++++++++++++- include/sqlpp11/select.h | 22 +++++ include/sqlpp11/statement.h | 45 ++++++++- include/sqlpp11/update.h | 166 +++++++++++----------------------- include/sqlpp11/vendor/into.h | 1 + tests/CMakeLists.txt | 2 +- tests/InsertTest.cpp | 3 +- tests/MockDb.h | 2 +- tests/RemoveTest.cpp | 5 +- tests/SelectTest.cpp | 3 + tests/UpdateTest.cpp | 4 +- 12 files changed, 228 insertions(+), 127 deletions(-) diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index 3a8fdbd7..fa9320fb 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -38,8 +38,30 @@ namespace sqlpp { + struct insert_name_t {}; + + struct insert_t: public vendor::statement_name_t + {}; + + namespace vendor + { + template + struct serializer_t + { + using T = insert_name_t; + + static Context& _(const T& t, Context& context) + { + context << "INSERT "; + + return context; + } + }; + } + template using blank_insert_t = statement_t; diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index 305af315..753c2539 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -33,17 +33,91 @@ #include #include #warning: need to use another table provider, since delete can be used with several tables -#include +#include #include #include #include namespace sqlpp { + struct remove_name_t {}; + struct remove_t: public vendor::statement_name_t + { + using _traits = make_traits; + struct _name_t {}; + + template + struct _result_methods_t + { + using _statement_t = typename Policies::_statement_t; + + const _statement_t& _get_statement() const + { + return static_cast(*this); + } + + static constexpr size_t _get_static_no_of_parameters() + { +#warning need to fix this + return 0; + //return _parameter_list_t::size::value; + } + + size_t _get_no_of_parameters() const + { +#warning need to fix this + return 0; + //return _parameter_list_t::size::value; + } + + void _check_consistency() const + { + // FIXME: Read up on what is allowed/prohibited in INSERT + } + + template + auto _run(Db& db) const -> decltype(db.remove(_get_statement())) + { + _check_consistency(); + + static_assert(_get_static_no_of_parameters() == 0, "cannot run remove directly with parameters, use prepare instead"); + return db.remove(*this); + } + + /* + template + auto _prepare(Db& db) const + -> prepared_remove_t + { + _check_consistency(); + + return {{}, db.prepare_remove(*this)}; + } + */ + }; + }; + + + namespace vendor + { + template + struct serializer_t + { + using T = remove_name_t; + + static Context& _(const T& t, Context& context) + { + context << "DELETE"; + + return context; + } + }; + } + template using blank_remove_t = statement_t; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index a49b0201..bda042f9 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -46,8 +46,30 @@ namespace sqlpp { + struct select_name_t {}; + + struct select_t: public vendor::statement_name_t + {}; + + namespace vendor + { + template + struct serializer_t + { + using T = select_name_t; + + static Context& _(const T& t, Context& context) + { + context << "SELECT "; + + return context; + } + }; + } + template using blank_select_t = statement_t @@ -178,15 +177,53 @@ namespace sqlpp static Context& _(const T& t, Context& context) { -#warning: Need to have a class that provides the "SELECT" or "INSERT", etc - context << "SELECT "; - using swallow = int[]; (void) swallow{(serialize(static_cast&>(t)()._data, context), 0)...}; return context; } }; + + template + struct statement_name_t + { + using _traits = make_traits; + using _recursive_traits = make_recursive_traits<>; + + // Data + using _data_t = NameData; + + // Member implementation with data and methods + template + struct _impl_t + { + _data_t _data; + }; + + // Member template for adding the named member to a statement + template + struct _member_t + { + using _data_t = NameData; + + _impl_t statement_name; + _impl_t& operator()() { return statement_name; } + const _impl_t& operator()() const { return statement_name; } + + template + static auto _get_member(T t) -> decltype(t.statement_name) + { + return t.statement_name; + } + }; + + // Additional methods for the statement + template + struct _methods_t + { + }; + }; + } } diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 7c9ab963..d83909b8 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -39,148 +39,84 @@ namespace sqlpp { -#if 0 - template - struct update_t; + struct update_name_t {}; - namespace detail + struct update_t: public vendor::statement_name_t { - template - struct update_policies_t + using _traits = make_traits; + struct _name_t {}; + + template + struct _result_methods_t { - using _database_t = Db; + using _statement_t = typename Policies::_statement_t; - using _statement_t = update_t; + const _statement_t& _get_statement() const + { + return static_cast(*this); + } - struct _methods_t: public Policies::template _methods_t... - {}; + static constexpr size_t _get_static_no_of_parameters() + { +#warning need to fix this + return 0; + //return _parameter_list_t::size::value; + } - template - struct _policies_update_t + size_t _get_no_of_parameters() const + { +#warning need to fix this + return 0; + //return _parameter_list_t::size::value; + } + + void _check_consistency() const + { + // FIXME: Read up on what is allowed/prohibited in INSERT + } + + template + auto _run(Db& db) const -> decltype(db.update(_get_statement())) { - static_assert(detail::is_element_of>::value, "policies update for non-policy class detected"); - using type = update_t...>; - }; + _check_consistency(); - template - using _new_statement_t = typename _policies_update_t::type; + static_assert(_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead"); + return db.update(*this); + } - using _all_required_tables = detail::make_joined_set_t...>; - using _all_provided_tables = detail::make_joined_set_t...>; - using _all_extra_tables = detail::make_joined_set_t...>; - - using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>; - - template - using _no_unknown_tables = detail::is_subset_of, _known_tables>; - - // The tables not covered by the from. - using _required_tables = detail::make_difference_set_t< - _all_required_tables, - _all_provided_tables // Hint: extra_tables are not used here because they are just a helper for dynamic .add_*() - >; - - using _traits = make_traits; // FIXME - - struct _recursive_traits - { - using _parameters = std::tuple<>; // FIXME - using _required_tables = _required_tables; - using _provided_tables = detail::type_set<>; - using _extra_tables = detail::type_set<>; - }; - }; - } - - // UPDATE - template - struct update_t: - public Policies..., - public detail::update_policies_t::_methods_t - { - using _policies_t = typename detail::update_policies_t; - using _database_t = typename _policies_t::_database_t; - - using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; - - using _parameter_list_t = typename make_parameter_list_t::type; - - // Constructors - constexpr update_t() - {} - - template - update_t(Statement statement, Term term): - Policies(detail::pick_arg(statement, term))... - {} - - update_t(const update_t&) = default; - update_t(update_t&&) = default; - update_t& operator=(const update_t&) = default; - update_t& operator=(update_t&&) = default; - ~update_t() = default; - - // run and prepare - static constexpr size_t _get_static_no_of_parameters() - { - return _parameter_list_t::size::value; - } - - size_t _get_no_of_parameters() const - { - return _parameter_list_t::size::value; - } - - void _check_consistency() const - { -#warning reactivate tests /* - static_assert(is_where_t<_where_t>::value, "cannot run update without having a where condition, use .where(true) to update all rows"); + template + auto _prepare(Db& db) const + -> prepared_update_t + { + _check_consistency(); - static_assert(is_table_subset_of_table<_update_list_t>::value, "updates require additional tables"); - static_assert(is_table_subset_of_table<_where_t>::value, "where requires additional tables"); - */ - } + return {{}, db.prepare_update(*this)}; + } + */ + }; + }; - template - std::size_t _run(Database& db) const - { - _check_consistency(); - - static_assert(_get_static_no_of_parameters() == 0, "cannot run update directly with parameters, use prepare instead"); - return db.update(*this); - } - - template - auto _prepare(Database& db) const - -> prepared_update_t - { - _check_consistency(); - - return {{}, db.prepare_update(*this)}; - } - }; namespace vendor { - template - struct serializer_t> + template + struct serializer_t { - using T = update_t; + using T = update_name_t; static Context& _(const T& t, Context& context) { context << "UPDATE "; - using swallow = int[]; - (void) swallow{(serialize(static_cast(t), context), 0)...}; + return context; } }; } -#endif template using blank_update_t = statement_t; diff --git a/include/sqlpp11/vendor/into.h b/include/sqlpp11/vendor/into.h index 5d474e9c..f88249c1 100644 --- a/include/sqlpp11/vendor/into.h +++ b/include/sqlpp11/vendor/into.h @@ -205,6 +205,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { + context << " INTO "; serialize(t._table, context); return context; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a5124694..9ea24a1f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ endmacro () build_and_run(InsertTest) build_and_run(RemoveTest) build_and_run(UpdateTest) -#build_and_run(SelectTest) +build_and_run(SelectTest) #build_and_run(SelectTypeTest) #build_and_run(FunctionTest) #build_and_run(PreparedTest) diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index 1bee7ba9..7a50f1c4 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -71,7 +71,8 @@ int main() multi_insert.values.add(t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); auto i = dynamic_insert_into(db, t).dynamic_set(); i.insert_list.add(t.beta = "kirschauflauf"); - serialize(i, printer).str(); + printer.reset(); + std::cerr << serialize(i, printer).str() << std::endl; db(multi_insert); diff --git a/tests/MockDb.h b/tests/MockDb.h index fd114baf..a80067de 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -43,7 +43,7 @@ struct MockDb: public sqlpp::connection void reset() { - _os.clear(); + _os.str(""); } template diff --git a/tests/RemoveTest.cpp b/tests/RemoveTest.cpp index 777e944e..52636a57 100644 --- a/tests/RemoveTest.cpp +++ b/tests/RemoveTest.cpp @@ -62,7 +62,10 @@ int main() auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where(); r.using_.add(t); r.where.add(t.beta != "transparent"); - serialize(r, printer).str(); + printer.reset(); + std::cerr << serialize(r, printer).str() << std::endl; + printer.reset(); + std::cerr << serialize(remove_from(t).where(true), printer).str() << std::endl; db(r); diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index e00312fc..14979a1d 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -85,6 +85,9 @@ int main() int64_t a = row.alpha; } + printer.reset(); + std::cerr << serialize(s, printer).str() << std::endl; + auto X = select(all_of(t)).from(t).as(t.alpha); return 0; diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index cc75f897..364d8a33 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -61,9 +61,11 @@ int main() serialize(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).str(); serialize(update(t).set(t.beta = "opaque").where(t.beta != t.beta), printer).str(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); +#warning: This should fail since gamma is set already u.assignments.add(t.gamma = false); u.where.add(t.gamma != false); - serialize(u, printer).str(); + printer.reset(); + std::cerr << serialize(u, printer).str() << std::endl; db(u);