diff --git a/CMakeLists.txt b/CMakeLists.txt index f606df00..16f12bd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ target_compile_features(sqlpp11 INTERFACE endif () add_subdirectory(tests) +add_subdirectory(test_serializer) add_subdirectory(test_static_asserts) add_subdirectory(test_constraints) add_subdirectory(examples) diff --git a/include/sqlpp11/dynamic_pre_join.h b/include/sqlpp11/dynamic_pre_join.h index be2472df..88aa9f84 100644 --- a/include/sqlpp11/dynamic_pre_join.h +++ b/include/sqlpp11/dynamic_pre_join.h @@ -109,6 +109,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { + context << JoinType::_name; context << " JOIN "; serialize(t._rhs, context); return context; diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index 74dc84e6..e737bd67 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -101,13 +101,13 @@ namespace sqlpp private: template - void _add_impl(DynamicJoin dynamicJoin, const std::true_type&) + auto _add_impl(DynamicJoin dynamicJoin, const std::true_type&) -> void { - return _data._dynamic_tables.emplace_back(from_table(dynamicJoin)); + _data._dynamic_tables.emplace_back(from_table(dynamicJoin)); } template - void _add_impl(DynamicJoin dynamicJoin, const std::false_type&); + auto _add_impl(DynamicJoin dynamicJoin, const std::false_type&) -> void; public: _data_t _data; @@ -281,8 +281,7 @@ namespace sqlpp serialize(t._table, context); if (not t._dynamic_tables.empty()) { - context << ' '; - interpret_list(t._dynamic_tables, ' ', context); + interpret_list(t._dynamic_tables, "", context); } return context; } @@ -293,6 +292,13 @@ namespace sqlpp { return statement_t().from(std::forward(t)); } + + template + auto dynamic_from(const Database&, T&& t) + -> decltype(statement_t().dynamic_from(std::forward(t))) + { + return statement_t().dynamic_from(std::forward(t)); + } } #endif diff --git a/include/sqlpp11/join_types.h b/include/sqlpp11/join_types.h index a58a127f..8b673be8 100644 --- a/include/sqlpp11/join_types.h +++ b/include/sqlpp11/join_types.h @@ -37,28 +37,28 @@ namespace sqlpp using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; - static constexpr const char* _name = " INNER "; + static constexpr const char* _name = " INNER"; }; struct outer_join_t { template using _provided_outer_tables = detail::make_joined_set_t, provided_tables_of>; - static constexpr const char* _name = " OUTER "; + static constexpr const char* _name = " OUTER"; }; struct left_outer_join_t { template using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; - static constexpr const char* _name = " LEFT OUTER "; + static constexpr const char* _name = " LEFT OUTER"; }; struct right_outer_join_t { template using _provided_outer_tables = detail::make_joined_set_t, provided_tables_of>; - static constexpr const char* _name = " RIGHT OUTER "; + static constexpr const char* _name = " RIGHT OUTER"; }; struct cross_join_t { @@ -66,7 +66,7 @@ namespace sqlpp using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; - static constexpr const char* _name = " CROSS "; + static constexpr const char* _name = " CROSS"; }; } diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index f3ba3a04..9a66b784 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -83,9 +83,8 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - context << " ON ("; + context << " ON "; serialize(t._expression, context); - context << " )"; return context; } }; diff --git a/include/sqlpp11/pre_join.h b/include/sqlpp11/pre_join.h index 38571276..00cccf0e 100644 --- a/include/sqlpp11/pre_join.h +++ b/include/sqlpp11/pre_join.h @@ -106,11 +106,23 @@ namespace sqlpp join_t>, bad_statement>::type { - check_join_on_t::_(); + using Check = check_join_on_t; + Check::_(); + return on_impl(Check{}, expr); + } + + private: + template + auto on_impl(const std::false_type&, const Expr&) const -> bad_statement; + + template + auto on_impl(const std::true_type&, const Expr& expr) const -> join_t> + { return {*this, {expr}}; } + public: Lhs _lhs; Rhs _rhs; }; diff --git a/test_serializer/CMakeLists.txt b/test_serializer/CMakeLists.txt new file mode 100644 index 00000000..8d2f1fa3 --- /dev/null +++ b/test_serializer/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2013-2016, 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. + +set(test_serializer_names + From + ) + +create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_serializer_names}) +add_executable(sqlpp11_test_serializer ${test_serializer_sources}) +target_link_libraries(sqlpp11_test_serializer PRIVATE sqlpp11 sqlpp11_testing) + +foreach(test_serializer IN LISTS test_serializer_names) + add_test(NAME sqlpp11.test_serializer.${test_serializer} + COMMAND sqlpp11_test_serializer ${test_serializer} + ) +endforeach() + diff --git a/test_serializer/From.cpp b/test_serializer/From.cpp new file mode 100644 index 00000000..1a184354 --- /dev/null +++ b/test_serializer/From.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013-2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Sample.h" +#include "MockDb.h" +#include + +#include + +namespace +{ + MockDb db = {}; + + template + void compare(int lineNo, const Expression& expr, const std::string& expected) + { + MockDb::_serializer_context_t printer = {}; + + const auto result = serialize(expr, printer).str(); + + if (result != expected) + { + std::cerr << __FILE__ << " " << lineNo << '\n' << "Expected: -->|" << expected << "|<--\n" + << "Received: -->|" << result << "|<--\n"; + throw std::runtime_error("unexpected serialization result"); + } + } +} + +int From(int, char* []) +{ + const auto foo = test::TabFoo{}; + const auto bar = test::TabBar{}; + const auto aFoo = foo.as(sqlpp::alias::a); + const auto bFoo = foo.as(sqlpp::alias::b); + const auto cFoo = foo.as(sqlpp::alias::c); + + // Single table + compare(__LINE__, from(foo), " FROM tab_foo"); + compare(__LINE__, from(bar), " FROM tab_bar"); + + // Static joins + compare(__LINE__, from(foo.cross_join(bar)), " FROM tab_foo CROSS JOIN tab_bar"); + compare(__LINE__, from(foo.join(bar).on(foo.omega > bar.alpha)), + " FROM tab_foo INNER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)"); + compare(__LINE__, from(aFoo.join(bFoo).on(aFoo.omega > bFoo.omega)), + " FROM tab_foo AS a INNER JOIN tab_foo AS b ON (a.omega>b.omega)"); + compare( + __LINE__, from(aFoo.join(bFoo).on(aFoo.omega > bFoo.omega).join(cFoo).on(bFoo.omega > cFoo.omega)), + " FROM tab_foo AS a INNER JOIN tab_foo AS b ON (a.omega>b.omega) INNER JOIN tab_foo AS c ON (b.omega>c.omega)"); + + // Dynamic joins + const auto df = dynamic_from(db, foo); + compare(__LINE__, df, " FROM tab_foo"); + { + auto dfa = df; + dfa.from.add(dynamic_cross_join(bar)); + compare(__LINE__, dfa, " FROM tab_foo CROSS JOIN tab_bar"); + } + { + auto dfa = df; + dfa.from.add(dynamic_inner_join(bar).on(bar.alpha > foo.omega)); + compare(__LINE__, dfa, " FROM tab_foo INNER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)"); + } + { + auto dfa = df; + dfa.from.add(dynamic_inner_join(bar).on(bar.alpha > foo.omega)); + dfa.from.add(dynamic_outer_join(aFoo).on(bar.alpha > aFoo.omega)); + compare(__LINE__, dfa, " FROM tab_foo INNER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega) OUTER JOIN tab_foo AS a " + "ON (tab_bar.alpha>a.omega)"); + } + + return 0; +}