0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 04:47:18 +08:00

more tests and more clarity for aggregates

This commit is contained in:
Roland Bock 2024-08-15 09:30:21 +02:00
parent dc38a81a8c
commit 843e39b3d0
12 changed files with 166 additions and 185 deletions

View File

@ -27,6 +27,16 @@ The library now offers `is_distinct_from` and `is_not_distinct_from` which safel
# Selecting aggregate functions
The automatic name for selected aggregate functions drops the `_`.
# Aggregates and non-aggregates
They must not be mixed in a select.
`group_by` accepts columns only (there is an escape hatch: `group_by_column`)
`select` requires either
- all selected columns are aggregate expressions (either an aggregate function or a group by column), or
- no selected column is an aggregate expression
If group_by is specified in the select, then all columns have to be aggregate expressions.
# Dynamic queries
We don't always have a completely fixed structure for our queries. For instance, there might columns that we only want to select under certain circumstances. In version 1.0, this was handled by dynamic queries. Now we introduce conditional query parts that may or may not be used at runtime:

View File

@ -63,12 +63,7 @@ namespace sqlpp
};
template <typename Flag, typename Expr>
struct contains_aggregate_function<avg_t<Flag, Expr>> : public std::true_type
{
};
template <typename Flag, typename Expr>
struct contains_non_aggregate<avg_t<Flag, Expr>> : public std::false_type
struct is_aggregate_function<avg_t<Flag, Expr>> : public std::true_type
{
};

View File

@ -63,12 +63,7 @@ namespace sqlpp
};
template <typename Flag, typename Expr>
struct contains_aggregate_function<count_t<Flag, Expr>> : public std::true_type
{
};
template <typename Flag, typename Expr>
struct contains_non_aggregate<count_t<Flag, Expr>> : public std::false_type
struct is_aggregate_function<count_t<Flag, Expr>> : public std::true_type
{
};

View File

@ -62,12 +62,7 @@ namespace sqlpp
};
template <typename Flag, typename Expr>
struct contains_aggregate_function<max_t<Flag, Expr>> : public std::true_type
{
};
template <typename Flag, typename Expr>
struct contains_non_aggregate<max_t<Flag, Expr>> : public std::false_type
struct is_aggregate_function<max_t<Flag, Expr>> : public std::true_type
{
};

View File

@ -62,12 +62,7 @@ namespace sqlpp
};
template <typename Flag, typename Expr>
struct contains_aggregate_function<min_t<Flag, Expr>> : public std::true_type
{
};
template <typename Flag, typename Expr>
struct contains_non_aggregate<min_t<Flag, Expr>> : public std::false_type
struct is_aggregate_function<min_t<Flag, Expr>> : public std::true_type
{
};

View File

@ -62,7 +62,7 @@ namespace sqlpp
struct value_type_of<over_t<Expr>>: public value_type_of<Expr> {};
template<typename Expr>
using check_over_args = ::sqlpp::enable_if_t<contains_aggregate_function<Expr>::value>;
using check_over_args = ::sqlpp::enable_if_t<is_aggregate_function<Expr>::value>;
template <typename Context, typename Expr>
auto to_sql_string(Context& context, const over_t<Expr>& t) -> std::string

View File

@ -62,12 +62,7 @@ namespace sqlpp
};
template <typename Flag, typename Expr>
struct contains_aggregate_function<sum_t<Flag, Expr>> : public std::true_type
{
};
template <typename Flag, typename Expr>
struct contains_non_aggregate<sum_t<Flag, Expr>> : public std::false_type
struct is_aggregate_function<sum_t<Flag, Expr>> : public std::true_type
{
};

View File

