diff --git a/include/sqlpp11/core/clause/cte.h b/include/sqlpp11/core/clause/cte.h index 10fbb13f..7ee3c801 100644 --- a/include/sqlpp11/core/clause/cte.h +++ b/include/sqlpp11/core/clause/cte.h @@ -168,7 +168,7 @@ namespace sqlpp { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); - static_assert(has_result_row_t::value, "argument of a clause/union.has to be a (complete) select statement"); + static_assert(has_result_row::value, "argument of a clause/union.has to be a (complete) select statement"); static_assert(std::is_same<_result_row_t, get_result_row_t>::value, "both select statements in a clause/union.have to have the same result columns (type and name)"); @@ -183,7 +183,7 @@ namespace sqlpp { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); - static_assert(has_result_row_t::value, "argument of a clause/union.has to be a (complete) select statement"); + static_assert(has_result_row::value, "argument of a clause/union.has to be a (complete) select statement"); static_assert(std::is_same<_result_row_t, get_result_row_t>::value, "both select statements in a clause/union.have to have the same result columns (type and name)"); diff --git a/include/sqlpp11/core/clause/union.h b/include/sqlpp11/core/clause/union.h index 6667dddb..1735bb7c 100644 --- a/include/sqlpp11/core/clause/union.h +++ b/include/sqlpp11/core/clause/union.h @@ -91,8 +91,16 @@ namespace sqlpp typename Rhs::_consistency_check>; }; + template + using _result_methods_t = typename Lhs::template _result_methods_t; }; + template + struct is_result_clause> : public std::true_type + { + }; + + SQLPP_PORTABLE_STATIC_ASSERT(assert_union_args_are_statements_t, "arguments for union() must be statements"); template struct check_union @@ -134,8 +142,8 @@ namespace sqlpp { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); - static_assert(has_result_row_t::value, "argument of a clause/union.has to be a complete select statement"); - static_assert(has_result_row_t>::value, + static_assert(has_result_row::value, "argument of a clause/union.has to be a complete select statement"); + static_assert(has_result_row>::value, "left hand side argument of a clause/union.has to be a complete select statement or union"); using lhs_result_row_t = get_result_row_t>; @@ -152,8 +160,8 @@ namespace sqlpp { static_assert(is_statement_t::value, "argument of union call has to be a statement"); static_assert(has_policy_t::value, "argument of union call has to be a select"); - static_assert(has_result_row_t::value, "argument of a clause/union.has to be a (complete) select statement"); - static_assert(has_result_row_t>::value, + static_assert(has_result_row::value, "argument of a clause/union.has to be a (complete) select statement"); + static_assert(has_result_row>::value, "left hand side argument of a clause/union.has to be a (complete) select statement"); using lhs_result_row_t = get_result_row_t>; diff --git a/include/sqlpp11/core/operator/exists_expression.h b/include/sqlpp11/core/operator/exists_expression.h index 0619ff0a..a17ac58b 100644 --- a/include/sqlpp11/core/operator/exists_expression.h +++ b/include/sqlpp11/core/operator/exists_expression.h @@ -49,7 +49,7 @@ namespace sqlpp }; template - using check_exists_arg = ::sqlpp::enable_if_t::value and has_result_row_t::value>; template struct value_type_of> diff --git a/include/sqlpp11/core/query/statement.h b/include/sqlpp11/core/query/statement.h index 1aa09df9..3f72bb3e 100644 --- a/include/sqlpp11/core/query/statement.h +++ b/include/sqlpp11/core/query/statement.h @@ -126,7 +126,7 @@ namespace sqlpp static constexpr bool _can_be_used_as_table() { #warning: reactivate - return has_result_row_t<_statement_t>::value and /*_required_tables::size::value == 0 and*/ + return has_result_row<_statement_t>::value and /*_required_tables::size::value == 0 and*/ _required_ctes::size::value == 0; } diff --git a/include/sqlpp11/core/type_traits.h b/include/sqlpp11/core/type_traits.h index 7c3b9d8e..2463988a 100644 --- a/include/sqlpp11/core/type_traits.h +++ b/include/sqlpp11/core/type_traits.h @@ -508,24 +508,19 @@ namespace sqlpp using prepare_check_t = typename prepare_check::type; template - struct has_result_row_impl + struct has_result_row: public std::false_type { - using type = std::false_type; }; template - struct has_result_row_impl< + struct has_result_row< Statement, typename std::enable_if< not wrong_t::template _result_row_t>::value, - void>::type> + void>::type>: public std::true_type { - using type = std::true_type; }; - template - using has_result_row_t = typename has_result_row_impl::type; - template struct get_result_row_impl { diff --git a/tests/core/serialize/clause/CMakeLists.txt b/tests/core/serialize/clause/CMakeLists.txt index ed6974f2..14b99ff7 100644 --- a/tests/core/serialize/clause/CMakeLists.txt +++ b/tests/core/serialize/clause/CMakeLists.txt @@ -40,6 +40,7 @@ create_test(insert_set) create_test(limit) create_test(offset) create_test(order_by) +create_test(select) create_test(select_columns) create_test(select_flags) create_test(union) diff --git a/tests/core/serialize/clause/select.cpp b/tests/core/serialize/clause/select.cpp new file mode 100644 index 00000000..cbee8b38 --- /dev/null +++ b/tests/core/serialize/clause/select.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, 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 main(int, char* []) +{ + const auto val = sqlpp::value(17); + const auto expr = sqlpp::value(17) + 4; + + const auto foo = test::TabFoo{}; + + // Empty. + SQLPP_COMPARE(sqlpp::select(), "SELECT "); + + // SELECT a value. + SQLPP_COMPARE(sqlpp::select(expr.as(foo.id)), "SELECT (17 + 4) AS id"); + + // SELECT FROM. + SQLPP_COMPARE(select(foo.id).from(foo).unconditionally(), "SELECT tab_foo.id FROM tab_foo"); + SQLPP_COMPARE(select(foo.id, foo.textNnD).from(foo).unconditionally(), "SELECT tab_foo.id, tab_foo.text_nn_d FROM tab_foo"); + SQLPP_COMPARE(sqlpp::select().columns(foo.id).from(foo).unconditionally(), "SELECT tab_foo.id FROM tab_foo"); + SQLPP_COMPARE(sqlpp::select().flags(sqlpp::all).columns(foo.id).from(foo).unconditionally(), "SELECT ALL tab_foo.id FROM tab_foo"); + + // SELECT FROM WHERE. + SQLPP_COMPARE(select(foo.id).from(foo).where(true), "SELECT tab_foo.id FROM tab_foo WHERE 1"); + SQLPP_COMPARE(select(foo.id).from(foo).where(foo.intN > 17), "SELECT tab_foo.id FROM tab_foo WHERE tab_foo.int_n > 17"); + SQLPP_COMPARE(select(foo.id).from(foo).where(dynamic(false,foo.intN > 17)), "SELECT tab_foo.id FROM tab_foo"); + + // SELECT FROM WHERE GROUP BY HAVING. + SQLPP_COMPARE(select(count(foo.id)).from(foo).where(true).group_by(foo.intN).having(max(foo.id) < 100), "SELECT COUNT(tab_foo.id) FROM tab_foo WHERE 1 GROUP BY tab_foo.int_n HAVING MAX(tab_foo.id) < 100"); + + // SELECT FROM WHERE GROUP BY HAVING ORDER BY LIMIT OFFSET + SQLPP_COMPARE(select(count(foo.id)).from(foo).where(true).group_by(foo.intN).having(max(foo.id) < 100).order_by(foo.intN.asc()).limit(10).offset(3), "SELECT COUNT(tab_foo.id) FROM tab_foo WHERE 1 GROUP BY tab_foo.int_n HAVING MAX(tab_foo.id) < 100 ORDER BY tab_foo.int_n ASC LIMIT 10 OFFSET 3"); + +#warning: If there is group by, does it make sense to order by non-aggregates? Need to add checks for that. +#warning: need to add type tests, including executability + + return 0; +} diff --git a/tests/core/serialize/clause/union.cpp b/tests/core/serialize/clause/union.cpp index c8a08859..7ff655a3 100644 --- a/tests/core/serialize/clause/union.cpp +++ b/tests/core/serialize/clause/union.cpp @@ -42,5 +42,13 @@ int main(int, char* []) .unconditionally() .union_distinct(select(f.id).from(f).unconditionally()), "SELECT tab_bar.id FROM tab_bar UNION DISTINCT SELECT tab_foo.id FROM tab_foo"); + SQLPP_COMPARE(select(t.intN.as(f.id)) + .from(t) + .unconditionally() + .union_distinct(select(f.id).from(f).unconditionally()) + .union_all(select(t.id).from(t).unconditionally()), + "SELECT tab_bar.int_n AS id FROM tab_bar UNION DISTINCT SELECT tab_foo.id FROM tab_foo UNION ALL " + "SELECT tab_bar.id FROM tab_bar"); + return 0; }