From 7bf7388907bb2d43a74faad0be5fd9e13cd4aedb Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 8 Apr 2016 21:09:36 +0200 Subject: [PATCH] Added more tests --- include/sqlpp11/having.h | 64 ++++++++-- include/sqlpp11/where.h | 6 +- test_static_asserts/CMakeLists.txt | 1 + test_static_asserts/having.cpp | 194 +++++++++++++++++++++++++++++ test_static_asserts/where.cpp | 2 +- 5 files changed, 250 insertions(+), 17 deletions(-) create mode 100644 test_static_asserts/having.cpp diff --git a/include/sqlpp11/having.h b/include/sqlpp11/having.h index 367bba6c..fba6db7e 100644 --- a/include/sqlpp11/having.h +++ b/include/sqlpp11/having.h @@ -56,10 +56,11 @@ namespace sqlpp }; SQLPP_PORTABLE_STATIC_ASSERT( - assert_no_unknown_tables_in_having_t, + assert_having_no_unknown_tables_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"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_having_no_non_aggregates_t, + "having expression not built out of aggregate expressions"); // HAVING template @@ -143,16 +144,44 @@ namespace sqlpp using _table_check = typename std::conditional::value, consistent_t, - assert_no_unknown_tables_in_having_t>::type; + assert_having_no_unknown_tables_t>::type; using _aggregate_check = typename std::conditional::value, consistent_t, - assert_no_non_aggregates_t>::type; + assert_having_no_non_aggregates_t>::type; using _consistency_check = detail::get_first_if; }; }; + SQLPP_PORTABLE_STATIC_ASSERT(assert_having_not_cpp_bool_t, + "having() argument has to be an sqlpp boolean expression. Please use " + "sqlpp::value(bool_expresson) if you really want to use a bool value here"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_having_boolean_expression_t, + "having() argument has to be an sqlpp boolean expression."); + SQLPP_PORTABLE_STATIC_ASSERT(assert_having_dynamic_statement_dynamic_t, + "dynamic_having() must not be called in a static statement"); + + template + struct check_having + { + using type = + static_combined_check_t::value, assert_having_not_cpp_bool_t>, + static_check_t::value, assert_having_boolean_expression_t>, + static_check_t::value, assert_having_boolean_expression_t>>; + }; + + template + using check_having_t = typename check_having::type; + + template + using check_having_static_t = check_having_t; + + template + using check_having_dynamic_t = static_combined_check_t< + static_check_t::value, assert_having_dynamic_statement_dynamic_t>, + check_having_t>; + // NO HAVING YET struct no_having_t { @@ -220,24 +249,27 @@ namespace sqlpp using _consistency_check = consistent_t; template - auto having(Expression expression) const -> _new_statement_t<_check, having_t> + auto having(Expression expression) const + -> _new_statement_t, having_t> { - static_assert(_check::value, "at least one argument is not an expression in having()"); + using Check = check_having_static_t; + Check{}._(); - return _having_impl(_check{}, expression); + return _having_impl(Check{}, expression); } template auto dynamic_having(Expression expression) const - -> _new_statement_t<_check, having_t<_database_t, Expression>> + -> _new_statement_t, having_t<_database_t, Expression>> { - 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{}, expression); + using Check = check_having_dynamic_t<_database_t, Expression>; + Check{}._(); + + return _having_impl<_database_t>(Check{}, expression); } - auto dynamic_having() const -> _new_statement_t<_check, having_t<_database_t, boolean_operand>> + auto dynamic_having() const -> _new_statement_t, + having_t<_database_t, boolean_operand>> { return dynamic_having(::sqlpp::value(true)); } @@ -273,6 +305,12 @@ namespace sqlpp return context; } }; + + template + auto having(T&& t) -> decltype(statement_t().having(std::forward(t))) + { + return statement_t().having(std::forward(t)); + } } #endif diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index b7f1626d..018dc509 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -392,10 +392,10 @@ namespace sqlpp } }; - template - auto where(T&&... t) -> decltype(statement_t>().where(std::forward(t)...)) + template + auto where(T&& t) -> decltype(statement_t>().where(std::forward(t))) { - return statement_t>().where(std::forward(t)...); + return statement_t>().where(std::forward(t)); } } diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 6726a39d..3e069787 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -33,6 +33,7 @@ test_compile(case) test_compile(from) test_compile(join) test_compile(where) +test_compile(having) test_compile(insert) test_compile(date) test_compile(date_time) diff --git a/test_static_asserts/having.cpp b/test_static_asserts/having.cpp new file mode 100644 index 00000000..b4998275 --- /dev/null +++ b/test_static_asserts/having.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016-2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + constexpr auto t = test::TabBar{}; + constexpr auto f = test::TabFoo{}; + + template + auto print_type_on_error(std::true_type) -> void + { + } + + template + auto print_type_on_error(std::false_type) -> void + { + T::_print_me_; + } + + template + auto having_static_check(const Expression& expression) -> void + { + using CheckResult = sqlpp::check_having_static_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ReturnType = decltype(select(all_of(t)).from(t).unconditionally().group_by(t.alpha).having(expression)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + auto having_dynamic_check(const Expression& expression) -> void + { + static auto db = MockDb{}; + using CheckResult = sqlpp::check_having_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, all_of(t)).from(t).unconditionally().group_by(t.alpha).dynamic_having(expression)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + auto static_having() -> void + { + // OK + having_static_check(t.gamma); + having_static_check(t.gamma == true); + + // OK using aggregate functions in having + having_static_check(count(t.alpha) > 0); + having_static_check(t.gamma and count(t.alpha) > 0); + having_static_check(case_when(count(t.alpha) > 0).then(t.gamma).else_(not t.gamma)); + + // Try assignment as condition + having_static_check(t.gamma = true); + + // Try non-boolean expression + having_static_check(t.alpha); + + // Try builtin bool + having_static_check(true); + having_static_check(17 > 3); + + // Try some other types as expressions + having_static_check("true"); + having_static_check(17); + having_static_check('c'); + having_static_check(nullptr); + having_static_check(t.alpha.as(t.beta)); + } + + auto dynamic_having() -> void + { + // OK + having_dynamic_check(t.gamma); + having_dynamic_check(t.gamma == true); + + // OK using aggregate functions in having + having_dynamic_check(count(t.alpha) > 0); + having_dynamic_check(t.gamma and count(t.alpha) > 0); + having_dynamic_check(case_when(count(t.alpha) > 0).then(t.gamma).else_(not t.gamma)); + + // Try assignment as condition + having_dynamic_check(t.gamma = true); + + // Try non-boolean expression + having_dynamic_check(t.alpha); + + // Try builtin bool + having_dynamic_check(true); + having_dynamic_check(17 > 3); + + // Try some other types as expressions + having_dynamic_check("true"); + having_dynamic_check(17); + having_dynamic_check('c'); + having_dynamic_check(nullptr); + having_dynamic_check(t.alpha.as(t.beta)); + + // Try dynamic_having on a non-dynamic select + using CheckResult = sqlpp::check_having_dynamic_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ReturnType = decltype(select(all_of(t)).from(t).dynamic_having()); + using ExpectedReturnType = std::is_same; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + auto static_consistency_check(const Statement statement, const HavingCondition condtion) -> void + { + using CheckResult = sqlpp::consistency_check_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + } + + auto consistency_check() -> void + { + const auto select_without_group_by = select(all_of(t)).from(t).unconditionally(); + + // OK + static_consistency_check(select_without_group_by, avg(t.alpha) > 17); + + // Try non aggregate + static_consistency_check(select_without_group_by, t.alpha > 17); + static_consistency_check(select_without_group_by, + count(t.alpha) > 3 and t.alpha > 17); + + // Try foreign table + static_consistency_check(select_without_group_by, f.omega > 17); + + const auto select_with_group_by = select(t.alpha).from(t).unconditionally().group_by(t.alpha); + + // OK + static_consistency_check(select_with_group_by, avg(t.alpha) > 17); + static_consistency_check(select_with_group_by, t.alpha > 17); + static_consistency_check(select_with_group_by, count(t.alpha) > 3 and t.alpha > 17); + + // Try non aggregate + static_consistency_check(select_with_group_by, t.beta > "17"); + static_consistency_check(select_with_group_by, + count(t.beta) > 3 and t.beta > "17"); + + // Try foreign table + static_consistency_check(select_with_group_by, f.omega > 17); + } +} + +int main(int, char* []) +{ + static_having(); + dynamic_having(); + consistency_check(); +} diff --git a/test_static_asserts/where.cpp b/test_static_asserts/where.cpp index 186b9c9d..d232adff 100644 --- a/test_static_asserts/where.cpp +++ b/test_static_asserts/where.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2015, Roland Bock + * Copyright (c) 2015-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification,