From 899c868f5e5b505e468134655cfdd776e773f20c Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 24 Dec 2015 15:28:07 +0100 Subject: [PATCH] Migrated where to portable assertions, added assertion tests to where() clause. --- include/sqlpp11/portable_static_assert.h | 12 +- include/sqlpp11/type_traits.h | 101 +++++++++------- include/sqlpp11/where.h | 51 +++++--- test_static_asserts/CMakeLists.txt | 1 + test_static_asserts/insert.cpp | 4 +- test_static_asserts/where.cpp | 145 +++++++++++++++++++++++ 6 files changed, 248 insertions(+), 66 deletions(-) create mode 100644 test_static_asserts/where.cpp diff --git a/include/sqlpp11/portable_static_assert.h b/include/sqlpp11/portable_static_assert.h index 06732f10..9246be9b 100644 --- a/include/sqlpp11/portable_static_assert.h +++ b/include/sqlpp11/portable_static_assert.h @@ -62,13 +62,13 @@ namespace sqlpp namespace detail { - template + template struct static_combined_check_impl; - template - struct static_combined_check_impl + template + struct static_combined_check_impl { - using type = Assert; + using type = StaticCheck; }; template @@ -84,8 +84,8 @@ namespace sqlpp }; } - template - using static_combined_check_t = typename detail::static_combined_check_impl::type; + template + using static_combined_check_t = typename detail::static_combined_check_impl::type; } #endif diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 8c978de6..2d6a4a08 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -206,26 +206,43 @@ namespace sqlpp template using cpp_value_type_of = typename value_type_of::_cpp_value_type; -#define SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(trait) \ - namespace detail \ - { \ - template \ - struct trait##_of_impl \ - { \ - using type = typename trait##_of_impl::type; \ - }; \ - template \ - struct trait##_of_impl::value>::type> \ - { \ - using type = typename T::_##trait; \ - }; \ - template \ - struct trait##_of_impl, void> \ - { \ - using type = detail::make_joined_set_t::type...>; \ - }; \ - } \ - template \ + namespace detail + { + template + struct nodes_of_impl + { + using type = type_vector<>; + }; + + template + struct nodes_of_impl> + { + using type = typename T::_nodes; + }; + } + template + using nodes_of = typename detail::nodes_of_impl::type; + +#define SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(trait) \ + namespace detail \ + { \ + template \ + struct trait##_of_impl \ + { \ + using type = typename trait##_of_impl>::type; \ + }; \ + template \ + struct trait##_of_impl> \ + { \ + using type = typename T::_##trait; \ + }; \ + template \ + struct trait##_of_impl, void> \ + { \ + using type = detail::make_joined_set_t::type...>; \ + }; \ + } \ + template \ using trait##_of = typename detail::trait##_of_impl::type; SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(required_ctes) @@ -236,26 +253,26 @@ namespace sqlpp SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(extra_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates) -#define SQLPP_RECURSIVE_TRAIT_GENERATOR(trait) \ - namespace detail \ - { \ - template \ - struct trait##_impl \ - { \ - using type = typename trait##_impl::type; \ - }; \ - template \ - struct trait##_impl::value>::type> \ - { \ - using type = typename T::_##trait; \ - }; \ - template \ - struct trait##_impl, void> \ - { \ - using type = logic::any_t::type::value...>; \ - }; \ - } \ - template \ +#define SQLPP_RECURSIVE_TRAIT_GENERATOR(trait) \ + namespace detail \ + { \ + template \ + struct trait##_impl \ + { \ + using type = typename trait##_impl>::type; \ + }; \ + template \ + struct trait##_impl> \ + { \ + using type = typename T::_##trait; \ + }; \ + template \ + struct trait##_impl, void> \ + { \ + using type = logic::any_t::type::value...>; \ + }; \ + } \ + template \ using trait##_t = typename detail::trait##_impl::type; SQLPP_RECURSIVE_TRAIT_GENERATOR(can_be_null) @@ -275,7 +292,7 @@ namespace sqlpp template struct is_aggregate_expression_impl { - using type = typename is_aggregate_expression_impl::type; + using type = typename is_aggregate_expression_impl>::type; }; template struct is_aggregate_expression_impl< @@ -307,7 +324,7 @@ namespace sqlpp template struct parameters_of_impl { - using type = typename parameters_of_impl::type; + using type = typename parameters_of_impl>::type; }; template struct parameters_of_impl::value>::type> diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 4c257632..3a452aa0 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -209,6 +209,32 @@ namespace sqlpp } }; + 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_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"); + + 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_no_aggregate_functions_t>>; + + template + using check_where_static_t = + static_combined_check_t, + static_check_t>; + + template + using check_where_dynamic_t = static_combined_check_t< + static_check_t::value, assert_where_dynamic_statement_dynamic_t>, + check_where_t>; + // NO WHERE YET template struct no_where_t @@ -250,9 +276,6 @@ namespace sqlpp using _database_t = typename Policies::_database_t; - template - using _check = logic::all_t::value...>; - template using _new_statement_t = new_statement_t; @@ -268,26 +291,22 @@ namespace sqlpp template auto where(Expressions... expressions) const - -> _new_statement_t<_check, where_t> + -> _new_statement_t, where_t> { - static_assert(_check::value, "at least one argument is not an expression in where()"); - static_assert(sizeof...(Expressions), "at least one expression argument required in where()"); - static_assert(logic::all_t<(not contains_aggregate_function_t::value)...>::value, - "where expression must not contain aggregate functions"); + using Check = check_where_static_t; + Check{}._(); - return _where_impl(_check{}, expressions...); + return _where_impl(typename Check::type{}, expressions...); } template auto dynamic_where(Expressions... expressions) const - -> _new_statement_t<_check, where_t<_database_t, Expressions...>> + -> _new_statement_t, where_t<_database_t, Expressions...>> { - static_assert(_check::value, "at least one argument is not an expression in where()"); - static_assert(not std::is_same<_database_t, void>::value, - "dynamic_where must not be called in a static statement"); - static_assert(logic::all_t<(not contains_aggregate_function_t::value)...>::value, - "where expression must not contain aggregate functions"); - return _where_impl<_database_t>(_check{}, expressions...); + using Check = check_where_dynamic_t<_database_t, Expressions...>; + Check{}._(); + + return _where_impl<_database_t>(typename Check::type{}, expressions...); } private: diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 34d5a051..a4d532ad 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -29,6 +29,7 @@ function(test_compile name) endfunction() test_compile(aggregates) +test_compile(where) test_compile(insert) test_compile(date) test_compile(date_time) diff --git a/test_static_asserts/insert.cpp b/test_static_asserts/insert.cpp index 6090c2f3..866ab1d4 100644 --- a/test_static_asserts/insert.cpp +++ b/test_static_asserts/insert.cpp @@ -49,14 +49,14 @@ namespace { using CheckResult = sqlpp::check_insert_static_set_t; using ExpectedCheckResult = std::is_same; - static_assert(ExpectedCheckResult::value, "Unexpected check result"); print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); using ReturnType = decltype(insert_into(t).set(assignments...)); using ExpectedReturnType = sqlpp::logic::all_t::value>; - static_assert(ExpectedReturnType::value, "Unexpected return type"); print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); } template diff --git a/test_static_asserts/where.cpp b/test_static_asserts/where.cpp new file mode 100644 index 00000000..5d300818 --- /dev/null +++ b/test_static_asserts/where.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015-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 +#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 where_static_check(const Expressions&... expressions) + { + 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 ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void set_dynamic_check(const Expressions&... expressions) + { + static auto db = MockDb{}; + 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 ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + void static_where() + { + // OK + 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); + + // Try non-boolean expression + 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); + + // Try using aggregate functions in where + where_static_check(count(t.alpha) > 0); + where_static_check(t.gamma and count(t.alpha) > 0); + } + + // column alpha is not allowed, column gamma is required + void dynamic_where() + { + // OK + set_dynamic_check(); + where_static_check(t.gamma); + where_static_check(t.gamma == true); + + // Try assignment as condition + where_static_check(t.gamma = true); + + // Try non-boolean expression + 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); + + // Try using aggregate functions in where + where_static_check(count(t.alpha) > 0); + where_static_check(t.gamma and count(t.alpha) > 0); + + // Try dynamic_where on a non-dynamic remove + 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(remove_from(t).dynamic_where()); + using ExpectedReturnType = std::is_same; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } +} + +int main(int, char**) +{ + static_where(); + dynamic_where(); +}