From bc935dbae8e635a5e89f35fc51b821ce1ce5d186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20D=C3=A1vid?= Date: Sat, 9 Jan 2016 18:55:45 +0100 Subject: [PATCH 01/90] Added cmake package config file Now sqlpp11 can be used with find_package(Sqlpp11) target_link_libraries(... sqlpp11) in your project's CMakeLists.txt --- CMakeLists.txt | 46 ++++++++++++++++++++++++++++++++++++--- cmake/Sqlpp11Config.cmake | 26 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 cmake/Sqlpp11Config.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f606df00..e82b728d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ endif() target_include_directories(sqlpp11 INTERFACE $ $ + $ ) if (NOT MSVC) @@ -64,10 +65,49 @@ target_compile_features(sqlpp11 INTERFACE ) endif () +install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" + DESTINATION include +) + +install(TARGETS sqlpp11 + EXPORT Sqlpp11Targets +) + +include(CMakePackageConfigHelpers) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11ConfigVersion.cmake" + VERSION ${Upstream_VERSION} + COMPATIBILITY AnyNewerVersion +) + +export(EXPORT Sqlpp11Targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11Targets.cmake" +) + +configure_file(cmake/Sqlpp11Config.cmake + "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11Config.cmake" + COPYONLY +) + +set(ConfigPackageLocation lib/cmake/Sqlpp11) +install(EXPORT Sqlpp11Targets + FILE + Sqlpp11Targets.cmake + DESTINATION + ${ConfigPackageLocation} +) + +install( + FILES + cmake/Sqlpp11Config.cmake + "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11ConfigVersion.cmake" + DESTINATION + ${ConfigPackageLocation} +) + + add_subdirectory(tests) add_subdirectory(test_static_asserts) add_subdirectory(test_constraints) add_subdirectory(examples) - -install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" DESTINATION include) - diff --git a/cmake/Sqlpp11Config.cmake b/cmake/Sqlpp11Config.cmake new file mode 100644 index 00000000..033d7f4b --- /dev/null +++ b/cmake/Sqlpp11Config.cmake @@ -0,0 +1,26 @@ +# Copyright (c) 2016, Christian David +# 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("${CMAKE_CURRENT_LIST_DIR}/Sqlpp11Targets.cmake") From 618a84e7a524c9a6b7d1f2af7367119adb8b0e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20D=C3=A1vid?= Date: Sun, 10 Jan 2016 12:25:04 +0100 Subject: [PATCH 02/90] Fixed error in CMakeLists.txt The version was not exported to the ...ConfigVersion.cmake file --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e82b728d..f75b5c42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/cmake/Sqlpp11ConfigVersion.cmake" - VERSION ${Upstream_VERSION} + VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) From e3022a68879e889e4ab617307a0bc1f271f321f3 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 23 Jan 2016 22:04:55 +0100 Subject: [PATCH 03/90] Fixed constructor of result_row. This accepted just any(!) argument. --- include/sqlpp11/dynamic_select_column_list.h | 75 ++++++++++++++++++++ include/sqlpp11/result_row.h | 5 +- include/sqlpp11/select_column_list.h | 39 +--------- 3 files changed, 78 insertions(+), 41 deletions(-) create mode 100644 include/sqlpp11/dynamic_select_column_list.h diff --git a/include/sqlpp11/dynamic_select_column_list.h b/include/sqlpp11/dynamic_select_column_list.h new file mode 100644 index 00000000..daf995f9 --- /dev/null +++ b/include/sqlpp11/dynamic_select_column_list.h @@ -0,0 +1,75 @@ +/* + * 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_SELECT_COLUMN_LIST_FWD_H +#define SQLPP_SELECT_COLUMN_LIST_FWD_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct dynamic_select_column_list + { + using _names_t = std::vector; + std::vector> _dynamic_columns; + _names_t _dynamic_expression_names; + + template + void emplace_back(Expr expr) + { + _dynamic_expression_names.push_back(name_of::char_ptr()); + _dynamic_columns.emplace_back(expr); + } + + bool empty() const + { + return _dynamic_columns.empty(); + } + }; + + template <> + struct dynamic_select_column_list + { + struct _names_t + { + static constexpr size_t size() + { + return 0; + } + }; + _names_t _dynamic_expression_names; + + static constexpr bool empty() + { + return true; + } + }; +} + +#endif diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index ba032005..c583280d 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -151,9 +152,7 @@ namespace sqlpp { } - template - result_row_t(const DynamicNames&) - : _impl(), _is_valid(false) + result_row_t(const typename dynamic_select_column_list::_names_t&) : _impl(), _is_valid(false) { } diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index d5ee8c05..2b903fb1 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -65,44 +66,6 @@ namespace sqlpp }; } - template - struct dynamic_select_column_list - { - using _names_t = std::vector; - std::vector> _dynamic_columns; - _names_t _dynamic_expression_names; - - template - void emplace_back(Expr expr) - { - _dynamic_expression_names.push_back(name_of::char_ptr()); - _dynamic_columns.emplace_back(expr); - } - - bool empty() const - { - return _dynamic_columns.empty(); - } - }; - - template <> - struct dynamic_select_column_list - { - struct _names_t - { - static constexpr size_t size() - { - return 0; - } - }; - _names_t _dynamic_expression_names; - - static constexpr bool empty() - { - return true; - } - }; - template struct serializer_t> { From d59b34e39cd0688d9c5a385d42d93bd3b71a338b Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 24 Jan 2016 15:39:51 +0100 Subject: [PATCH 04/90] Moved serialize code to dynamic_select_column_list.h --- include/sqlpp11/dynamic_select_column_list.h | 31 ++++++++++++++++++++ include/sqlpp11/select_column_list.h | 31 -------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/sqlpp11/dynamic_select_column_list.h b/include/sqlpp11/dynamic_select_column_list.h index daf995f9..f98cdc4d 100644 --- a/include/sqlpp11/dynamic_select_column_list.h +++ b/include/sqlpp11/dynamic_select_column_list.h @@ -70,6 +70,37 @@ namespace sqlpp return true; } }; + + template + struct serializer_t> + { + using T = dynamic_select_column_list; + + static Context& _(const T& t, Context& context) + { + bool first = true; + for (const auto column : t._dynamic_columns) + { + if (first) + first = false; + else + context << ','; + serialize(column, context); + } + return context; + } + }; + + template + struct serializer_t> + { + using T = dynamic_select_column_list; + + static Context& _(const T&, Context& context) + { + return context; + } + }; } #endif diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index 2b903fb1..c82f0f90 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -66,37 +66,6 @@ namespace sqlpp }; } - template - struct serializer_t> - { - using T = dynamic_select_column_list; - - static Context& _(const T& t, Context& context) - { - bool first = true; - for (const auto column : t._dynamic_columns) - { - if (first) - first = false; - else - context << ','; - serialize(column, context); - } - return context; - } - }; - - template - struct serializer_t> - { - using T = dynamic_select_column_list; - - static Context& _(const T&, Context& context) - { - return context; - } - }; - // SELECTED COLUMNS DATA template struct select_column_list_data_t From ac2bc0495eb596d765913e8473295b98488d7daa Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 25 Feb 2016 07:57:28 +0100 Subject: [PATCH 05/90] Prevent unconditional joins, and naked bool in where() or boolean expressions - `.from(t1, t2)` produces an unconditional join if you forget to add a condition in the .where() sqlpp11 therefore now deprecates unconditional joins. - more often than not, writing something like `where(name == "doe")`, you meant to write `where(t.name == "doe")`. It is hard to find bugs when the former expression compiles because you happen to have a variable `name` in the current scope as well. sqlpp11 therefore now deprecates `.where(bool)` and disallows raw bool values boolean expression like `something and bool` wrap bools in sqlpp::value(), if you REALLY want a bool value here --- include/sqlpp11/bad_statement.h | 2 + .../data_types/boolean/expression_operators.h | 6 +- include/sqlpp11/dynamic_join.h | 120 ++++++++++++++++++ include/sqlpp11/from.h | 53 +++++--- include/sqlpp11/join.h | 37 +----- include/sqlpp11/join_types.h | 65 ++++++++++ include/sqlpp11/on.h | 23 +++- include/sqlpp11/operand_check.h | 19 +-- include/sqlpp11/table_alias.h | 34 ++++- include/sqlpp11/type_traits.h | 1 + include/sqlpp11/unconditional.h | 36 ++++++ include/sqlpp11/where.h | 98 +++++++++++++- ...onversion_operator_if_null_not_trivial.cpp | 2 +- test_static_asserts/CMakeLists.txt | 1 + test_static_asserts/aggregates.cpp | 48 +++---- test_static_asserts/unwrapped_bool.cpp | 115 +++++++++++++++++ test_static_asserts/where.cpp | 1 - tests/DateTime.cpp | 2 +- tests/Function.cpp | 6 +- tests/Interpret.cpp | 11 +- tests/Remove.cpp | 2 +- tests/Result.cpp | 8 +- tests/Select.cpp | 16 +-- tests/SelectType.cpp | 11 +- tests/Union.cpp | 18 +-- tests/Update.cpp | 8 +- tests/With.cpp | 6 +- 27 files changed, 617 insertions(+), 132 deletions(-) create mode 100644 include/sqlpp11/dynamic_join.h create mode 100644 include/sqlpp11/join_types.h create mode 100644 include/sqlpp11/unconditional.h create mode 100644 test_static_asserts/unwrapped_bool.cpp 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..1ec70153 --- /dev/null +++ b/include/sqlpp11/dynamic_join.h @@ -0,0 +1,120 @@ +/* + * 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_DYNAMIC_JOIN_H +#define SQLPP_DYNAMIC_JOIN_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct dynamic_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 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(required_tables_of::size::value == 0, + "joined tables must not depend on other tables"); + + template + using set_on_t = dynamic_join_t; + + template + auto on(Expr... expr) -> set_on_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 {_rhs, {std::tuple{expr...}, {}}}; + } + + auto unconditionally() -> set_on_t> + { + static_assert(is_noop::value, "cannot call on() twice for a single join()"); + return {_rhs, {}}; + } + + Rhs _rhs; + On _on; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = dynamic_join_t; + + static Context& _(const T& t, Context& context) + { + static_assert(not is_noop::value, "joined tables require on()"); + context << " JOIN "; + serialize(t._rhs, context); + serialize(t._on, context); + return context; + } + }; + + template + dynamic_join_t dynamic_join(Table table) + { + return {table, {}}; + } + + template + dynamic_join_t dynamic_inner_join(Table table) + { + return {table, {}}; + } + + template + dynamic_join_t outer_join(Table table) + { + return {table, {}}; + } + + template + dynamic_join_t left_outer_join(Table table) + { + return {table, {}}; + } + + template + dynamic_join_t right_outer_join(Table table) + { + return {table, {}}; + } +} + +#endif diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index f6339819..35c77eaa 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -35,9 +35,16 @@ #include #include #include +#include namespace sqlpp { +#ifdef SQLPP_ALLOW_UNCONDITIONAL_JOIN + constexpr bool allow_unconditional_from = 1; +#else + constexpr bool allow_unconditional_from = 0; +#endif + // FROM DATA template struct from_data_t @@ -77,35 +84,40 @@ 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()"); + static_assert( + is_dynamic_join_t::value or (allow_unconditional_from and is_table_t::value), + "invalid argument in from::add(), or #define ALLOW_UNCONDITIONAL_JOIN " + "for a grace period of using tables here"); using _known_tables = detail::make_joined_set_t...>; // 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 + void _add_impl(DynamicJoin dynamicJoin, const std::true_type&) { - return _data._dynamic_tables.emplace_back(from_table(table)); + return _data._dynamic_tables.emplace_back(from_table(dynamicJoin)); } - template - void _add_impl(Table table, const std::false_type&); + template + void _add_impl(DynamicJoin dynamicJoin, const std::false_type&); public: _data_t _data; @@ -210,12 +222,15 @@ namespace sqlpp using _consistency_check = consistent_t; - template - auto from(Tables... tables) const -> _new_statement_t<_check, from_t...>> + template + auto from(Table table, Tables... tables) const + -> _new_statement_t<_check, from_t, from_table_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...); + static_assert(_check::value, "at least one argument is not a table or join in from()"); + static_assert(sizeof...(Tables) == 0 or ::sqlpp::allow_unconditional_from, + "unconditional join is deprecated, please use explicit joins or #define ALLOW_UNCONDITIONAL_JOIN " + "for a grace period"); + return _from_impl(_check{}, table, tables...); } template @@ -225,6 +240,10 @@ namespace sqlpp 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()"); + static_assert( + sizeof...(Tables) == 1 or ::sqlpp::allow_unconditional_from, + "unconditional join is deprecated, please use explicit joins or #define SQLPP_ALLOW_UNCONDITIONAL_JOIN " + "for a grace period"); return _from_impl<_database_t>(_check{}, tables...); } diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 5db3f7a1..67e8643f 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -27,42 +27,12 @@ #ifndef SQLPP_JOIN_H #define SQLPP_JOIN_H -#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 struct join_t { @@ -93,6 +63,11 @@ namespace sqlpp return {_lhs, _rhs, {std::tuple{expr...}, {}}}; } + auto unconditionally() -> set_on_t> + { + return {_lhs, _rhs, {}}; + } + template join_t join(T t) { diff --git a/include/sqlpp11/join_types.h b/include/sqlpp11/join_types.h new file mode 100644 index 00000000..1f670b7c --- /dev/null +++ b/include/sqlpp11/join_types.h @@ -0,0 +1,65 @@ +/* + * 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 "; + }; +} + +#endif diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index bccdc3e8..dea4789d 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace sqlpp @@ -72,6 +73,25 @@ namespace sqlpp interpretable_list_t _dynamic_expressions; }; + template <> + struct 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> { @@ -82,11 +102,12 @@ namespace sqlpp { if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) return context; - context << " ON "; + 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); + 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/table_alias.h b/include/sqlpp11/table_alias.h index af73784a..b89b5e09 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,36 @@ namespace sqlpp { } + template + join_t join(T t) const + { + return {*this, t, {}}; + } + + template + join_t inner_join(T t) const + { + return {*this, t, {}}; + } + + template + join_t outer_join(T t) const + { + return {*this, t, {}}; + } + + template + join_t left_outer_join(T t) const + { + return {*this, t, {}}; + } + + template + join_t right_outer_join(T t) const + { + return {*this, t, {}}; + } + Table _table; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 1b413161..1600d230 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -164,6 +164,7 @@ namespace sqlpp SQLPP_VALUE_TRAIT_GENERATOR(is_table) SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table) SQLPP_VALUE_TRAIT_GENERATOR(is_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) 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..4327e3ff 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace sqlpp @@ -153,6 +154,7 @@ namespace sqlpp }; }; +#ifdef SQLPP_ALLOW_NAKED_BOOL_EXPRESSION template <> struct where_data_t { @@ -214,8 +216,70 @@ namespace sqlpp using _consistency_check = consistent_t; }; }; +#endif - SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "where expression required, e.g. where(true)"); + template <> + struct where_data_t + { + }; + + // WHERE() UNCONDITIONALLY + template <> + struct where_t + { + using _traits = make_traits; + using _nodes = detail::type_vector<>; + + // Data + using _data_t = where_data_t; + + // Member implementation with data and methods + template + struct _impl_t + { + // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 + _impl_t() = default; + _impl_t(const _data_t& data) : _data(data) + { + } + + _data_t _data; + }; + + // Base template to be inherited by the statement + template + struct _base_t + { + using _data_t = where_data_t; + + // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 + template + _base_t(Args&&... args) + : where{std::forward(args)...} + { + } + + _impl_t where; + _impl_t& operator()() + { + return where; + } + const _impl_t& operator()() const + { + return where; + } + + template + static auto _get_member(T t) -> decltype(t.where) + { + return t.where; + } + + using _consistency_check = consistent_t; + }; + }; + + 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()"); @@ -328,10 +392,28 @@ namespace sqlpp assert_where_t, consistent_t>::type; +#ifdef SQLPP_ALLOW_NAKED_BOOL_EXPRESSION + template auto where(bool b) const -> _new_statement_t> { return {static_cast&>(*this), where_data_t{b}}; } +#else + template + auto where(bool b) const -> bad_statement + { + static_assert( + wrong_t::value, + "where(bool) is deprecated, please use unconditionally() or #define SQLPP_ALLOW_NAKED_BOOL_EXPRESSION " + "for a grace period"); + return {static_cast&>(*this), where_data_t{b}}; + } +#endif + + auto unconditionally() const -> _new_statement_t> + { + return {static_cast&>(*this), where_data_t{}}; + } template auto where(Expressions... expressions) const @@ -387,6 +469,7 @@ namespace sqlpp } }; +#ifdef SQLPP_ALLOW_NAKED_BOOL_EXPRESSION template struct serializer_t> { @@ -400,6 +483,19 @@ namespace sqlpp return context; } }; +#endif + + template + struct serializer_t> + { + using _serialize_check = consistent_t; + using T = where_data_t; + + static Context& _(const T&, Context& context) + { + return context; + } + }; template auto where(T&&... t) -> decltype(statement_t>().where(std::forward(t)...)) 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_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 54d9b158..234f2127 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -34,4 +34,5 @@ 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/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..4783ceb7 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) 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..ad85898e 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_join(f).unconditionally()); 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..b733a636 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
; 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 @@ -88,12 +82,8 @@ namespace sqlpp void add(DynamicJoin dynamicJoin) { static_assert(_is_dynamic::value, "from::add() must not be called for static from()"); - static_assert( - is_dynamic_join_t::value or (allow_unconditional_from and is_table_t::value), - "invalid argument in from::add(), or #define ALLOW_UNCONDITIONAL_JOIN " - "for a grace period of using tables here"); - 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>; @@ -127,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 @@ -222,44 +212,35 @@ namespace sqlpp using _consistency_check = consistent_t; - template - auto from(Table table, Tables... tables) const - -> _new_statement_t<_check, from_t, from_table_t...>> + template + auto from(Table table) const -> _new_statement_t<_check
, from_t>> { - static_assert(_check::value, "at least one argument is not a table or join in from()"); - static_assert(sizeof...(Tables) == 0 or ::sqlpp::allow_unconditional_from, - "unconditional join is deprecated, please use explicit joins or #define ALLOW_UNCONDITIONAL_JOIN " - "for a grace period"); - return _from_impl(_check{}, table, tables...); + static_assert(_check
::value, "argument is not a table or join in from()"); + 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<_check
, 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()"); - static_assert( - sizeof...(Tables) == 1 or ::sqlpp::allow_unconditional_from, - "unconditional join is deprecated, please use explicit joins or #define SQLPP_ALLOW_UNCONDITIONAL_JOIN " - "for a grace period"); - return _from_impl<_database_t>(_check{}, tables...); + static_assert(_check
::value, "argument is not a table or join in from()"); + 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, + 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...>; + static constexpr std::size_t _number_of_tables = detail::sum(provided_tables_of
::size::value); + using _unique_tables = provided_tables_of
; 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()"); @@ -267,35 +248,35 @@ namespace sqlpp "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()) + { + context << ' '; + 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)); } } 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) From 425e75219cace8a7da5dfe8716f014f42e17c465 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 26 Feb 2016 22:28:11 +0100 Subject: [PATCH 07/90] Removed where(true). --- include/sqlpp11/where.h | 99 +++-------------------------------------- 1 file changed, 5 insertions(+), 94 deletions(-) diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 4327e3ff..fac903dd 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -154,70 +154,6 @@ namespace sqlpp }; }; -#ifdef SQLPP_ALLOW_NAKED_BOOL_EXPRESSION - template <> - struct where_data_t - { - bool _condition; - }; - - // WHERE(BOOL) - template <> - struct where_t - { - using _traits = make_traits; - using _nodes = detail::type_vector<>; - - // Data - using _data_t = where_data_t; - - // Member implementation with data and methods - template - struct _impl_t - { - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 - _impl_t() = default; - _impl_t(const _data_t& data) : _data(data) - { - } - - _data_t _data; - }; - - // Base template to be inherited by the statement - template - struct _base_t - { - using _data_t = where_data_t; - - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 - template - _base_t(Args&&... args) - : where{std::forward(args)...} - { - } - - _impl_t where; - _impl_t& operator()() - { - return where; - } - const _impl_t& operator()() const - { - return where; - } - - template - static auto _get_member(T t) -> decltype(t.where) - { - return t.where; - } - - using _consistency_check = consistent_t; - }; - }; -#endif - template <> struct where_data_t { @@ -392,23 +328,14 @@ namespace sqlpp assert_where_t, consistent_t>::type; -#ifdef SQLPP_ALLOW_NAKED_BOOL_EXPRESSION template - auto where(bool b) const -> _new_statement_t> + auto where(bool) const -> bad_statement { - return {static_cast&>(*this), where_data_t{b}}; + static_assert(wrong_t::value, + ".where(bool) is not allowed any more. Please use unconditionally() to replace " + ".where(true). Use sqlpp::value(bool) if you really want to use a bool here"); + return {}; } -#else - template - auto where(bool b) const -> bad_statement - { - static_assert( - wrong_t::value, - "where(bool) is deprecated, please use unconditionally() or #define SQLPP_ALLOW_NAKED_BOOL_EXPRESSION " - "for a grace period"); - return {static_cast&>(*this), where_data_t{b}}; - } -#endif auto unconditionally() const -> _new_statement_t> { @@ -469,22 +396,6 @@ namespace sqlpp } }; -#ifdef SQLPP_ALLOW_NAKED_BOOL_EXPRESSION - template - struct serializer_t> - { - using _serialize_check = consistent_t; - using T = where_data_t; - - static Context& _(const T& t, Context& context) - { - if (not t._condition) - context << " WHERE NULL"; - return context; - } - }; -#endif - template struct serializer_t> { From d7a29fac977995b6044ecb9b5ec957025e8a9a4e Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 27 Feb 2016 19:31:02 +0100 Subject: [PATCH 08/90] Cleaning up static asserts for .where(true) --- include/sqlpp11/where.h | 24 ++++++++---------------- test_static_asserts/where.cpp | 28 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index fac903dd..ae570602 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -217,9 +217,9 @@ namespace sqlpp 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_boolean_expression_t, + "at least one argument is not a sqlpp::boolean expression in where(). Please use " + ".unconditionally() instead of .where(true), or sqlpp::value(bool)"); 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,8 +230,9 @@ 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_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 @@ -239,8 +240,8 @@ namespace sqlpp { using type = static_combined_check_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>>; }; @@ -328,15 +329,6 @@ namespace sqlpp assert_where_t, consistent_t>::type; - template - auto where(bool) const -> bad_statement - { - static_assert(wrong_t::value, - ".where(bool) is not allowed any more. Please use unconditionally() to replace " - ".where(true). Use sqlpp::value(bool) if you really want to use a bool here"); - return {}; - } - auto unconditionally() const -> _new_statement_t> { return {static_cast&>(*this), where_data_t{}}; diff --git a/test_static_asserts/where.cpp b/test_static_asserts/where.cpp index 4783ceb7..8f838716 100644 --- a/test_static_asserts/where.cpp +++ b/test_static_asserts/where.cpp @@ -84,17 +84,17 @@ 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 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); @@ -111,17 +111,17 @@ 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 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); From 3461918d8889251f3ce4f7b16e194943b44737d8 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 28 Feb 2016 12:07:56 +0100 Subject: [PATCH 09/90] Made from() testable with portable static asserts, added tests Added cross_join_t, simplifying join a lot --- include/sqlpp11/cross_join.h | 91 ++++++++++++++++++++++ include/sqlpp11/dynamic_join.h | 10 +-- include/sqlpp11/from.h | 69 ++++++++++------- include/sqlpp11/join.h | 83 +++++++------------- include/sqlpp11/on.h | 13 ++-- include/sqlpp11/table.h | 20 ++--- include/sqlpp11/table_alias.h | 20 ++--- include/sqlpp11/type_traits.h | 13 +++- include/sqlpp11/where.h | 18 ++--- test_static_asserts/CMakeLists.txt | 1 + test_static_asserts/from.cpp | 119 +++++++++++++++++++++++++++++ test_static_asserts/where.cpp | 8 ++ 12 files changed, 336 insertions(+), 129 deletions(-) create mode 100644 include/sqlpp11/cross_join.h create mode 100644 test_static_asserts/from.cpp diff --git a/include/sqlpp11/cross_join.h b/include/sqlpp11/cross_join.h new file mode 100644 index 00000000..77caa374 --- /dev/null +++ b/include/sqlpp11/cross_join.h @@ -0,0 +1,91 @@ +/* + * 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_CROSS_JOIN_H +#define SQLPP_CROSS_JOIN_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct join_t; + + template + struct cross_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) -> join_t> + { + static_assert(is_expression_t::value, "argument is not an expression in on()"); + + static_assert(is_boolean_t::value, "argument is not a boolean expression in on()"); + + return {*this, {expr, {}}}; + } + + auto unconditionally() -> join_t> + { + return {*this, {}}; + } + + Lhs _lhs; + Rhs _rhs; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = cross_join_t; + + static Context& _(const T& t, Context& context) + { + serialize(t._lhs, context); + context << JoinType::_name; + context << " JOIN "; + serialize(t._rhs, context); + return context; + } + }; +} + +#endif diff --git a/include/sqlpp11/dynamic_join.h b/include/sqlpp11/dynamic_join.h index 1ec70153..20dc0930 100644 --- a/include/sqlpp11/dynamic_join.h +++ b/include/sqlpp11/dynamic_join.h @@ -50,14 +50,14 @@ namespace sqlpp template using set_on_t = dynamic_join_t; - template - auto on(Expr... expr) -> set_on_t> + template + auto on(Expr expr) -> set_on_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()"); + static_assert(is_expression_t::value, "argument is not a boolean expression in on()"); + static_assert(is_boolean_t::value, "argument is not a boolean expression in on()"); - return {_rhs, {std::tuple{expr...}, {}}}; + return {_rhs, {expr, {}}}; } auto unconditionally() -> set_on_t> diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index 8604e955..83b906fe 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -147,6 +147,39 @@ namespace sqlpp }; }; + SQLPP_PORTABLE_STATIC_ASSERT( + assert_from_not_cross_join_t, + "from() argument is a cross 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_cross_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; @@ -199,33 +232,26 @@ 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(Table table) const -> _new_statement_t<_check
, from_t>> + auto from(Table table) const -> _new_statement_t, from_t>> { - static_assert(_check
::value, "argument is not a table or join in from()"); - return _from_impl(_check
{}, table); + using Check = check_from_static_t
; + Check{}._(); + return _from_impl(Check{}, table); } template - auto dynamic_from(Table table) const -> _new_statement_t<_check
, from_t<_database_t, from_table_t
>> + 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, "argument is not a table or join in from()"); - return _from_impl<_database_t>(_check
{}, table); + using Check = check_from_dynamic_t<_database_t, Table>; + Check{}._(); + return _from_impl<_database_t>(Check{}, table); } private: @@ -236,17 +262,6 @@ namespace sqlpp 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 = provided_tables_of
; - 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(table)}}; } diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 67e8643f..86c92d1f 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -28,99 +28,70 @@ #define SQLPP_JOIN_H #include +#include #include -#include namespace sqlpp { - 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(is_cross_join_t::value, "lhs argument for join() has to be a table or join"); + static_assert(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"); + static_assert(detail::is_subset_of, provided_tables_of>::value, + "on() condition must not depend on other tables"); - 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 + cross_join_t join(T 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...}, {}}}; - } - - auto unconditionally() -> set_on_t> - { - return {_lhs, _rhs, {}}; + return {*this, t}; } template - join_t join(T t) + cross_join_t inner_join(T t) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return {*this, t}; } template - join_t inner_join(T t) + cross_join_t outer_join(T t) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return {*this, t}; } template - join_t outer_join(T t) + cross_join_t left_outer_join(T t) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return {*this, t}; } template - join_t left_outer_join(T t) + cross_join_t right_outer_join(T t) { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; + return {*this, t}; } - template - join_t right_outer_join(T t) - { - static_assert(not is_noop::value, "join type requires on()"); - return {*this, t, {}}; - } - - Lhs _lhs; - Rhs _rhs; + CrossJoin _cross_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._cross_join, context); serialize(t._on, context); return context; } diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index dea4789d..58fb3996 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -28,23 +28,20 @@ #define SQLPP_ON_H #include -#include #include #include #include namespace sqlpp { - template + 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) { @@ -69,7 +66,7 @@ namespace sqlpp void _add_impl(Expr expr, const std::false_type&); public: - std::tuple _expressions; + Expression _expression; interpretable_list_t _dynamic_expressions; }; @@ -103,8 +100,8 @@ namespace sqlpp 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()) + serialize(t._expression, context); + if (not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); context << " )"; diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 3a8f590b..029d44a6 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 + cross_join_t join(T t) const { - return {*static_cast(this), t, {}}; + return {*static_cast(this), t}; } template - join_t inner_join(T t) const + cross_join_t inner_join(T t) const { - return {*static_cast(this), t, {}}; + return {*static_cast(this), t}; } template - join_t outer_join(T t) const + cross_join_t outer_join(T t) const { - return {*static_cast(this), t, {}}; + return {*static_cast(this), t}; } template - join_t left_outer_join(T t) const + cross_join_t left_outer_join(T t) const { - return {*static_cast(this), t, {}}; + return {*static_cast(this), t}; } template - join_t right_outer_join(T t) const + cross_join_t right_outer_join(T t) const { - return {*static_cast(this), t, {}}; + return {*static_cast(this), t}; } template diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index b89b5e09..a86d7915 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -61,33 +61,33 @@ namespace sqlpp } template - join_t join(T t) const + cross_join_t join(T t) const { - return {*this, t, {}}; + return {*this, t}; } template - join_t inner_join(T t) const + cross_join_t inner_join(T t) const { - return {*this, t, {}}; + return {*this, t}; } template - join_t outer_join(T t) const + cross_join_t outer_join(T t) const { - return {*this, t, {}}; + return {*this, t}; } template - join_t left_outer_join(T t) const + cross_join_t left_outer_join(T t) const { - return {*this, t, {}}; + return {*this, t}; } template - join_t right_outer_join(T t) const + cross_join_t right_outer_join(T t) const { - return {*this, t, {}}; + return {*this, t}; } Table _table; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 1600d230..b35e8087 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,6 +169,7 @@ 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_cross_join) SQLPP_VALUE_TRAIT_GENERATOR(is_join) SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join) SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table) @@ -374,6 +381,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, @@ -382,12 +390,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/where.h b/include/sqlpp11/where.h index ae570602..d9591b9e 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -93,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, @@ -217,9 +218,11 @@ namespace sqlpp SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "calling where() or uncontionally() required"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_expression_t, - "at least one argument is not a sqlpp::boolean expression in where(). Please use " + 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,6 +233,8 @@ 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_not_cpp_bool_t>, // static_check_t::value...>::value, // assert_where_boolean_expressions_t>, // static_check_t::value...>::value, assert_where_boolean_expression_t>, @@ -239,6 +244,7 @@ namespace sqlpp 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_boolean_expression_t>, static_check_t::value...>::value, assert_where_boolean_expression_t>, @@ -313,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; diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 234f2127..23b9ca67 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -30,6 +30,7 @@ endfunction() test_compile(aggregates) test_compile(case) +test_compile(from) test_compile(where) test_compile(insert) test_compile(date) diff --git a/test_static_asserts/from.cpp b/test_static_asserts/from.cpp new file mode 100644 index 00000000..a102e804 --- /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.join(f).unconditionally()); + 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.join(f).unconditionally()); + 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/where.cpp b/test_static_asserts/where.cpp index 8f838716..5694a296 100644 --- a/test_static_asserts/where.cpp +++ b/test_static_asserts/where.cpp @@ -89,6 +89,10 @@ namespace // Try non-boolean expression 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); @@ -116,6 +120,10 @@ namespace // Try non-boolean expression 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); From 57d6d3c9921baf1508185a2b2aa25fe8a74137bd Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 28 Feb 2016 12:31:09 +0100 Subject: [PATCH 10/90] Introduced dynamic_cross_join (simplifying dynamic_join) --- include/sqlpp11/dynamic_cross_join.h | 113 +++++++++++++++++++++++++++ include/sqlpp11/dynamic_join.h | 82 ++++--------------- include/sqlpp11/type_traits.h | 1 + 3 files changed, 128 insertions(+), 68 deletions(-) create mode 100644 include/sqlpp11/dynamic_cross_join.h diff --git a/include/sqlpp11/dynamic_cross_join.h b/include/sqlpp11/dynamic_cross_join.h new file mode 100644 index 00000000..325dbf23 --- /dev/null +++ b/include/sqlpp11/dynamic_cross_join.h @@ -0,0 +1,113 @@ +/* + * 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_DYNAMIC_CROSS_JOIN_H +#define SQLPP_DYNAMIC_CROSS_JOIN_H + +#include +#include + +namespace sqlpp +{ + template + struct dynamic_join_t; + + template + struct dynamic_cross_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) -> dynamic_join_t> + { + static_assert(is_expression_t::value, "argument is not a boolean expression in on()"); + static_assert(is_boolean_t::value, "argument is not a boolean expression in on()"); + + return {*this, {expr, {}}}; + } + + auto unconditionally() -> dynamic_join_t> + { + return {*this, {}}; + } + + Rhs _rhs; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = dynamic_cross_join_t; + + static Context& _(const T& t, Context& context) + { + context << " JOIN "; + serialize(t._rhs, context); + return context; + } + }; + + template + dynamic_cross_join_t dynamic_join(Table table) + { + return {table}; + } + + template + dynamic_cross_join_t dynamic_inner_join(Table table) + { + return {table}; + } + + template + dynamic_cross_join_t outer_join(Table table) + { + return {table}; + } + + template + dynamic_cross_join_t left_outer_join(Table table) + { + return {table}; + } + + template + dynamic_cross_join_t right_outer_join(Table table) + { + return {table}; + } +} + +#endif diff --git a/include/sqlpp11/dynamic_join.h b/include/sqlpp11/dynamic_join.h index 20dc0930..6316c610 100644 --- a/include/sqlpp11/dynamic_join.h +++ b/include/sqlpp11/dynamic_join.h @@ -27,94 +27,40 @@ #ifndef SQLPP_DYNAMIC_JOIN_H #define SQLPP_DYNAMIC_JOIN_H -#include -#include -#include +#include namespace sqlpp { - template + template struct dynamic_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::type_set<>; - 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(is_dynamic_cross_join_t::value, "lhs argument for on() has to be a cross 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()"); - static_assert(required_tables_of::size::value == 0, - "joined tables must not depend on other tables"); - - template - using set_on_t = dynamic_join_t; - - template - auto on(Expr expr) -> set_on_t> - { - static_assert(is_noop::value, "cannot call on() twice for a single join()"); - static_assert(is_expression_t::value, "argument is not a boolean expression in on()"); - static_assert(is_boolean_t::value, "argument is not a boolean expression in on()"); - - return {_rhs, {expr, {}}}; - } - - auto unconditionally() -> set_on_t> - { - static_assert(is_noop::value, "cannot call on() twice for a single join()"); - return {_rhs, {}}; - } - - Rhs _rhs; + CrossJoin _cross_join; On _on; }; - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = dynamic_join_t; + using _serialize_check = serialize_check_of; + using T = dynamic_join_t; static Context& _(const T& t, Context& context) { - static_assert(not is_noop::value, "joined tables require on()"); - context << " JOIN "; - serialize(t._rhs, context); + serialize(t._cross_join, context); serialize(t._on, context); return context; } }; - - template - dynamic_join_t dynamic_join(Table table) - { - return {table, {}}; - } - - template - dynamic_join_t dynamic_inner_join(Table table) - { - return {table, {}}; - } - - template - dynamic_join_t outer_join(Table table) - { - return {table, {}}; - } - - template - dynamic_join_t left_outer_join(Table table) - { - return {table, {}}; - } - - template - dynamic_join_t right_outer_join(Table table) - { - return {table, {}}; - } } #endif diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index b35e8087..adbf0b99 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -171,6 +171,7 @@ namespace sqlpp SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table) SQLPP_VALUE_TRAIT_GENERATOR(is_cross_join) SQLPP_VALUE_TRAIT_GENERATOR(is_join) + SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_cross_join) SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join) SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table) SQLPP_VALUE_TRAIT_GENERATOR(is_column) From 5c7d5884507c53246be1afe16d14d0a2323da525 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 4 Mar 2016 21:07:42 +0100 Subject: [PATCH 11/90] Added portable static asserts for joins and first static tests --- include/sqlpp11/cross_join.h | 70 ++++++++++++ include/sqlpp11/join.h | 22 ++-- include/sqlpp11/table.h | 20 ++-- include/sqlpp11/table_alias.h | 20 ++-- test_static_asserts/CMakeLists.txt | 1 + test_static_asserts/join.cpp | 167 +++++++++++++++++++++++++++++ tests/SelectType.cpp | 1 - 7 files changed, 269 insertions(+), 32 deletions(-) create mode 100644 test_static_asserts/join.cpp diff --git a/include/sqlpp11/cross_join.h b/include/sqlpp11/cross_join.h index 77caa374..a0e97b74 100644 --- a/include/sqlpp11/cross_join.h +++ b/include/sqlpp11/cross_join.h @@ -33,6 +33,26 @@ namespace sqlpp { + SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_lhs_table_t, "lhs argument of join() has to be a table or a join"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_table_t, "rhs argument of join() has to be a table"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_no_join_t, "rhs argument of join() must not be a table"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_unique_names_t, "joined table names have to be unique"); + + template + struct check_cross_join + { + using type = static_combined_check_t< + static_check_t::value, assert_cross_join_lhs_table_t>, + static_check_t::value, assert_cross_join_rhs_table_t>, + static_check_t::value, assert_cross_join_rhs_no_join_t>, + static_check_t>, + detail::make_name_of_set_t>>::value, + assert_cross_join_unique_names_t>>; + }; + + template + using check_cross_join_t = typename check_cross_join::type; + template struct join_t; @@ -86,6 +106,56 @@ namespace sqlpp return context; } }; + + template + auto join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } } #endif diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 86c92d1f..26198688 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, @@ -50,33 +50,33 @@ namespace sqlpp "on() condition must not depend on other tables"); template - cross_join_t join(T t) + auto join(T t) const -> decltype(::sqlpp::join(*this, t)) { - return {*this, t}; + return ::sqlpp::join(*this, t); } template - cross_join_t inner_join(T t) + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) { - return {*this, t}; + return ::sqlpp::inner_join(*this, t); } template - cross_join_t outer_join(T t) + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::left_outer_join(*this, t); } template - cross_join_t left_outer_join(T t) + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::right_outer_join(*this, t); } template - cross_join_t right_outer_join(T t) + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::outer_join(*this, t); } CrossJoin _cross_join; diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 029d44a6..61574e02 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -62,33 +62,33 @@ namespace sqlpp using _alias_t = table_alias_t; template - cross_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 - cross_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 - cross_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 - cross_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 - cross_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 diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index a86d7915..06ffe23d 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -61,33 +61,33 @@ namespace sqlpp } template - cross_join_t join(T t) const + auto join(T t) const -> decltype(::sqlpp::join(*this, t)) { - return {*this, t}; + return ::sqlpp::join(*this, t); } template - cross_join_t inner_join(T t) const + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) { - return {*this, t}; + return ::sqlpp::inner_join(*this, t); } template - cross_join_t outer_join(T t) const + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::left_outer_join(*this, t); } template - cross_join_t left_outer_join(T t) const + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::right_outer_join(*this, t); } template - cross_join_t right_outer_join(T t) const + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::outer_join(*this, t); } Table _table; diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 23b9ca67..0416116a 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -31,6 +31,7 @@ endfunction() test_compile(aggregates) test_compile(case) test_compile(from) +test_compile(join) test_compile(where) test_compile(insert) test_compile(date) diff --git a/test_static_asserts/join.cpp b/test_static_asserts/join.cpp new file mode 100644 index 00000000..a9463448 --- /dev/null +++ b/test_static_asserts/join.cpp @@ -0,0 +1,167 @@ +/* + * 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 join_static_check(const Lhs& lhs, const Rhs& rhs) + { + using CheckResult = sqlpp::check_cross_join_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using JoinType = decltype(join(lhs, rhs)); + using InnerJoinType = decltype(inner_join(lhs, rhs)); + using LeftOuterJoinType = decltype(left_outer_join(lhs, rhs)); + using RightOuterJoinType = decltype(right_outer_join(lhs, rhs)); + using OuterJoinType = decltype(outer_join(lhs, rhs)); + using ExpectedReturnType = + sqlpp::logic::all_t::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{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + /* + template + void join_dynamic_check(const Expression& expression) + { + static auto db = MockDb{}; + using CheckResult = sqlpp::check_join_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_join(expression)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + */ + + void static_join() + { + // OK: Join two different tables + join_static_check(t, f); + join_static_check(t, f.as(sqlpp::alias::a)); + join_static_check(t.as(sqlpp::alias::a), f.as(sqlpp::alias::b)); + + // OK: Self join + join_static_check(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)); + join_static_check(t, t.as(sqlpp::alias::b)); + join_static_check(t.as(sqlpp::alias::a), t); + + // Prepare a join for tests: + const auto j = join(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)).unconditionally(); + + // 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(t.as(sqlpp::alias::a), f.as(sqlpp::alias::a)); + join_static_check(j, f.as(sqlpp::alias::a)); + join_static_check(j, f.as(sqlpp::alias::b)); + join_static_check(j, t.as(sqlpp::alias::a)); + join_static_check(j, t.as(sqlpp::alias::b)); + } + + void dynamic_join() + { + /* + // OK + join_dynamic_check(t); + join_dynamic_check(t.join(f).unconditionally()); + join_dynamic_check(t.join(f).on(t.alpha > f.omega)); + + // 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 cross joins (missing condition) + join_dynamic_check(t.join(f)); + */ + } +} + +int main(int, char* []) +{ + static_join(); + dynamic_join(); +} diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index b733a636..968542df 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -326,7 +326,6 @@ int SelectType(int, char* []) { auto s = dynamic_select(db, all_of(t)).dynamic_from(t).dynamic_where().dynamic_limit().dynamic_offset(); -#warning : Need to test the deprecated stuff s.from.add(dynamic_join(f).on(f.omega > t.alpha)); s.where.add_ntc(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); s.limit.set(30); From e5931aa4eb3e38bd07890ea34cb637f08b48a3a3 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 5 Mar 2016 19:32:27 +0100 Subject: [PATCH 12/90] Added portable static asserts for (dynamic) join.on() Also removed inaccessible code for adding more conditions to on() dynamically. If someone should ever want that, he/she should use dynamic_where(), I guess. --- include/sqlpp11/cross_join.h | 41 ++++++++++++++++--- include/sqlpp11/dynamic_cross_join.h | 39 +++++++++++++++--- include/sqlpp11/dynamic_join.h | 2 +- include/sqlpp11/join.h | 7 ---- include/sqlpp11/on.h | 61 ++++++++++------------------ 5 files changed, 90 insertions(+), 60 deletions(-) diff --git a/include/sqlpp11/cross_join.h b/include/sqlpp11/cross_join.h index a0e97b74..b5ea2a6f 100644 --- a/include/sqlpp11/cross_join.h +++ b/include/sqlpp11/cross_join.h @@ -53,6 +53,35 @@ namespace sqlpp template using check_cross_join_t = typename check_cross_join::type; + SQLPP_PORTABLE_STATIC_ASSERT(assert_join_consist_of_cross_join_and_on_t, + "join has to consist of a cross_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_cross_join_and_on_t>, + static_check_t::value, assert_join_consist_of_cross_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; @@ -73,16 +102,16 @@ namespace sqlpp static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); template - auto on(Expr expr) -> join_t> + auto on(Expr expr) -> typename std::conditional::value, + join_t>, + bad_statement>::type { - static_assert(is_expression_t::value, "argument is not an expression in on()"); + check_join_on_t::_(); - static_assert(is_boolean_t::value, "argument is not a boolean expression in on()"); - - return {*this, {expr, {}}}; + return {*this, {expr}}; } - auto unconditionally() -> join_t> + auto unconditionally() -> join_t> { return {*this, {}}; } diff --git a/include/sqlpp11/dynamic_cross_join.h b/include/sqlpp11/dynamic_cross_join.h index 325dbf23..3c2dfec4 100644 --- a/include/sqlpp11/dynamic_cross_join.h +++ b/include/sqlpp11/dynamic_cross_join.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, Roland Bock + * Copyright (c) 2016-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -32,6 +32,32 @@ namespace sqlpp { + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_consist_of_cross_join_and_on_t, + "dynamic join has to consist of a dynamic cross_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_cross_join_and_on_t>, + static_check_t::value, assert_dynamic_join_consist_of_cross_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; @@ -49,15 +75,16 @@ namespace sqlpp "joined tables must not depend on other tables"); template - auto on(Expr expr) -> dynamic_join_t> + auto on(Expr expr) -> typename std::conditional::value, + dynamic_join_t>, + bad_statement>::type { - static_assert(is_expression_t::value, "argument is not a boolean expression in on()"); - static_assert(is_boolean_t::value, "argument is not a boolean expression in on()"); + check_dynamic_join_on_t::_(); - return {*this, {expr, {}}}; + return {*this, {expr}}; } - auto unconditionally() -> dynamic_join_t> + auto unconditionally() -> dynamic_join_t> { return {*this, {}}; } diff --git a/include/sqlpp11/dynamic_join.h b/include/sqlpp11/dynamic_join.h index 6316c610..90cb3045 100644 --- a/include/sqlpp11/dynamic_join.h +++ b/include/sqlpp11/dynamic_join.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2016-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 26198688..8679cf02 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -42,13 +42,6 @@ namespace sqlpp using _provided_tables = provided_tables_of; using _required_tables = detail::make_difference_set_t, _provided_tables>; - static_assert(is_cross_join_t::value, "lhs argument for join() has to be a table or join"); - static_assert(is_on_t::value, "invalid on expression in join().on()"); - - static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); - static_assert(detail::is_subset_of, provided_tables_of>::value, - "on() condition must not depend on other tables"); - template auto join(T t) const -> decltype(::sqlpp::join(*this, t)) { diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index 58fb3996..f3ba3a04 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -34,54 +34,40 @@ 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 _is_dynamic = is_database; - - 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: Expression _expression; - interpretable_list_t _dynamic_expressions; }; template <> - struct on_t + struct on_t { using _traits = make_traits; using _nodes = detail::type_vector<>; }; template - struct serializer_t> + struct serializer_t> { using _serialize_check = consistent_t; - using T = on_t; + using T = on_t; static Context& _(const T&, Context& context) { @@ -89,21 +75,16 @@ namespace sqlpp } }; - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = on_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 ("; serialize(t._expression, context); - if (not t._dynamic_expressions.empty()) - context << " AND "; - interpret_list(t._dynamic_expressions, " AND ", context); context << " )"; return context; } From 2cbdd87dac9299341eeb5e4af6226d8f2c9ae1e0 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 5 Mar 2016 22:27:11 +0100 Subject: [PATCH 13/90] Added tests for dynamic joins --- include/sqlpp11/cross_join.h | 8 +- include/sqlpp11/dynamic_cross_join.h | 40 ++++-- test_static_asserts/join.cpp | 196 +++++++++++++++++++++------ 3 files changed, 188 insertions(+), 56 deletions(-) diff --git a/include/sqlpp11/cross_join.h b/include/sqlpp11/cross_join.h index b5ea2a6f..3510cb0a 100644 --- a/include/sqlpp11/cross_join.h +++ b/include/sqlpp11/cross_join.h @@ -35,7 +35,7 @@ namespace sqlpp { SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_lhs_table_t, "lhs argument of join() has to be a table or a join"); SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_table_t, "rhs argument of join() has to be a table"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_no_join_t, "rhs argument of join() must not be a table"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_no_join_t, "rhs argument of join() must not be a join"); SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_unique_names_t, "joined table names have to be unique"); template @@ -102,9 +102,9 @@ namespace sqlpp static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); template - auto on(Expr expr) -> typename std::conditional::value, - join_t>, - bad_statement>::type + auto on(Expr expr) const -> typename std::conditional::value, + join_t>, + bad_statement>::type { check_join_on_t::_(); diff --git a/include/sqlpp11/dynamic_cross_join.h b/include/sqlpp11/dynamic_cross_join.h index 3c2dfec4..2795417c 100644 --- a/include/sqlpp11/dynamic_cross_join.h +++ b/include/sqlpp11/dynamic_cross_join.h @@ -32,6 +32,20 @@ namespace sqlpp { + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_cross_join_table_t, "argument of dynamic_join() has to be a table"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_cross_join_no_join_t, "argument of dynamic_join() must not be a table"); + + template + struct check_dynamic_cross_join + { + using type = + static_combined_check_t::value, assert_dynamic_cross_join_table_t>, + static_check_t::value, assert_dynamic_cross_join_no_join_t>>; + }; + + template + using check_dynamic_cross_join_t = typename check_dynamic_cross_join
::type; + SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_consist_of_cross_join_and_on_t, "dynamic join has to consist of a dynamic cross_join and a join condition"); SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_no_table_dependencies_t, @@ -75,9 +89,9 @@ namespace sqlpp "joined tables must not depend on other tables"); template - auto on(Expr expr) -> typename std::conditional::value, - dynamic_join_t>, - bad_statement>::type + auto on(Expr expr) const -> typename std::conditional::value, + dynamic_join_t>, + bad_statement>::type { check_dynamic_join_on_t::_(); @@ -106,33 +120,43 @@ namespace sqlpp } }; + template + using make_dynamic_cross_join_t = typename std::conditional::value, + dynamic_cross_join_t, + bad_statement>::type; + template - dynamic_cross_join_t dynamic_join(Table table) + auto dynamic_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t dynamic_inner_join(Table table) + auto dynamic_inner_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t outer_join(Table table) + auto dynamic_left_outer_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t left_outer_join(Table table) + auto dynamic_right_outer_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t right_outer_join(Table table) + auto dynamic_outer_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } } diff --git a/test_static_asserts/join.cpp b/test_static_asserts/join.cpp index a9463448..ebaed7c6 100644 --- a/test_static_asserts/join.cpp +++ b/test_static_asserts/join.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Roland Bock + * Copyright (c) 2016-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -52,17 +52,20 @@ namespace print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); - using JoinType = decltype(join(lhs, rhs)); - using InnerJoinType = decltype(inner_join(lhs, rhs)); - using LeftOuterJoinType = decltype(left_outer_join(lhs, rhs)); - using RightOuterJoinType = decltype(right_outer_join(lhs, rhs)); - using OuterJoinType = decltype(outer_join(lhs, rhs)); - using ExpectedReturnType = - sqlpp::logic::all_t::value and - std::is_same::value and - std::is_same::value and - std::is_same::value and - std::is_same::value)>; + 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 ExpectedReturnType = sqlpp::logic::all_t< + (Assert::value and sqlpp::is_cross_join_t::value and sqlpp::is_cross_join_t::value and + sqlpp::is_cross_join_t::value and sqlpp::is_cross_join_t::value and + sqlpp::is_cross_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)>; print_type_on_error(ExpectedReturnType{}); print_type_on_error(ExpectedReturnType{}); print_type_on_error(ExpectedReturnType{}); @@ -71,38 +74,41 @@ namespace static_assert(ExpectedReturnType::value, "Unexpected return type"); } - /* - template - void join_dynamic_check(const Expression& expression) + template + void on_static_check(const Lhs& lhs, const Rhs& rhs) { - static auto db = MockDb{}; - using CheckResult = sqlpp::check_join_dynamic_t; + 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 ReturnType = decltype(dynamic_select(db, t.alpha).dynamic_join(expression)); - using ExpectedReturnType = - sqlpp::logic::all_t::value>; - print_type_on_error(ExpectedReturnType{}); + 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, f.as(sqlpp::alias::a)); - join_static_check(t.as(sqlpp::alias::a), f.as(sqlpp::alias::b)); + join_static_check(t, fa); + join_static_check(ta, fb); // OK: Self join - join_static_check(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)); - join_static_check(t, t.as(sqlpp::alias::b)); - join_static_check(t.as(sqlpp::alias::a), t); + join_static_check(ta, tb); + join_static_check(t, tb); + join_static_check(ta, t); // Prepare a join for tests: - const auto j = join(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)).unconditionally(); + const auto j = join(ta, tb).unconditionally(); // OK: Add a third table join_static_check(j, f); @@ -132,31 +138,133 @@ namespace join_static_check(f, f); join_static_check(t.as(f), f); join_static_check(t, f.as(t)); - join_static_check(t.as(sqlpp::alias::a), f.as(sqlpp::alias::a)); - join_static_check(j, f.as(sqlpp::alias::a)); - join_static_check(j, f.as(sqlpp::alias::b)); - join_static_check(j, t.as(sqlpp::alias::a)); - join_static_check(j, t.as(sqlpp::alias::b)); + 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 cross_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_cross_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 ExpectedReturnType = + sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_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)>; + 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(t.join(f).unconditionally()); - join_dynamic_check(t.join(f).on(t.alpha > f.omega)); + 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); + 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 cross joins (missing condition) - join_dynamic_check(t.join(f)); - */ + // Try (cross) joins + join_dynamic_check(t.join(f)); + join_dynamic_check(t.join(f).unconditionally()); + + // Prepare a dynamic_cross_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); } } From 1060996df4b6c6afaa87671a0de00e0ad0482d3d Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 6 Mar 2016 10:36:42 +0100 Subject: [PATCH 14/90] Added "real" cross join --- include/sqlpp11/dynamic_join.h | 24 ++-- ...ynamic_cross_join.h => dynamic_pre_join.h} | 99 +++++++-------- include/sqlpp11/from.h | 6 +- include/sqlpp11/join.h | 26 ++-- include/sqlpp11/join_types.h | 8 ++ include/sqlpp11/{cross_join.h => pre_join.h} | 114 +++++++++--------- include/sqlpp11/table.h | 6 + include/sqlpp11/table_alias.h | 6 + include/sqlpp11/type_traits.h | 4 +- test_static_asserts/from.cpp | 8 +- test_static_asserts/join.cpp | 106 ++++++++-------- tests/Select.cpp | 2 +- tests/SelectType.cpp | 2 +- 13 files changed, 227 insertions(+), 184 deletions(-) rename include/sqlpp11/{dynamic_cross_join.h => dynamic_pre_join.h} (54%) rename include/sqlpp11/{cross_join.h => pre_join.h} (62%) diff --git a/include/sqlpp11/dynamic_join.h b/include/sqlpp11/dynamic_join.h index 90cb3045..5aa9b7a1 100644 --- a/include/sqlpp11/dynamic_join.h +++ b/include/sqlpp11/dynamic_join.h @@ -27,36 +27,36 @@ #ifndef SQLPP_DYNAMIC_JOIN_H #define SQLPP_DYNAMIC_JOIN_H -#include +#include namespace sqlpp { - template + template struct dynamic_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 _provided_tables = provided_tables_of; using _required_tables = detail::type_set<>; - static_assert(is_dynamic_cross_join_t::value, "lhs argument for on() has to be a cross join"); - static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); + 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()"); - CrossJoin _cross_join; + PreJoin _pre_join; On _on; }; - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = dynamic_join_t; + using _serialize_check = serialize_check_of; + using T = dynamic_join_t; static Context& _(const T& t, Context& context) { - serialize(t._cross_join, context); + serialize(t._pre_join, context); serialize(t._on, context); return context; } diff --git a/include/sqlpp11/dynamic_cross_join.h b/include/sqlpp11/dynamic_pre_join.h similarity index 54% rename from include/sqlpp11/dynamic_cross_join.h rename to include/sqlpp11/dynamic_pre_join.h index 2795417c..be2472df 100644 --- a/include/sqlpp11/dynamic_cross_join.h +++ b/include/sqlpp11/dynamic_pre_join.h @@ -24,93 +24,88 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_DYNAMIC_CROSS_JOIN_H -#define SQLPP_DYNAMIC_CROSS_JOIN_H +#ifndef SQLPP_DYNAMIC_PRE_JOIN_H +#define SQLPP_DYNAMIC_PRE_JOIN_H #include #include namespace sqlpp { - SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_cross_join_table_t, "argument of dynamic_join() has to be a table"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_cross_join_no_join_t, "argument of dynamic_join() must not be a table"); + 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_cross_join + struct check_dynamic_pre_join { using type = - static_combined_check_t::value, assert_dynamic_cross_join_table_t>, - static_check_t::value, assert_dynamic_cross_join_no_join_t>>; + 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_cross_join_t = typename check_dynamic_cross_join
::type; + using check_dynamic_pre_join_t = typename check_dynamic_pre_join
::type; - SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_consist_of_cross_join_and_on_t, - "dynamic join has to consist of a dynamic cross_join and a join condition"); + 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 + template struct check_dynamic_join { using type = static_combined_check_t< - static_check_t::value, assert_dynamic_join_consist_of_cross_join_and_on_t>, - static_check_t::value, assert_dynamic_join_consist_of_cross_join_and_on_t>, - static_check_t::size::value == 0, assert_dynamic_join_no_table_dependencies_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 + using check_dynamic_join_t = typename check_dynamic_join::type; - template + template struct check_dynamic_join_on { - using type = static_combined_check_t, check_dynamic_join_t>>; + using type = static_combined_check_t, check_dynamic_join_t>>; }; - template - using check_dynamic_join_on_t = typename check_dynamic_join_on::type; + template + using check_dynamic_join_on_t = typename check_dynamic_join_on::type; - template + template struct dynamic_join_t; template - struct dynamic_cross_join_t + struct dynamic_pre_join_t { - using _traits = make_traits; + 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, + 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>, + auto on(Expr expr) const -> typename std::conditional::value, + dynamic_join_t>, bad_statement>::type { - check_dynamic_join_on_t::_(); + check_dynamic_join_on_t::_(); return {*this, {expr}}; } - auto unconditionally() -> dynamic_join_t> - { - return {*this, {}}; - } - Rhs _rhs; }; template - struct serializer_t> + struct serializer_t> { using _serialize_check = serialize_check_of; - using T = dynamic_cross_join_t; + using T = dynamic_pre_join_t; static Context& _(const T& t, Context& context) { @@ -121,44 +116,54 @@ namespace sqlpp }; template - using make_dynamic_cross_join_t = typename std::conditional::value, - dynamic_cross_join_t, - bad_statement>::type; + 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_cross_join_t + auto dynamic_join(Table table) -> make_dynamic_pre_join_t { - check_dynamic_cross_join_t
::_(); + check_dynamic_pre_join_t
::_(); return {table}; } template - auto dynamic_inner_join(Table table) -> make_dynamic_cross_join_t + auto dynamic_inner_join(Table table) -> make_dynamic_pre_join_t { - check_dynamic_cross_join_t
::_(); + check_dynamic_pre_join_t
::_(); return {table}; } template - auto dynamic_left_outer_join(Table table) -> make_dynamic_cross_join_t + auto dynamic_left_outer_join(Table table) -> make_dynamic_pre_join_t { - check_dynamic_cross_join_t
::_(); + check_dynamic_pre_join_t
::_(); return {table}; } template - auto dynamic_right_outer_join(Table table) -> make_dynamic_cross_join_t + auto dynamic_right_outer_join(Table table) -> make_dynamic_pre_join_t { - check_dynamic_cross_join_t
::_(); + check_dynamic_pre_join_t
::_(); return {table}; } template - auto dynamic_outer_join(Table table) -> make_dynamic_cross_join_t + auto dynamic_outer_join(Table table) -> make_dynamic_pre_join_t { - check_dynamic_cross_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 83b906fe..74dc84e6 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -148,8 +148,8 @@ namespace sqlpp }; SQLPP_PORTABLE_STATIC_ASSERT( - assert_from_not_cross_join_t, - "from() argument is a cross join, please use an explicit on() condition or unconditionally()"); + 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()"); @@ -161,7 +161,7 @@ namespace sqlpp struct check_from { using type = static_combined_check_t< - static_check_t::value, assert_from_not_cross_join_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 == diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 8679cf02..09ecb8fa 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -28,18 +28,18 @@ #define SQLPP_JOIN_H #include -#include +#include #include namespace sqlpp { - 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 _provided_tables = provided_tables_of; using _required_tables = detail::make_difference_set_t, _provided_tables>; template @@ -72,19 +72,25 @@ namespace sqlpp return ::sqlpp::outer_join(*this, t); } - CrossJoin _cross_join; + template + auto cross_join(T t) const -> decltype(::sqlpp::cross_join(*this, t)) + { + return ::sqlpp::cross_join(*this, t); + } + + 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) { - serialize(t._cross_join, 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 index 1f670b7c..a58a127f 100644 --- a/include/sqlpp11/join_types.h +++ b/include/sqlpp11/join_types.h @@ -60,6 +60,14 @@ namespace sqlpp 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/cross_join.h b/include/sqlpp11/pre_join.h similarity index 62% rename from include/sqlpp11/cross_join.h rename to include/sqlpp11/pre_join.h index 3510cb0a..38571276 100644 --- a/include/sqlpp11/cross_join.h +++ b/include/sqlpp11/pre_join.h @@ -24,8 +24,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_CROSS_JOIN_H -#define SQLPP_CROSS_JOIN_H +#ifndef SQLPP_PRE_JOIN_H +#define SQLPP_PRE_JOIN_H #include #include @@ -33,62 +33,62 @@ namespace sqlpp { - SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_lhs_table_t, "lhs argument of join() has to be a table or a join"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_table_t, "rhs argument of join() has to be a table"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_no_join_t, "rhs argument of join() must not be a join"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_unique_names_t, "joined table names have to be unique"); + 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_cross_join + struct check_pre_join { using type = static_combined_check_t< - static_check_t::value, assert_cross_join_lhs_table_t>, - static_check_t::value, assert_cross_join_rhs_table_t>, - static_check_t::value, assert_cross_join_rhs_no_join_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_cross_join_unique_names_t>>; + assert_pre_join_unique_names_t>>; }; template - using check_cross_join_t = typename check_cross_join::type; + using check_pre_join_t = typename check_pre_join::type; - SQLPP_PORTABLE_STATIC_ASSERT(assert_join_consist_of_cross_join_and_on_t, - "join has to consist of a cross_join and a join condition"); + 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 + template struct check_join { using type = static_combined_check_t< - static_check_t::value, assert_join_consist_of_cross_join_and_on_t>, - static_check_t::value, assert_join_consist_of_cross_join_and_on_t>, - static_check_t::size::value == 0, assert_join_no_table_dependencies_t>, - static_check_t, provided_tables_of>::value, + 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 + using check_join_t = typename check_join::type; - template + template struct check_join_on { - using type = static_combined_check_t, check_join_t>>; + using type = static_combined_check_t, check_join_t>>; }; - template - using check_join_on_t = typename check_join_on::type; + template + using check_join_on_t = typename check_join_on::type; - template + template struct join_t; template - struct cross_join_t + struct pre_join_t { - using _traits = make_traits; + using _traits = make_traits; using _nodes = detail::type_vector; using _can_be_null = std::false_type; @@ -99,32 +99,27 @@ namespace sqlpp 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"); + 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>, + auto on(Expr expr) const -> typename std::conditional::value, + join_t>, bad_statement>::type { - check_join_on_t::_(); + check_join_on_t::_(); return {*this, {expr}}; } - auto unconditionally() -> join_t> - { - return {*this, {}}; - } - Lhs _lhs; Rhs _rhs; }; template - struct serializer_t> + struct serializer_t> { using _serialize_check = serialize_check_of; - using T = cross_join_t; + using T = pre_join_t; static Context& _(const T& t, Context& context) { @@ -137,54 +132,65 @@ namespace sqlpp }; template - auto join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, - cross_join_t, + auto join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, bad_statement>::type { - check_cross_join_t::_(); + check_pre_join_t::_(); return {lhs, rhs}; } template - auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, - cross_join_t, + auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, bad_statement>::type { - check_cross_join_t::_(); + check_pre_join_t::_(); return {lhs, rhs}; } template - auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, - cross_join_t, + auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, bad_statement>::type { - check_cross_join_t::_(); + check_pre_join_t::_(); return {lhs, rhs}; } template - auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, - cross_join_t, + auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, bad_statement>::type { - check_cross_join_t::_(); + check_pre_join_t::_(); return {lhs, rhs}; } template - auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, - cross_join_t, + auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + pre_join_t, bad_statement>::type { - check_cross_join_t::_(); + 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 61574e02..7e51f22d 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -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 06ffe23d..52e04c31 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -90,6 +90,12 @@ namespace sqlpp 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 adbf0b99..f97a05d2 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -169,9 +169,9 @@ 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_cross_join) + SQLPP_VALUE_TRAIT_GENERATOR(is_pre_join) SQLPP_VALUE_TRAIT_GENERATOR(is_join) - SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_cross_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) diff --git a/test_static_asserts/from.cpp b/test_static_asserts/from.cpp index a102e804..fff9d433 100644 --- a/test_static_asserts/from.cpp +++ b/test_static_asserts/from.cpp @@ -79,7 +79,7 @@ namespace { // OK from_static_check(t); - from_static_check(t.join(f).unconditionally()); + from_static_check(t.cross_join(f)); from_static_check(t.join(f).on(t.alpha > f.omega)); // Try a bunch of non-tables @@ -90,14 +90,14 @@ namespace from_static_check(t.delta); // Try cross joins (missing condition) - from_static_check(t.join(f)); + from_static_check(t.join(f)); } void dynamic_from() { // OK from_dynamic_check(t); - from_dynamic_check(t.join(f).unconditionally()); + from_dynamic_check(t.cross_join(f)); from_dynamic_check(t.join(f).on(t.alpha > f.omega)); // Try a bunch of non-tables @@ -108,7 +108,7 @@ namespace from_dynamic_check(t.delta); // Try cross joins (missing condition) - from_dynamic_check(t.join(f)); + from_dynamic_check(t.join(f)); } } diff --git a/test_static_asserts/join.cpp b/test_static_asserts/join.cpp index ebaed7c6..29369ed3 100644 --- a/test_static_asserts/join.cpp +++ b/test_static_asserts/join.cpp @@ -47,7 +47,7 @@ namespace template void join_static_check(const Lhs& lhs, const Rhs& rhs) { - using CheckResult = sqlpp::check_cross_join_t; + using CheckResult = sqlpp::check_pre_join_t; using ExpectedCheckResult = std::is_same; print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); @@ -57,20 +57,23 @@ namespace 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_cross_join_t::value and sqlpp::is_cross_join_t::value and - sqlpp::is_cross_join_t::value and sqlpp::is_cross_join_t::value and - sqlpp::is_cross_join_t::value) xor + (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)>; + 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"); } @@ -108,7 +111,7 @@ namespace join_static_check(ta, t); // Prepare a join for tests: - const auto j = join(ta, tb).unconditionally(); + const auto j = cross_join(ta, tb); // OK: Add a third table join_static_check(j, f); @@ -116,35 +119,35 @@ namespace 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(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); + 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); + 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); + 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 cross_joins for tests: + // 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); @@ -176,7 +179,7 @@ namespace template void join_dynamic_check(const Table& table) { - using CheckResult = sqlpp::check_dynamic_cross_join_t
; + 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"); @@ -186,22 +189,25 @@ namespace 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 ExpectedReturnType = - sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_cross_join_t::value and - sqlpp::is_dynamic_cross_join_t::value and - sqlpp::is_dynamic_cross_join_t::value and - sqlpp::is_dynamic_cross_join_t::value and - sqlpp::is_dynamic_cross_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)>; + 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"); } @@ -233,17 +239,17 @@ namespace 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); + 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 (cross) joins - join_dynamic_check(t.join(f)); - join_dynamic_check(t.join(f).unconditionally()); + // Try (pre) joins + join_dynamic_check(t.join(f)); + join_dynamic_check(t.cross_join(f)); - // Prepare a dynamic_cross_joins for tests: + // Prepare a dynamic_pre_joins for tests: const auto tj = dynamic_join(t); const auto fj = dynamic_join(f); diff --git a/tests/Select.cpp b/tests/Select.cpp index ad85898e..43be425c 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -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(dynamic_join(f).unconditionally()); + s.from.add(dynamic_cross_join(f)); s.where.add(t.alpha > 7); s.having.add(t.alpha > 7); s.limit.set(3); diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index 968542df..85978cdd 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -376,7 +376,7 @@ int SelectType(int, char* []) auto s1 = sqlpp::select() .flags(sqlpp::distinct, sqlpp::straight_join) .columns(l.gamma, r.a) - .from(r.join(t).unconditionally().join(l).unconditionally()) + .from(r.cross_join(t).cross_join(l)) .where(t.beta == "hello world" and select(t.gamma).from(t)) // .as(alias::right)) .group_by(l.gamma, r.a) .having(r.a != true) From f6ce65330225f9f5b3c7d61d2ef75e8dedfe2566 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 6 Mar 2016 16:59:21 +0100 Subject: [PATCH 15/90] Added several serialization tests for from() and joins --- CMakeLists.txt | 1 + include/sqlpp11/dynamic_pre_join.h | 1 + include/sqlpp11/from.h | 16 +++-- include/sqlpp11/join_types.h | 10 ++-- include/sqlpp11/on.h | 3 +- include/sqlpp11/pre_join.h | 14 ++++- test_serializer/CMakeLists.txt | 38 ++++++++++++ test_serializer/From.cpp | 96 ++++++++++++++++++++++++++++++ 8 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 test_serializer/CMakeLists.txt create mode 100644 test_serializer/From.cpp 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; +} From 2122ee62757b8aa7bc5ac84beb988652dd8267cf Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 9 Mar 2016 21:01:22 +0100 Subject: [PATCH 16/90] Added serialize tests for in() --- test_serializer/CMakeLists.txt | 1 + test_serializer/From.cpp | 19 +--------- test_serializer/In.cpp | 65 ++++++++++++++++++++++++++++++++++ test_serializer/compare.h | 50 ++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 test_serializer/In.cpp create mode 100644 test_serializer/compare.h diff --git a/test_serializer/CMakeLists.txt b/test_serializer/CMakeLists.txt index 8d2f1fa3..dc5f015a 100644 --- a/test_serializer/CMakeLists.txt +++ b/test_serializer/CMakeLists.txt @@ -24,6 +24,7 @@ set(test_serializer_names From + In ) create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_serializer_names}) diff --git a/test_serializer/From.cpp b/test_serializer/From.cpp index 1a184354..360de453 100644 --- a/test_serializer/From.cpp +++ b/test_serializer/From.cpp @@ -23,30 +23,13 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "compare.h" #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* []) diff --git a/test_serializer/In.cpp b/test_serializer/In.cpp new file mode 100644 index 00000000..4319aa10 --- /dev/null +++ b/test_serializer/In.cpp @@ -0,0 +1,65 @@ +/* + * 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 "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.7, 2.5, 17., 0.})), + "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/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 From 22d10269d05bae2fd1fc7f1ca49aaa1830fea118 Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 9 Mar 2016 21:26:51 +0100 Subject: [PATCH 17/90] Fixed narrowing warning/error --- test_serializer/In.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_serializer/In.cpp b/test_serializer/In.cpp index 4319aa10..989a0805 100644 --- a/test_serializer/In.cpp +++ b/test_serializer/In.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2016-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -50,7 +50,7 @@ int In(int, char* []) "tab_foo.omega IN(tab_foo.omega,tab_bar.alpha,17)"); // Lists - compare(__LINE__, foo.omega.in(sqlpp::value_list(std::vector{1.7, 2.5, 17., 0.})), + 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 From c4eec85bc95b0e35a3ad58a97bdec7a4be1eb95e Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 9 Mar 2016 21:27:30 +0100 Subject: [PATCH 18/90] Added serializer tests for where() --- test_serializer/CMakeLists.txt | 1 + test_serializer/From.cpp | 2 +- test_serializer/Where.cpp | 65 ++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 test_serializer/Where.cpp diff --git a/test_serializer/CMakeLists.txt b/test_serializer/CMakeLists.txt index dc5f015a..6b19a24a 100644 --- a/test_serializer/CMakeLists.txt +++ b/test_serializer/CMakeLists.txt @@ -25,6 +25,7 @@ set(test_serializer_names From In + Where ) create_test_sourcelist(test_serializer_sources test_serializer_main.cpp ${test_serializer_names}) diff --git a/test_serializer/From.cpp b/test_serializer/From.cpp index 360de453..2827b719 100644 --- a/test_serializer/From.cpp +++ b/test_serializer/From.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2016-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, diff --git a/test_serializer/Where.cpp b/test_serializer/Where.cpp new file mode 100644 index 00000000..4de5f1c4 --- /dev/null +++ b/test_serializer/Where.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 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__, 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; +} From 93b06b4187b524cac0909a92ea232e62e87082b4 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 10 Mar 2016 09:28:59 +0100 Subject: [PATCH 19/90] Added more serializer tests for where() --- test_serializer/Where.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_serializer/Where.cpp b/test_serializer/Where.cpp index 4de5f1c4..a4e80112 100644 --- a/test_serializer/Where.cpp +++ b/test_serializer/Where.cpp @@ -51,6 +51,8 @@ int Where(int, char* []) // 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 From f753697584ef0301db98cd1847b98d27269b8e5c Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 11 Mar 2016 09:25:36 +0100 Subject: [PATCH 20/90] Fixed outer-tables for joins, added tests --- CMakeLists.txt | 1 + include/sqlpp11/aggregate_functions/avg.h | 6 +- include/sqlpp11/join_types.h | 4 +- include/sqlpp11/pre_join.h | 3 +- test_serializer/From.cpp | 28 +++ test_types/CMakeLists.txt | 32 ++++ test_types/compare.h | 50 +++++ test_types/result_row.cpp | 212 ++++++++++++++++++++++ tests/Sample.h | 2 +- 9 files changed, 331 insertions(+), 7 deletions(-) create mode 100644 test_types/CMakeLists.txt create mode 100644 test_types/compare.h create mode 100644 test_types/result_row.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 16f12bd6..9f155e68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ target_compile_features(sqlpp11 INTERFACE endif () add_subdirectory(tests) +add_subdirectory(test_types) add_subdirectory(test_serializer) add_subdirectory(test_static_asserts) add_subdirectory(test_constraints) diff --git a/include/sqlpp11/aggregate_functions/avg.h b/include/sqlpp11/aggregate_functions/avg.h index 4d274d46..f3c273b8 100644 --- a/include/sqlpp11/aggregate_functions/avg.h +++ b/include/sqlpp11/aggregate_functions/avg.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, @@ -111,7 +111,7 @@ namespace sqlpp { static_assert(not contains_aggregate_function_t>::value, "avg() cannot be used on an aggregate function"); - static_assert(is_numeric_t>::value, "avg() requires a value expression as argument"); + static_assert(is_numeric_t>::value, "avg() requires a numeric value expression as argument"); return {t}; } @@ -120,7 +120,7 @@ namespace sqlpp { static_assert(not contains_aggregate_function_t>::value, "avg() cannot be used on an aggregate function"); - static_assert(is_numeric_t>::value, "avg() requires a value expression as argument"); + static_assert(is_numeric_t>::value, "avg() requires a numeric value expression as argument"); return {t}; } } diff --git a/include/sqlpp11/join_types.h b/include/sqlpp11/join_types.h index 8b673be8..50b01ed8 100644 --- a/include/sqlpp11/join_types.h +++ b/include/sqlpp11/join_types.h @@ -49,14 +49,14 @@ namespace sqlpp struct left_outer_join_t { template - using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; + using _provided_outer_tables = detail::make_joined_set_t, provided_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>; + using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; static constexpr const char* _name = " RIGHT OUTER"; }; diff --git a/include/sqlpp11/pre_join.h b/include/sqlpp11/pre_join.h index 00cccf0e..07dc4078 100644 --- a/include/sqlpp11/pre_join.h +++ b/include/sqlpp11/pre_join.h @@ -91,6 +91,7 @@ namespace sqlpp using _traits = make_traits; using _nodes = detail::type_vector; using _can_be_null = std::false_type; + using _provided_outer_tables = typename JoinType::template _provided_outer_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"); @@ -185,7 +186,7 @@ namespace sqlpp template auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, - pre_join_t, + pre_join_t, bad_statement>::type { check_pre_join_t::_(); diff --git a/test_serializer/From.cpp b/test_serializer/From.cpp index 2827b719..a7978ea3 100644 --- a/test_serializer/From.cpp +++ b/test_serializer/From.cpp @@ -48,6 +48,14 @@ int From(int, char* []) 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(foo.inner_join(bar).on(foo.omega > bar.alpha)), + " FROM tab_foo INNER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)"); + compare(__LINE__, from(foo.outer_join(bar).on(foo.omega > bar.alpha)), + " FROM tab_foo OUTER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)"); + compare(__LINE__, from(foo.left_outer_join(bar).on(foo.omega > bar.alpha)), + " FROM tab_foo LEFT OUTER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)"); + compare(__LINE__, from(foo.right_outer_join(bar).on(foo.omega > bar.alpha)), + " FROM tab_foo RIGHT OUTER 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( @@ -62,11 +70,31 @@ int From(int, char* []) dfa.from.add(dynamic_cross_join(bar)); compare(__LINE__, dfa, " FROM tab_foo CROSS JOIN tab_bar"); } + { + auto dfa = df; + dfa.from.add(dynamic_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)); compare(__LINE__, dfa, " FROM tab_foo INNER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)"); } + { + auto dfa = df; + dfa.from.add(dynamic_outer_join(bar).on(bar.alpha > foo.omega)); + compare(__LINE__, dfa, " FROM tab_foo OUTER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)"); + } + { + auto dfa = df; + dfa.from.add(dynamic_left_outer_join(bar).on(bar.alpha > foo.omega)); + compare(__LINE__, dfa, " FROM tab_foo LEFT OUTER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)"); + } + { + auto dfa = df; + dfa.from.add(dynamic_right_outer_join(bar).on(bar.alpha > foo.omega)); + compare(__LINE__, dfa, " FROM tab_foo RIGHT OUTER 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)); diff --git a/test_types/CMakeLists.txt b/test_types/CMakeLists.txt new file mode 100644 index 00000000..cb2b8a8b --- /dev/null +++ b/test_types/CMakeLists.txt @@ -0,0 +1,32 @@ +# 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. + +function(test_compile name) + set(target sqlpp11_${name}) + add_executable(${target} ${name}.cpp) + target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing) +endfunction() + +test_compile(result_row) + diff --git a/test_types/compare.h b/test_types/compare.h new file mode 100644 index 00000000..9709a44c --- /dev/null +++ b/test_types/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_types/result_row.cpp b/test_types/result_row.cpp new file mode 100644 index 00000000..31858a91 --- /dev/null +++ b/test_types/result_row.cpp @@ -0,0 +1,212 @@ +/* + * 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 "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + constexpr auto bar = test::TabBar{}; + constexpr auto foo = test::TabFoo{}; + + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(not sqlpp::can_be_null_t::value, ""); + static_assert(not sqlpp::can_be_null_t::value, ""); + const auto seven = sqlpp::value(7).as(sqlpp::alias::s); + static_assert(not sqlpp::can_be_null_t::value, ""); + + auto db = MockDb{}; + + void single_table() + { + { + // result fields are as nullable as the expressions they represent + const auto& x = db(select(bar.alpha, bar.gamma, seven).from(bar).unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(not sqlpp::can_be_null_t::value, ""); + static_assert(not sqlpp::can_be_null_t::value, ""); + } + } + + void join() + { + // Join + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(foo.join(bar).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of (inner) join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "right side of (inner) join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(bar.join(foo).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of (inner) join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "right side of (inner) join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + + // Inner join + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(foo.inner_join(bar).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of inner join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "right side of inner join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(bar.inner_join(foo).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of inner join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "right side of inner join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + + // Left outer join + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(foo.left_outer_join(bar).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of left outer join cannot be null"); + static_assert(sqlpp::can_be_null_t::value, "right side of left outer join can be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(bar.left_outer_join(foo).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of left outer join cannot be null"); + static_assert(sqlpp::can_be_null_t::value, "right side of left outer join can be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + + // Right outer join + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(foo.right_outer_join(bar).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(sqlpp::can_be_null_t::value, "left side of right outer join can be null"); + static_assert(not sqlpp::can_be_null_t::value, + "right side of right outer join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(bar.right_outer_join(foo).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(sqlpp::can_be_null_t::value, "left side of right outer join can be null"); + static_assert(not sqlpp::can_be_null_t::value, + "right side of right outer join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + + // Outer join + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(foo.outer_join(bar).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(sqlpp::can_be_null_t::value, "left side of outer join can be null"); + static_assert(sqlpp::can_be_null_t::value, "right side of outer join can be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + { + const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven) + .from(bar.outer_join(foo).on(foo.omega > bar.alpha)) + .unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(sqlpp::can_be_null_t::value, "left side of outer join can be null"); + static_assert(sqlpp::can_be_null_t::value, "right side of outer join can be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + + // Cross join + { + const auto& x = + db(select(bar.alpha, foo.delta, bar.gamma, seven).from(foo.cross_join(bar)).unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of cross join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "right side of cross join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + { + const auto& x = + db(select(bar.alpha, foo.delta, bar.gamma, seven).from(bar.cross_join(foo)).unconditionally()).front(); + static_assert(sqlpp::can_be_null_t::value, "nullable value can always be null"); + static_assert(not sqlpp::can_be_null_t::value, "left side of cross join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "right side of cross join cannot be null"); + static_assert(not sqlpp::can_be_null_t::value, "constant non-null value can not be null"); + } + } + + void aggregates() + { + { + // aggregates of nullable values + const auto a = bar.alpha; + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + const auto& x = db(select(count(a), avg(a), max(a), min(a), sum(a)).from(bar).unconditionally()).front(); + static_assert(not sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + } + { + // aggregates of nullable values + const auto o = foo.omega; + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + const auto& x = db(select(count(o), avg(o), max(o), min(o), sum(o)).from(foo).unconditionally()).front(); + static_assert(not sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + static_assert(sqlpp::can_be_null_t::value, ""); + } + } +} + +int main(int, char* []) +{ + single_table(); + join(); + aggregates(); +} diff --git a/tests/Sample.h b/tests/Sample.h index c95cd98e..0bb6dc51 100644 --- a/tests/Sample.h +++ b/tests/Sample.h @@ -29,7 +29,7 @@ namespace test } }; }; - using _traits = sqlpp::make_traits; + using _traits = sqlpp::make_traits; }; struct Epsilon { From 3815dcadfa63e472891a19616de84f39342ae0b6 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 15 Mar 2016 08:07:24 +0100 Subject: [PATCH 21/90] Removed obsolete file --- test_types/compare.h | 50 -------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 test_types/compare.h diff --git a/test_types/compare.h b/test_types/compare.h deleted file mode 100644 index 9709a44c..00000000 --- a/test_types/compare.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 From fe0323bf5dd671431bb9758e4d8e89eeec168afb Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 15 Mar 2016 08:08:13 +0100 Subject: [PATCH 22/90] Adjusted ddl2cpp to work with pyparsing-2.10 --- scripts/ddl2cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/ddl2cpp b/scripts/ddl2cpp index 78c15442..122b5c7e 100755 --- a/scripts/ddl2cpp +++ b/scripts/ddl2cpp @@ -29,6 +29,7 @@ from __future__ import print_function import sys import re import os +import pprint from pyparsing import CaselessLiteral, Literal, SkipTo, restOfLine, oneOf, ZeroOrMore, Optional, Combine, \ WordStart, WordEnd, Word, alphas, alphanums, nums, QuotedString, nestedExpr, MatchFirst, OneOrMore, delimitedList, Or, Group @@ -79,7 +80,7 @@ ddlColumn = Group(Optional(ddlConstraint).setResultsName("isConstraint") + One createTable = Group(ddlWord("CREATE") + ddlWord("TABLE") + ddlTerm.setResultsName("tableName") + "(" + Group(delimitedList(ddlColumn)).setResultsName("columns") + ")").setResultsName("create") -ddl = ZeroOrMore(SkipTo(createTable, True)) +ddl = ZeroOrMore(SkipTo(createTable, include=True)) ddlComment = oneOf(["--", "#"]) + restOfLine ddl.ignore(ddlComment) @@ -131,14 +132,23 @@ print('{', file=header) tableCreations = ddl.parseFile(pathToDdl) for tableCreation in tableCreations: - sqlTableName = tableCreation.create.tableName + # get the actual table parse result depending on the version of pyparsing + if isinstance(tableCreation, basestring): # Since pyparsing-2.10 + continue + create = None + if tableCreation.create: + create = tableCreation.create # Before pyparsing-2.10 + elif tableCreation.tableName: + create = tableCreation # Since pyparsing-2.10 + + sqlTableName = create.tableName tableClass = toClassName(sqlTableName) tableMember = toMemberName(sqlTableName) tableNamespace = tableClass + '_' tableTemplateParameters = tableClass print(' namespace ' + tableNamespace, file=header) print(' {', file=header) - for column in tableCreation.create.columns: + for column in create.columns: if column.isConstraint: continue sqlColumnName = column[0] From fc076464e1042489db46e759bab4d7466b665d5b Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 15 Mar 2016 09:07:30 +0100 Subject: [PATCH 23/90] Removed multi-argument option for having --- include/sqlpp11/having.h | 86 +++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index e95877ea..6a2b397f 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -37,10 +37,10 @@ namespace sqlpp { // HAVING DATA - template + template struct having_data_t { - having_data_t(Expressions... expressions) : _expressions(expressions...) + having_data_t(Expression expression) : _expression(expression) { } @@ -50,7 +50,7 @@ namespace sqlpp having_data_t& operator=(having_data_t&&) = default; ~having_data_t() = default; - std::tuple _expressions; + Expression _expression; interpretable_list_t _dynamic_expressions; }; @@ -59,16 +59,16 @@ namespace sqlpp "at least one having-expression requires a table which is otherwise not known in the statement"); // HAVING - template + template struct having_t { using _traits = make_traits; - using _nodes = detail::type_vector; + using _nodes = detail::type_vector; using _is_dynamic = is_database; // Data - using _data_t = having_data_t; + using _data_t = having_data_t; // Member implementation with data and methods template @@ -80,36 +80,36 @@ namespace sqlpp { } - template - void add_ntc(Expression expression) + template + void add_ntc(Expr expression) { - add(expression); + add(expression); } - template - void add(Expression expression) + template + void add(Expr expression) { static_assert(_is_dynamic::value, "having::add() can only be called for dynamic_having"); - static_assert(is_expression_t::value, "invalid expression argument in having::add()"); - static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(is_expression_t::value, "invalid expression argument in having::add()"); + static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in having::add()"); - 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_expression_t::value, _serialize_check::type::value>; + using ok = logic::all_t<_is_dynamic::value, is_expression_t::value, _serialize_check::type::value>; _add_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert } private: - template - void _add_impl(Expression expression, const std::true_type&) + template + void _add_impl(Expr expression, const std::true_type&) { return _data._dynamic_expressions.emplace_back(expression); } - template - void _add_impl(Expression expression, const std::false_type&); + template + void _add_impl(Expr expression, const std::false_type&); public: _data_t _data; @@ -119,7 +119,7 @@ namespace sqlpp template struct _base_t { - using _data_t = having_data_t; + using _data_t = having_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 template @@ -216,54 +216,50 @@ namespace sqlpp using _consistency_check = consistent_t; - template - auto having(Expressions... expressions) const - -> _new_statement_t<_check, having_t> + template + auto having(Expression expression) const -> _new_statement_t<_check, having_t> { - static_assert(_check::value, "at least one argument is not an expression in having()"); - static_assert(sizeof...(Expressions), "at least one expression argument required in having()"); + static_assert(_check::value, "at least one argument is not an expression in having()"); - return _having_impl(_check{}, expressions...); + return _having_impl(_check{}, expression); } - template - auto dynamic_having(Expressions... expressions) const - -> _new_statement_t<_check, having_t<_database_t, Expressions...>> + template + auto dynamic_having(Expression expression) const + -> _new_statement_t<_check, having_t<_database_t, Expression>> { - static_assert(_check::value, "at least one argument is not an expression in having()"); + static_assert(_check::value, "at least one argument is not an expression in having()"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_having must not be called in a static statement"); - return _having_impl<_database_t>(_check{}, expressions...); + return _having_impl<_database_t>(_check{}, expression); } private: - template - auto _having_impl(const std::false_type&, Expressions... expressions) const -> bad_statement; + template + auto _having_impl(const std::false_type&, Expression expression) const -> bad_statement; - template - auto _having_impl(const std::true_type&, Expressions... expressions) const - -> _new_statement_t> + template + auto _having_impl(const std::true_type&, Expression expression) const + -> _new_statement_t> { return {static_cast&>(*this), - having_data_t{expressions...}}; + having_data_t{expression}}; } }; }; // Interpreters - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = having_data_t; + using _serialize_check = serialize_check_of; + using T = having_data_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) - return context; context << " HAVING "; - interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) + serialize(t._expression, context); + if (not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); return context; From a8cb63cb7e7c8294f4258ee275e57802073dfedb Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 16 Mar 2016 07:58:12 +0100 Subject: [PATCH 24/90] Simplified where() to have one argument only --- include/sqlpp11/from.h | 2 +- include/sqlpp11/functions.h | 11 +-- include/sqlpp11/having.h | 8 +- include/sqlpp11/value.h | 43 +++++++++++ include/sqlpp11/verbatim_table.h | 3 +- include/sqlpp11/where.h | 126 +++++++++++++++---------------- test_static_asserts/where.cpp | 22 +++--- tests/Remove.cpp | 2 +- 8 files changed, 128 insertions(+), 89 deletions(-) create mode 100644 include/sqlpp11/value.h diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index e737bd67..6a50bea8 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.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, diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index 1351c0d2..bb208eb3 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.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, @@ -42,19 +42,12 @@ #include #include // Csaba Csoma suggests: unsafe_sql instead of verbatim #include +#include #include #include namespace sqlpp { - template - auto value(T t) -> wrap_operand_t - { - static_assert(is_wrapped_value_t>::value, - "value() is to be called with non-sql-type like int, or string"); - return {t}; - } - template auto flatten(const Expression& exp, Db& db) -> verbatim_t> { diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index 6a2b397f..534cf291 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.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, @@ -28,6 +28,7 @@ #define SQLPP_HAVING_H #include +#include #include #include #include @@ -234,6 +235,11 @@ namespace sqlpp return _having_impl<_database_t>(_check{}, expression); } + auto dynamic_having() const -> _new_statement_t<_check, having_t<_database_t, boolean_operand>> + { + return dynamic_having(::sqlpp::value(true)); + } + private: template auto _having_impl(const std::false_type&, Expression expression) const -> bad_statement; diff --git a/include/sqlpp11/value.h b/include/sqlpp11/value.h new file mode 100644 index 00000000..0df9a34b --- /dev/null +++ b/include/sqlpp11/value.h @@ -0,0 +1,43 @@ +/* + * 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_VALUE_H +#define SQLPP_VALUE_H + +#include + +namespace sqlpp +{ + template + auto value(T t) -> wrap_operand_t + { + static_assert(is_wrapped_value_t>::value, + "value() is to be called with non-sql-type like int, or string"); + return {t}; + } +} + +#endif diff --git a/include/sqlpp11/verbatim_table.h b/include/sqlpp11/verbatim_table.h index 1618bd07..2fb2df7a 100644 --- a/include/sqlpp11/verbatim_table.h +++ b/include/sqlpp11/verbatim_table.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,6 +27,7 @@ #ifndef SQLPP_VERBATIM_TABLE_H #define SQLPP_VERBATIM_TABLE_H +#include #include namespace sqlpp diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index d9591b9e..3a8f1d39 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.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, @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -39,10 +40,10 @@ namespace sqlpp { // WHERE DATA - template + template struct where_data_t { - where_data_t(Expressions... expressions) : _expressions(expressions...) + where_data_t(Expression expression) : _expression(expression) { } @@ -52,7 +53,7 @@ namespace sqlpp where_data_t& operator=(where_data_t&&) = default; ~where_data_t() = default; - std::tuple _expressions; + Expression _expression; interpretable_list_t _dynamic_expressions; }; @@ -61,16 +62,16 @@ namespace sqlpp "at least one expression in where() requires a table which is otherwise not known in the statement"); // WHERE(EXPR) - template + template struct where_t { using _traits = make_traits; - using _nodes = detail::type_vector; + using _nodes = detail::type_vector; using _is_dynamic = is_database; // Data - using _data_t = where_data_t; + using _data_t = where_data_t; // Member implementation with data and methods template @@ -82,39 +83,39 @@ namespace sqlpp { } - template - void add_ntc(Expression expression) + template + void add_ntc(Expr expression) { - add(expression); + add(expression); } - template - void add(Expression expression) + template + void add(Expr expression) { 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, + 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, + static_assert(not contains_aggregate_function_t::value, "where expression must not contain aggregate functions"); - 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_expression_t::value, _serialize_check::type::value>; + using ok = logic::all_t<_is_dynamic::value, is_expression_t::value, _serialize_check::type::value>; _add_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert } private: - template - void _add_impl(Expression expression, const std::true_type&) + template + void _add_impl(Expr expression, const std::true_type&) { return _data._dynamic_expressions.emplace_back(expression); } - template - void _add_impl(Expression expression, const std::false_type&); + template + void _add_impl(Expr expression, const std::false_type&); public: _data_t _data; @@ -124,7 +125,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 @@ -225,7 +226,6 @@ namespace sqlpp "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()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_dynamic_statement_dynamic_t, "dynamic_where() must not be called in a static statement"); @@ -240,30 +240,26 @@ namespace sqlpp // static_check_t::value...>::value, assert_where_boolean_expression_t>, // static_check_t::value)...>::value, // assert_where_no_aggregate_functions_t>>; - template + 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_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>>; + static_check_t::value, assert_where_not_cpp_bool_t>, + static_check_t::value, assert_where_boolean_expression_t>, + static_check_t::value, assert_where_boolean_expression_t>, + static_check_t::value, assert_where_no_aggregate_functions_t>>; }; - template - using check_where_t = typename check_where::type; + template + using check_where_t = typename check_where::type; - template - using check_where_static_t = - static_combined_check_t, - static_check_t>; + template + using check_where_static_t = check_where_t; - template + template using check_where_dynamic_t = static_combined_check_t< static_check_t::value, assert_where_dynamic_statement_dynamic_t>, - check_where_t>; + check_where_t>; // NO WHERE YET template @@ -332,54 +328,58 @@ namespace sqlpp return {static_cast&>(*this), where_data_t{}}; } - template - auto where(Expressions... expressions) const - -> _new_statement_t, where_t> + template + auto where(Expression expression) const + -> _new_statement_t, where_t> { - using Check = check_where_static_t; + using Check = check_where_static_t; Check{}._(); - return _where_impl(Check{}, expressions...); + return _where_impl(Check{}, expression); } - template - auto dynamic_where(Expressions... expressions) const - -> _new_statement_t, where_t<_database_t, Expressions...>> + template + auto dynamic_where(Expression expression) const + -> _new_statement_t, where_t<_database_t, Expression>> { - using Check = check_where_dynamic_t<_database_t, Expressions...>; + using Check = check_where_dynamic_t<_database_t, Expression>; Check{}._(); - return _where_impl<_database_t>(Check{}, expressions...); + return _where_impl<_database_t>(Check{}, expression); + } + + auto dynamic_where() const -> _new_statement_t, + where_t<_database_t, boolean_operand>> + { + return dynamic_where(::sqlpp::value(true)); } private: - template - auto _where_impl(const std::false_type&, Expressions... expressions) const -> bad_statement; + template + auto _where_impl(const std::false_type&, Expression expression) const -> bad_statement; - template - auto _where_impl(const std::true_type&, Expressions... expressions) const - -> _new_statement_t> + template + auto _where_impl(const std::true_type&, Expression expression) const + -> _new_statement_t> { return {static_cast&>(*this), - where_data_t{expressions...}}; + where_data_t{expression}}; } }; }; // Interpreters - template - struct serializer_t> + template + struct serializer_t> { - using _serialize_check = serialize_check_of; - using T = where_data_t; + using _serialize_check = serialize_check_of; + using T = where_data_t; static Context& _(const T& t, Context& context) { - if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) - return context; context << " WHERE "; - interpret_tuple(t._expressions, " AND ", context); - if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) + serialize(t._expression, context); + if (not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); return context; diff --git a/test_static_asserts/where.cpp b/test_static_asserts/where.cpp index 5694a296..186b9c9d 100644 --- a/test_static_asserts/where.cpp +++ b/test_static_asserts/where.cpp @@ -43,31 +43,31 @@ namespace T::_print_me_; } - template - void where_static_check(const Expressions&... expressions) + template + void where_static_check(const Expression& expression) { - using CheckResult = sqlpp::check_where_static_t; + using CheckResult = sqlpp::check_where_static_t; using ExpectedCheckResult = std::is_same; print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); - using ReturnType = decltype(remove_from(t).where(expressions...)); + using ReturnType = decltype(remove_from(t).where(expression)); using ExpectedReturnType = sqlpp::logic::all_t::value>; print_type_on_error(ExpectedReturnType{}); static_assert(ExpectedReturnType::value, "Unexpected return type"); } - template - void where_dynamic_check(const Expressions&... expressions) + template + void where_dynamic_check(const Expression& expression) { static auto db = MockDb{}; - using CheckResult = sqlpp::check_where_dynamic_t; + using CheckResult = sqlpp::check_where_dynamic_t; using ExpectedCheckResult = std::is_same; print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); - using ReturnType = decltype(dynamic_remove_from(db, t).dynamic_where(expressions...)); + using ReturnType = decltype(dynamic_remove_from(db, t).dynamic_where(expression)); using ExpectedReturnType = sqlpp::logic::all_t::value>; print_type_on_error(ExpectedReturnType{}); @@ -80,9 +80,6 @@ namespace where_static_check(t.gamma); where_static_check(t.gamma == true); - // Try no expression - where_static_check(); - // Try assignment as condition where_static_check(t.gamma = true); @@ -110,7 +107,6 @@ namespace void dynamic_where() { // OK - where_dynamic_check(); where_dynamic_check(t.gamma); where_dynamic_check(t.gamma == true); @@ -138,7 +134,7 @@ namespace case_when(count(t.alpha) > 0).then(t.gamma).else_(not t.gamma)); // Try dynamic_where on a non-dynamic remove - using CheckResult = sqlpp::check_where_dynamic_t; + using CheckResult = sqlpp::check_where_dynamic_t; using ExpectedCheckResult = std::is_same; print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); diff --git a/tests/Remove.cpp b/tests/Remove.cpp index b1442c09..679299a4 100644 --- a/tests/Remove.cpp +++ b/tests/Remove.cpp @@ -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, From f1fb1b22a28bade3f7982370cfddff46fc74160f Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 16 Mar 2016 18:17:28 +0100 Subject: [PATCH 25/90] Added explicit without_table_check function This removes the "required" tables from an expression --- include/sqlpp11/sqlpp11.h | 3 +- include/sqlpp11/without_table_check.h | 77 +++++++++++++++++++++++++++ tests/SelectType.cpp | 5 +- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 include/sqlpp11/without_table_check.h diff --git a/include/sqlpp11/sqlpp11.h b/include/sqlpp11/sqlpp11.h index eb8a2d0f..8c822e49 100644 --- a/include/sqlpp11/sqlpp11.h +++ b/include/sqlpp11/sqlpp11.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, @@ -36,6 +36,7 @@ #include #include #include +#include #include #endif diff --git a/include/sqlpp11/without_table_check.h b/include/sqlpp11/without_table_check.h new file mode 100644 index 00000000..37bc26c9 --- /dev/null +++ b/include/sqlpp11/without_table_check.h @@ -0,0 +1,77 @@ +/* + * 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_WITHOUT_TABLE_CHECK_H +#define SQLPP_ALIAS_H + +#include +#include + +namespace sqlpp +{ + template + struct without_table_check_t + { + using _traits = typename Expression::_traits; + using _nodes = detail::type_vector; + using _required_tables = detail::type_set<>; + + without_table_check_t(Expression expression) : _expression(expression) + { + } + + without_table_check_t(const without_table_check_t&) = default; + without_table_check_t(without_table_check_t&&) = default; + without_table_check_t& operator=(const without_table_check_t&) = default; + without_table_check_t& operator=(without_table_check_t&&) = default; + ~without_table_check_t() = default; + + Expression _expression; + }; + + template + struct serializer_t> + { + using _serialize_check = serialize_check_of; + using T = without_table_check_t; + + static Context& _(const T& t, Context& context) + { + serialize(t._expression, context); + return context; + } + }; + + template + auto without_table_check(Expression expr) -> without_table_check_t + { + static_assert(is_expression_t::value, "invalid argument (expression expected)"); + + return {expr}; + } +} + +#endif diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index 85978cdd..cb710b89 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -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, @@ -31,6 +31,7 @@ #include #include #include +#include namespace alias { @@ -327,7 +328,7 @@ int SelectType(int, char* []) { auto s = dynamic_select(db, all_of(t)).dynamic_from(t).dynamic_where().dynamic_limit().dynamic_offset(); s.from.add(dynamic_join(f).on(f.omega > t.alpha)); - s.where.add_ntc(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); + s.where.add(without_table_check(f.omega > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3)))); s.limit.set(30); s.limit.set(3); std::cerr << "------------------------\n"; From 03aee23616c5a03bf0c3340c8825797ec909fcfc Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 16 Mar 2016 18:26:51 +0100 Subject: [PATCH 26/90] Removed the add_ntc functions (use without_table_check) --- include/sqlpp11/group_by.h | 10 ++-------- include/sqlpp11/having.h | 8 +------- include/sqlpp11/insert_value_list.h | 8 +------- include/sqlpp11/order_by.h | 10 ++-------- include/sqlpp11/select_column_list.h | 10 ++-------- include/sqlpp11/select_flag_list.h | 10 ++-------- include/sqlpp11/update_list.h | 10 ++-------- include/sqlpp11/where.h | 8 +------- 8 files changed, 13 insertions(+), 61 deletions(-) diff --git a/include/sqlpp11/group_by.h b/include/sqlpp11/group_by.h index e707144a..fa969b56 100644 --- a/include/sqlpp11/group_by.h +++ b/include/sqlpp11/group_by.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, @@ -85,17 +85,11 @@ namespace sqlpp } template - void add_ntc(Expression expression) - { - add(expression); - } - - template void add(Expression expression) { static_assert(_is_dynamic::value, "add() must not be called for static group_by"); static_assert(is_expression_t::value, "invalid expression argument in group_by::add()"); - static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in group_by::add()"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index 534cf291..8939acd1 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -82,17 +82,11 @@ namespace sqlpp } template - void add_ntc(Expr expression) - { - add(expression); - } - - template void add(Expr expression) { static_assert(_is_dynamic::value, "having::add() can only be called for dynamic_having"); static_assert(is_expression_t::value, "invalid expression argument in having::add()"); - static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in having::add()"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); diff --git a/include/sqlpp11/insert_value_list.h b/include/sqlpp11/insert_value_list.h index 2e68e33c..0dab1c9a 100644 --- a/include/sqlpp11/insert_value_list.h +++ b/include/sqlpp11/insert_value_list.h @@ -252,12 +252,6 @@ namespace sqlpp } template - void add_ntc(Assignment assignment) - { - add(assignment); - } - - template void add(Assignment assignment) { static_assert(_is_dynamic::value, "add must not be called for static from()"); @@ -266,7 +260,7 @@ namespace sqlpp static_assert(not detail::is_element_of, _assigned_columns>::value, "Must not assign value to column twice"); static_assert(not must_not_insert_t>::value, "add() argument must not be used in insert"); - static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "add() contains a column from a foreign table"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); diff --git a/include/sqlpp11/order_by.h b/include/sqlpp11/order_by.h index 0445d90f..53d9c87f 100644 --- a/include/sqlpp11/order_by.h +++ b/include/sqlpp11/order_by.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, @@ -82,17 +82,11 @@ namespace sqlpp } template - void add_ntc(Expression expression) - { - add(expression); - } - - template void add(Expression expression) { static_assert(_is_dynamic::value, "add() must not be called for static order_by"); static_assert(is_sort_order_t::value, "invalid expression argument in order_by::add()"); - static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in order_by::add()"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index c82f0f90..cf0da031 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.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, @@ -123,19 +123,13 @@ namespace sqlpp } template - void add_ntc(NamedExpression namedExpression) - { - add(namedExpression); - } - - template void add(NamedExpression namedExpression) { using named_expression = auto_alias_t; static_assert(_is_dynamic::value, "selected_columns::add() can only be called for dynamic_column"); static_assert(is_selectable_t::value, "invalid named expression argument in selected_columns::add()"); - static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "named expression uses tables unknown to this statement in selected_columns::add()"); using column_names = detail::make_type_set_t; static_assert(not detail::is_element_of::value, diff --git a/include/sqlpp11/select_flag_list.h b/include/sqlpp11/select_flag_list.h index 91704ca0..e8d0bd02 100644 --- a/include/sqlpp11/select_flag_list.h +++ b/include/sqlpp11/select_flag_list.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, @@ -78,17 +78,11 @@ namespace sqlpp } template - void add_ntc(Flag flag) - { - add(flag); - } - - template void add(Flag flag) { static_assert(_is_dynamic::value, "select_flags::add() must not be called for static select flags"); static_assert(is_select_flag_t::value, "invalid select flag argument in select_flags::add()"); - static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "flag uses tables unknown to this statement in select_flags::add()"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); diff --git a/include/sqlpp11/update_list.h b/include/sqlpp11/update_list.h index e48a742b..ab4af1b0 100644 --- a/include/sqlpp11/update_list.h +++ b/include/sqlpp11/update_list.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, @@ -78,12 +78,6 @@ namespace sqlpp } template - void add_ntc(Assignment assignment) - { - add(assignment); - } - - template void add(Assignment assignment) { static_assert(_is_dynamic::value, "add must not be called for static from()"); @@ -92,7 +86,7 @@ namespace sqlpp static_assert(not detail::is_element_of, _assigned_columns>::value, "Must not assign value to column twice"); static_assert(logic::not_t>::value, "add() argument must not be updated"); - static_assert(TableCheckRequired::value or Policies::template _no_unknown_tables::value, + static_assert(Policies::template _no_unknown_tables::value, "assignment uses tables unknown to this statement in add()"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check::_(); diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 3a8f1d39..b7f1626d 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -84,18 +84,12 @@ namespace sqlpp } template - void add_ntc(Expr expression) - { - add(expression); - } - - template void add(Expr expression) { 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, + static_assert(Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in where::add()"); static_assert(not contains_aggregate_function_t::value, "where expression must not contain aggregate functions"); From 24745fec23cbcdc2e4b08cdeadb4e775386d89b8 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 17 Mar 2016 17:28:59 +0100 Subject: [PATCH 27/90] Removed extra_tables (use without_table_check) instead --- include/sqlpp11/extra_tables.h | 220 -------------------------- include/sqlpp11/remove.h | 3 +- include/sqlpp11/select.h | 2 - include/sqlpp11/statement.h | 11 +- include/sqlpp11/type_traits.h | 2 - include/sqlpp11/without_table_check.h | 16 +- tests/Interpret.cpp | 12 +- tests/Select.cpp | 8 +- tests/SelectType.cpp | 4 +- 9 files changed, 16 insertions(+), 262 deletions(-) delete mode 100644 include/sqlpp11/extra_tables.h diff --git a/include/sqlpp11/extra_tables.h b/include/sqlpp11/extra_tables.h deleted file mode 100644 index 90332156..00000000 --- a/include/sqlpp11/extra_tables.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 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_EXTRA_TABLES_H -#define SQLPP_EXTRA_TABLES_H - -#include -#include -#include - -namespace sqlpp -{ - template - struct extra_tables_data_t - { - extra_tables_data_t() - { - } - - extra_tables_data_t(const extra_tables_data_t&) = default; - extra_tables_data_t(extra_tables_data_t&&) = default; - extra_tables_data_t& operator=(const extra_tables_data_t&) = default; - extra_tables_data_t& operator=(extra_tables_data_t&&) = default; - ~extra_tables_data_t() = default; - }; - - // EXTRA_TABLES - template - struct extra_tables_t - { - using _traits = make_traits; - using _nodes = detail::type_vector<>; - using _required_ctes = detail::make_joined_set_t...>; - using _extra_tables = detail::type_set; - - // Data - using _data_t = extra_tables_data_t; - - // Member implementation with data and methods - template - struct _impl_t - { - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 - _impl_t() = default; - _impl_t(const _data_t& data) : _data(data) - { - } - - _data_t _data; - }; - - // Base template to be inherited by the statement - template - struct _base_t - { - using _data_t = extra_tables_data_t; - - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 - template - _base_t(Args&&... args) - : extra_tables{std::forward(args)...} - { - } - - _impl_t extra_tables; - _impl_t& operator()() - { - return extra_tables; - } - const _impl_t& operator()() const - { - return extra_tables; - } - - template - static auto _get_member(T t) -> decltype(t.extra_tables) - { - return t.extra_tables; - } - - using _consistency_check = consistent_t; - }; - }; - - // NO EXTRA TABLES YET - struct no_extra_tables_t - { - using _traits = make_traits; - using _nodes = detail::type_vector<>; - - // Data - using _data_t = no_data_t; - - // Member implementation with data and methods - template - struct _impl_t - { - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 - _impl_t() = default; - _impl_t(const _data_t& data) : _data(data) - { - } - - _data_t _data; - }; - - // Base template to be inherited by the statement - template - struct _base_t - { - using _data_t = no_data_t; - - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 - template - _base_t(Args&&... args) - : no_extra_tables{std::forward(args)...} - { - } - - _impl_t no_extra_tables; - _impl_t& operator()() - { - return no_extra_tables; - } - const _impl_t& operator()() const - { - return no_extra_tables; - } - - template - static auto _get_member(T t) -> decltype(t.no_extra_tables) - { - return t.no_extra_tables; - } - - template - using _new_statement_t = new_statement_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...> - { - }; - - using _consistency_check = consistent_t; - - template - auto extra_tables(Tables... tables) const -> _new_statement_t<_check, extra_tables_t> - { - static_assert(_check::value, "at least one argument is not a table or join in extra_tables()"); - - return _extra_tables_impl(_check{}, tables...); - } - - private: - template - auto _extra_tables_impl(const std::false_type&, Tables... tables) const -> bad_statement; - - template - auto _extra_tables_impl(const std::true_type&, Tables...) const - -> _new_statement_t> - { - static_assert(required_tables_of>::size::value == 0, - "at least one table depends on another table in extra_tables()"); - - static constexpr std::size_t _number_of_tables = detail::sum(provided_tables_of::size::value...); - using _unique_tables = detail::make_joined_set_t...>; - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/feedback/details/2173198 - // using _unique_table_names = detail::transform_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 extra_tables()"); - static_assert(_number_of_tables == _unique_table_names::size::value, - "at least one duplicate table name detected in extra_tables()"); - - return {static_cast&>(*this), extra_tables_data_t{}}; - } - }; - }; - - // Interpreters - template - struct serializer_t> - { - using _serialize_check = serialize_check_of; - using T = extra_tables_data_t; - - static Context& _(const T&, Context& context) - { - return context; - } - }; -} - -#endif diff --git a/include/sqlpp11/remove.h b/include/sqlpp11/remove.h index e53faeba..fe63205e 100644 --- a/include/sqlpp11/remove.h +++ b/include/sqlpp11/remove.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -103,7 +102,7 @@ namespace sqlpp }; template - using blank_remove_t = statement_t>; + using blank_remove_t = statement_t>; inline auto remove() -> blank_remove_t { diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 16be853e..824645c4 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -77,7 +76,6 @@ namespace sqlpp no_select_flag_list_t, no_select_column_list_t, no_from_t, - no_extra_tables_t, no_where_t, no_group_by_t, no_having_t, diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index 846aefde..f338222b 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -76,13 +76,10 @@ namespace sqlpp using _all_required_tables = detail::make_joined_set_t...>; using _all_provided_tables = detail::make_joined_set_t...>; using _all_provided_outer_tables = detail::make_joined_set_t...>; - using _all_extra_tables = detail::make_joined_set_t...>; using _all_provided_aggregates = detail::make_joined_set_t...>; - using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>; - template - using _no_unknown_tables = detail::is_subset_of, _known_tables>; + using _no_unknown_tables = detail::is_subset_of, _all_provided_tables>; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2086629 // template @@ -100,11 +97,7 @@ namespace sqlpp using any_t = logic::any_t::value...>; // The tables not covered by the from. - using _required_tables = - detail::make_difference_set_t<_all_required_tables, - _all_provided_tables // Hint: extra_tables are not used here because they are - // just a helper for dynamic .add_*() - >; + using _required_tables = detail::make_difference_set_t<_all_required_tables, _all_provided_tables>; // The common table expressions not covered by the with. using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index f97a05d2..d8f3fd9e 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -181,7 +181,6 @@ namespace sqlpp SQLPP_VALUE_TRAIT_GENERATOR(is_from) SQLPP_VALUE_TRAIT_GENERATOR(is_single_table) SQLPP_VALUE_TRAIT_GENERATOR(is_into) - SQLPP_VALUE_TRAIT_GENERATOR(is_extra_tables) SQLPP_VALUE_TRAIT_GENERATOR(is_on) SQLPP_VALUE_TRAIT_GENERATOR(is_where) SQLPP_VALUE_TRAIT_GENERATOR(is_group_by) @@ -259,7 +258,6 @@ namespace sqlpp SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(required_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_outer_tables) - SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(extra_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates) #define SQLPP_RECURSIVE_TRAIT_GENERATOR(trait) \ diff --git a/include/sqlpp11/without_table_check.h b/include/sqlpp11/without_table_check.h index 37bc26c9..82051860 100644 --- a/include/sqlpp11/without_table_check.h +++ b/include/sqlpp11/without_table_check.h @@ -33,23 +33,13 @@ namespace sqlpp { template - struct without_table_check_t + struct without_table_check_t : Expression { - using _traits = typename Expression::_traits; - using _nodes = detail::type_vector; using _required_tables = detail::type_set<>; - without_table_check_t(Expression expression) : _expression(expression) + without_table_check_t(Expression expression) : Expression(expression) { } - - without_table_check_t(const without_table_check_t&) = default; - without_table_check_t(without_table_check_t&&) = default; - without_table_check_t& operator=(const without_table_check_t&) = default; - without_table_check_t& operator=(without_table_check_t&&) = default; - ~without_table_check_t() = default; - - Expression _expression; }; template @@ -60,7 +50,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - serialize(t._expression, context); + serialize(t, context); return context; } }; diff --git a/tests/Interpret.cpp b/tests/Interpret.cpp index 24841870..8e671948 100644 --- a/tests/Interpret.cpp +++ b/tests/Interpret.cpp @@ -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, @@ -163,13 +163,11 @@ int Interpret(int, char* []) serialize(s, printer).str(); } { - auto s = dynamic_select(db) - .dynamic_flags(sqlpp::distinct) - .dynamic_columns(t.alpha) - .extra_tables(t); // Would fail to run() + // Behold, dynamically constructed queries might compile but be illegal SQL + auto s = dynamic_select(db).dynamic_flags(sqlpp::distinct).dynamic_columns(t.alpha); s.select_flags.add(sqlpp::all); - s.selected_columns.add(t.beta); - s.selected_columns.add(t.gamma); + s.selected_columns.add(without_table_check(t.beta)); + s.selected_columns.add(without_table_check(t.gamma)); serialize(s, printer).str(); } diff --git a/tests/Select.cpp b/tests/Select.cpp index 43be425c..1b4a8b58 100644 --- a/tests/Select.cpp +++ b/tests/Select.cpp @@ -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, @@ -31,6 +31,7 @@ #include #include #include +#include template int64_t getColumn(Db&& db, const Column& column) @@ -108,7 +109,6 @@ int Select(int, char* []) .columns(all_of(t)) .flags(sqlpp::all) .from(t) - .extra_tables(f, t) .where(t.alpha > 0) .group_by(t.alpha) .order_by(t.gamma.asc()) @@ -122,7 +122,6 @@ int Select(int, char* []) .columns(all_of(t)) .flags(sqlpp::all) .from(t) - .extra_tables(f, t) .where(t.alpha > 0) .group_by(t.alpha) .order_by(t.gamma.asc()) @@ -137,7 +136,6 @@ int Select(int, char* []) .dynamic_columns(all_of(t)) .dynamic_flags() .dynamic_from(t) - .extra_tables(f, t) .dynamic_where() .dynamic_group_by(t.alpha) .dynamic_order_by() @@ -145,7 +143,7 @@ int Select(int, char* []) .dynamic_limit() .dynamic_offset(); s.select_flags.add(sqlpp::distinct); - s.selected_columns.add(f.omega); + s.selected_columns.add(without_table_check(f.omega)); s.from.add(dynamic_cross_join(f)); s.where.add(t.alpha > 7); s.having.add(t.alpha > 7); diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index cb710b89..c1ecb262 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -340,8 +340,8 @@ int SelectType(int, char* []) // Test that select can be called with zero columns if it is used with dynamic columns. { - auto s = dynamic_select(db).dynamic_columns().extra_tables(t); - s.selected_columns.add(t.alpha); + auto s = dynamic_select(db).dynamic_columns(); + s.selected_columns.add(without_table_check(t.alpha)); serialize(s, printer).str(); } From 153427d2b8b0d08c1f1bde1eb0224fb22811eb09 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 17 Mar 2016 19:18:14 +0100 Subject: [PATCH 28/90] Enforce having expression to consist of aggregates --- include/sqlpp11/having.h | 14 +++++++++++--- include/sqlpp11/select_column_list.h | 13 ++++++------- include/sqlpp11/statement.h | 4 ++++ test_static_asserts/aggregates.cpp | 8 ++++---- tests/Select.cpp | 2 +- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index 8939acd1..367bba6c 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -59,6 +59,8 @@ namespace sqlpp assert_no_unknown_tables_in_having_t, "at least one having-expression requires a table which is otherwise not known in the statement"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_no_non_aggregates_t, "having expression not built out of aggregate expressions"); + // HAVING template struct having_t @@ -139,9 +141,15 @@ namespace sqlpp return t.having; } - using _consistency_check = typename std::conditional::value, - consistent_t, - assert_no_unknown_tables_in_having_t>::type; + using _table_check = typename std::conditional::value, + consistent_t, + assert_no_unknown_tables_in_having_t>::type; + + using _aggregate_check = typename std::conditional::value, + consistent_t, + assert_no_non_aggregates_t>::type; + + using _consistency_check = detail::get_first_if; }; }; diff --git a/include/sqlpp11/select_column_list.h b/include/sqlpp11/select_column_list.h index cf0da031..36ed87a2 100644 --- a/include/sqlpp11/select_column_list.h +++ b/include/sqlpp11/select_column_list.h @@ -91,7 +91,7 @@ namespace sqlpp SQLPP_PORTABLE_STATIC_ASSERT( assert_no_unknown_tables_in_selected_columns_t, "at least one selected column requires a table which is otherwise not known in the statement"); - SQLPP_PORTABLE_STATIC_ASSERT(assert_aggregates_t, + SQLPP_PORTABLE_STATIC_ASSERT(assert_no_unknown_aggregates_t, "not all columns are made of aggregates, despite group_by or similar"); // SELECTED COLUMNS @@ -195,16 +195,15 @@ namespace sqlpp return t.selected_columns; } - using _column_check = - typename std::conditional::value, - consistent_t, - assert_no_unknown_tables_in_selected_columns_t>::type; + using _table_check = typename std::conditional::value, + consistent_t, + assert_no_unknown_tables_in_selected_columns_t>::type; using _aggregate_check = typename std::conditional::value, consistent_t, - assert_aggregates_t>::type; + assert_no_unknown_aggregates_t>::type; - using _consistency_check = detail::get_first_if; + using _consistency_check = detail::get_first_if; }; // Result methods diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index f338222b..cc51ca6e 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -93,6 +93,10 @@ namespace sqlpp logic::all_t::type::value...>::value>; + template + using _no_non_aggregates = logic::any_t::type::value...>::value>; + template