0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Added check if all selected columns are aggregates if group_by is present

This commit is contained in:
rbock 2015-10-03 17:00:53 +02:00
parent 25ff700c01
commit bd385f7377
7 changed files with 108 additions and 2 deletions

View File

@ -75,6 +75,9 @@ namespace sqlpp
using _nodes = detail::type_vector<Expressions...>; using _nodes = detail::type_vector<Expressions...>;
using _is_dynamic = is_database<Database>; 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 // Data
using _data_t = group_by_data_t<Database, Expressions...>; using _data_t = group_by_data_t<Database, Expressions...>;

View File

@ -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 // SELECTED COLUMNS
template <typename Database, typename... Columns> template <typename Database, typename... Columns>
struct select_column_list_t struct select_column_list_t
@ -262,10 +273,16 @@ namespace sqlpp
return t.selected_columns; return t.selected_columns;
} }
using _consistency_check = using _column_check =
typename std::conditional<Policies::template _no_unknown_tables<select_column_list_t>::value, typename std::conditional<Policies::template _no_unknown_tables<select_column_list_t>::value,
consistent_t, consistent_t,
assert_no_unknown_tables_in_selected_columns_t>::type; 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 // Result methods

View File

@ -103,12 +103,18 @@ namespace sqlpp
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of<Policies>...>; 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_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_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>; using _known_tables = detail::make_joined_set_t<_all_provided_tables, _all_extra_tables>;
template <typename Expression> template <typename Expression>
using _no_unknown_tables = detail::is_subset_of<required_tables_of<Expression>, _known_tables>; 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> template <template <typename> class Predicate>
using any_t = logic::any_t<Predicate<Policies>::value...>; using any_t = logic::any_t<Predicate<Policies>::value...>;

View File

@ -195,6 +195,7 @@ namespace sqlpp
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_tables)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_outer_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_outer_tables)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(extra_tables) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(extra_tables)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates)
#define SQLPP_RECURSIVE_TRAIT_GENERATOR(trait) \ #define SQLPP_RECURSIVE_TRAIT_GENERATOR(trait) \
namespace detail \ namespace detail \
@ -221,6 +222,38 @@ namespace sqlpp
SQLPP_RECURSIVE_TRAIT_GENERATOR(can_be_null) SQLPP_RECURSIVE_TRAIT_GENERATOR(can_be_null)
SQLPP_RECURSIVE_TRAIT_GENERATOR(contains_aggregate_function) 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 namespace detail
{ {
template <typename T, typename Leaf = void> template <typename T, typename Leaf = void>
@ -259,6 +292,7 @@ namespace sqlpp
{ {
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _contains_aggregate_function = std::true_type; using _contains_aggregate_function = std::true_type;
using _is_aggregate_expression = std::true_type;
}; };
template <typename NameProvider, typename Member> template <typename NameProvider, typename Member>

45
tests/Aggregates.cpp Normal file
View File

@ -0,0 +1,45 @@
/*
* 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>
int Aggregates(int, char**)
{
MockDb db = {};
MockDb::_serializer_context_t printer;
// test::TabFoo f;
test::TabBar t;
db(select(t.alpha).from(t).where(true).group_by(t.alpha));
return 0;
}

View File

@ -30,6 +30,7 @@ target_compile_options(sqlpp11_testing INTERFACE -Wall -Wextra -pedantic)
endif () endif ()
set(test_names set(test_names
Aggregates
BooleanExpression BooleanExpression
CustomQuery CustomQuery
Interpret Interpret

View File

@ -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"); static_assert(sqlpp::is_boolean_t<decltype(select(r.a).from(r))>::value, "select(bool) has to be a bool");
auto s1 = sqlpp::select() auto s1 = sqlpp::select()
.flags(sqlpp::distinct, sqlpp::straight_join) .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) .from(r, t, l)
.where(t.beta == "hello world" and select(t.gamma).from(t)) // .as(alias::right)) .where(t.beta == "hello world" and select(t.gamma).from(t)) // .as(alias::right))
.group_by(l.gamma, r.a) .group_by(l.gamma, r.a)