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

Added portable static asserts for (dynamic) join.on()

Also removed inaccessible code for adding more conditions to on()
dynamically. If someone should ever want that, he/she should use
dynamic_where(), I guess.
This commit is contained in:
rbock 2016-03-05 19:32:27 +01:00
parent 5c7d588450
commit e5931aa4eb
5 changed files with 90 additions and 60 deletions

View File

@ -53,6 +53,35 @@ namespace sqlpp
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using check_cross_join_t = typename check_cross_join<Lhs, Rhs>::type; using check_cross_join_t = typename check_cross_join<Lhs, Rhs>::type;
SQLPP_PORTABLE_STATIC_ASSERT(assert_join_consist_of_cross_join_and_on_t,
"join has to consist of a cross_join and a join condition");
SQLPP_PORTABLE_STATIC_ASSERT(assert_join_no_table_dependencies_t, "joined tables must not depend on other tables");
SQLPP_PORTABLE_STATIC_ASSERT(assert_join_on_no_foreign_table_dependencies_t,
"on() condition must not depend on other tables");
template <typename CrossJoin, typename On>
struct check_join
{
using type = static_combined_check_t<
static_check_t<is_cross_join_t<CrossJoin>::value, assert_join_consist_of_cross_join_and_on_t>,
static_check_t<is_on_t<On>::value, assert_join_consist_of_cross_join_and_on_t>,
static_check_t<required_tables_of<CrossJoin>::size::value == 0, assert_join_no_table_dependencies_t>,
static_check_t<detail::is_subset_of<required_tables_of<On>, provided_tables_of<CrossJoin>>::value,
assert_join_on_no_foreign_table_dependencies_t>>;
};
template <typename CrossJoin, typename On>
using check_join_t = typename check_join<CrossJoin, On>::type;
template <typename CrossJoin, typename Expr>
struct check_join_on
{
using type = static_combined_check_t<check_on_t<Expr>, check_join_t<CrossJoin, on_t<Expr>>>;
};
template <typename CrossJoin, typename Expr>
using check_join_on_t = typename check_join_on<CrossJoin, Expr>::type;
template <typename CrossJoin, typename On> template <typename CrossJoin, typename On>
struct join_t; struct join_t;
@ -73,16 +102,16 @@ namespace sqlpp
static_assert(required_tables_of<cross_join_t>::size::value == 0, "joined tables must not depend on other tables"); static_assert(required_tables_of<cross_join_t>::size::value == 0, "joined tables must not depend on other tables");
template <typename Expr> template <typename Expr>
auto on(Expr expr) -> join_t<cross_join_t, on_t<void, Expr>> auto on(Expr expr) -> typename std::conditional<check_join_on_t<cross_join_t, Expr>::value,
join_t<cross_join_t, on_t<Expr>>,
bad_statement>::type
{ {
static_assert(is_expression_t<Expr>::value, "argument is not an expression in on()"); check_join_on_t<cross_join_t, Expr>::_();
static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()"); return {*this, {expr}};
return {*this, {expr, {}}};
} }
auto unconditionally() -> join_t<cross_join_t, on_t<void, unconditional_t>> auto unconditionally() -> join_t<cross_join_t, on_t<unconditional_t>>
{ {
return {*this, {}}; return {*this, {}};
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2016, Roland Bock * Copyright (c) 2016-2016, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
@ -32,6 +32,32 @@
namespace sqlpp namespace sqlpp
{ {
SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_consist_of_cross_join_and_on_t,
"dynamic join has to consist of a dynamic cross_join and a join condition");
SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_join_no_table_dependencies_t,
"dynamically joined tables must not depend on other tables");
template <typename CrossJoin, typename On>
struct check_dynamic_join
{
using type = static_combined_check_t<
static_check_t<is_dynamic_cross_join_t<CrossJoin>::value, assert_dynamic_join_consist_of_cross_join_and_on_t>,
static_check_t<is_on_t<On>::value, assert_dynamic_join_consist_of_cross_join_and_on_t>,
static_check_t<required_tables_of<CrossJoin>::size::value == 0, assert_dynamic_join_no_table_dependencies_t>>;
};
template <typename CrossJoin, typename On>
using check_dynamic_join_t = typename check_dynamic_join<CrossJoin, On>::type;
template <typename CrossJoin, typename Expr>
struct check_dynamic_join_on
{
using type = static_combined_check_t<check_on_t<Expr>, check_dynamic_join_t<CrossJoin, on_t<Expr>>>;
};
template <typename CrossJoin, typename Expr>
using check_dynamic_join_on_t = typename check_dynamic_join_on<CrossJoin, Expr>::type;
template <typename CrossJoin, typename On> template <typename CrossJoin, typename On>
struct dynamic_join_t; struct dynamic_join_t;
@ -49,15 +75,16 @@ namespace sqlpp
"joined tables must not depend on other tables"); "joined tables must not depend on other tables");
template <typename Expr> template <typename Expr>
auto on(Expr expr) -> dynamic_join_t<dynamic_cross_join_t, on_t<void, Expr>> auto on(Expr expr) -> typename std::conditional<check_dynamic_join_on_t<dynamic_cross_join_t, Expr>::value,
dynamic_join_t<dynamic_cross_join_t, on_t<Expr>>,
bad_statement>::type
{ {
static_assert(is_expression_t<Expr>::value, "argument is not a boolean expression in on()"); check_dynamic_join_on_t<dynamic_cross_join_t, Expr>::_();
static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
return {*this, {expr, {}}}; return {*this, {expr}};
} }
auto unconditionally() -> dynamic_join_t<dynamic_cross_join_t, on_t<void, unconditional_t>> auto unconditionally() -> dynamic_join_t<dynamic_cross_join_t, on_t<unconditional_t>>
{ {
return {*this, {}}; return {*this, {}};
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2015, Roland Bock * Copyright (c) 2016-2016, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,

View File

@ -42,13 +42,6 @@ namespace sqlpp
using _provided_tables = provided_tables_of<CrossJoin>; using _provided_tables = provided_tables_of<CrossJoin>;
using _required_tables = detail::make_difference_set_t<required_tables_of<On>, _provided_tables>; using _required_tables = detail::make_difference_set_t<required_tables_of<On>, _provided_tables>;
static_assert(is_cross_join_t<CrossJoin>::value, "lhs argument for join() has to be a table or join");
static_assert(is_on_t<On>::value, "invalid on expression in join().on()");
static_assert(required_tables_of<CrossJoin>::size::value == 0, "joined tables must not depend on other tables");
static_assert(detail::is_subset_of<required_tables_of<On>, provided_tables_of<CrossJoin>>::value,
"on() condition must not depend on other tables");
template <typename T> template <typename T>
auto join(T t) const -> decltype(::sqlpp::join(*this, t)) auto join(T t) const -> decltype(::sqlpp::join(*this, t))
{ {

View File

@ -34,54 +34,40 @@
namespace sqlpp namespace sqlpp
{ {
template <typename Database, typename Expression> SQLPP_PORTABLE_STATIC_ASSERT(assert_on_is_expression_t, "argument is not an expression in on()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_on_is_boolean_expression_t, "argument is not a boolean expression in on()");
template <typename Expr>
struct check_on
{
using type = static_combined_check_t<static_check_t<is_expression_t<Expr>::value, assert_on_is_expression_t>,
static_check_t<is_boolean_t<Expr>::value, assert_on_is_boolean_expression_t>>;
};
template <typename Expr>
using check_on_t = typename check_on<Expr>::type;
template <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<Expression>; using _nodes = detail::type_vector<Expression>;
using _is_dynamic = is_database<Database>;
template <typename Expr>
void add(Expr expr)
{
static_assert(_is_dynamic::value, "on::add() must not be called for static on()");
static_assert(is_expression_t<Expr>::value, "invalid expression argument in on::add()");
using _serialize_check = sqlpp::serialize_check_t<typename Database::_serializer_context_t, Expr>;
_serialize_check::_();
using ok = logic::all_t<_is_dynamic::value, is_expression_t<Expr>::value, _serialize_check::type::value>;
_add_impl(expr, ok()); // dispatch to prevent compile messages after the static_assert
}
private:
template <typename Expr>
void _add_impl(Expr expr, const std::true_type&)
{
return _dynamic_expressions.emplace_back(expr);
}
template <typename Expr>
void _add_impl(Expr expr, const std::false_type&);
public:
Expression _expression; Expression _expression;
interpretable_list_t<Database> _dynamic_expressions;
}; };
template <> template <>
struct on_t<void, unconditional_t> struct on_t<unconditional_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<>; using _nodes = detail::type_vector<>;
}; };
template <typename Context> template <typename Context>
struct serializer_t<Context, on_t<void, unconditional_t>> struct serializer_t<Context, on_t<unconditional_t>>
{ {
using _serialize_check = consistent_t; using _serialize_check = consistent_t;
using T = on_t<void, unconditional_t>; using T = on_t<unconditional_t>;
static Context& _(const T&, Context& context) static Context& _(const T&, Context& context)
{ {
@ -89,21 +75,16 @@ namespace sqlpp
} }
}; };
template <typename Context, typename Database, typename... Expressions> template <typename Context, typename Expression>
struct serializer_t<Context, on_t<Database, Expressions...>> struct serializer_t<Context, on_t<Expression>>
{ {
using _serialize_check = serialize_check_of<Context, Expressions...>; using _serialize_check = serialize_check_of<Context, Expression>;
using T = on_t<Database, Expressions...>; using T = on_t<Expression>;
static Context& _(const T& t, Context& context) static Context& _(const T& t, Context& context)
{ {
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context;
context << " ON ("; context << " ON (";
serialize(t._expression, context); serialize(t._expression, context);
if (not t._dynamic_expressions.empty())
context << " AND ";
interpret_list(t._dynamic_expressions, " AND ", context);
context << " )"; context << " )";
return context; return context;
} }