mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 12:51:13 +08:00
More tests and cleaner detection for result clause
(that is the clause that determines the result type of the statement)
This commit is contained in:
parent
40d03f5312
commit
b95a23b161
@ -43,7 +43,7 @@ namespace sqlpp
|
||||
|
||||
struct insert_t : public statement_name_t<insert_name_t>
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_return_value>;
|
||||
using _traits = make_traits<no_value_t>;
|
||||
struct _sqlpp_name_tag
|
||||
{
|
||||
};
|
||||
@ -86,6 +86,9 @@ namespace sqlpp
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_result_clause<insert_t> : public std::true_type {};
|
||||
|
||||
template <typename Context>
|
||||
auto to_sql_string(Context& , const insert_name_t&) -> std::string
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace sqlpp
|
||||
};
|
||||
struct remove_t : public statement_name_t<remove_name_t>
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_return_value>;
|
||||
using _traits = make_traits<no_value_t>;
|
||||
struct _sqlpp_name_tag
|
||||
{
|
||||
};
|
||||
@ -85,6 +85,9 @@ namespace sqlpp
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_result_clause<remove_t> : public std::true_type {};
|
||||
|
||||
template <typename Context>
|
||||
auto to_sql_string(Context& , const remove_name_t&) -> std::string
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ namespace sqlpp
|
||||
template <typename... Columns>
|
||||
struct select_traits
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_select_column_list, tag::is_return_value>;
|
||||
using _traits = make_traits<no_value_t, tag::is_select_column_list>;
|
||||
};
|
||||
|
||||
template <typename Column>
|
||||
@ -75,7 +75,6 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<value_type_of_t<Column>,
|
||||
tag::is_select_column_list,
|
||||
tag::is_return_value,
|
||||
tag::is_expression,
|
||||
tag::is_selectable>;
|
||||
};
|
||||
@ -227,6 +226,24 @@ namespace sqlpp
|
||||
{
|
||||
};
|
||||
|
||||
// If a GROUP BY clause defines known aggregate columns or the SELECT columns contain an aggregate function then ALL
|
||||
// columns need to be aggregate.
|
||||
template <typename KnownAggregateColumns, typename... Columns>
|
||||
struct has_correct_aggregates<KnownAggregateColumns, select_column_list_t<Columns...>>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
(detail::type_vector_size<KnownAggregateColumns>::value == 0 and
|
||||
logic::none_t<contains_aggregate_function<remove_dynamic_t<remove_as_t<Columns>>>::value...>::value) or
|
||||
logic::all_t<is_aggregate_expression<KnownAggregateColumns,
|
||||
remove_dynamic_t<remove_as_t<Columns>>>::value...>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename... Columns>
|
||||
struct is_result_clause<select_column_list_t<Columns...>> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename... Columns>
|
||||
struct nodes_of<select_column_list_t<Columns...>>
|
||||
{
|
||||
|
@ -60,7 +60,7 @@ namespace sqlpp
|
||||
template <typename Flag, typename Lhs, typename Rhs>
|
||||
struct union_t
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_union, tag::is_return_value>;
|
||||
using _traits = make_traits<no_value_t, tag::is_union>;
|
||||
using _nodes = detail::type_vector<Lhs, Rhs>;
|
||||
|
||||
using _data_t = union_data_t<Flag, Lhs, Rhs>;
|
||||
@ -91,8 +91,6 @@ namespace sqlpp
|
||||
typename Rhs::_consistency_check>;
|
||||
};
|
||||
|
||||
template <typename Statement>
|
||||
using _result_methods_t = typename Lhs::template _result_methods_t<Statement>;
|
||||
};
|
||||
|
||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_union_args_are_statements_t, "arguments for union() must be statements");
|
||||
|
@ -43,7 +43,7 @@ namespace sqlpp
|
||||
|
||||
struct update_t : public statement_name_t<update_name_t>
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_return_value>;
|
||||
using _traits = make_traits<no_value_t>;
|
||||
struct _sqlpp_name_tag
|
||||
{
|
||||
};
|
||||
@ -86,6 +86,9 @@ namespace sqlpp
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_result_clause<update_t> : public std::true_type {};
|
||||
|
||||
template <typename Context>
|
||||
auto to_sql_string(Context& , const update_name_t&) -> std::string
|
||||
{
|
||||
|
@ -33,22 +33,23 @@ namespace sqlpp
|
||||
namespace detail
|
||||
{
|
||||
template <template <typename> class Predicate, typename Default, typename... T>
|
||||
struct get_last_if_impl;
|
||||
struct get_last_if;
|
||||
|
||||
template <template <typename> class Predicate, typename Default>
|
||||
struct get_last_if_impl<Predicate, Default>
|
||||
struct get_last_if<Predicate, Default>
|
||||
{
|
||||
using type = Default;
|
||||
};
|
||||
|
||||
template <template <typename> class Predicate, typename Default, typename T, typename... Rest>
|
||||
struct get_last_if_impl<Predicate, Default, T, Rest...>
|
||||
struct get_last_if<Predicate, Default, T, Rest...>
|
||||
{
|
||||
using rest = typename get_last_if_impl<Predicate, Default, Rest...>::type;
|
||||
using type = typename std::conditional<std::is_same<rest, Default>::value and Predicate<T>::value, T, rest>::type;
|
||||
using type = typename get_last_if<Predicate,
|
||||
typename std::conditional<Predicate<T>::value, T, Default>::type,
|
||||
Rest...>::type;
|
||||
};
|
||||
|
||||
template <template <typename> class Predicate, typename Default, typename... T>
|
||||
using get_last_if = typename get_last_if_impl<Predicate, Default, T...>::type;
|
||||
using get_last_if_t = typename get_last_if<Predicate, Default, T...>::type;
|
||||
} // namespace detail
|
||||
} // namespace sqlpp
|
||||
|
@ -48,6 +48,11 @@ namespace sqlpp
|
||||
Expr _expr;
|
||||
};
|
||||
|
||||
template <typename KnownAggregateColumns, typename Expr>
|
||||
struct is_aggregate_expression<KnownAggregateColumns, group_by_column<Expr>> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename Expr>
|
||||
struct is_group_by_column<group_by_column<Expr>> : public std::true_type
|
||||
{
|
||||
|
@ -53,6 +53,21 @@ namespace sqlpp
|
||||
|
||||
// No value_type_of or name_tag_of defined for as_expression, to prevent its usage outside of select columns.
|
||||
|
||||
template <typename T>
|
||||
struct remove_as
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename Expression, typename AliasProvider>
|
||||
struct remove_as<as_expression<Expression, AliasProvider>>
|
||||
{
|
||||
using type = Expression;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_as_t = typename remove_as<T>::type;
|
||||
|
||||
template <typename Expression, typename AliasProvider>
|
||||
struct nodes_of<as_expression<Expression, AliasProvider>>
|
||||
{
|
||||
|
@ -54,7 +54,8 @@ namespace sqlpp
|
||||
struct custom_parts_t
|
||||
{
|
||||
using _custom_query_t = custom_query_t<Parts...>;
|
||||
using _maybe_hidden_result_type_provider = detail::get_first_if<is_return_value_t, noop, Parts...>;
|
||||
#warning: This should be get_last_if, I think.
|
||||
using _maybe_hidden_result_type_provider = detail::get_first_if<is_result_clause, noop, Parts...>;
|
||||
using _result_type_provider = typename unhide<_maybe_hidden_result_type_provider>::type;
|
||||
using _result_methods_t = typename _result_type_provider::template _result_methods_t<_result_type_provider>;
|
||||
};
|
||||
|
@ -114,7 +114,7 @@ namespace sqlpp
|
||||
// The common table expressions not covered by the with.
|
||||
using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>;
|
||||
|
||||
using _result_type_provider = detail::get_last_if<is_return_value_t, noop, Policies...>;
|
||||
using _result_type_provider = detail::get_last_if_t<is_result_clause, noop, Policies...>;
|
||||
|
||||
struct _result_methods_t : public _result_type_provider::template _result_methods_t<_statement_t>
|
||||
{
|
||||
@ -203,8 +203,10 @@ namespace sqlpp
|
||||
tag::is_statement,
|
||||
tag_if<tag::is_select, logic::any_t<is_select_t<Policies>::value...>::value>,
|
||||
tag_if<tag::is_expression, is_expression_t<_policies_t>::value>,
|
||||
tag_if<tag::is_selectable, is_expression_t<_policies_t>::value>,
|
||||
tag_if<tag::is_return_value, logic::none_t<is_noop_t<_result_type_provider>::value>::value>>;
|
||||
tag_if<tag::is_selectable, is_expression_t<_policies_t>::value>
|
||||
#warning: reactivate
|
||||
//,tag_if<tag::is_return_value, logic::none_t<is_noop_t<_result_type_provider>::value>::value>
|
||||
>;
|
||||
using _name_tag_of = name_tag_of<_result_type_provider>;
|
||||
using _nodes = detail::type_vector<_policies_t>;
|
||||
using _used_outer_tables = typename _policies_t::_all_provided_outer_tables;
|
||||
|
@ -222,7 +222,6 @@ namespace sqlpp
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_cte)
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_noop)
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_missing)
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table)
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_pre_join)
|
||||
SQLPP_VALUE_TRAIT_GENERATOR(is_join)
|
||||
@ -590,4 +589,7 @@ namespace sqlpp
|
||||
|
||||
template <typename Db>
|
||||
using serializer_context_of = typename serializer_context_of_impl<Db>::type;
|
||||
|
||||
template<typename T>
|
||||
struct is_result_clause : public std::false_type {};
|
||||
} // namespace sqlpp
|
||||
|
@ -80,5 +80,11 @@ namespace sqlpp
|
||||
{
|
||||
};
|
||||
|
||||
// If a GROUP BY clause defines known aggregate columns or the SELECT columns contain an aggregate function then ALL
|
||||
// columns need to be aggregate.
|
||||
// SELECT-like clauses will need to specialize this.
|
||||
template <typename KnownAggregateColumns, typename T>
|
||||
struct has_correct_aggregates : public std::true_type {};
|
||||
|
||||
} // namespace sqlpp11
|
||||
|
||||
|
@ -49,7 +49,7 @@ namespace sqlpp
|
||||
template <typename InsertOrAlternative>
|
||||
struct insert_or_t : public statement_name_t<InsertOrAlternative>
|
||||
{
|
||||
using _traits = make_traits<no_value_t, tag::is_return_value>;
|
||||
using _traits = make_traits<no_value_t>;
|
||||
struct _sqlpp_name_tag
|
||||
{
|
||||
};
|
||||
@ -78,6 +78,9 @@ namespace sqlpp
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_result_clause<insert_or_t> : public std::true_type {};
|
||||
|
||||
template <typename InsertOrAlternative>
|
||||
using blank_insert_or_t =
|
||||
statement_t<insert_or_t<InsertOrAlternative>, no_into_t, no_insert_value_list_t>;
|
||||
|
@ -38,4 +38,5 @@ test_compile(value)
|
||||
add_subdirectory(aggregate_function)
|
||||
add_subdirectory(operator)
|
||||
add_subdirectory(clause)
|
||||
add_subdirectory(detail)
|
||||
add_subdirectory(type_traits)
|
||||
|
@ -46,12 +46,21 @@ void test_select_columns()
|
||||
{
|
||||
auto v = sqlpp::value("text");
|
||||
auto col_int = test::TabFoo{}.id;
|
||||
auto col_txt = test::TabFoo{}.textNnD;
|
||||
|
||||
using unknown = sqlpp::detail::type_vector<>;
|
||||
using knownInt = sqlpp::detail::type_vector<decltype(col_int)>;
|
||||
using knownTxt = sqlpp::detail::type_vector<decltype(col_txt)>;
|
||||
|
||||
// Single column
|
||||
{
|
||||
using T = clause_of_t<decltype(select_columns(col_int))>;
|
||||
static_assert(std::is_same<sqlpp::name_tag_of_t<T>, test::TabFoo_::Id::_sqlpp_name_tag>::value, "");
|
||||
static_assert(std::is_same<sqlpp::value_type_of_t<T>, sqlpp::integral>::value, "");
|
||||
static_assert(sqlpp::is_result_clause<T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<unknown, T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<knownInt, T>::value, "");
|
||||
static_assert(not sqlpp::has_correct_aggregates<knownTxt, T>::value, "");
|
||||
}
|
||||
|
||||
// Single dynamic column
|
||||
@ -59,6 +68,10 @@ void test_select_columns()
|
||||
using T = clause_of_t<decltype(select_columns(dynamic(true, col_int)))>;
|
||||
static_assert(std::is_same<sqlpp::name_tag_of_t<T>, test::TabFoo_::Id::_sqlpp_name_tag>::value, "");
|
||||
static_assert(std::is_same<sqlpp::value_type_of_t<T>, sqlpp::optional<sqlpp::integral>>::value, "");
|
||||
static_assert(sqlpp::is_result_clause<T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<unknown, T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<knownInt, T>::value, "");
|
||||
static_assert(not sqlpp::has_correct_aggregates<knownTxt, T>::value, "");
|
||||
}
|
||||
|
||||
// Single declared group by column
|
||||
@ -66,6 +79,10 @@ void test_select_columns()
|
||||
using T = clause_of_t<decltype(select_columns(declare_group_by_column(v).as(cheese)))>;
|
||||
static_assert(std::is_same<sqlpp::name_tag_of_t<T>, cheese_t::_sqlpp_name_tag>::value, "");
|
||||
static_assert(std::is_same<sqlpp::value_type_of_t<T>, sqlpp::text>::value, "");
|
||||
static_assert(sqlpp::is_result_clause<T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<unknown, T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<knownInt, T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<knownTxt, T>::value, "");
|
||||
}
|
||||
|
||||
// Single dynamic declared group by column
|
||||
@ -73,6 +90,10 @@ void test_select_columns()
|
||||
using T = clause_of_t<decltype(select_columns(dynamic(true, declare_group_by_column(v)).as(cheese)))>;
|
||||
static_assert(std::is_same<sqlpp::name_tag_of_t<T>, cheese_t::_sqlpp_name_tag>::value, "");
|
||||
static_assert(std::is_same<sqlpp::value_type_of_t<T>, sqlpp::optional<sqlpp::text>>::value, "");
|
||||
static_assert(sqlpp::is_result_clause<T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<unknown, T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<knownInt, T>::value, "");
|
||||
static_assert(sqlpp::has_correct_aggregates<knownTxt, T>::value, "");
|
||||
}
|
||||
|
||||
#warning: add actual tests here
|
||||
|
32
tests/core/types/detail/CMakeLists.txt
Normal file
32
tests/core/types/detail/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
# 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.
|
||||
|
||||
function(test_compile name)
|
||||
set(target sqlpp11_core_types_clause_${name})
|
||||
add_executable(${target} ${name}.cpp)
|
||||
target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing)
|
||||
endfunction()
|
||||
|
||||
test_compile(get_last_if)
|
||||
|
54
tests/core/types/detail/get_last_if.cpp
Normal file
54
tests/core/types/detail/get_last_if.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <sqlpp11/sqlpp11.h>
|
||||
|
||||
void test_get_last_if()
|
||||
{
|
||||
auto v = sqlpp::value("text");
|
||||
auto col_int = test::TabFoo{}.id;
|
||||
|
||||
// Ending on a matching type
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop>, sqlpp::noop>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int>, int>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, float, long>, long>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, float, long, short>, short>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, float, long, short, size_t>, short>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_numeric, sqlpp::noop, int, float, long, short, size_t>, size_t>::value, "");
|
||||
|
||||
// Ending on a non-matching type
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, double>, sqlpp::noop>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, double>, int>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, float, double>, int>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, float, long, double>, long>::value, "");
|
||||
static_assert(std::is_same<sqlpp::detail::get_last_if_t<sqlpp::is_integral, sqlpp::noop, int, float, long, short, double>, short>::value, "");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
void test_get_last_if();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user