mirror of
https://github.com/rbock/sqlpp11.git
synced 2026-01-03 11:40:39 -06:00
Merge branch 'feature/detect_mixing_aggreage_non_aggregate' into develop
This commit is contained in:
@@ -60,6 +60,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<floating_point, tag::is_expression, tag::is_selectable>;
|
||||
using _nodes = detail::type_vector<Expr, aggregate_function>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
static_assert(is_noop<Flag>::value or std::is_same<distinct_t, Flag>::value,
|
||||
"avg() used with flag other than 'distinct'");
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace sqlpp
|
||||
using _traits = make_traits<integral, tag::is_expression /*, tag::is_selectable*/>;
|
||||
|
||||
using _nodes = detail::type_vector<Expr, aggregate_function>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
using _can_be_null = std::false_type;
|
||||
|
||||
static_assert(is_noop<Flag>::value or std::is_same<distinct_t, Flag>::value,
|
||||
|
||||
@@ -75,6 +75,9 @@ namespace sqlpp
|
||||
using _nodes = detail::type_vector<Expressions...>;
|
||||
|
||||
using _is_dynamic = is_database<Database>;
|
||||
using _provided_aggregates = typename std::conditional<_is_dynamic::value,
|
||||
detail::type_set<>,
|
||||
detail::make_type_set_t<Expressions...>>::type;
|
||||
|
||||
// Data
|
||||
using _data_t = group_by_data_t<Database, Expressions...>;
|
||||
|
||||
@@ -39,14 +39,14 @@ namespace sqlpp
|
||||
|
||||
// see http://lists.boost.org/Archives/boost/2014/05/212946.php :-)
|
||||
template <bool... B>
|
||||
using all_t = std::is_same<logic_helper<B...>, logic_helper<(B, true)...>>;
|
||||
using all_t = std::is_same<logic_helper<B...>, logic_helper<(B or true)...>>;
|
||||
|
||||
template <bool... B>
|
||||
using any_t =
|
||||
std::integral_constant<bool, not std::is_same<logic_helper<B...>, logic_helper<(B, false)...>>::value>;
|
||||
std::integral_constant<bool, not std::is_same<logic_helper<B...>, logic_helper<(B and false)...>>::value>;
|
||||
|
||||
template <bool... B>
|
||||
using none_t = std::is_same<logic_helper<B...>, logic_helper<(B, false)...>>;
|
||||
using none_t = std::is_same<logic_helper<B...>, logic_helper<(B or false)...>>;
|
||||
|
||||
template <bool>
|
||||
struct not_impl;
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<value_type_of<Expr>, tag::is_expression, tag::is_selectable>;
|
||||
using _nodes = detail::type_vector<Expr, aggregate_function>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
using _auto_alias_t = max_alias_t;
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<value_type_of<Expr>, tag::is_expression, tag::is_selectable>;
|
||||
using _nodes = detail::type_vector<Expr, aggregate_function>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
using _auto_alias_t = min_alias_t;
|
||||
|
||||
|
||||
@@ -168,6 +168,17 @@ namespace sqlpp
|
||||
}
|
||||
};
|
||||
|
||||
struct assert_aggregates_t
|
||||
{
|
||||
using type = std::false_type;
|
||||
|
||||
template <typename T = void>
|
||||
static void _()
|
||||
{
|
||||
static_assert(wrong_t<T>::value, "not all columns are made of aggregates, despite group_by or similar");
|
||||
}
|
||||
};
|
||||
|
||||
// SELECTED COLUMNS
|
||||
template <typename Database, typename... Columns>
|
||||
struct select_column_list_t
|
||||
@@ -262,10 +273,16 @@ namespace sqlpp
|
||||
return t.selected_columns;
|
||||
}
|
||||
|
||||
using _consistency_check =
|
||||
using _column_check =
|
||||
typename std::conditional<Policies::template _no_unknown_tables<select_column_list_t>::value,
|
||||
consistent_t,
|
||||
assert_no_unknown_tables_in_selected_columns_t>::type;
|
||||
|
||||
using _aggregate_check = typename std::conditional<Policies::template _no_unknown_aggregates<Columns...>::value,
|
||||
consistent_t,
|
||||
assert_aggregates_t>::type;
|
||||
|
||||
using _consistency_check = detail::get_first_if<is_inconsistent_t, consistent_t, _column_check, _aggregate_check>;
|
||||
};
|
||||
|
||||
// Result methods
|
||||
|
||||
@@ -103,12 +103,18 @@ namespace sqlpp
|
||||
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of<Policies>...>;
|
||||
using _all_provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Policies>...>;
|
||||
using _all_extra_tables = detail::make_joined_set_t<extra_tables_of<Policies>...>;
|
||||
using _all_provided_aggregates = detail::make_joined_set_t<provided_aggregates_of<Policies>...>;
|
||||
|
||||
using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>;
|
||||
|
||||
template <typename Expression>
|
||||
using _no_unknown_tables = detail::is_subset_of<required_tables_of<Expression>, _known_tables>;
|
||||
|
||||
template <typename... Expressions>
|
||||
using _no_unknown_aggregates =
|
||||
logic::any_t<_all_provided_aggregates::size::value == 0,
|
||||
logic::all_t<is_aggregate_expression_t<_all_provided_aggregates, Expressions>::value...>::value>;
|
||||
|
||||
template <template <typename> class Predicate>
|
||||
using any_t = logic::any_t<Predicate<Policies>::value...>;
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<value_type_of<Expr>, tag::is_expression, tag::is_selectable>;
|
||||
using _nodes = detail::type_vector<Expr, aggregate_function>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
static_assert(is_noop<Flag>::value or std::is_same<distinct_t, Flag>::value,
|
||||
"sum() used with flag other than 'distinct'");
|
||||
|
||||
@@ -195,6 +195,7 @@ namespace sqlpp
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_tables)
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_outer_tables)
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(extra_tables)
|
||||
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates)
|
||||
|
||||
#define SQLPP_RECURSIVE_TRAIT_GENERATOR(trait) \
|
||||
namespace detail \
|
||||
@@ -221,6 +222,38 @@ namespace sqlpp
|
||||
SQLPP_RECURSIVE_TRAIT_GENERATOR(can_be_null)
|
||||
SQLPP_RECURSIVE_TRAIT_GENERATOR(contains_aggregate_function)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename KnownAggregates, typename T, typename Leaf = void>
|
||||
struct is_aggregate_expression_impl
|
||||
{
|
||||
using type = typename is_aggregate_expression_impl<KnownAggregates, typename T::_nodes>::type;
|
||||
};
|
||||
template <typename KnownAggregates, typename T>
|
||||
struct is_aggregate_expression_impl<
|
||||
KnownAggregates,
|
||||
T,
|
||||
typename std::enable_if<std::is_class<typename T::_is_aggregate_expression>::value>::type>
|
||||
{
|
||||
using type = typename T::_is_aggregate_expression;
|
||||
};
|
||||
template <typename KnownAggregates, typename T>
|
||||
struct is_aggregate_expression_impl<KnownAggregates,
|
||||
T,
|
||||
typename std::enable_if<detail::is_element_of<T, KnownAggregates>::value>::type>
|
||||
{
|
||||
using type = std::true_type;
|
||||
};
|
||||
template <typename KnownAggregates, typename... Nodes>
|
||||
struct is_aggregate_expression_impl<KnownAggregates, type_vector<Nodes...>, void>
|
||||
{
|
||||
using type =
|
||||
logic::all_t<sizeof...(Nodes) != 0, is_aggregate_expression_impl<KnownAggregates, Nodes>::type::value...>;
|
||||
};
|
||||
}
|
||||
template <typename KnownAggregates, typename T>
|
||||
using is_aggregate_expression_t = typename detail::is_aggregate_expression_impl<KnownAggregates, T>::type;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename Leaf = void>
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<boolean, tag::is_expression, tag::is_wrapped_value>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
using _value_t = bool;
|
||||
|
||||
@@ -86,6 +87,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<integral, tag::is_expression, tag::is_wrapped_value>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
using _value_t = int64_t;
|
||||
|
||||
@@ -128,6 +130,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<floating_point, tag::is_expression, tag::is_wrapped_value>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
using _value_t = double;
|
||||
|
||||
@@ -170,6 +173,7 @@ namespace sqlpp
|
||||
{
|
||||
using _traits = make_traits<text, tag::is_expression, tag::is_wrapped_value>;
|
||||
using _nodes = detail::type_vector<>;
|
||||
using _is_aggregate_expression = std::true_type;
|
||||
|
||||
using _value_t = std::string;
|
||||
|
||||
|
||||
110
tests/Aggregates.cpp
Normal file
110
tests/Aggregates.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015, 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 <iostream>
|
||||
#include "Sample.h"
|
||||
#include "MockDb.h"
|
||||
#include <sqlpp11/alias_provider.h>
|
||||
#include <sqlpp11/select.h>
|
||||
#include <sqlpp11/functions.h>
|
||||
#include <sqlpp11/connection.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
template <typename T>
|
||||
void print_type_on_error(std::true_type, const T&)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void print_type_on_error(std::false_type, const T& t)
|
||||
{
|
||||
t._print_me_;
|
||||
}
|
||||
|
||||
template <typename Assert, typename Expression>
|
||||
void run_check(const Expression&)
|
||||
{
|
||||
using Context = MockDb::_serializer_context_t;
|
||||
using CheckResult = std::is_same<sqlpp::run_check_t<Context, Expression>, Assert>;
|
||||
static_assert(CheckResult::value, "Unexpected run_check result");
|
||||
print_type_on_error(CheckResult{}, sqlpp::run_check_t<Context, Expression>{});
|
||||
}
|
||||
|
||||
template <typename Expression>
|
||||
void run_check(const Expression&)
|
||||
{
|
||||
using Context = MockDb::_serializer_context_t;
|
||||
using CheckResult = std::is_same<sqlpp::run_check_t<Context, Expression>, consistent_t>;
|
||||
static_assert(CheckResult::value, "Unexpected run_check result");
|
||||
print_type_on_error(CheckResult{}, sqlpp::run_check_t<Context, Expression>{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SQLPP_ALIAS_PROVIDER(whatever);
|
||||
|
||||
int Aggregates(int, char**)
|
||||
{
|
||||
using sqlpp::test::run_check;
|
||||
|
||||
// test::TabFoo f;
|
||||
test::TabBar t;
|
||||
|
||||
// If there is no group_by, we can select whatever we want
|
||||
run_check(select(all_of(t)).from(t).where(true));
|
||||
run_check(select(t.alpha).from(t).where(true));
|
||||
run_check(select(count(t.alpha)).from(t).where(true));
|
||||
|
||||
// If there is a static group_by, selected columns must be made of group_by expressions, or aggregate expression (e.g.
|
||||
// count(t.id)) or values to be valid
|
||||
run_check(select(t.alpha).from(t).where(true).group_by(t.alpha));
|
||||
run_check(select((t.alpha + 42).as(whatever)).from(t).where(true).group_by(t.alpha));
|
||||
run_check(select((t.alpha + 42).as(whatever)).from(t).where(true).group_by(t.alpha, t.alpha + t.delta * 17));
|
||||
run_check(
|
||||
select((t.alpha + t.delta * 17).as(whatever)).from(t).where(true).group_by(t.alpha, t.alpha + t.delta * 17));
|
||||
run_check(select((t.beta + "fortytwo").as(whatever)).from(t).where(true).group_by(t.beta));
|
||||
|
||||
run_check(select(avg(t.alpha)).from(t).where(true).group_by(t.beta));
|
||||
run_check(select(count(t.alpha)).from(t).where(true).group_by(t.beta));
|
||||
run_check(select(max(t.alpha)).from(t).where(true).group_by(t.beta));
|
||||
run_check(select(min(t.alpha)).from(t).where(true).group_by(t.beta));
|
||||
run_check(select(sum(t.alpha)).from(t).where(true).group_by(t.beta));
|
||||
|
||||
run_check(select((t.alpha + count(t.delta)).as(whatever)).from(t).where(true).group_by(t.alpha));
|
||||
|
||||
run_check(select(sqlpp::value(1).as(whatever)).from(t).where(true).group_by(t.alpha));
|
||||
run_check(select(sqlpp::value("whatever").as(whatever)).from(t).where(true).group_by(t.alpha));
|
||||
|
||||
// Otherwise, they are invalid
|
||||
run_check<sqlpp::assert_aggregates_t>(select(t.beta).from(t).where(true).group_by(t.alpha));
|
||||
run_check<sqlpp::assert_aggregates_t>(select((t.alpha + t.delta).as(whatever)).from(t).where(true).group_by(t.alpha));
|
||||
run_check<sqlpp::assert_aggregates_t>(
|
||||
select((t.alpha + t.delta).as(whatever)).from(t).where(true).group_by(t.alpha, t.alpha + t.delta * 17));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -30,6 +30,7 @@ target_compile_options(sqlpp11_testing INTERFACE -Wall -Wextra -pedantic)
|
||||
endif ()
|
||||
|
||||
set(test_names
|
||||
Aggregates
|
||||
BooleanExpression
|
||||
CustomQuery
|
||||
Interpret
|
||||
|
||||
@@ -375,7 +375,7 @@ int SelectType(int, char**)
|
||||
static_assert(sqlpp::is_boolean_t<decltype(select(r.a).from(r))>::value, "select(bool) has to be a bool");
|
||||
auto s1 = sqlpp::select()
|
||||
.flags(sqlpp::distinct, sqlpp::straight_join)
|
||||
.columns(l.alpha, l.beta, select(r.a).from(r))
|
||||
.columns(l.gamma, r.a)
|
||||
.from(r, t, l)
|
||||
.where(t.beta == "hello world" and select(t.gamma).from(t)) // .as(alias::right))
|
||||
.group_by(l.gamma, r.a)
|
||||
|
||||
Reference in New Issue
Block a user