@ -85,9 +85,6 @@ namespace sqlpp
}
};
template<typename Table, typename ColumnSpec>
struct contains_non_aggregate<column_t<Table, ColumnSpec>> : public std::true_type {};
template<typename Table, typename ColumnSpec>
struct value_type_of<column_t<Table, ColumnSpec>>
{

View File

@ -62,8 +62,6 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_group_by>;
using _nodes = detail::type_vector<Expressions...>;
using _provided_aggregates = detail::make_type_set_t<Expressions...>;
using _data_t = group_by_data_t<Expressions...>;
// Base template to be inherited by the statement
@ -82,8 +80,14 @@ namespace sqlpp
};
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_group_by_args_have_values_t,
"all arguments for group_by() must have values");
template <typename... Expressions>
struct known_aggregate_expressions_of<group_by_t<Expressions...>>
{
using type = detail::type_vector<Expressions...>;
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_group_by_args_have_values_t, "all arguments for group_by() must have values");
template <typename... Exprs>
struct check_group_by
{
@ -118,6 +122,7 @@ namespace sqlpp
using _consistency_check = consistent_t;
#warning: Arguments should not be constants and not contain aggregate functions
template <typename... Expressions>
auto group_by(Expressions... expressions) const
-> _new_statement_t<check_group_by_t<Expressions...>, group_by_t<Expressions...>>

View File

@ -55,8 +55,9 @@ namespace sqlpp
// No value_type_of or name_tag_of defined for dynamic_t, to prevent its usage outside of select columns.
template <typename Expr>
struct nodes_of<dynamic_t<Expr>> : public nodes_of<Expr>
struct nodes_of<dynamic_t<Expr>>
{
using type = Expr;
};
template <typename T>

View File

@ -32,47 +32,51 @@
namespace sqlpp
{
// Finds calls to aggregate functions (avg, count, max, min, sum).
// We don't want to mix aggregate and non-aggregate expressions as the results are unspecified.
// Aggregates are either results of aggregate functions or GROUP BY columns.
// Non-aggregates are columns (unless they are aggregate expressions).
// Constant values are neutral.
template <typename T>
struct contains_aggregate_function : public std::integral_constant<bool, contains_aggregate_function<nodes_of_t<T>>::value>
struct is_aggregate_function : public std::false_type
{
};
// Finds calls to aggregate functions (avg, count, max, min, sum) in expressions.
// This is important as aggregated functions must not be nested.
template <typename T>
struct contains_aggregate_function
: public std::integral_constant<bool,
is_aggregate_function<T>::value or
contains_aggregate_function<nodes_of_t<T>>::value>
{
};
template <typename... T>
struct contains_aggregate_function<detail::type_vector<T...>>
: public std::integral_constant<bool, logic::any_t<contains_aggregate_function<T>::value...>::value>
{
};
// Finds group_by expression.
// @GroupByExpressions: type_vector
template <typename GroupByExpressions, typename T>
struct contains_aggregate_expression
: public std::integral_constant<bool,
GroupByExpressions::template contains<T>::value or
contains_aggregate_expression<GroupByExpressions, nodes_of_t<T>>::value>
{
};
template <typename GroupByExpressions, typename... T>
struct contains_aggregate_expression<GroupByExpressions, detail::type_vector<T...>>
: public std::integral_constant<
bool,
logic::any_t<(GroupByExpressions::template contains<T>::value or
contains_aggregate_expression<GroupByExpressions, T>::value)...>::value>
logic::any_t<(is_aggregate_function<T>::value or contains_aggregate_function<T>::value)...>::value>
{
};
// Finds columns.
// Note that explicit values like `value(7)` are compatible with both aggregate and non-aggregate.
// Obtain known aggregate expressions, i.e. GROUP BY columns.
template <typename T>
struct contains_non_aggregate : public std::integral_constant<bool, contains_non_aggregate<nodes_of_t<T>>::value>
struct known_aggregate_expressions_of
{
using type = detail::type_vector<>;
};
template <typename... T>
struct contains_non_aggregate<detail::type_vector<T...>>
: public std::integral_constant<bool, logic::any_t<contains_non_aggregate<T>::value...>::value>
template <typename T>
using known_aggregate_expressions_of_t = typename known_aggregate_expressions_of<T>::type;
// Checks if T is an aggregate expression (either an aggregate function or a known aggregate).
// @KnownAggregateExpressions: type_vector as obtained through known_aggregate_expressions_of_t
template <typename KnownAggregateExpressions, typename T>
struct is_aggregate_expression
: public std::integral_constant<bool,
is_aggregate_function<T>::value or
KnownAggregateExpressions::template contains<T>::value>
{
};

View File

@ -28,6 +28,65 @@
SQLPP_ALIAS_PROVIDER(cheese);
void test_is_aggregate_function()
{
auto v = sqlpp::value(17);
auto t = sqlpp::value("");
auto col_int = test::TabFoo{}.id;
auto col_txt = test::TabFoo{}.textNnD;
// Constant values are neutral and therefore considered neither aggregate and non-aggregate.
static_assert(not sqlpp::is_aggregate_function<decltype(v)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(v + v)>::value, "");
// Columns are not aggregate functions
static_assert(not sqlpp::is_aggregate_function<decltype(col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(col_int + v)>::value, "");
// Normal functions of values or non-aggregates do not contain aggregate functions.
static_assert(not sqlpp::is_aggregate_function<decltype(trim(t))>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(trim(col_txt))>::value, "");
// Aggregate functions of non-aggregates and values are aggregate functions :-)
static_assert(sqlpp::is_aggregate_function<decltype(avg(v))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(count(v))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(min(v))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(max(v))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(sum(v))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(avg(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(count(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(min(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(max(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(sum(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_function<decltype(max(trim(col_txt)))>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(trim(upper(lower(max(col_txt)))) + trim(col_txt))>::value, "");
// Expressions containing aggregate functions are not aggregate functions.
static_assert(not sqlpp::is_aggregate_function<decltype(avg(col_int) + v)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(count(col_int) + v)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(min(col_int) + v)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(max(col_int) + v)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(sum(col_int) + v)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(trim(max(col_txt)))>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(avg(col_int) + col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(count(col_int) + col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(min(col_int) + col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(max(col_int) + col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(sum(col_int) + col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(max(trim(col_txt)) + trim(col_txt))>::value, "");
// Clauses do not expose aggregates functions.
static_assert(not sqlpp::is_aggregate_function<decltype(where(col_int > v))>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(select_columns(v.as(cheese), col_int))>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(select_columns(max(col_int), v.as(cheese), col_int))>::value, "");
static_assert(not sqlpp::is_aggregate_function<decltype(select_columns(dynamic(true, max(col_int)), v.as(cheese), col_int))>::value, "");
}
void test_contains_aggregate_function()
{
auto v = sqlpp::value(17);
@ -35,7 +94,7 @@ void test_contains_aggregate_function()
auto col_int = test::TabFoo{}.id;
auto col_txt = test::TabFoo{}.textNnD;
// Values are aggregate neutral and therefore considered neither aggregate and non-aggregate context.
// Constant values are neutral and therefore considered neither aggregate and non-aggregate.
static_assert(not sqlpp::contains_aggregate_function<decltype(v)>::value, "");
static_assert(not sqlpp::contains_aggregate_function<decltype(v + v)>::value, "");
@ -48,11 +107,11 @@ void test_contains_aggregate_function()
static_assert(not sqlpp::contains_aggregate_function<decltype(trim(col_txt))>::value, "");
// Aggregate functions of non-aggregates and values contain aggregate functions.
static_assert(not sqlpp::contains_non_aggregate<decltype(avg(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(count(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(min(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(max(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(sum(v))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(avg(v))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(count(v))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(min(v))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(max(v))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(sum(v))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(avg(col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(count(col_int))>::value, "");
@ -79,140 +138,70 @@ void test_contains_aggregate_function()
static_assert(sqlpp::contains_aggregate_function<decltype(trim(upper(lower(max(col_txt)))) + trim(col_txt))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(max(trim(col_txt)) + trim(col_txt))>::value, "");
// Clauses expose non-aggregates (probably irrelevant)
// Clauses expose non-aggregates.
static_assert(not sqlpp::contains_aggregate_function<decltype(where(col_int > v))>::value, "");
static_assert(not sqlpp::contains_aggregate_function<decltype(select_columns(v.as(cheese), col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(select_columns(max(col_int), v.as(cheese), col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_function<decltype(select_columns(dynamic(true, max(col_int)), v.as(cheese), col_int))>::value, "");
}
void test_contains_aggregate_expression()
void test_is_aggregate_expression()
{
auto v_not_null = sqlpp::value(17);
auto v = sqlpp::value(17);
auto t = sqlpp::value("");
auto col_int = test::TabFoo{}.id;
auto col_txt = test::TabFoo{}.textNnD;
auto agg_int = test::TabFoo{}.id;
auto agg_txt = test::TabFoo{}.textNnD;
auto col_int = test::TabBar{}.id;
auto col_txt = test::TabBar{}.textN;
using known_aggregates = sqlpp::detail::type_vector<decltype(v), decltype(col_txt), decltype(col_int + v)>;
using unknown = sqlpp::detail::type_vector<>;
using known_aggregates = sqlpp::detail::type_vector<decltype(agg_txt), decltype(agg_int)>;
// ...
static_assert(sqlpp::contains_aggregate_expression<known_aggregates, decltype(v)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<known_aggregates, decltype(v + v)>::value, "");
// If there are no known aggregate expressions, then only aggregate functions will be found.
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(v)>::value, "");
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(v + v)>::value, "");
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(col_int)>::value, "");
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(col_txt)>::value, "");
static_assert(sqlpp::is_aggregate_expression<unknown, decltype(count(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_expression<unknown, decltype(count(col_txt))>::value, "");
static_assert(sqlpp::is_aggregate_expression<unknown, decltype(max(v))>::value, "");
static_assert(sqlpp::is_aggregate_expression<unknown, decltype(max(col_int))>::value, "");
static_assert(sqlpp::is_aggregate_expression<unknown, decltype(max(col_txt))>::value, "");
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(dynamic(true, max(v)))>::value, "");
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(dynamic(true, max(col_int)))>::value, "");
static_assert(not sqlpp::is_aggregate_expression<unknown, decltype(dynamic(true, max(col_txt)))>::value, "");
// ...
static_assert(not sqlpp::contains_aggregate_expression<unknown, decltype(v)>::value, "");
static_assert(not sqlpp::contains_aggregate_expression<unknown, decltype(v + v)>::value, "");
// Known aggregate expressions are detected as such.
static_assert(sqlpp::is_aggregate_expression<known_aggregates, decltype(agg_int)>::value, "");
static_assert(sqlpp::is_aggregate_expression<known_aggregates, decltype(agg_txt)>::value, "");
#warning: activate
#if 0
// Columns are non-aggregates.
static_assert(not sqlpp::contains_aggregate_expression<decltype(col_int)>::value, "");
static_assert(not sqlpp::contains_aggregate_expression<decltype(col_int + v)>::value, "");
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(dynamic(true, agg_int))>::value, "");
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(dynamic(true, agg_txt))>::value, "");
// Normal expressions of values or non-aggregates do not contain aggregate functions.
static_assert(not sqlpp::contains_aggregate_expression<decltype(trim(t))>::value, "");
static_assert(not sqlpp::contains_aggregate_expression<decltype(trim(col_txt))>::value, "");
// Known aggregate expressions are not detected as such in expressions.
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(agg_int + 17)>::value, "");
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(17 + agg_int)>::value, "");
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(agg_txt.like("%"))>::value, "");
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype((agg_int + v).between(1, 10))>::value, "");
// Aggregate expressions of non-aggregates contain aggregate functions.
static_assert(not sqlpp::contains_aggregate_expressions<decltype(avg(v))>::value, "");
static_assert(not sqlpp::contains_aggregate_expressions<decltype(count(v))>::value, "");
static_assert(not sqlpp::contains_aggregate_expressions<decltype(min(v))>::value, "");
static_assert(not sqlpp::contains_aggregate_expressions<decltype(max(v))>::value, "");
static_assert(not sqlpp::contains_aggregate_expressions<decltype(sum(v))>::value, "");
// Known aggregate expressions are not detected as such in aggregate functions.
static_assert(sqlpp::is_aggregate_expression<known_aggregates, decltype(max(agg_int + 17))>::value, "");
static_assert(sqlpp::is_aggregate_expression<known_aggregates, decltype(max(17 + agg_int))>::value, "");
static_assert(sqlpp::is_aggregate_expression<known_aggregates, decltype(count(agg_txt.like("%")))>::value, "");
static_assert(sqlpp::is_aggregate_expression<known_aggregates, decltype(count((agg_int + v).between(1, 10)))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(avg(col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(count(col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(min(col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(max(col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(sum(col_int))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(avg(col_int) + v)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(count(col_int) + v)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(min(col_int) + v)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(max(col_int) + v)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(sum(col_int) + v)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(trim(max(col_txt)))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(max(trim(col_txt)))>::value, "");
// Expressions of aggregate expressions and non-aggregates contain aggregate functions.
static_assert(sqlpp::contains_aggregate_expression<decltype(avg(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(count(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(min(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(max(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(sum(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(trim(upper(lower(max(col_txt)))) + trim(col_txt))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(max(trim(col_txt)) + trim(col_txt))>::value, "");
// Clauses expose non-aggregates (probably irrelevant)
static_assert(not sqlpp::contains_aggregate_expression<decltype(where(col_int > v))>::value, "");
static_assert(sqlpp::contains_aggregate_expression<decltype(select_columns(max(col_int), v.as(cheese), col_int))>::value, "");
#endif
}
void test_contains_non_aggregate()
{
auto v = sqlpp::value(17);
auto t = sqlpp::value("");
auto col_int = test::TabFoo{}.id;
auto col_txt = test::TabFoo{}.textNnD;
// Values are aggregate neutral and therefore considered neither aggregate and non-aggregate context.
static_assert(not sqlpp::contains_non_aggregate<decltype(v)>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(v + v)>::value, "");
// Columns are non-aggregates.
static_assert(sqlpp::contains_non_aggregate<decltype(col_int)>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(col_int + v)>::value, "");
// Functions can contain non-aggregates.
static_assert(not sqlpp::contains_non_aggregate<decltype(trim(t))>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(trim(col_txt))>::value, "");
// Aggregate functions of non-aggregates and values are aggregate functions.
static_assert(not sqlpp::contains_non_aggregate<decltype(avg(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(count(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(min(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(max(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(sum(v))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(avg(col_int))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(count(col_int))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(min(col_int))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(max(col_int))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(sum(col_int))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(avg(col_int) + v)>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(count(col_int) + v)>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(min(col_int) + v)>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(max(col_int) + v)>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(sum(col_int) + v)>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(trim(max(col_txt)))>::value, "");
static_assert(not sqlpp::contains_non_aggregate<decltype(max(trim(col_txt)))>::value, "");
// Expressions of aggregate functions and non-aggregates contain non-aggregates.
static_assert(sqlpp::contains_non_aggregate<decltype(avg(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(count(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(min(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(max(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(sum(col_int) + col_int)>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(trim(max(col_txt)) + trim(col_txt))>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(max(trim(col_txt)) + trim(col_txt))>::value, "");
// Clauses expose non-aggregates (probably irrelevant)
static_assert(sqlpp::contains_non_aggregate<decltype(where(col_int > v))>::value, "");
static_assert(sqlpp::contains_non_aggregate<decltype(select_columns(max(col_int), v.as(cheese), col_int))>::value, "");
// Known aggregate expressions are not exposed as such by clauses.
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(select(agg_txt))>::value, "");
static_assert(not sqlpp::is_aggregate_expression<known_aggregates, decltype(select(agg_int))>::value, "");
}
int main()
{
void test_is_aggregate_function();
void test_contains_aggregate_function();
void test_contains_aggregate_expression();
void test_contains_non_aggregate();
void test_is_aggregate_expression();
}