From 82758a20464e2775078fb343cda23da7b73ec482 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 29 Jan 2023 14:39:07 +0100 Subject: [PATCH] Add missing braces to aggregatedfunctions with sub select #469 Also allow MIN and MAX to be used with DISTINCT. --- include/sqlpp11/aggregate_functions/avg.h | 6 +-- include/sqlpp11/aggregate_functions/count.h | 6 +-- include/sqlpp11/aggregate_functions/max.h | 30 +++++++++---- include/sqlpp11/aggregate_functions/min.h | 30 +++++++++---- tests/core/serialize/Avg.cpp | 48 +++++++++++++++++++++ tests/core/serialize/CMakeLists.txt | 4 ++ tests/core/serialize/Count.cpp | 48 +++++++++++++++++++++ tests/core/serialize/Max.cpp | 48 +++++++++++++++++++++ tests/core/serialize/Min.cpp | 48 +++++++++++++++++++++ tests/core/serialize/Sum.cpp | 14 +++++- 10 files changed, 255 insertions(+), 27 deletions(-) create mode 100644 tests/core/serialize/Avg.cpp create mode 100644 tests/core/serialize/Count.cpp create mode 100644 tests/core/serialize/Max.cpp create mode 100644 tests/core/serialize/Min.cpp diff --git a/include/sqlpp11/aggregate_functions/avg.h b/include/sqlpp11/aggregate_functions/avg.h index 129cb643..b530ae35 100644 --- a/include/sqlpp11/aggregate_functions/avg.h +++ b/include/sqlpp11/aggregate_functions/avg.h @@ -91,12 +91,8 @@ namespace sqlpp { serialize(Flag(), context); context << ' '; - serialize_operand(t._expr, context); - } - else - { - serialize(t._expr, context); } + serialize_operand(t._expr, context); context << ")"; return context; } diff --git a/include/sqlpp11/aggregate_functions/count.h b/include/sqlpp11/aggregate_functions/count.h index 542a978e..ea8a6131 100644 --- a/include/sqlpp11/aggregate_functions/count.h +++ b/include/sqlpp11/aggregate_functions/count.h @@ -94,12 +94,8 @@ namespace sqlpp { serialize(Flag(), context); context << ' '; - serialize_operand(t._expr, context); - } - else - { - serialize(t._expr, context); } + serialize_operand(t._expr, context); context << ")"; return context; } diff --git a/include/sqlpp11/aggregate_functions/max.h b/include/sqlpp11/aggregate_functions/max.h index 90dabe4b..7ca55351 100644 --- a/include/sqlpp11/aggregate_functions/max.h +++ b/include/sqlpp11/aggregate_functions/max.h @@ -54,10 +54,10 @@ namespace sqlpp }; }; - template - struct max_t : public expression_operators, value_type_of>, - public aggregate_function_operators>, - public alias_operators> + template + struct max_t : public expression_operators, value_type_of>, + public aggregate_function_operators>, + public alias_operators> { using _traits = make_traits, tag::is_expression, tag::is_selectable>; using _nodes = detail::type_vector; @@ -79,17 +79,31 @@ namespace sqlpp Expr _expr; }; - template - Context& serialize(const max_t& t, Context& context) + template + Context& serialize(const max_t& t, Context& context) { context << "MAX("; - serialize(t._expr, context); + if (std::is_same::value) + { + serialize(Flag(), context); + context << ' '; + } + serialize_operand(t._expr, context); context << ")"; return context; } template - auto max(T t) -> max_t> + auto max(T t) -> max_t> + { + static_assert(not contains_aggregate_function_t>::value, + "max() cannot be used on an aggregate function"); + static_assert(is_expression_t>::value, "max() requires an expression as argument"); + return {t}; + } + + template + auto max(const distinct_t& /*unused*/, T t) -> max_t> { static_assert(not contains_aggregate_function_t>::value, "max() cannot be used on an aggregate function"); diff --git a/include/sqlpp11/aggregate_functions/min.h b/include/sqlpp11/aggregate_functions/min.h index e46cbfaa..14b8e706 100644 --- a/include/sqlpp11/aggregate_functions/min.h +++ b/include/sqlpp11/aggregate_functions/min.h @@ -54,10 +54,10 @@ namespace sqlpp }; }; - template - struct min_t : public expression_operators, value_type_of>, - public aggregate_function_operators>, - public alias_operators> + template + struct min_t : public expression_operators, value_type_of>, + public aggregate_function_operators>, + public alias_operators> { using _traits = make_traits, tag::is_expression, tag::is_selectable>; using _nodes = detail::type_vector; @@ -79,17 +79,31 @@ namespace sqlpp Expr _expr; }; - template - Context& serialize(const min_t& t, Context& context) + template + Context& serialize(const min_t& t, Context& context) { context << "MIN("; - serialize(t._expr, context); + if (std::is_same::value) + { + serialize(Flag(), context); + context << ' '; + } + serialize_operand(t._expr, context); context << ")"; return context; } template - auto min(T t) -> min_t> + auto min(T t) -> min_t> + { + static_assert(not contains_aggregate_function_t>::value, + "min() cannot be used on an aggregate function"); + static_assert(is_expression_t>::value, "min() requires an expression as argument"); + return {t}; + } + + template + auto min(const distinct_t& /*unused*/, T t) -> min_t> { static_assert(not contains_aggregate_function_t>::value, "min() cannot be used on an aggregate function"); diff --git a/tests/core/serialize/Avg.cpp b/tests/core/serialize/Avg.cpp new file mode 100644 index 00000000..9ae5c595 --- /dev/null +++ b/tests/core/serialize/Avg.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2023, 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 "compare.h" +#include + +int Avg(int, char* []) +{ + const auto bar = test::TabBar{}; + + // Single column. + compare(__LINE__, avg(bar.alpha), "AVG(tab_bar.alpha)"); + compare(__LINE__, avg(sqlpp::distinct, bar.alpha), "AVG(DISTINCT tab_bar.alpha)"); + + // Expression. + // Note that the inner parens aren't necessary. + compare(__LINE__, avg(bar.alpha + 7), "AVG((tab_bar.alpha+7))"); + compare(__LINE__, avg(sqlpp::distinct, bar.alpha + 7), "AVG(DISTINCT (tab_bar.alpha+7))"); + + // With sub select. + compare(__LINE__, avg(select(sqlpp::value(7).as(sqlpp::alias::a))), "AVG((SELECT 7 AS a))"); + compare(__LINE__, avg(sqlpp::distinct, select(sqlpp::value(7).as(sqlpp::alias::a))), "AVG(DISTINCT (SELECT 7 AS a))"); + + return 0; +} diff --git a/tests/core/serialize/CMakeLists.txt b/tests/core/serialize/CMakeLists.txt index caf0c575..32130a41 100644 --- a/tests/core/serialize/CMakeLists.txt +++ b/tests/core/serialize/CMakeLists.txt @@ -24,13 +24,17 @@ set(test_files As.cpp + Avg.cpp Blob.cpp + Count.cpp CustomQuery.cpp DynamicWhere.cpp ForUpdate.cpp From.cpp In.cpp Insert.cpp + Max.cpp + Min.cpp Operator.cpp Over.cpp Sum.cpp diff --git a/tests/core/serialize/Count.cpp b/tests/core/serialize/Count.cpp new file mode 100644 index 00000000..eb23619c --- /dev/null +++ b/tests/core/serialize/Count.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2023, 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 "compare.h" +#include + +int Count(int, char* []) +{ + const auto bar = test::TabBar{}; + + // Single column. + compare(__LINE__, count(bar.alpha), "COUNT(tab_bar.alpha)"); + compare(__LINE__, count(sqlpp::distinct, bar.alpha), "COUNT(DISTINCT tab_bar.alpha)"); + + // Expression. + // Note that the inner parens aren't necessary. + compare(__LINE__, count(bar.alpha + 7), "COUNT((tab_bar.alpha+7))"); + compare(__LINE__, count(sqlpp::distinct, bar.alpha + 7), "COUNT(DISTINCT (tab_bar.alpha+7))"); + + // With sub select. + compare(__LINE__, count(select(sqlpp::value(7).as(sqlpp::alias::a))), "COUNT((SELECT 7 AS a))"); + compare(__LINE__, count(sqlpp::distinct, select(sqlpp::value(7).as(sqlpp::alias::a))), "COUNT(DISTINCT (SELECT 7 AS a))"); + + return 0; +} diff --git a/tests/core/serialize/Max.cpp b/tests/core/serialize/Max.cpp new file mode 100644 index 00000000..aacf6a22 --- /dev/null +++ b/tests/core/serialize/Max.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2023, 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 "compare.h" +#include + +int Max(int, char* []) +{ + const auto bar = test::TabBar{}; + + // Single column. + compare(__LINE__, max(bar.alpha), "MAX(tab_bar.alpha)"); + compare(__LINE__, max(sqlpp::distinct, bar.alpha), "MAX(DISTINCT tab_bar.alpha)"); + + // Expression. + // Note that the inner parens aren't necessary. + compare(__LINE__, max(bar.alpha + 7), "MAX((tab_bar.alpha+7))"); + compare(__LINE__, max(sqlpp::distinct, bar.alpha + 7), "MAX(DISTINCT (tab_bar.alpha+7))"); + + // With sub select. + compare(__LINE__, max(select(sqlpp::value(7).as(sqlpp::alias::a))), "MAX((SELECT 7 AS a))"); + compare(__LINE__, max(sqlpp::distinct, select(sqlpp::value(7).as(sqlpp::alias::a))), "MAX(DISTINCT (SELECT 7 AS a))"); + + return 0; +} diff --git a/tests/core/serialize/Min.cpp b/tests/core/serialize/Min.cpp new file mode 100644 index 00000000..86a358d0 --- /dev/null +++ b/tests/core/serialize/Min.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2023, 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 "compare.h" +#include + +int Min(int, char* []) +{ + const auto bar = test::TabBar{}; + + // Single column. + compare(__LINE__, min(bar.alpha), "MIN(tab_bar.alpha)"); + compare(__LINE__, min(sqlpp::distinct, bar.alpha), "MIN(DISTINCT tab_bar.alpha)"); + + // Expression. + // Note that the inner parens aren't necessary. + compare(__LINE__, min(bar.alpha + 7), "MIN((tab_bar.alpha+7))"); + compare(__LINE__, min(sqlpp::distinct, bar.alpha + 7), "MIN(DISTINCT (tab_bar.alpha+7))"); + + // With sub select. + compare(__LINE__, min(select(sqlpp::value(7).as(sqlpp::alias::a))), "MIN((SELECT 7 AS a))"); + compare(__LINE__, min(sqlpp::distinct, select(sqlpp::value(7).as(sqlpp::alias::a))), "MIN(DISTINCT (SELECT 7 AS a))"); + + return 0; +} diff --git a/tests/core/serialize/Sum.cpp b/tests/core/serialize/Sum.cpp index 9bfffb0d..b0d64845 100644 --- a/tests/core/serialize/Sum.cpp +++ b/tests/core/serialize/Sum.cpp @@ -29,8 +29,20 @@ int Sum(int, char* []) { - // Function + const auto bar = test::TabBar{}; + + // Single column. + compare(__LINE__, sum(bar.alpha), "SUM(tab_bar.alpha)"); + compare(__LINE__, sum(sqlpp::distinct, bar.alpha), "SUM(DISTINCT tab_bar.alpha)"); + + // Expression. + // Note that the inner parens aren't necessary. + compare(__LINE__, sum(bar.alpha + 7), "SUM((tab_bar.alpha+7))"); + compare(__LINE__, sum(sqlpp::distinct, bar.alpha + 7), "SUM(DISTINCT (tab_bar.alpha+7))"); + + // With sub select. compare(__LINE__, sum(select(sqlpp::value(7).as(sqlpp::alias::a))), "SUM((SELECT 7 AS a))"); + compare(__LINE__, sum(sqlpp::distinct, select(sqlpp::value(7).as(sqlpp::alias::a))), "SUM(DISTINCT (SELECT 7 AS a))"); return 0; }