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

Made from() testable with portable static asserts, added tests

Added cross_join_t, simplifying join a lot
This commit is contained in:
rbock 2016-02-28 12:07:56 +01:00
parent d7a29fac97
commit 3461918d88
12 changed files with 336 additions and 129 deletions

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2013-2016, 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.
*/
#ifndef SQLPP_CROSS_JOIN_H
#define SQLPP_CROSS_JOIN_H
#include <sqlpp11/join_types.h>
#include <sqlpp11/on.h>
#include <sqlpp11/noop.h>
namespace sqlpp
{
template <typename CrossJoin, typename On>
struct join_t;
template <typename JoinType, typename Lhs, typename Rhs>
struct cross_join_t
{
using _traits = make_traits<no_value_t, tag::is_cross_join>;
using _nodes = detail::type_vector<Lhs, Rhs>;
using _can_be_null = std::false_type;
static_assert(is_table_t<Lhs>::value, "lhs argument for join() has to be a table or join");
static_assert(is_table_t<Rhs>::value, "rhs argument for join() has to be a table");
static_assert(not is_join_t<Rhs>::value, "rhs argument for join must not be a join");
static_assert(detail::is_disjunct_from<provided_tables_of<Lhs>, provided_tables_of<Rhs>>::value,
"joined tables must not be identical");
static_assert(required_tables_of<cross_join_t>::size::value == 0, "joined tables must not depend on other tables");
template <typename Expr>
auto on(Expr expr) -> join_t<cross_join_t, on_t<void, Expr>>
{
static_assert(is_expression_t<Expr>::value, "argument is not an expression in on()");
static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
return {*this, {expr, {}}};
}
auto unconditionally() -> join_t<cross_join_t, on_t<void, unconditional_t>>
{
return {*this, {}};
}
Lhs _lhs;
Rhs _rhs;
};
template <typename Context, typename JoinType, typename Lhs, typename Rhs>
struct serializer_t<Context, cross_join_t<JoinType, Lhs, Rhs>>
{
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
using T = cross_join_t<JoinType, Lhs, Rhs>;
static Context& _(const T& t, Context& context)
{
serialize(t._lhs, context);
context << JoinType::_name;
context << " JOIN ";
serialize(t._rhs, context);
return context;
}
};
}
#endif

View File

@ -50,14 +50,14 @@ namespace sqlpp
template <typename OnT> template <typename OnT>
using set_on_t = dynamic_join_t<JoinType, Rhs, OnT>; using set_on_t = dynamic_join_t<JoinType, Rhs, OnT>;
template <typename... Expr> template <typename Expr>
auto on(Expr... expr) -> set_on_t<on_t<void, Expr...>> auto on(Expr expr) -> set_on_t<on_t<void, Expr>>
{ {
static_assert(is_noop<On>::value, "cannot call on() twice for a single join()"); static_assert(is_noop<On>::value, "cannot call on() twice for a single join()");
static_assert(logic::all_t<is_expression_t<Expr>::value...>::value, static_assert(is_expression_t<Expr>::value, "argument is not a boolean expression in on()");
"at least one argument is not an expression in on()"); static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
return {_rhs, {std::tuple<Expr...>{expr...}, {}}}; return {_rhs, {expr, {}}};
} }
auto unconditionally() -> set_on_t<on_t<void, unconditional_t>> auto unconditionally() -> set_on_t<on_t<void, unconditional_t>>

View File

