Skip to content

Commit

Permalink
Added portable static asserts for (dynamic) join.on()
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rbock committed Mar 5, 2016
1 parent 5c7d588 commit e5931aa
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 60 deletions.
41 changes: 35 additions & 6 deletions include/sqlpp11/cross_join.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,35 @@ namespace sqlpp
template <typename Lhs, typename Rhs>
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>
struct join_t;

Expand All @@ -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");

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()");

static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
check_join_on_t<cross_join_t, Expr>::_();

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, {}};
}
Expand Down
39 changes: 33 additions & 6 deletions include/sqlpp11/dynamic_cross_join.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2016, Roland Bock
* Copyright (c) 2016-2016, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
Expand Down Expand Up @@ -32,6 +32,32 @@

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>
struct dynamic_join_t;

Expand All @@ -49,15 +75,16 @@ namespace sqlpp
"joined tables must not depend on other tables");

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()");
static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
check_dynamic_join_on_t<dynamic_cross_join_t, Expr>::_();

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, {}};
}
Expand Down
2 changes: 1 addition & 1 deletion include/sqlpp11/dynamic_join.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, Roland Bock
* Copyright (c) 2016-2016, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
Expand Down
7 changes: 0 additions & 7 deletions include/sqlpp11/join.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ namespace sqlpp
using _provided_tables = provided_tables_of<CrossJoin>;
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>
auto join(T t) const -> decltype(::sqlpp::join(*this, t))
{
Expand Down
61 changes: 21 additions & 40 deletions include/sqlpp11/on.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,76 +34,57 @@

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
{
using _traits = make_traits<no_value_t, tag::is_on>;
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;
interpretable_list_t<Database> _dynamic_expressions;
};

template <>
struct on_t<void, unconditional_t>
struct on_t<unconditional_t>
{
using _traits = make_traits<no_value_t, tag::is_on>;
using _nodes = detail::type_vector<>;
};

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 T = on_t<void, unconditional_t>;
using T = on_t<unconditional_t>;

static Context& _(const T&, Context& context)
{
return context;
}
};

template <typename Context, typename Database, typename... Expressions>
struct serializer_t<Context, on_t<Database, Expressions...>>
template <typename Context, typename Expression>
struct serializer_t<Context, on_t<Expression>>
{
using _serialize_check = serialize_check_of<Context, Expressions...>;
using T = on_t<Database, Expressions...>;
using _serialize_check = serialize_check_of<Context, Expression>;
using T = on_t<Expression>;

static Context& _(const T& t, Context& context)
{
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
return context;
context << " ON (";
serialize(t._expression, context);
if (not t._dynamic_expressions.empty())
context << " AND ";
interpret_list(t._dynamic_expressions, " AND ", context);
context << " )";
return context;
}
Expand Down

0 comments on commit e5931aa

Please sign in to comment.