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/bad_statement.h b/include/sqlpp11/bad_statement.h index 03635a28..c8b78a5c 100644 --- a/include/sqlpp11/bad_statement.h +++ b/include/sqlpp11/bad_statement.h @@ -31,6 +31,8 @@ namespace sqlpp { struct bad_statement { + static constexpr bool value = false; + template bad_statement(T&&...) { diff --git a/include/sqlpp11/data_types/boolean/expression_operators.h b/include/sqlpp11/data_types/boolean/expression_operators.h index 41b946bd..42e700f9 100644 --- a/include/sqlpp11/data_types/boolean/expression_operators.h +++ b/include/sqlpp11/data_types/boolean/expression_operators.h @@ -40,21 +40,21 @@ namespace sqlpp }; template - struct return_type_and> + struct return_type_and> { using check = consistent_t; using type = logical_and_t, wrap_operand_t>; }; template - struct return_type_or> + struct return_type_or> { using check = consistent_t; using type = logical_or_t, wrap_operand_t>; }; template - struct return_type_not> + struct return_type_not> { using check = consistent_t; using type = logical_not_t>; diff --git a/include/sqlpp11/dynamic_join.h b/include/sqlpp11/dynamic_join.h new file mode 100644 index 00000000..5aa9b7a1 --- /dev/null +++ b/include/sqlpp11/dynamic_join.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016-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. + */ + +#ifndef SQLPP_DYNAMIC_JOIN_H +#define SQLPP_DYNAMIC_JOIN_H + +#include + +namespace sqlpp +{ + template + struct dynamic_join_t + { + using _traits = make_traits; + using _nodes = detail::type_vector; + using _can_be_null = std::false_type; + using _provided_tables = provided_tables_of; + using _required_tables = detail::type_set<>; + + static_assert(is_dynamic_pre_join_t::value, "lhs argument for on() has to be a pre join"); + static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); + static_assert(is_on_t::value, "invalid on expression in join().on()"); + + PreJoin _pre_join; + On _on; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = dynamic_join_t; + + static Context& _(const T& t, Context& context) + { + serialize(t._pre_join, context); + serialize(t._on, context); + return context; + } + }; +} + +#endif diff --git a/include/sqlpp11/dynamic_pre_join.h b/include/sqlpp11/dynamic_pre_join.h new file mode 100644 index 00000000..88aa9f84 --- /dev/null +++ b/include/sqlpp11/dynamic_pre_join.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016-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. + */ + +#ifndef SQLPP_DYNAMIC_PRE_JOIN_H +#define SQLPP_DYNAMIC_PRE_JOIN_H + +#include +#include + +namespace sqlpp +{ + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_pre_join_table_t, "argument of dynamic_join() has to be a table"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_pre_join_no_join_t, "argument of dynamic_join() must not be a table"); + + template + struct check_dynamic_pre_join + { + using type = + static_combined_check_t::value, assert_dynamic_pre_join_table_t>, + static_check_t::value, assert_dynamic_pre_join_no_join_t>>; + }; + + template + using check_dynamic_pre_join_t = typename check_dynamic_pre_join::type; + + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_consist_of_pre_join_and_on_t, + "dynamic join has to consist of a dynamic pre_join and a join condition"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_no_table_dependencies_t, + "dynamically joined tables must not depend on other tables"); + + template + struct check_dynamic_join + { + using type = static_combined_check_t< + static_check_t::value, assert_dynamic_join_consist_of_pre_join_and_on_t>, + static_check_t::value, assert_dynamic_join_consist_of_pre_join_and_on_t>, + static_check_t::size::value == 0, assert_dynamic_join_no_table_dependencies_t>>; + }; + + template + using check_dynamic_join_t = typename check_dynamic_join::type; + + template + struct check_dynamic_join_on + { + using type = static_combined_check_t, check_dynamic_join_t>>; + }; + + template + using check_dynamic_join_on_t = typename check_dynamic_join_on::type; + + template + struct dynamic_join_t; + + template + struct dynamic_pre_join_t + { + using _traits = make_traits; + using _nodes = detail::type_vector; + using _can_be_null = std::false_type; + + static_assert(is_table_t::value, "rhs argument for dynamic_join() has to be a table"); + static_assert(not is_join_t::value, "rhs argument for dynamic_join must not be a join"); + + static_assert(required_tables_of::size::value == 0, + "joined tables must not depend on other tables"); + + template + auto on(Expr expr) const -> typename std::conditional::value, + dynamic_join_t>, + bad_statement>::type + { + check_dynamic_join_on_t::_(); + + return {*this, {expr}}; + } + + Rhs _rhs; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = dynamic_pre_join_t; + + static Context& _(const T& t, Context& context) + { + context << JoinType::_name; + context << " JOIN "; + serialize(t._rhs, context); + return context; + } + }; + + template + using make_dynamic_pre_join_t = typename std::conditional::value, + dynamic_pre_join_t, + bad_statement>::type; + + template + auto dynamic_join(Table table) -> make_dynamic_pre_join_t + { + check_dynamic_pre_join_t
::_(); + return {table}; + } + + template + auto dynamic_inner_join(Table table) -> make_dynamic_pre_join_t + { + check_dynamic_pre_join_t
::_(); + return {table}; + } + + template + auto dynamic_left_outer_join(Table table) -> make_dynamic_pre_join_t + { + check_dynamic_pre_join_t
::_(); + return {table}; + } + + template + auto dynamic_right_outer_join(Table table) -> make_dynamic_pre_join_t + { + check_dynamic_pre_join_t
::_(); + return {table}; + } + + template + auto dynamic_outer_join(Table table) -> make_dynamic_pre_join_t + { + check_dynamic_pre_join_t
::_(); + return {table}; + } + + template + auto dynamic_cross_join(Table table) -> + typename std::conditional::value, + dynamic_join_t, on_t>, + bad_statement>::type + { + check_dynamic_pre_join_t
::_(); + return {dynamic_pre_join_t{table}, {}}; + } +} + +#endif diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index f6339819..e737bd67 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -35,14 +35,15 @@ #include #include #include +#include namespace sqlpp { // FROM DATA - template + template struct from_data_t { - from_data_t(Tables... tables) : _tables(tables...) + from_data_t(Table table) : _table(table) { } @@ -52,20 +53,20 @@ namespace sqlpp from_data_t& operator=(from_data_t&&) = default; ~from_data_t() = default; - std::tuple _tables; + Table _table; interpretable_list_t _dynamic_tables; }; // FROM - template + template struct from_t { using _traits = make_traits; - using _nodes = detail::type_vector; + using _nodes = detail::type_vector
; using _is_dynamic = is_database; // Data - using _data_t = from_data_t; + using _data_t = from_data_t; // Member implementation with data and methods template @@ -77,35 +78,36 @@ namespace sqlpp { } - template - void add(Table table) + template + void add(DynamicJoin dynamicJoin) { static_assert(_is_dynamic::value, "from::add() must not be called for static from()"); - static_assert(is_table_t
::value, "invalid table argument in from::add()"); - using _known_tables = - detail::make_joined_set_t...>; // Hint: Joins contain more than one table + static_assert(is_dynamic_join_t::value, "invalid argument in from::add(), expected dynamic_join"); + using _known_tables = provided_tables_of
; // Hint: Joins contain more than one table // workaround for msvc bug https://connect.microsoft.com/VisualStudio/feedback/details/2173198 // using _known_table_names = detail::transform_set_t; using _known_table_names = detail::make_name_of_set_t<_known_tables>; - static_assert(not detail::is_element_of::value, + using _joined_tables = provided_tables_of; + using _joined_table_names = detail::make_name_of_set_t<_joined_tables>; + static_assert(detail::is_disjunct_from<_joined_table_names, _known_table_names>::value, "Must not use the same table name twice in from()"); - using _serialize_check = sqlpp::serialize_check_t; + using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); - using ok = logic::all_t<_is_dynamic::value, is_table_t
::value, _serialize_check::type::value>; + using ok = logic::all_t<_is_dynamic::value, is_table_t::value, _serialize_check::type::value>; - _add_impl(table, ok()); // dispatch to prevent compile messages after the static_assert + _add_impl(dynamicJoin, ok()); // dispatch to prevent compile messages after the static_assert } private: - template - void _add_impl(Table table, const std::true_type&) + template + auto _add_impl(DynamicJoin dynamicJoin, const std::true_type&) -> void { - return _data._dynamic_tables.emplace_back(from_table(table)); + _data._dynamic_tables.emplace_back(from_table(dynamicJoin)); } - template - void _add_impl(Table table, const std::false_type&); + template + auto _add_impl(DynamicJoin dynamicJoin, const std::false_type&) -> void; public: _data_t _data; @@ -115,7 +117,7 @@ namespace sqlpp template struct _base_t { - using _data_t = from_data_t; + using _data_t = from_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 template @@ -145,6 +147,39 @@ namespace sqlpp }; }; + SQLPP_PORTABLE_STATIC_ASSERT( + assert_from_not_pre_join_t, + "from() argument is a pre join, please use an explicit on() condition or unconditionally()"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_from_table_t, "from() argument has to be a table or join expression"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dependency_free_t, "at least one table depends on another table in from()"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_from_no_duplicates_t, "at least one duplicate table name detected in from()"); + + SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dynamic_statement_dynamic_t, + "dynamic_from must not be called in a static statement"); + + template + struct check_from + { + using type = static_combined_check_t< + static_check_t::value, assert_from_not_pre_join_t>, + static_check_t::value, assert_from_table_t>, + static_check_t::size::value == 0, assert_from_dependency_free_t>, + static_check_t::size::value == + detail::make_name_of_set_t>::size::value, + assert_from_no_duplicates_t>>; + }; + + template + using check_from_t = typename check_from
::type; + + template + using check_from_static_t = check_from_t
; + + template + using check_from_dynamic_t = static_combined_check_t< + static_check_t::value, assert_from_dynamic_statement_dynamic_t>, + check_from_t
>; + struct no_from_t { using _traits = make_traits; @@ -197,86 +232,72 @@ namespace sqlpp using _database_t = typename Policies::_database_t; - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 - // template - // using _check = logic::all_t::value...>; - template - struct _check : logic::all_t::value...> - { - }; - template using _new_statement_t = new_statement_t; using _consistency_check = consistent_t; - template - auto from(Tables... tables) const -> _new_statement_t<_check, from_t...>> + template + auto from(Table table) const -> _new_statement_t, from_t>> { - static_assert(_check::value, "at least one argument is not a table or join in from()"); - static_assert(sizeof...(Tables), "at least one table or join argument required in from()"); - return _from_impl(_check{}, tables...); + using Check = check_from_static_t
; + Check{}._(); + return _from_impl(Check{}, table); } - template - auto dynamic_from(Tables... tables) const - -> _new_statement_t<_check, from_t<_database_t, from_table_t...>> + template + auto dynamic_from(Table table) const + -> _new_statement_t, from_t<_database_t, from_table_t
>> { - static_assert(not std::is_same<_database_t, void>::value, - "dynamic_from must not be called in a static statement"); - static_assert(_check::value, "at least one argument is not a table or join in from()"); - return _from_impl<_database_t>(_check{}, tables...); + using Check = check_from_dynamic_t<_database_t, Table>; + Check{}._(); + return _from_impl<_database_t>(Check{}, table); } private: - template - auto _from_impl(const std::false_type&, Tables... tables) const -> bad_statement; + template + auto _from_impl(const std::false_type&, Table table) const -> bad_statement; - template - auto _from_impl(const std::true_type&, Tables... tables) const - -> _new_statement_t...>> + template + auto _from_impl(const std::true_type&, Table table) const + -> _new_statement_t>> { - static_assert(required_tables_of>::size::value == 0, - "at least one table depends on another table in from()"); - - static constexpr std::size_t _number_of_tables = detail::sum(provided_tables_of::size::value...); - using _unique_tables = detail::make_joined_set_t...>; - using _unique_table_names = detail::make_name_of_set_t<_unique_tables>; - static_assert(_number_of_tables == _unique_tables::size::value, - "at least one duplicate table detected in from()"); - static_assert(_number_of_tables == _unique_table_names::size::value, - "at least one duplicate table name detected in from()"); - return {static_cast&>(*this), - from_data_t...>{from_table(tables)...}}; + from_data_t>{from_table(table)}}; } }; }; // Interpreters - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = from_data_t; + using _serialize_check = serialize_check_of; + using T = from_data_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Tables) == 0 and t._dynamic_tables.empty()) - return context; context << " FROM "; - interpret_tuple(t._tables, ',', context); - if (sizeof...(Tables) and not t._dynamic_tables.empty()) - context << ','; - interpret_list(t._dynamic_tables, ',', context); + serialize(t._table, context); + if (not t._dynamic_tables.empty()) + { + interpret_list(t._dynamic_tables, "", context); + } return context; } }; - template - auto from(T&&... t) -> decltype(statement_t().from(std::forward(t)...)) + template + auto from(T&& t) -> decltype(statement_t().from(std::forward(t))) { - return statement_t().from(std::forward(t)...); + 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)); } } diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 5db3f7a1..09ecb8fa 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2013-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -27,125 +27,70 @@ #ifndef SQLPP_JOIN_H #define SQLPP_JOIN_H -#include +#include +#include #include -#include namespace sqlpp { - struct inner_join_t - { - template - using _provided_outer_tables = - detail::make_joined_set_t, provided_outer_tables_of>; - - 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 "; - }; - 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 "; - }; - 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 "; - }; - - template + template struct join_t { using _traits = make_traits; - using _nodes = detail::type_vector; + using _nodes = detail::type_vector; using _can_be_null = std::false_type; + using _provided_tables = provided_tables_of; + using _required_tables = detail::make_difference_set_t, _provided_tables>; - static_assert(is_table_t::value, "lhs argument for join() has to be a table or join"); - static_assert(is_table_t::value, "rhs argument for join() has to be a table"); - static_assert(not is_join_t::value, "rhs argument for join must not be a join"); - static_assert(is_noop::value or is_on_t::value, "invalid on expression in join().on()"); - - static_assert(detail::is_disjunct_from, provided_tables_of>::value, - "joined tables must not be identical"); - - static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); - - template - using set_on_t = join_t; - - template - auto on(Expr... expr) -> set_on_t> + template + auto join(T t) const -> decltype(::sqlpp::join(*this, t)) { - static_assert(is_noop::value, "cannot call on() twice for a single join()"); - static_assert(logic::all_t::value...>::value, - "at least one argument is not an expression in on()"); - - return {_lhs, _rhs, {std::tuple{expr...}, {}}}; + return ::sqlpp::join(*this, t); } template - join_t join(T t) + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return ::sqlpp::inner_join(*this, t); } template - join_t inner_join(T t) + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return ::sqlpp::left_outer_join(*this, t); } template - join_t outer_join(T t) + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t)) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return ::sqlpp::right_outer_join(*this, t); } template - join_t left_outer_join(T t) + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t)) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return ::sqlpp::outer_join(*this, t); } template - join_t right_outer_join(T t) + auto cross_join(T t) const -> decltype(::sqlpp::cross_join(*this, t)) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return ::sqlpp::cross_join(*this, t); } - Lhs _lhs; - Rhs _rhs; + PreJoin _pre_join; On _on; }; - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = join_t; + using _serialize_check = serialize_check_of; + using T = join_t; static Context& _(const T& t, Context& context) { - static_assert(not is_noop::value, "joined tables require on()"); - serialize(t._lhs, context); - context << JoinType::_name; - context << " JOIN "; - serialize(t._rhs, context); + serialize(t._pre_join, context); serialize(t._on, context); return context; } diff --git a/include/sqlpp11/join_types.h b/include/sqlpp11/join_types.h new file mode 100644 index 00000000..8b673be8 --- /dev/null +++ b/include/sqlpp11/join_types.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef SQLPP_JOIN_TYPES_H +#define SQLPP_JOIN_TYPES_H + +#include + +namespace sqlpp +{ + struct inner_join_t + { + template + using _provided_outer_tables = + detail::make_joined_set_t, provided_outer_tables_of>; + + 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"; + }; + 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"; + }; + 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"; + }; + struct cross_join_t + { + template + using _provided_outer_tables = + detail::make_joined_set_t, provided_outer_tables_of>; + + static constexpr const char* _name = " CROSS"; + }; +} + +#endif diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index bccdc3e8..9a66b784 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -28,65 +28,63 @@ #define SQLPP_ON_H #include -#include #include +#include #include namespace sqlpp { - template + SQLPP_PORTABLE_STATIC_ASSERT(assert_on_is_expression_t, "argument is not an expression in on()"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_on_is_boolean_expression_t, "argument is not a boolean expression in on()"); + + template + struct check_on + { + using type = static_combined_check_t::value, assert_on_is_expression_t>, + static_check_t::value, assert_on_is_boolean_expression_t>>; + }; + + template + using check_on_t = typename check_on::type; + + template struct on_t { using _traits = make_traits; - using _nodes = detail::type_vector; + using _nodes = detail::type_vector; - using _is_dynamic = is_database; - - static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in on()"); - - template - void add(Expr expr) - { - static_assert(_is_dynamic::value, "on::add() must not be called for static on()"); - static_assert(is_expression_t::value, "invalid expression argument in on::add()"); - using _serialize_check = sqlpp::serialize_check_t; - _serialize_check::_(); - - using ok = logic::all_t<_is_dynamic::value, is_expression_t::value, _serialize_check::type::value>; - - _add_impl(expr, ok()); // dispatch to prevent compile messages after the static_assert - } - - private: - template - void _add_impl(Expr expr, const std::true_type&) - { - return _dynamic_expressions.emplace_back(expr); - } - - template - void _add_impl(Expr expr, const std::false_type&); - - public: - std::tuple _expressions; - interpretable_list_t _dynamic_expressions; + Expression _expression; }; - template - struct serializer_t> + template <> + struct on_t { - using _serialize_check = serialize_check_of; - using T = on_t; + using _traits = make_traits; + using _nodes = detail::type_vector<>; + }; + + template + struct serializer_t> + { + using _serialize_check = consistent_t; + using T = on_t; + + static Context& _(const T&, Context& context) + { + return context; + } + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = on_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) - return context; context << " ON "; - interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) - context << " AND "; - interpret_list(t._dynamic_expressions, " AND ", context); + serialize(t._expression, context); return context; } }; diff --git a/include/sqlpp11/operand_check.h b/include/sqlpp11/operand_check.h index 45df1cfb..1de5abec 100644 --- a/include/sqlpp11/operand_check.h +++ b/include/sqlpp11/operand_check.h @@ -38,13 +38,16 @@ namespace sqlpp }; template class Pred> - struct unary_operand_check>::value>> + struct unary_operand_check::value>> { using type = void; }; template class Pred> - using unary_operand_check_t = typename unary_operand_check::type; + using unary_operand_check_t = typename unary_operand_check, Pred>::type; + + template class Pred> + using unwrapped_unary_operand_check_t = typename unary_operand_check::type; template class LPred, @@ -56,17 +59,17 @@ namespace sqlpp }; template class LPred, typename R, template class RPred> - struct binary_operand_check>::value and RPred>::value>> + struct binary_operand_check::value and RPred::value>> { using type = void; }; template class LPred, typename R, template class RPred> - using binary_operand_check_t = typename binary_operand_check::type; + using binary_operand_check_t = + typename binary_operand_check, LPred, wrap_operand_t, RPred>::type; + + template class LPred, typename R, template class RPred> + using unwrapped_binary_operand_check_t = typename binary_operand_check::type; } #endif diff --git a/include/sqlpp11/pre_join.h b/include/sqlpp11/pre_join.h new file mode 100644 index 00000000..00cccf0e --- /dev/null +++ b/include/sqlpp11/pre_join.h @@ -0,0 +1,208 @@ +/* + * 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. + */ + +#ifndef SQLPP_PRE_JOIN_H +#define SQLPP_PRE_JOIN_H + +#include +#include +#include + +namespace sqlpp +{ + SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_lhs_table_t, "lhs argument of join() has to be a table or a join"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_rhs_table_t, "rhs argument of join() has to be a table"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_rhs_no_join_t, "rhs argument of join() must not be a join"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_unique_names_t, "joined table names have to be unique"); + + template + struct check_pre_join + { + using type = static_combined_check_t< + static_check_t::value, assert_pre_join_lhs_table_t>, + static_check_t::value, assert_pre_join_rhs_table_t>, + static_check_t::value, assert_pre_join_rhs_no_join_t>, + static_check_t>, + detail::make_name_of_set_t>>::value, + assert_pre_join_unique_names_t>>; + }; + + template + using check_pre_join_t = typename check_pre_join::type; + + SQLPP_PORTABLE_STATIC_ASSERT(assert_join_consist_of_pre_join_and_on_t, + "join has to consist of a pre_join and a join condition"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_join_no_table_dependencies_t, "joined tables must not depend on other tables"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_join_on_no_foreign_table_dependencies_t, + "on() condition must not depend on other tables"); + + template + struct check_join + { + using type = static_combined_check_t< + static_check_t::value, assert_join_consist_of_pre_join_and_on_t>, + static_check_t::value, assert_join_consist_of_pre_join_and_on_t>, + static_check_t::size::value == 0, assert_join_no_table_dependencies_t>, + static_check_t, provided_tables_of>::value, + assert_join_on_no_foreign_table_dependencies_t>>; + }; + + template + using check_join_t = typename check_join::type; + + template + struct check_join_on + { + using type = static_combined_check_t, check_join_t>>; + }; + + template + using check_join_on_t = typename check_join_on::type; + + template + struct join_t; + + template + struct pre_join_t + { + using _traits = make_traits; + using _nodes = detail::type_vector; + using _can_be_null = std::false_type; + + static_assert(is_table_t::value, "lhs argument for join() has to be a table or join"); + static_assert(is_table_t::value, "rhs argument for join() has to be a table"); + static_assert(not is_join_t::value, "rhs argument for join must not be a join"); + + static_assert(detail::is_disjunct_from, provided_tables_of>::value, + "joined tables must not be identical"); + + static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); + + template + auto on(Expr expr) const -> typename std::conditional::value, + join_t>, + bad_statement>::type + { + 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; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = pre_join_t; + + static Context& _(const T& t, Context& context) + { + serialize(t._lhs, context); + context << JoinType::_name; + context << " JOIN "; + serialize(t._rhs, context); + return context; + } + }; + + template + auto join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, + bad_statement>::type + { + check_pre_join_t::_(); + + return {lhs, rhs}; + } + + template + auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, + bad_statement>::type + { + check_pre_join_t::_(); + + return {lhs, rhs}; + } + + template + auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, + bad_statement>::type + { + check_pre_join_t::_(); + + return {lhs, rhs}; + } + + template + auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, + bad_statement>::type + { + check_pre_join_t::_(); + + return {lhs, rhs}; + } + + template + auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, + bad_statement>::type + { + check_pre_join_t::_(); + + return {lhs, rhs}; + } + + template + auto cross_join(Lhs lhs, Rhs rhs) -> + typename std::conditional::value, + join_t, on_t>, + bad_statement>::type + { + check_pre_join_t::_(); + + return {pre_join_t{lhs, rhs}, {}}; + } +} + +#endif diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 3a8f590b..7e51f22d 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -62,33 +62,33 @@ namespace sqlpp using _alias_t = table_alias_t; template - join_t join(T t) const + auto join(T t) const -> decltype(::sqlpp::join(std::declval
(), t)) { - return {*static_cast(this), t, {}}; + return ::sqlpp::join(*static_cast(this), t); } template - join_t inner_join(T t) const + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(std::declval
(), t)) { - return {*static_cast(this), t, {}}; + return ::sqlpp::inner_join(*static_cast(this), t); } template - join_t outer_join(T t) const + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(std::declval
(), t)) { - return {*static_cast(this), t, {}}; + return ::sqlpp::left_outer_join(*static_cast(this), t); } template - join_t left_outer_join(T t) const + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(std::declval
(), t)) { - return {*static_cast(this), t, {}}; + return ::sqlpp::right_outer_join(*static_cast(this), t); } template - join_t right_outer_join(T t) const + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(std::declval
(), t)) { - return {*static_cast(this), t, {}}; + return ::sqlpp::outer_join(*static_cast(this), t); } template @@ -97,6 +97,12 @@ namespace sqlpp return {*static_cast(this)}; } + template + auto cross_join(T t) const -> decltype(::sqlpp::cross_join(std::declval
(), t)) + { + return ::sqlpp::cross_join(*static_cast(this), t); + } + const Table& ref() const { return *static_cast(this); diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index af73784a..52e04c31 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2013-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,6 @@ namespace sqlpp template struct table_alias_t : public ColumnSpec::_alias_t::template _member_t>... { - // FIXME: Need to add join functionality using _traits = make_traits, tag::is_table, tag::is_alias, @@ -60,6 +60,42 @@ namespace sqlpp { } + template + auto join(T t) const -> decltype(::sqlpp::join(*this, t)) + { + return ::sqlpp::join(*this, t); + } + + template + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) + { + return ::sqlpp::inner_join(*this, t); + } + + template + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) + { + return ::sqlpp::left_outer_join(*this, t); + } + + template + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t)) + { + return ::sqlpp::right_outer_join(*this, t); + } + + template + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t)) + { + return ::sqlpp::outer_join(*this, t); + } + + template + auto cross_join(T t) const -> decltype(::sqlpp::cross_join(*this, t)) + { + return ::sqlpp::cross_join(*this, t); + } + Table _table; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 1b413161..f97a05d2 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -56,6 +56,12 @@ namespace sqlpp template using value_type_of = typename detail::value_type_of_impl::type; + template + struct is_not_cpp_bool_t + { + static constexpr bool value = not std::is_same::value; + }; + // data types struct boolean; template @@ -163,7 +169,10 @@ namespace sqlpp SQLPP_VALUE_TRAIT_GENERATOR(is_return_value) SQLPP_VALUE_TRAIT_GENERATOR(is_table) SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table) + SQLPP_VALUE_TRAIT_GENERATOR(is_pre_join) SQLPP_VALUE_TRAIT_GENERATOR(is_join) + SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_pre_join) + SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join) SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table) SQLPP_VALUE_TRAIT_GENERATOR(is_column) SQLPP_VALUE_TRAIT_GENERATOR(is_select) @@ -373,6 +382,7 @@ namespace sqlpp using serialize_check_of = detail::get_first_if::_serialize_check...>; + SQLPP_PORTABLE_STATIC_ASSERT(assert_sqlpp_type_t, "expression is not an sqlpp type, consistency cannot be verified"); SQLPP_PORTABLE_STATIC_ASSERT(assert_run_statement_or_prepared_t, "connection cannot run something that is neither statement nor prepared statement"); SQLPP_PORTABLE_STATIC_ASSERT(assert_prepare_statement_t, @@ -381,12 +391,11 @@ namespace sqlpp template struct consistency_check { - using type = assert_run_statement_or_prepared_t; + using type = assert_sqlpp_type_t; }; template - struct consistency_check::value or is_prepared_statement_t::value>::type> + struct consistency_check> { using type = typename T::_consistency_check; }; diff --git a/include/sqlpp11/unconditional.h b/include/sqlpp11/unconditional.h new file mode 100644 index 00000000..ac4d9349 --- /dev/null +++ b/include/sqlpp11/unconditional.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef SQLPP_UNCONDITIONAL_H +#define SQLPP_UNCONDITIONAL_H + +namespace sqlpp +{ + struct unconditional_t + { + }; +} +#endif diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 448b2fbf..d9591b9e 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace sqlpp @@ -92,6 +93,7 @@ namespace sqlpp { static_assert(_is_dynamic::value, "where::add() can only be called for dynamic_where"); static_assert(is_expression_t::value, "invalid expression argument in where::add()"); + static_assert(is_boolean_t::value, "invalid expression argument in where::add()"); static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in where::add()"); static_assert(not contains_aggregate_function_t::value, @@ -154,20 +156,19 @@ namespace sqlpp }; template <> - struct where_data_t + struct where_data_t { - bool _condition; }; - // WHERE(BOOL) + // WHERE() UNCONDITIONALLY template <> - struct where_t + struct where_t { using _traits = make_traits; using _nodes = detail::type_vector<>; // Data - using _data_t = where_data_t; + using _data_t = where_data_t; // Member implementation with data and methods template @@ -186,7 +187,7 @@ namespace sqlpp template struct _base_t { - using _data_t = where_data_t; + using _data_t = where_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 template @@ -215,11 +216,13 @@ namespace sqlpp }; }; - SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "where expression required, e.g. where(true)"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "calling where() or uncontionally() required"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_where_expressions_t, - "at least one argument is not a boolean expression in where()"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_t, "at least one argument is not a boolean expression in where()"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_where_not_cpp_bool_t, + "where() argument has to be an sqlpp boolean expression. Please use " + ".unconditionally() instead of .where(true), or sqlpp::value(bool)"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_expression_t, + "where() argument has to be an sqlpp boolean expression."); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_no_aggregate_functions_t, "at least one aggregate function used in where()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_static_count_args_t, "missing argument in where()"); @@ -230,17 +233,21 @@ namespace sqlpp // https://connect.microsoft.com/VisualStudio/feedback/details/2173198 // template // using check_where_t = static_combined_check_t< - // static_check_t::value...>::value, assert_where_expressions_t>, - // static_check_t::value...>::value, assert_where_boolean_t>, + // static_check_t::value...>::value, + // assert_where_not_cpp_bool_t>, + // static_check_t::value...>::value, + // assert_where_boolean_expressions_t>, + // static_check_t::value...>::value, assert_where_boolean_expression_t>, // static_check_t::value)...>::value, // assert_where_no_aggregate_functions_t>>; template struct check_where { using type = static_combined_check_t< + static_check_t::value...>::value, assert_where_not_cpp_bool_t>, static_check_t::type::value...>::value, - assert_where_expressions_t>, - static_check_t::value...>::value, assert_where_boolean_t>, + assert_where_boolean_expression_t>, + static_check_t::value...>::value, assert_where_boolean_expression_t>, static_check_t::type::value)...>::value, assert_where_no_aggregate_functions_t>>; }; @@ -312,14 +319,6 @@ namespace sqlpp using _database_t = typename Policies::_database_t; - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 - // template - // using _check = logic::all_t::value...>; - template - struct _check : logic::all_t::value...> - { - }; - template using _new_statement_t = new_statement_t; @@ -328,9 +327,9 @@ namespace sqlpp assert_where_t, consistent_t>::type; - auto where(bool b) const -> _new_statement_t> + auto unconditionally() const -> _new_statement_t> { - return {static_cast&>(*this), where_data_t{b}}; + return {static_cast&>(*this), where_data_t{}}; } template @@ -388,15 +387,13 @@ namespace sqlpp }; template - struct serializer_t> + struct serializer_t> { using _serialize_check = consistent_t; - using T = where_data_t; + using T = where_data_t; - static Context& _(const T& t, Context& context) + static Context& _(const T&, Context& context) { - if (not t._condition) - context << " WHERE NULL"; return context; } }; diff --git a/test_constraints/no_conversion_operator_if_null_not_trivial.cpp b/test_constraints/no_conversion_operator_if_null_not_trivial.cpp index 091c5759..a74400f3 100644 --- a/test_constraints/no_conversion_operator_if_null_not_trivial.cpp +++ b/test_constraints/no_conversion_operator_if_null_not_trivial.cpp @@ -36,7 +36,7 @@ int main() static_assert(sqlpp::can_be_null_t::value, "t.alpha can be null"); static_assert(not sqlpp::null_is_trivial_value_t::value, "t.alpha does not say null_is_trivial"); - for (const auto& row : edb(select(all_of(t)).from(t).where(true))) + for (const auto& row : edb(select(all_of(t)).from(t).unconditionally())) { static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); static_assert(not sqlpp::null_is_trivial_value_t::value, diff --git a/test_serializer/CMakeLists.txt b/test_serializer/CMakeLists.txt new file mode 100644 index 00000000..6b19a24a --- /dev/null +++ b/test_serializer/CMakeLists.txt @@ -0,0 +1,40 @@ +# 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 + In + Where + ) + +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..2827b719 --- /dev/null +++ b/test_serializer/From.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016-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. + */ + +#include "compare.h" +#include "Sample.h" +#include + +namespace +{ + MockDb db = {}; +} + +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; +} diff --git a/test_serializer/In.cpp b/test_serializer/In.cpp new file mode 100644 index 00000000..989a0805 --- /dev/null +++ b/test_serializer/In.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016-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. + */ + +#include "compare.h" +#include "Sample.h" +#include + +#include + +namespace +{ + auto getFalse() -> std::string + { + MockDb::_serializer_context_t printer = {}; + return serialize(sqlpp::value(false), printer).str(); + } +} + +int In(int, char* []) +{ + const auto foo = test::TabFoo{}; + const auto bar = test::TabBar{}; + + // Individual values + compare(__LINE__, foo.omega.in(foo.omega), "tab_foo.omega IN(tab_foo.omega)"); + compare(__LINE__, foo.omega.in(foo.omega, bar.alpha), "tab_foo.omega IN(tab_foo.omega,tab_bar.alpha)"); + compare(__LINE__, foo.omega.in(foo.omega, bar.alpha, sqlpp::value(17)), + "tab_foo.omega IN(tab_foo.omega,tab_bar.alpha,17)"); + + // Lists + compare(__LINE__, foo.omega.in(sqlpp::value_list(std::vector{1.7f, 2.5f, 17.f, 0.f})), + "tab_foo.omega IN(1.7,2.5,17,0)"); + + // Sub select + compare(__LINE__, foo.omega.in(select(bar.alpha).from(bar).unconditionally()), + "tab_foo.omega IN(SELECT tab_bar.alpha FROM tab_bar)"); + + // Empty lists (not normally covered by SQL) + compare(__LINE__, foo.omega.in(), getFalse()); + compare(__LINE__, foo.omega.in(sqlpp::value_list(std::vector{})), getFalse()); + + return 0; +} diff --git a/test_serializer/Where.cpp b/test_serializer/Where.cpp new file mode 100644 index 00000000..a4e80112 --- /dev/null +++ b/test_serializer/Where.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016-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. + */ + +#include "compare.h" +#include "Sample.h" +#include + +#include + +namespace +{ + auto getTrue() -> std::string + { + MockDb::_serializer_context_t printer = {}; + return serialize(sqlpp::value(true), printer).str(); + } + + auto getFalse() -> std::string + { + MockDb::_serializer_context_t printer = {}; + return serialize(sqlpp::value(false), printer).str(); + } +} + +int Where(int, char* []) +{ + const auto foo = test::TabFoo{}; + const auto bar = test::TabBar{}; + + // Unconditionally + compare(__LINE__, select(foo.omega).from(foo).unconditionally(), "SELECT tab_foo.omega FROM tab_foo"); + compare(__LINE__, remove_from(foo).unconditionally(), "DELETE FROM tab_foo"); + compare(__LINE__, update(foo).set(foo.omega = 42).unconditionally(), "UPDATE tab_foo SET omega=42"); + compare(__LINE__, where(sqlpp::value(true)), " WHERE " + getTrue()); + + // Never + compare(__LINE__, where(sqlpp::value(false)), " WHERE " + getFalse()); + + // Sometimes + compare(__LINE__, where(bar.gamma), " WHERE tab_bar.gamma"); + compare(__LINE__, where(bar.gamma == false), " WHERE (tab_bar.gamma=" + getFalse() + ")"); + compare(__LINE__, where(bar.beta == "SQL"), " WHERE (tab_bar.beta='SQL')"); + + return 0; +} diff --git a/test_serializer/compare.h b/test_serializer/compare.h new file mode 100644 index 00000000..9709a44c --- /dev/null +++ b/test_serializer/compare.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef SQLPP_TEST_SERIALIZER_H +#define SQLPP_TEST_SERIALIZER_H + +#include "MockDb.h" +#include + +namespace +{ + 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"); + } + } +} + +#endif diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 54d9b158..0416116a 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -30,8 +30,11 @@ endfunction() test_compile(aggregates) test_compile(case) +test_compile(from) +test_compile(join) test_compile(where) test_compile(insert) test_compile(date) test_compile(date_time) +test_compile(unwrapped_bool) diff --git a/test_static_asserts/aggregates.cpp b/test_static_asserts/aggregates.cpp index 929bd843..f685f2ec 100644 --- a/test_static_asserts/aggregates.cpp +++ b/test_static_asserts/aggregates.cpp @@ -75,51 +75,53 @@ namespace // If there is no group_by, we can select whatever we want void no_group_by() { - run_check(select(all_of(t)).from(t).where(true)); - run_check(select(t.alpha).from(t).where(true)); - run_check(select(count(t.alpha)).from(t).where(true)); + run_check(select(all_of(t)).from(t).unconditionally()); + run_check(select(t.alpha).from(t).unconditionally()); + run_check(select(count(t.alpha)).from(t).unconditionally()); } // If there is a dynamic group_by, we can still select whatever we want // because there is no way of knowing which expressions might have been added dynamically void dynamic_group_by() { - run_check(select(all_of(t)).from(t).where(true)); - run_check(select(t.alpha).from(t).where(true)); - run_check(select(count(t.alpha)).from(t).where(true)); + run_check(select(all_of(t)).from(t).unconditionally()); + run_check(select(t.alpha).from(t).unconditionally()); + run_check(select(count(t.alpha)).from(t).unconditionally()); } // If there is a static group_by, selected columns must be made of group_by expressions, or aggregate expression (e.g. // count(t.id)) or values to be valid void static_group_by_ok() { - run_check(select(t.alpha).from(t).where(true).group_by(t.alpha)); - run_check(select((t.alpha + 42).as(whatever)).from(t).where(true).group_by(t.alpha)); - run_check(select((t.alpha + 42).as(whatever)).from(t).where(true).group_by(t.alpha, t.alpha + t.delta * 17)); - run_check( - select((t.alpha + t.delta * 17).as(whatever)).from(t).where(true).group_by(t.alpha, t.alpha + t.delta * 17)); - run_check(select((t.beta + "fortytwo").as(whatever)).from(t).where(true).group_by(t.beta)); + run_check(select(t.alpha).from(t).unconditionally().group_by(t.alpha)); + run_check(select((t.alpha + 42).as(whatever)).from(t).unconditionally().group_by(t.alpha)); + run_check(select((t.alpha + 42).as(whatever)).from(t).unconditionally().group_by(t.alpha, t.alpha + t.delta * 17)); + run_check(select((t.alpha + t.delta * 17).as(whatever)) + .from(t) + .unconditionally() + .group_by(t.alpha, t.alpha + t.delta * 17)); + run_check(select((t.beta + "fortytwo").as(whatever)).from(t).unconditionally().group_by(t.beta)); - run_check(select(avg(t.alpha)).from(t).where(true).group_by(t.beta)); - run_check(select(count(t.alpha)).from(t).where(true).group_by(t.beta)); - run_check(select(max(t.alpha)).from(t).where(true).group_by(t.beta)); - run_check(select(min(t.alpha)).from(t).where(true).group_by(t.beta)); - run_check(select(sum(t.alpha)).from(t).where(true).group_by(t.beta)); + run_check(select(avg(t.alpha)).from(t).unconditionally().group_by(t.beta)); + run_check(select(count(t.alpha)).from(t).unconditionally().group_by(t.beta)); + run_check(select(max(t.alpha)).from(t).unconditionally().group_by(t.beta)); + run_check(select(min(t.alpha)).from(t).unconditionally().group_by(t.beta)); + run_check(select(sum(t.alpha)).from(t).unconditionally().group_by(t.beta)); - run_check(select((t.alpha + count(t.delta)).as(whatever)).from(t).where(true).group_by(t.alpha)); + run_check(select((t.alpha + count(t.delta)).as(whatever)).from(t).unconditionally().group_by(t.alpha)); - run_check(select(sqlpp::value(1).as(whatever)).from(t).where(true).group_by(t.alpha)); - run_check(select(sqlpp::value("whatever").as(whatever)).from(t).where(true).group_by(t.alpha)); + run_check(select(sqlpp::value(1).as(whatever)).from(t).unconditionally().group_by(t.alpha)); + run_check(select(sqlpp::value("whatever").as(whatever)).from(t).unconditionally().group_by(t.alpha)); } // Failures with static group_by and selected non-aggregates or incorrect aggregates void static_group_by_nok() { - run_check(select(t.beta).from(t).where(true).group_by(t.alpha)); + run_check(select(t.beta).from(t).unconditionally().group_by(t.alpha)); run_check( - select((t.alpha + t.delta).as(whatever)).from(t).where(true).group_by(t.alpha)); + select((t.alpha + t.delta).as(whatever)).from(t).unconditionally().group_by(t.alpha)); run_check( - select((t.alpha + t.delta).as(whatever)).from(t).where(true).group_by(t.alpha, t.alpha + t.delta * 17)); + select((t.alpha + t.delta).as(whatever)).from(t).unconditionally().group_by(t.alpha, t.alpha + t.delta * 17)); } } diff --git a/test_static_asserts/case.cpp b/test_static_asserts/case.cpp index 5b37e551..44506abb 100644 --- a/test_static_asserts/case.cpp +++ b/test_static_asserts/case.cpp @@ -31,7 +31,6 @@ namespace { constexpr auto t = test::TabBar{}; - constexpr auto f = test::TabFoo{}; template void print_type_on_error(std::true_type) diff --git a/test_static_asserts/from.cpp b/test_static_asserts/from.cpp new file mode 100644 index 00000000..fff9d433 --- /dev/null +++ b/test_static_asserts/from.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015-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. + */ + +#include +#include "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + constexpr auto t = test::TabBar{}; + constexpr auto f = test::TabFoo{}; + + template + void print_type_on_error(std::true_type) + { + } + + template + void print_type_on_error(std::false_type) + { + T::_print_me_; + } + + template + void from_static_check(const Expression& expression) + { + using CheckResult = sqlpp::check_from_static_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ReturnType = decltype(select(t.alpha).from(expression)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void from_dynamic_check(const Expression& expression) + { + static auto db = MockDb{}; + using CheckResult = sqlpp::check_from_dynamic_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ReturnType = decltype(dynamic_select(db, t.alpha).dynamic_from(expression)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + void static_from() + { + // OK + from_static_check(t); + from_static_check(t.cross_join(f)); + from_static_check(t.join(f).on(t.alpha > f.omega)); + + // Try a bunch of non-tables + from_static_check(7); + from_static_check(t.alpha); + from_static_check(t.beta); + from_static_check(t.gamma); + from_static_check(t.delta); + + // Try cross joins (missing condition) + from_static_check(t.join(f)); + } + + void dynamic_from() + { + // OK + from_dynamic_check(t); + from_dynamic_check(t.cross_join(f)); + from_dynamic_check(t.join(f).on(t.alpha > f.omega)); + + // Try a bunch of non-tables + from_dynamic_check(7); + from_dynamic_check(t.alpha); + from_dynamic_check(t.beta); + from_dynamic_check(t.gamma); + from_dynamic_check(t.delta); + + // Try cross joins (missing condition) + from_dynamic_check(t.join(f)); + } +} + +int main(int, char* []) +{ + static_from(); + dynamic_from(); +} diff --git a/test_static_asserts/join.cpp b/test_static_asserts/join.cpp new file mode 100644 index 00000000..29369ed3 --- /dev/null +++ b/test_static_asserts/join.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2016-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. + */ + +#include +#include "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + constexpr auto t = test::TabBar{}; + constexpr auto f = test::TabFoo{}; + + template + void print_type_on_error(std::true_type) + { + } + + template + void print_type_on_error(std::false_type) + { + T::_print_me_; + } + + template + void join_static_check(const Lhs& lhs, const Rhs& rhs) + { + using CheckResult = sqlpp::check_pre_join_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using JoinType = decltype(sqlpp::join(lhs, rhs)); + using InnerJoinType = decltype(sqlpp::inner_join(lhs, rhs)); + using LeftOuterJoinType = decltype(sqlpp::left_outer_join(lhs, rhs)); + using RightOuterJoinType = decltype(sqlpp::right_outer_join(lhs, rhs)); + using OuterJoinType = decltype(sqlpp::outer_join(lhs, rhs)); + using CrossJoinType = decltype(sqlpp::cross_join(lhs, rhs)); + using ExpectedReturnType = sqlpp::logic::all_t< + (Assert::value and sqlpp::is_pre_join_t::value and sqlpp::is_pre_join_t::value and + sqlpp::is_pre_join_t::value and sqlpp::is_pre_join_t::value and + sqlpp::is_pre_join_t::value and sqlpp::is_join_t::value) xor + (std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value)>; + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void on_static_check(const Lhs& lhs, const Rhs& rhs) + { + using CheckResult = sqlpp::check_join_on_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ResultType = decltype(lhs.on(rhs)); + using ExpectedReturnType = sqlpp::logic::all_t<(Assert::value and sqlpp::is_join_t::value) xor + std::is_same::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + void static_join() + { + // Prepare a few table aliases for tests + const auto ta = t.as(sqlpp::alias::a); + const auto tb = t.as(sqlpp::alias::b); + const auto fa = f.as(sqlpp::alias::a); + const auto fb = f.as(sqlpp::alias::b); + + // OK: Join two different tables + join_static_check(t, f); + join_static_check(t, fa); + join_static_check(ta, fb); + + // OK: Self join + join_static_check(ta, tb); + join_static_check(t, tb); + join_static_check(ta, t); + + // Prepare a join for tests: + const auto j = cross_join(ta, tb); + + // OK: Add a third table + join_static_check(j, f); + join_static_check(j, t.as(sqlpp::alias::c)); + join_static_check(j, t); + + // Try a bunch of non-tables + join_static_check(t, 7); + join_static_check(t, t.alpha); + join_static_check(t, t.beta); + join_static_check(t, t.gamma); + join_static_check(t, t.delta); + + join_static_check(7, t); + join_static_check(t.alpha, t); + join_static_check(t.beta, t); + join_static_check(t.gamma, t); + join_static_check(t.delta, t); + + // Try to join with join (rhs) + join_static_check(t, j); + join_static_check(f, j); + join_static_check(t.as(sqlpp::alias::left), j); + + // Try to join identical table names + join_static_check(t, t); + join_static_check(f, f); + join_static_check(t.as(f), f); + join_static_check(t, f.as(t)); + join_static_check(ta, fa); + join_static_check(j, fa); + join_static_check(j, fb); + join_static_check(j, ta); + join_static_check(j, tb); + + // Prepare a pre_joins for tests: + const auto t_f = join(t, f); + const auto f_t = join(f, t); + const auto t_t = join(ta, tb); + const auto f_f = join(fa, fb); + + // OK join.on() + on_static_check(t_f, t.alpha > f.omega); + on_static_check(f_t, t.alpha < f.omega); + on_static_check(f_f, fa.omega == fb.omega); + on_static_check(t_t, ta.alpha == tb.alpha); + on_static_check(t_f, t.gamma); + + // Try join.on(non-expression) + on_static_check(t_f, true); + on_static_check(t_f, 7); + on_static_check(t_f, t); + + // Try join.on(non-boolean) + on_static_check(t_f, t.alpha); + on_static_check(t_f, t.beta); + on_static_check(t_f, f.omega); + + // Try join.on(foreign-table) + on_static_check(t_f, ta.alpha != 0); + on_static_check(t_t, t.gamma); + on_static_check(f_f, f.omega > fa.omega); + } + + template + void join_dynamic_check(const Table& table) + { + using CheckResult = sqlpp::check_dynamic_pre_join_t
; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using JoinType = decltype(sqlpp::dynamic_join(table)); + using InnerJoinType = decltype(sqlpp::dynamic_inner_join(table)); + using LeftOuterJoinType = decltype(sqlpp::dynamic_left_outer_join(table)); + using RightOuterJoinType = decltype(sqlpp::dynamic_right_outer_join(table)); + using OuterJoinType = decltype(sqlpp::dynamic_outer_join(table)); + using CrossJoinType = decltype(sqlpp::dynamic_cross_join(table)); + using ExpectedReturnType = sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_pre_join_t::value and + sqlpp::is_dynamic_pre_join_t::value and + sqlpp::is_dynamic_pre_join_t::value and + sqlpp::is_dynamic_pre_join_t::value and + sqlpp::is_dynamic_pre_join_t::value and + sqlpp::is_dynamic_join_t::value) xor + (std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value)>; + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void on_dynamic_check(const Lhs& lhs, const Rhs& rhs) + { + using CheckResult = sqlpp::check_dynamic_join_on_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ResultType = decltype(lhs.on(rhs)); + using ExpectedReturnType = sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_join_t::value) xor + std::is_same::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + void dynamic_join() + { + // Prepare a few table aliases for tests + const auto ta = t.as(sqlpp::alias::a); + const auto fa = f.as(sqlpp::alias::a); + + // OK + join_dynamic_check(t); + join_dynamic_check(f); + join_dynamic_check(ta); + join_dynamic_check(fa); + + // Try a bunch of non-tables + join_dynamic_check(7); + join_dynamic_check(t.alpha); + join_dynamic_check(t.beta); + join_dynamic_check(t.gamma); + join_dynamic_check(t.delta); + + // Try (pre) joins + join_dynamic_check(t.join(f)); + join_dynamic_check(t.cross_join(f)); + + // Prepare a dynamic_pre_joins for tests: + const auto tj = dynamic_join(t); + const auto fj = dynamic_join(f); + + // OK dynamic_join.on() + on_dynamic_check(tj, t.alpha > f.omega); + on_dynamic_check(fj, t.alpha < f.omega); + + // Try dynamic_join.on(non-expression) + on_dynamic_check(tj, true); + on_dynamic_check(tj, 7); + on_dynamic_check(tj, t); + + // Try dynamic_join.on(non-boolean) + on_dynamic_check(tj, t.alpha); + on_dynamic_check(tj, t.beta); + on_dynamic_check(tj, f.omega); + + // OK dynamic_join.on(foreign-table) + on_dynamic_check(tj, ta.alpha != 0); + on_dynamic_check(tj, t.gamma); + on_dynamic_check(tj, f.omega > fa.omega); + } +} + +int main(int, char* []) +{ + static_join(); + dynamic_join(); +} diff --git a/test_static_asserts/unwrapped_bool.cpp b/test_static_asserts/unwrapped_bool.cpp new file mode 100644 index 00000000..431a5ea8 --- /dev/null +++ b/test_static_asserts/unwrapped_bool.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015-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. + */ + +#include +#include "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + constexpr auto t = test::TabBar{}; + + template + struct wrap + { + }; + + template + void print_type_on_error(std::true_type) + { + } + + template + void print_type_on_error(std::false_type) + { + wrap::_print_me_; + } + + template + void and_check(const Lhs& lhs, const Rhs& rhs) + { + using ReturnType = decltype(lhs and rhs); + using ExpectedReturnType = + sqlpp::logic::all_t>::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void or_check(const Lhs& lhs, const Rhs& rhs) + { + using ReturnType = decltype(lhs or rhs); + using ExpectedReturnType = + sqlpp::logic::all_t>::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void not_check(const Lhs& lhs) + { + using ReturnType = decltype(not lhs); + using ExpectedReturnType = + sqlpp::logic::all_t>::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void where_check(const Condition& condition) + { + using ReturnType = decltype(sqlpp::where(condition)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + void boolean() + { + and_check(t.gamma, t.gamma); + and_check(t.gamma, true); + // and_check(true, t.gamma); // Cannot currently do that + + or_check(t.gamma, t.gamma); + or_check(t.gamma, true); + // or_check(true, t.gamma); // Cannot currently do that + + not_check(t.gamma); + } + + void where() + { + where_check(t.gamma); + where_check(true); + } +} + +int main(int, char* []) +{ + boolean(); + where(); +} diff --git a/test_static_asserts/where.cpp b/test_static_asserts/where.cpp index 9fb5d9b3..5694a296 100644 --- a/test_static_asserts/where.cpp +++ b/test_static_asserts/where.cpp @@ -31,7 +31,6 @@ namespace { constexpr auto t = test::TabBar{}; - constexpr auto f = test::TabFoo{}; template void print_type_on_error(std::true_type) @@ -85,17 +84,21 @@ namespace where_static_check(); // Try assignment as condition - where_static_check(t.gamma = true); + where_static_check(t.gamma = true); // Try non-boolean expression - where_static_check(t.alpha); + where_static_check(t.alpha); + + // Try builtin bool + where_static_check(true); + where_static_check(17 > 3); // Try some other types as expressions - where_static_check("true"); - where_static_check(17); - where_static_check('c'); - where_static_check(nullptr); - where_static_check(t.alpha.as(t.beta)); + where_static_check("true"); + where_static_check(17); + where_static_check('c'); + where_static_check(nullptr); + where_static_check(t.alpha.as(t.beta)); // Try using aggregate functions in where where_static_check(count(t.alpha) > 0); @@ -112,17 +115,21 @@ namespace where_dynamic_check(t.gamma == true); // Try assignment as condition - where_dynamic_check(t.gamma = true); + where_dynamic_check(t.gamma = true); // Try non-boolean expression - where_dynamic_check(t.alpha); + where_dynamic_check(t.alpha); + + // Try builtin bool + where_dynamic_check(true); + where_dynamic_check(17 > 3); // Try some other types as expressions - where_dynamic_check("true"); - where_dynamic_check(17); - where_dynamic_check('c'); - where_dynamic_check(nullptr); - where_dynamic_check(t.alpha.as(t.beta)); + where_dynamic_check("true"); + where_dynamic_check(17); + where_dynamic_check('c'); + where_dynamic_check(nullptr); + where_dynamic_check(t.alpha.as(t.beta)); // Try using aggregate functions in where where_dynamic_check(count(t.alpha) > 0); diff --git a/tests/DateTime.cpp b/tests/DateTime.cpp index b244bed2..c0b77c33 100644 --- a/tests/DateTime.cpp +++ b/tests/DateTime.cpp @@ -40,7 +40,7 @@ int DateTime(int, char* []) { std::cout << row.now; } - for (const auto& row : db(select(all_of(t)).from(t).where(true))) + for (const auto& row : db(select(all_of(t)).from(t).unconditionally())) { std::cout << row.colDayPoint; std::cout << row.colTimePoint; diff --git a/tests/Function.cpp b/tests/Function.cpp index 7f3e3a0d..e31fcd5c 100644 --- a/tests/Function.cpp +++ b/tests/Function.cpp @@ -197,7 +197,7 @@ int Function(int, char* []) static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); - if (false and db(select(exists(select(t.alpha).from(t).where(true)))).front().exists) + if (false and db(select(exists(select(t.alpha).from(t).unconditionally()))).front().exists) { /* do something */ } } @@ -286,7 +286,7 @@ int Function(int, char* []) static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - if (false and db(select(count(t.alpha)).from(t).where(true)).front().count > 0) + if (false and db(select(count(t.alpha)).from(t).unconditionally()).front().count > 0) { /* do something */ } } @@ -444,7 +444,7 @@ int Function(int, char* []) static_assert(std::is_same>::value, "text values are accepted and wrapped"); - for (const auto& row : db(select(all_of(t)).from(t).where(true))) + for (const auto& row : db(select(all_of(t)).from(t).unconditionally())) { static_assert(std::is_same::type>>::value, diff --git a/tests/Interpret.cpp b/tests/Interpret.cpp index 9b9fffe2..24841870 100644 --- a/tests/Interpret.cpp +++ b/tests/Interpret.cpp @@ -178,10 +178,9 @@ int Interpret(int, char* []) serialize(avg(sqlpp::distinct, t.alpha - 7), printer).str(); serialize(sum(sqlpp::distinct, t.alpha + 7), printer).str(); - serialize(select(all_of(t)).from(t).where(true), printer).str(); - serialize(select(all_of(t)).from(t).where(false), printer).str(); + serialize(select(all_of(t)).from(t).unconditionally(), printer).str(); - for (const auto& row : db(select(all_of(t)).from(t).where(true))) + for (const auto& row : db(select(all_of(t)).from(t).unconditionally())) { serialize(row.alpha, printer); serialize(row.beta, printer); @@ -201,8 +200,8 @@ int Interpret(int, char* []) std::cerr << serialize(x, printer).str() << std::endl; printer.reset(); - std::cerr << serialize(select(all_of(t)).from(t).where(t.alpha.in(select(f.epsilon).from(f).where(true))), printer) - .str() << std::endl; + std::cerr << serialize(select(all_of(t)).from(t).where(t.alpha.in(select(f.epsilon).from(f).unconditionally())), + printer).str() << std::endl; printer.reset(); std::cerr << serialize(select(all_of(t)).from(t).where(t.alpha.in()), printer).str() << std::endl; @@ -214,7 +213,7 @@ int Interpret(int, char* []) auto s = schema_qualified_table(schema, t).as(sqlpp::alias::x); printer.reset(); - std::cerr << serialize(select(all_of(s)).from(s).where(true), printer).str() << std::endl; + std::cerr << serialize(select(all_of(s)).from(s).unconditionally(), printer).str() << std::endl; printer.reset(); std::cerr << serialize(sqlpp::case_when(true).then(t.alpha).else_(t.alpha + 1).as(t.beta), printer).str() diff --git a/tests/Remove.cpp b/tests/Remove.cpp index d0461b75..b1442c09 100644 --- a/tests/Remove.cpp +++ b/tests/Remove.cpp @@ -60,7 +60,7 @@ int Remove(int, char* []) printer.reset(); std::cerr << serialize(r, printer).str() << std::endl; printer.reset(); - std::cerr << serialize(remove_from(t).where(true), printer).str() << std::endl; + std::cerr << serialize(remove_from(t).unconditionally(), printer).str() << std::endl; db(r); diff --git a/tests/Result.cpp b/tests/Result.cpp index c3219be8..aac0f0e8 100644 --- a/tests/Result.cpp +++ b/tests/Result.cpp @@ -42,7 +42,7 @@ int Result(int, char* []) static_assert(not sqlpp::null_is_trivial_value_t::value, "t.alpha does not say null_is_trivial"); // Using a non-enforcing db - for (const auto& row : db(select(all_of(t), t.beta.like("")).from(t).where(true))) + for (const auto& row : db(select(all_of(t), t.beta.like("")).from(t).unconditionally())) { static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); static_assert(sqlpp::null_is_trivial_value_t::value, "row.alpha interprets null_is_trivial"); @@ -64,14 +64,14 @@ int Result(int, char* []) } sqlpp::select((t.alpha + 1).as(t.alpha)).flags(sqlpp::all).from(t); - for (const auto& row : db(select(all_of(t)).from(t).where(true))) + for (const auto& row : db(select(all_of(t)).from(t).unconditionally())) { static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); static_assert(sqlpp::null_is_trivial_value_t::value, "row.alpha interprets null_is_trivial"); } // Using a non-enforcing db - for (const auto& row : edb(select(all_of(t)).from(t).where(true))) + for (const auto& row : edb(select(all_of(t)).from(t).unconditionally())) { static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); static_assert(not sqlpp::null_is_trivial_value_t::value, @@ -79,7 +79,7 @@ int Result(int, char* []) } sqlpp::select((t.alpha + 1).as(t.alpha)).flags(sqlpp::all).from(t); - for (const auto& row : edb(select(all_of(t)).from(t).where(true))) + for (const auto& row : edb(select(all_of(t)).from(t).unconditionally())) { static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); static_assert(not sqlpp::null_is_trivial_value_t::value, diff --git a/tests/Select.cpp b/tests/Select.cpp index db7c7172..43be425c 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -35,7 +35,7 @@ template int64_t getColumn(Db&& db, const Column& column) { - auto result = db(select(column.as(sqlpp::alias::a)).from(column.table()).where(true)); + auto result = db(select(column.as(sqlpp::alias::a)).from(column.table()).unconditionally()); if (not result.empty()) return result.front().a; else @@ -59,14 +59,14 @@ int Select(int, char* []) std::cout << row.a << std::endl; } - for (const auto& row : db(select(all_of(t)).from(t).where(true))) + for (const auto& row : db(select(all_of(t)).from(t).unconditionally())) { int64_t a = row.alpha; const std::string b = row.beta; std::cout << a << ", " << b << std::endl; } - for (const auto& row : db(select(all_of(t).as(t)).from(t).where(true))) + for (const auto& row : db(select(all_of(t).as(t)).from(t).unconditionally())) { int64_t a = row.tabBar.alpha; const std::string b = row.tabBar.beta; @@ -82,19 +82,19 @@ int Select(int, char* []) } for (const auto& row : - db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega and not t.gamma)).where(true))) + db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega and not t.gamma)).unconditionally())) { std::cout << row.alpha << std::endl; } for (const auto& row : db(select(all_of(t), all_of(f)) .from(t.join(f).on(t.alpha > f.omega).join(tab_a).on(t.alpha == tab_a.omega)) - .where(true))) + .unconditionally())) { std::cout << row.alpha << std::endl; } - for (const auto& row : db(select(count(t.alpha), avg(t.alpha)).from(t).where(true))) + for (const auto& row : db(select(count(t.alpha), avg(t.alpha)).from(t).unconditionally())) { std::cout << row.count << std::endl; } @@ -146,7 +146,7 @@ int Select(int, char* []) .dynamic_offset(); s.select_flags.add(sqlpp::distinct); s.selected_columns.add(f.omega); - s.from.add(f); + s.from.add(dynamic_cross_join(f)); s.where.add(t.alpha > 7); s.having.add(t.alpha > 7); s.limit.set(3); @@ -165,7 +165,7 @@ int Select(int, char* []) select(sqlpp::value(7).as(t.alpha)); for (const auto& row : - db(select(sqlpp::case_when(true).then(sqlpp::null).else_(sqlpp::null).as(t.beta)).from(t).where(true))) + db(select(sqlpp::case_when(true).then(sqlpp::null).else_(sqlpp::null).as(t.beta)).from(t).unconditionally())) { std::cerr << row.beta << std::endl; } diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index d516e21d..85978cdd 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -298,7 +298,7 @@ int SelectType(int, char* []) t.alpha.as(alias::a) // index 12 ) .from(t) - .where(true)); // next index is 13 + .unconditionally()); // next index is 13 using ResultRow = typename Select::_result_methods_t