@ -147,6 +147,39 @@ namespace sqlpp
}; };
}; };
SQLPP_PORTABLE_STATIC_ASSERT(
assert_from_not_cross_join_t,
"from() argument is a cross join, please use an explicit on() condition or unconditionally()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_from_table_t, "from() argument has to be a table or join expression");
SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dependency_free_t, "at least one table depends on another table in from()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_from_no_duplicates_t, "at least one duplicate table name detected in from()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dynamic_statement_dynamic_t,
"dynamic_from must not be called in a static statement");
template <typename Table>
struct check_from
{
using type = static_combined_check_t<
static_check_t<not is_cross_join_t<Table>::value, assert_from_not_cross_join_t>,
static_check_t<is_table_t<Table>::value, assert_from_table_t>,
static_check_t<required_tables_of<Table>::size::value == 0, assert_from_dependency_free_t>,
static_check_t<provided_tables_of<Table>::size::value ==
detail::make_name_of_set_t<provided_tables_of<Table>>::size::value,
assert_from_no_duplicates_t>>;
};
template <typename Table>
using check_from_t = typename check_from<Table>::type;
template <typename Table>
using check_from_static_t = check_from_t<Table>;
template <typename Database, typename Table>
using check_from_dynamic_t = static_combined_check_t<
static_check_t<not std::is_same<Database, void>::value, assert_from_dynamic_statement_dynamic_t>,
check_from_t<Table>>;
struct no_from_t struct no_from_t
{ {
using _traits = make_traits<no_value_t, tag::is_noop>; using _traits = make_traits<no_value_t, tag::is_noop>;
@ -199,33 +232,26 @@ namespace sqlpp
using _database_t = typename Policies::_database_t; using _database_t = typename Policies::_database_t;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
// template <typename... T>
// using _check = logic::all_t<is_table_t<T>::value...>;
template <typename... T>
struct _check : logic::all_t<is_table_t<T>::value...>
{
};
template <typename Check, typename T> template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check::value, Policies, no_from_t, T>; using _new_statement_t = new_statement_t<Check::value, Policies, no_from_t, T>;
using _consistency_check = consistent_t; using _consistency_check = consistent_t;
template <typename Table> template <typename Table>
auto from(Table table) const -> _new_statement_t<_check<Table>, from_t<void, from_table_t<Table>>> auto from(Table table) const -> _new_statement_t<check_from_static_t<Table>, from_t<void, from_table_t<Table>>>
{ {
static_assert(_check<Table>::value, "argument is not a table or join in from()"); using Check = check_from_static_t<Table>;
return _from_impl<void>(_check<Table>{}, table); Check{}._();
return _from_impl<void>(Check{}, table);
} }
template <typename Table> template <typename Table>
auto dynamic_from(Table table) const -> _new_statement_t<_check<Table>, from_t<_database_t, from_table_t<Table>>> auto dynamic_from(Table table) const
-> _new_statement_t<check_from_dynamic_t<_database_t, Table>, from_t<_database_t, from_table_t<Table>>>
{ {
static_assert(not std::is_same<_database_t, void>::value, using Check = check_from_dynamic_t<_database_t, Table>;
"dynamic_from must not be called in a static statement"); Check{}._();
static_assert(_check<Table>::value, "argument is not a table or join in from()"); return _from_impl<_database_t>(Check{}, table);
return _from_impl<_database_t>(_check<Table>{}, table);
} }
private: private:
@ -236,17 +262,6 @@ namespace sqlpp
auto _from_impl(const std::true_type&, Table table) const auto _from_impl(const std::true_type&, Table table) const
-> _new_statement_t<std::true_type, from_t<Database, from_table_t<Table>>> -> _new_statement_t<std::true_type, from_t<Database, from_table_t<Table>>>
{ {
static_assert(required_tables_of<from_t<Database, Table>>::size::value == 0,
"at least one table depends on another table in from()");
static constexpr std::size_t _number_of_tables = detail::sum(provided_tables_of<Table>::size::value);
using _unique_tables = provided_tables_of<Table>;
using _unique_table_names = detail::make_name_of_set_t<_unique_tables>;
static_assert(_number_of_tables == _unique_tables::size::value,
"at least one duplicate table detected in from()");
static_assert(_number_of_tables == _unique_table_names::size::value,
"at least one duplicate table name detected in from()");
return {static_cast<const derived_statement_t<Policies>&>(*this), return {static_cast<const derived_statement_t<Policies>&>(*this),
from_data_t<Database, from_table_t<Table>>{from_table(table)}}; from_data_t<Database, from_table_t<Table>>{from_table(table)}};
} }

View File

@ -28,99 +28,70 @@
#define SQLPP_JOIN_H #define SQLPP_JOIN_H
#include <sqlpp11/join_types.h> #include <sqlpp11/join_types.h>
#include <sqlpp11/cross_join.h>
#include <sqlpp11/on.h> #include <sqlpp11/on.h>
#include <sqlpp11/noop.h>
namespace sqlpp namespace sqlpp
{ {
template <typename JoinType, typename Lhs, typename Rhs, typename On = noop> template <typename CrossJoin, typename On>
struct join_t struct join_t
{ {
using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>; using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>;
using _nodes = detail::type_vector<Lhs, Rhs>; using _nodes = detail::type_vector<CrossJoin, On>;
using _can_be_null = std::false_type; using _can_be_null = std::false_type;
using _provided_tables = provided_tables_of<CrossJoin>;
using _required_tables = detail::make_difference_set_t<required_tables_of<On>, _provided_tables>;
static_assert(is_table_t<Lhs>::value, "lhs argument for join() has to be a table or join"); static_assert(is_cross_join_t<CrossJoin>::value, "lhs argument for join() has to be a table or join");
static_assert(is_table_t<Rhs>::value, "rhs argument for join() has to be a table"); static_assert(is_on_t<On>::value, "invalid on expression in join().on()");
static_assert(not is_join_t<Rhs>::value, "rhs argument for join must not be a join");
static_assert(is_noop<On>::value or is_on_t<On>::value, "invalid on expression in join().on()");
static_assert(detail::is_disjunct_from<provided_tables_of<Lhs>, provided_tables_of<Rhs>>::value, static_assert(required_tables_of<CrossJoin>::size::value == 0, "joined tables must not depend on other tables");
"joined tables must not be identical"); static_assert(detail::is_subset_of<required_tables_of<On>, provided_tables_of<CrossJoin>>::value,
"on() condition must not depend on other tables");
static_assert(required_tables_of<join_t>::size::value == 0, "joined tables must not depend on other tables"); template <typename T>
cross_join_t<inner_join_t, join_t, T> join(T t)
template <typename OnT>
using set_on_t = join_t<JoinType, Lhs, Rhs, OnT>;
template <typename... Expr>
auto on(Expr... expr) -> set_on_t<on_t<void, Expr...>>
{ {
static_assert(is_noop<On>::value, "cannot call on() twice for a single join()"); return {*this, t};
static_assert(logic::all_t<is_expression_t<Expr>::value...>::value,
"at least one argument is not an expression in on()");
return {_lhs, _rhs, {std::tuple<Expr...>{expr...}, {}}};
}
auto unconditionally() -> set_on_t<on_t<void, unconditional_t>>
{
return {_lhs, _rhs, {}};
} }
template <typename T> template <typename T>
join_t<inner_join_t, join_t, T> join(T t) cross_join_t<inner_join_t, join_t, T> inner_join(T t)
{ {
static_assert(not is_noop<On>::value, "join type requires on()"); return {*this, t};
return {*this, t, {}};
} }
template <typename T> template <typename T>
join_t<inner_join_t, join_t, T> inner_join(T t) cross_join_t<outer_join_t, join_t, T> outer_join(T t)
{ {
static_assert(not is_noop<On>::value, "join type requires on()"); return {*this, t};
return {*this, t, {}};
} }
template <typename T> template <typename T>
join_t<outer_join_t, join_t, T> outer_join(T t) cross_join_t<left_outer_join_t, join_t, T> left_outer_join(T t)
{ {
static_assert(not is_noop<On>::value, "join type requires on()"); return {*this, t};
return {*this, t, {}};
} }
template <typename T> template <typename T>
join_t<left_outer_join_t, join_t, T> left_outer_join(T t) cross_join_t<right_outer_join_t, join_t, T> right_outer_join(T t)
{ {
static_assert(not is_noop<On>::value, "join type requires on()"); return {*this, t};
return {*this, t, {}};
} }
template <typename T> CrossJoin _cross_join;
join_t<right_outer_join_t, join_t, T> right_outer_join(T t)
{
static_assert(not is_noop<On>::value, "join type requires on()");
return {*this, t, {}};
}
Lhs _lhs;
Rhs _rhs;
On _on; On _on;
}; };
template <typename Context, typename JoinType, typename Lhs, typename Rhs, typename On> template <typename Context, typename CrossJoin, typename On>
struct serializer_t<Context, join_t<JoinType, Lhs, Rhs, On>> struct serializer_t<Context, join_t<CrossJoin, On>>
{ {
using _serialize_check = serialize_check_of<Context, Lhs, Rhs, On>; using _serialize_check = serialize_check_of<Context, CrossJoin, On>;
using T = join_t<JoinType, Lhs, Rhs, On>; using T = join_t<CrossJoin, On>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
static_assert(not is_noop<On>::value, "joined tables require on()"); serialize(t._cross_join, context);
serialize(t._lhs, context);
context << JoinType::_name;
context << " JOIN ";
serialize(t._rhs, context);
serialize(t._on, context); serialize(t._on, context);
return context; return context;
} }

View File

@ -28,23 +28,20 @@
#define SQLPP_ON_H #define SQLPP_ON_H
#include <sqlpp11/type_traits.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/interpretable_list.h> #include <sqlpp11/interpretable_list.h>
#include <sqlpp11/unconditional.h> #include <sqlpp11/unconditional.h>
#include <sqlpp11/logic.h> #include <sqlpp11/logic.h>
namespace sqlpp namespace sqlpp
{ {
template <typename Database, typename... Expressions> template <typename Database, typename Expression>
struct on_t struct on_t
{ {
using _traits = make_traits<no_value_t, tag::is_on>; using _traits = make_traits<no_value_t, tag::is_on>;
using _nodes = detail::type_vector<Expressions...>; using _nodes = detail::type_vector<Expression>;
using _is_dynamic = is_database<Database>; using _is_dynamic = is_database<Database>;
static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in on()");
template <typename Expr> template <typename Expr>
void add(Expr expr) void add(Expr expr)
{ {
@ -69,7 +66,7 @@ namespace sqlpp
void _add_impl(Expr expr, const std::false_type&); void _add_impl(Expr expr, const std::false_type&);
public: public:
std::tuple<Expressions...> _expressions; Expression _expression;
interpretable_list_t<Database> _dynamic_expressions; interpretable_list_t<Database> _dynamic_expressions;
}; };
@ -103,8 +100,8 @@ namespace sqlpp
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty()) if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context; return context;
context << " ON ("; context << " ON (";
interpret_tuple(t._expressions, " AND ", context); serialize(t._expression, context);
if (sizeof...(Expressions) and not t._dynamic_expressions.empty()) if (not t._dynamic_expressions.empty())
context << " AND "; context << " AND ";
interpret_list(t._dynamic_expressions, " AND ", context); interpret_list(t._dynamic_expressions, " AND ", context);
context << " )"; context << " )";

View File

@ -62,33 +62,33 @@ namespace sqlpp
using _alias_t = table_alias_t<AliasProvider, Table, ColumnSpec...>; using _alias_t = table_alias_t<AliasProvider, Table, ColumnSpec...>;
template <typename T> template <typename T>
join_t<inner_join_t, Table, T> join(T t) const cross_join_t<inner_join_t, Table, T> join(T t) const
{ {
return {*static_cast<const Table*>(this), t, {}}; return {*static_cast<const Table*>(this), t};
} }
template <typename T> template <typename T>
join_t<inner_join_t, Table, T> inner_join(T t) const cross_join_t<inner_join_t, Table, T> inner_join(T t) const
{ {
return {*static_cast<const Table*>(this), t, {}}; return {*static_cast<const Table*>(this), t};
} }
template <typename T> template <typename T>
join_t<outer_join_t, Table, T> outer_join(T t) const cross_join_t<outer_join_t, Table, T> outer_join(T t) const
{ {
return {*static_cast<const Table*>(this), t, {}}; return {*static_cast<const Table*>(this), t};
} }
template <typename T> template <typename T>
join_t<left_outer_join_t, Table, T> left_outer_join(T t) const cross_join_t<left_outer_join_t, Table, T> left_outer_join(T t) const
{ {
return {*static_cast<const Table*>(this), t, {}}; return {*static_cast<const Table*>(this), t};
} }
template <typename T> template <typename T>
join_t<right_outer_join_t, Table, T> right_outer_join(T t) const cross_join_t<right_outer_join_t, Table, T> right_outer_join(T t) const
{ {
return {*static_cast<const Table*>(this), t, {}}; return {*static_cast<const Table*>(this), t};
} }
template <typename AliasProvider> template <typename AliasProvider>

View File

@ -61,33 +61,33 @@ namespace sqlpp
} }
template <typename T> template <typename T>
join_t<inner_join_t, table_alias_t, T> join(T t) const cross_join_t<inner_join_t, table_alias_t, T> join(T t) const
{ {
return {*this, t, {}}; return {*this, t};
} }
template <typename T> template <typename T>
join_t<inner_join_t, table_alias_t, T> inner_join(T t) const cross_join_t<inner_join_t, table_alias_t, T> inner_join(T t) const
{ {
return {*this, t, {}}; return {*this, t};
} }
template <typename T> template <typename T>
join_t<outer_join_t, table_alias_t, T> outer_join(T t) const cross_join_t<outer_join_t, table_alias_t, T> outer_join(T t) const
{ {
return {*this, t, {}}; return {*this, t};
} }
template <typename T> template <typename T>
join_t<left_outer_join_t, table_alias_t, T> left_outer_join(T t) const cross_join_t<left_outer_join_t, table_alias_t, T> left_outer_join(T t) const
{ {
return {*this, t, {}}; return {*this, t};
} }
template <typename T> template <typename T>
join_t<right_outer_join_t, table_alias_t, T> right_outer_join(T t) const cross_join_t<right_outer_join_t, table_alias_t, T> right_outer_join(T t) const
{ {
return {*this, t, {}}; return {*this, t};
} }
Table _table; Table _table;

View File

@ -56,6 +56,12 @@ namespace sqlpp
template <typename T> template <typename T>
using value_type_of = typename detail::value_type_of_impl<T>::type; using value_type_of = typename detail::value_type_of_impl<T>::type;
template <typename T>
struct is_not_cpp_bool_t
{
static constexpr bool value = not std::is_same<T, bool>::value;
};
// data types // data types
struct boolean; struct boolean;
template <typename T> template <typename T>
@ -163,6 +169,7 @@ namespace sqlpp
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value) SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_table) SQLPP_VALUE_TRAIT_GENERATOR(is_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table) SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_cross_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_join) SQLPP_VALUE_TRAIT_GENERATOR(is_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join) SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table) SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table)
@ -374,6 +381,7 @@ namespace sqlpp
using serialize_check_of = using serialize_check_of =
detail::get_first_if<is_inconsistent_t, consistent_t, typename serializer_t<Context, T>::_serialize_check...>; detail::get_first_if<is_inconsistent_t, consistent_t, typename serializer_t<Context, T>::_serialize_check...>;
SQLPP_PORTABLE_STATIC_ASSERT(assert_sqlpp_type_t, "expression is not an sqlpp type, consistency cannot be verified");
SQLPP_PORTABLE_STATIC_ASSERT(assert_run_statement_or_prepared_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_run_statement_or_prepared_t,
"connection cannot run something that is neither statement nor prepared statement"); "connection cannot run something that is neither statement nor prepared statement");
SQLPP_PORTABLE_STATIC_ASSERT(assert_prepare_statement_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_prepare_statement_t,
@ -382,12 +390,11 @@ namespace sqlpp
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
struct consistency_check struct consistency_check
{ {
using type = assert_run_statement_or_prepared_t; using type = assert_sqlpp_type_t;
}; };
template <typename T> template <typename T>
struct consistency_check<T, struct consistency_check<T, detail::void_t<typename T::_consistency_check>>
typename std::enable_if<is_statement_t<T>::value or is_prepared_statement_t<T>::value>::type>
{ {
using type = typename T::_consistency_check; using type = typename T::_consistency_check;
}; };

View File

@ -93,6 +93,7 @@ namespace sqlpp
{ {
static_assert(_is_dynamic::value, "where::add() can only be called for dynamic_where"); static_assert(_is_dynamic::value, "where::add() can only be called for dynamic_where");
static_assert(is_expression_t<Expression>::value, "invalid expression argument in where::add()"); static_assert(is_expression_t<Expression>::value, "invalid expression argument in where::add()");
static_assert(is_boolean_t<Expression>::value, "invalid expression argument in where::add()");
static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables<Expression>::value, static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables<Expression>::value,
"expression uses tables unknown to this statement in where::add()"); "expression uses tables unknown to this statement in where::add()");
static_assert(not contains_aggregate_function_t<Expression>::value, static_assert(not contains_aggregate_function_t<Expression>::value,
@ -217,9 +218,11 @@ namespace sqlpp
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "calling where() or uncontionally() required"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "calling where() or uncontionally() required");
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_expression_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_where_not_cpp_bool_t,
"at least one argument is not a sqlpp::boolean expression in where(). Please use " "where() argument has to be an sqlpp boolean expression. Please use "
".unconditionally() instead of .where(true), or sqlpp::value(bool)"); ".unconditionally() instead of .where(true), or sqlpp::value(bool)");
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_expression_t,
"where() argument has to be an sqlpp boolean expression.");
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_no_aggregate_functions_t, SQLPP_PORTABLE_STATIC_ASSERT(assert_where_no_aggregate_functions_t,
"at least one aggregate function used in where()"); "at least one aggregate function used in where()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_static_count_args_t, "missing argument in where()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_static_count_args_t, "missing argument in where()");
@ -230,6 +233,8 @@ namespace sqlpp
// https://connect.microsoft.com/VisualStudio/feedback/details/2173198 // https://connect.microsoft.com/VisualStudio/feedback/details/2173198
// template <typename... Expressions> // template <typename... Expressions>
// using check_where_t = static_combined_check_t< // using check_where_t = static_combined_check_t<
// static_check_t<logic::all_t<is_not_cpp_bool_t<Expressions>::value...>::value,
// assert_where_not_cpp_bool_t>,
// static_check_t<logic::all_t<is_expression_t<Expressions>::value...>::value, // static_check_t<logic::all_t<is_expression_t<Expressions>::value...>::value,
// assert_where_boolean_expressions_t>, // assert_where_boolean_expressions_t>,
// static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>, // static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>,
@ -239,6 +244,7 @@ namespace sqlpp
struct check_where struct check_where
{ {
using type = static_combined_check_t< using type = static_combined_check_t<
static_check_t<logic::all_t<is_not_cpp_bool_t<Expressions>::value...>::value, assert_where_not_cpp_bool_t>,
static_check_t<logic::all_t<detail::is_expression_impl<Expressions>::type::value...>::value, static_check_t<logic::all_t<detail::is_expression_impl<Expressions>::type::value...>::value,
assert_where_boolean_expression_t>, assert_where_boolean_expression_t>,
static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>, static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>,
@ -313,14 +319,6 @@ namespace sqlpp
using _database_t = typename Policies::_database_t; using _database_t = typename Policies::_database_t;
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
// template <typename... T>
// using _check = logic::all_t<is_expression_t<T>::value...>;
template <typename... T>
struct _check : logic::all_t<is_expression_t<T>::value...>
{
};
template <typename Check, typename T> template <typename Check, typename T>
using _new_statement_t = new_statement_t<Check::value, Policies, no_where_t, T>; using _new_statement_t = new_statement_t<Check::value, Policies, no_where_t, T>;

View File

@ -30,6 +30,7 @@ endfunction()
test_compile(aggregates) test_compile(aggregates)
test_compile(case) test_compile(case)
test_compile(from)
test_compile(where) test_compile(where)
test_compile(insert) test_compile(insert)
test_compile(date) test_compile(date)

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2015-2016, 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 "MockDb.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
namespace
{
constexpr auto t = test::TabBar{};
constexpr auto f = test::TabFoo{};
template <typename T>
void print_type_on_error(std::true_type)
{
}
template <typename T>
void print_type_on_error(std::false_type)
{
T::_print_me_;
}
template <typename Assert, typename Expression>
void from_static_check(const Expression& expression)
{
using CheckResult = sqlpp::check_from_static_t<Expression>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
using ReturnType = decltype(select(t.alpha).from(expression));
using ExpectedReturnType =
sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, sqlpp::bad_statement>::value>;
print_type_on_error<ReturnType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
template <typename Assert, typename Expression>
void from_dynamic_check(const Expression& expression)
{
static auto db = MockDb{};
using CheckResult = sqlpp::check_from_dynamic_t<decltype(db), Expression>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
using ReturnType = decltype(dynamic_select(db, t.alpha).dynamic_from(expression));
using ExpectedReturnType =
sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, sqlpp::bad_statement>::value>;
print_type_on_error<ReturnType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
void static_from()
{
// OK
from_static_check<sqlpp::consistent_t>(t);
from_static_check<sqlpp::consistent_t>(t.join(f).unconditionally());
from_static_check<sqlpp::consistent_t>(t.join(f).on(t.alpha > f.omega));
// Try a bunch of non-tables
from_static_check<sqlpp::assert_from_table_t>(7);
from_static_check<sqlpp::assert_from_table_t>(t.alpha);
from_static_check<sqlpp::assert_from_table_t>(t.beta);
from_static_check<sqlpp::assert_from_table_t>(t.gamma);
from_static_check<sqlpp::assert_from_table_t>(t.delta);
// Try cross joins (missing condition)
from_static_check<sqlpp::assert_from_not_cross_join_t>(t.join(f));
}
void dynamic_from()
{
// OK
from_dynamic_check<sqlpp::consistent_t>(t);
from_dynamic_check<sqlpp::consistent_t>(t.join(f).unconditionally());
from_dynamic_check<sqlpp::consistent_t>(t.join(f).on(t.alpha > f.omega));
// Try a bunch of non-tables
from_dynamic_check<sqlpp::assert_from_table_t>(7);
from_dynamic_check<sqlpp::assert_from_table_t>(t.alpha);
from_dynamic_check<sqlpp::assert_from_table_t>(t.beta);
from_dynamic_check<sqlpp::assert_from_table_t>(t.gamma);
from_dynamic_check<sqlpp::assert_from_table_t>(t.delta);
// Try cross joins (missing condition)
from_dynamic_check<sqlpp::assert_from_not_cross_join_t>(t.join(f));
}
}
int main(int, char* [])
{
static_from();
dynamic_from();
}

View File

@ -89,6 +89,10 @@ namespace
// Try non-boolean expression // Try non-boolean expression
where_static_check<sqlpp::assert_where_boolean_expression_t>(t.alpha); where_static_check<sqlpp::assert_where_boolean_expression_t>(t.alpha);
// Try builtin bool
where_static_check<sqlpp::assert_where_not_cpp_bool_t>(true);
where_static_check<sqlpp::assert_where_not_cpp_bool_t>(17 > 3);
// Try some other types as expressions // Try some other types as expressions
where_static_check<sqlpp::assert_where_boolean_expression_t>("true"); where_static_check<sqlpp::assert_where_boolean_expression_t>("true");
where_static_check<sqlpp::assert_where_boolean_expression_t>(17); where_static_check<sqlpp::assert_where_boolean_expression_t>(17);
@ -116,6 +120,10 @@ namespace
// Try non-boolean expression // Try non-boolean expression
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(t.alpha); where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(t.alpha);
// Try builtin bool
where_dynamic_check<sqlpp::assert_where_not_cpp_bool_t>(true);
where_dynamic_check<sqlpp::assert_where_not_cpp_bool_t>(17 > 3);
// Try some other types as expressions // Try some other types as expressions
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>("true"); where_dynamic_check<sqlpp::assert_where_boolean_expression_t>("true");
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(17); where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(17);