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

Added "real" cross join

This commit is contained in:
rbock 2016-03-06 10:36:42 +01:00
parent 20b74206ae
commit d15cb2a410
13 changed files with 227 additions and 184 deletions

View File

@ -27,36 +27,36 @@
#ifndef SQLPP_DYNAMIC_JOIN_H
#define SQLPP_DYNAMIC_JOIN_H
#include <sqlpp11/dynamic_cross_join.h>
#include <sqlpp11/dynamic_pre_join.h>
namespace sqlpp
{
template <typename CrossJoin, typename On>
template <typename PreJoin, typename On>
struct dynamic_join_t
{
using _traits = make_traits<no_value_t, tag::is_table, tag::is_dynamic_join>;
using _nodes = detail::type_vector<CrossJoin, On>;
using _nodes = detail::type_vector<PreJoin, On>;
using _can_be_null = std::false_type;
using _provided_tables = provided_tables_of<CrossJoin>;
using _provided_tables = provided_tables_of<PreJoin>;
using _required_tables = detail::type_set<>;
static_assert(is_dynamic_cross_join_t<CrossJoin>::value, "lhs argument for on() has to be a cross join");
static_assert(required_tables_of<CrossJoin>::size::value == 0, "joined tables must not depend on other tables");
static_assert(is_dynamic_pre_join_t<PreJoin>::value, "lhs argument for on() has to be a pre join");
static_assert(required_tables_of<PreJoin>::size::value == 0, "joined tables must not depend on other tables");
static_assert(is_on_t<On>::value, "invalid on expression in join().on()");
CrossJoin _cross_join;
PreJoin _pre_join;
On _on;
};
template <typename Context, typename CrossJoin, typename On>
struct serializer_t<Context, dynamic_join_t<CrossJoin, On>>
template <typename Context, typename PreJoin, typename On>
struct serializer_t<Context, dynamic_join_t<PreJoin, On>>
{
using _serialize_check = serialize_check_of<Context, CrossJoin, On>;
using T = dynamic_join_t<CrossJoin, On>;
using _serialize_check = serialize_check_of<Context, PreJoin, On>;
using T = dynamic_join_t<PreJoin, On>;
static Context& _(const T& t, Context& context)
{
serialize(t._cross_join, context);
serialize(t._pre_join, context);
serialize(t._on, context);
return context;
}

View File

@ -24,93 +24,88 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_DYNAMIC_CROSS_JOIN_H
#define SQLPP_DYNAMIC_CROSS_JOIN_H
#ifndef SQLPP_DYNAMIC_PRE_JOIN_H
#define SQLPP_DYNAMIC_PRE_JOIN_H
#include <sqlpp11/join_types.h>
#include <sqlpp11/on.h>
namespace sqlpp
{
SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_cross_join_table_t, "argument of dynamic_join() has to be a table");
SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_cross_join_no_join_t, "argument of dynamic_join() must not be a table");
SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_pre_join_table_t, "argument of dynamic_join() has to be a table");
SQLPP_PORTABLE_STATIC_ASSERT(assert_dynamic_pre_join_no_join_t, "argument of dynamic_join() must not be a table");
template <typename Table>
struct check_dynamic_cross_join
struct check_dynamic_pre_join
{
using type =
static_combined_check_t<static_check_t<is_table_t<Table>::value, assert_dynamic_cross_join_table_t>,
static_check_t<not is_join_t<Table>::value, assert_dynamic_cross_join_no_join_t>>;
static_combined_check_t<static_check_t<is_table_t<Table>::value, assert_dynamic_pre_join_table_t>,
static_check_t<not is_join_t<Table>::value, assert_dynamic_pre_join_no_join_t>>;
};
template <typename Table>
using check_dynamic_cross_join_t = typename check_dynamic_cross_join<Table>::type;
using check_dynamic_pre_join_t = typename check_dynamic_pre_join<Table>::type;
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_consist_of_pre_join_and_on_t,
"dynamic join has to consist of a dynamic pre_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>
template <typename PreJoin, 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>>;
static_check_t<is_dynamic_pre_join_t<PreJoin>::value, assert_dynamic_join_consist_of_pre_join_and_on_t>,
static_check_t<is_on_t<On>::value, assert_dynamic_join_consist_of_pre_join_and_on_t>,
static_check_t<required_tables_of<PreJoin>::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 PreJoin, typename On>
using check_dynamic_join_t = typename check_dynamic_join<PreJoin, On>::type;
template <typename CrossJoin, typename Expr>
template <typename PreJoin, 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>>>;
using type = static_combined_check_t<check_on_t<Expr>, check_dynamic_join_t<PreJoin, on_t<Expr>>>;
};
template <typename CrossJoin, typename Expr>
using check_dynamic_join_on_t = typename check_dynamic_join_on<CrossJoin, Expr>::type;
template <typename PreJoin, typename Expr>
using check_dynamic_join_on_t = typename check_dynamic_join_on<PreJoin, Expr>::type;
template <typename CrossJoin, typename On>
template <typename PreJoin, typename On>
struct dynamic_join_t;
template <typename JoinType, typename Rhs>
struct dynamic_cross_join_t
struct dynamic_pre_join_t
{
using _traits = make_traits<no_value_t, tag::is_table, tag::is_dynamic_cross_join>;
using _traits = make_traits<no_value_t, tag::is_table, tag::is_dynamic_pre_join>;
using _nodes = detail::type_vector<Rhs>;
using _can_be_null = std::false_type;
static_assert(is_table_t<Rhs>::value, "rhs argument for dynamic_join() has to be a table");
static_assert(not is_join_t<Rhs>::value, "rhs argument for dynamic_join must not be a join");
static_assert(required_tables_of<dynamic_cross_join_t>::size::value == 0,
static_assert(required_tables_of<dynamic_pre_join_t>::size::value == 0,
"joined tables must not depend on other tables");
template <typename Expr>
auto on(Expr expr) const -> typename std::conditional<check_dynamic_join_on_t<dynamic_cross_join_t, Expr>::value,
dynamic_join_t<dynamic_cross_join_t, on_t<Expr>>,
auto on(Expr expr) const -> typename std::conditional<check_dynamic_join_on_t<dynamic_pre_join_t, Expr>::value,
dynamic_join_t<dynamic_pre_join_t, on_t<Expr>>,
bad_statement>::type
{
check_dynamic_join_on_t<dynamic_cross_join_t, Expr>::_();
check_dynamic_join_on_t<dynamic_pre_join_t, Expr>::_();
return {*this, {expr}};
}
auto unconditionally() -> dynamic_join_t<dynamic_cross_join_t, on_t<unconditional_t>>
{
return {*this, {}};
}
Rhs _rhs;
};
template <typename Context, typename JoinType, typename Rhs>
struct serializer_t<Context, dynamic_cross_join_t<JoinType, Rhs>>
struct serializer_t<Context, dynamic_pre_join_t<JoinType, Rhs>>
{
using _serialize_check = serialize_check_of<Context, Rhs>;
using T = dynamic_cross_join_t<JoinType, Rhs>;
using T = dynamic_pre_join_t<JoinType, Rhs>;
static Context& _(const T& t, Context& context)
{
@ -121,44 +116,54 @@ namespace sqlpp
};
template <typename JoinType, typename Table>
using make_dynamic_cross_join_t = typename std::conditional<check_dynamic_cross_join_t<Table>::value,
dynamic_cross_join_t<JoinType, Table>,
bad_statement>::type;
using make_dynamic_pre_join_t = typename std::conditional<check_dynamic_pre_join_t<Table>::value,
dynamic_pre_join_t<JoinType, Table>,
bad_statement>::type;
template <typename Table>
auto dynamic_join(Table table) -> make_dynamic_cross_join_t<inner_join_t, Table>
auto dynamic_join(Table table) -> make_dynamic_pre_join_t<inner_join_t, Table>
{
check_dynamic_cross_join_t<Table>::_();
check_dynamic_pre_join_t<Table>::_();
return {table};
}
template <typename Table>
auto dynamic_inner_join(Table table) -> make_dynamic_cross_join_t<inner_join_t, Table>
auto dynamic_inner_join(Table table) -> make_dynamic_pre_join_t<inner_join_t, Table>
{
check_dynamic_cross_join_t<Table>::_();
check_dynamic_pre_join_t<Table>::_();
return {table};
}
template <typename Table>
auto dynamic_left_outer_join(Table table) -> make_dynamic_cross_join_t<left_outer_join_t, Table>
auto dynamic_left_outer_join(Table table) -> make_dynamic_pre_join_t<left_outer_join_t, Table>
{
check_dynamic_cross_join_t<Table>::_();
check_dynamic_pre_join_t<Table>::_();
return {table};
}
template <typename Table>
auto dynamic_right_outer_join(Table table) -> make_dynamic_cross_join_t<right_outer_join_t, Table>
auto dynamic_right_outer_join(Table table) -> make_dynamic_pre_join_t<right_outer_join_t, Table>
{
check_dynamic_cross_join_t<Table>::_();
check_dynamic_pre_join_t<Table>::_();
return {table};
}
template <typename Table>
auto dynamic_outer_join(Table table) -> make_dynamic_cross_join_t<outer_join_t, Table>
auto dynamic_outer_join(Table table) -> make_dynamic_pre_join_t<outer_join_t, Table>
{
check_dynamic_cross_join_t<Table>::_();
check_dynamic_pre_join_t<Table>::_();
return {table};
}
template <typename Table>
auto dynamic_cross_join(Table table) ->
typename std::conditional<check_dynamic_pre_join_t<Table>::value,
dynamic_join_t<dynamic_pre_join_t<cross_join_t, Table>, on_t<unconditional_t>>,
bad_statement>::type
{
check_dynamic_pre_join_t<Table>::_();
return {dynamic_pre_join_t<cross_join_t, Table>{table}, {}};
}
}
#endif

View File

@ -148,8 +148,8 @@ 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()");
assert_from_not_pre_join_t,
"from() argument is a pre 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()");
@ -161,7 +161,7 @@ namespace sqlpp
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<not is_pre_join_t<Table>::value, assert_from_not_pre_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 ==

View File

@ -28,18 +28,18 @@
#define SQLPP_JOIN_H
#include <sqlpp11/join_types.h>
#include <sqlpp11/cross_join.h>
#include <sqlpp11/pre_join.h>
#include <sqlpp11/on.h>
namespace sqlpp
{
template <typename CrossJoin, typename On>
template <typename PreJoin, typename On>
struct join_t
{
using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>;
using _nodes = detail::type_vector<CrossJoin, On>;
using _nodes = detail::type_vector<PreJoin, On>;
using _can_be_null = std::false_type;
using _provided_tables = provided_tables_of<CrossJoin>;
using _provided_tables = provided_tables_of<PreJoin>;
using _required_tables = detail::make_difference_set_t<required_tables_of<On>, _provided_tables>;
template <typename T>
@ -72,19 +72,25 @@ namespace sqlpp
return ::sqlpp::outer_join(*this, t);
}
CrossJoin _cross_join;
template <typename T>
auto cross_join(T t) const -> decltype(::sqlpp::cross_join(*this, t))
{
return ::sqlpp::cross_join(*this, t);
}
PreJoin _pre_join;
On _on;
};
template <typename Context, typename CrossJoin, typename On>
struct serializer_t<Context, join_t<CrossJoin, On>>
template <typename Context, typename PreJoin, typename On>
struct serializer_t<Context, join_t<PreJoin, On>>
{
using _serialize_check = serialize_check_of<Context, CrossJoin, On>;
using T = join_t<CrossJoin, On>;
using _serialize_check = serialize_check_of<Context, PreJoin, On>;
using T = join_t<PreJoin, On>;
static Context& _(const T& t, Context& context)
{
serialize(t._cross_join, context);
serialize(t._pre_join, context);
serialize(t._on, context);
return context;
}

View File

@ -60,6 +60,14 @@ namespace sqlpp
static constexpr const char* _name = " RIGHT OUTER ";
};
struct cross_join_t
{
template <typename Lhs, typename Rhs>
using _provided_outer_tables =
detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_outer_tables_of<Rhs>>;
static constexpr const char* _name = " CROSS ";
};
}
#endif

View File

@ -24,8 +24,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SQLPP_CROSS_JOIN_H
#define SQLPP_CROSS_JOIN_H
#ifndef SQLPP_PRE_JOIN_H
#define SQLPP_PRE_JOIN_H
#include <sqlpp11/join_types.h>
#include <sqlpp11/on.h>
@ -33,62 +33,62 @@
namespace sqlpp
{
SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_lhs_table_t, "lhs argument of join() has to be a table or a join");
SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_table_t, "rhs argument of join() has to be a table");
SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_rhs_no_join_t, "rhs argument of join() must not be a join");
SQLPP_PORTABLE_STATIC_ASSERT(assert_cross_join_unique_names_t, "joined table names have to be unique");
SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_lhs_table_t, "lhs argument of join() has to be a table or a join");
SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_rhs_table_t, "rhs argument of join() has to be a table");
SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_rhs_no_join_t, "rhs argument of join() must not be a join");
SQLPP_PORTABLE_STATIC_ASSERT(assert_pre_join_unique_names_t, "joined table names have to be unique");
template <typename Lhs, typename Rhs>
struct check_cross_join
struct check_pre_join
{
using type = static_combined_check_t<
static_check_t<is_table_t<Lhs>::value, assert_cross_join_lhs_table_t>,
static_check_t<is_table_t<Rhs>::value, assert_cross_join_rhs_table_t>,
static_check_t<not is_join_t<Rhs>::value, assert_cross_join_rhs_no_join_t>,
static_check_t<is_table_t<Lhs>::value, assert_pre_join_lhs_table_t>,
static_check_t<is_table_t<Rhs>::value, assert_pre_join_rhs_table_t>,
static_check_t<not is_join_t<Rhs>::value, assert_pre_join_rhs_no_join_t>,
static_check_t<detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of<Lhs>>,
detail::make_name_of_set_t<provided_tables_of<Rhs>>>::value,
assert_cross_join_unique_names_t>>;
assert_pre_join_unique_names_t>>;
};
template <typename Lhs, typename Rhs>
using check_cross_join_t = typename check_cross_join<Lhs, Rhs>::type;
using check_pre_join_t = typename check_pre_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_consist_of_pre_join_and_on_t,
"join has to consist of a pre_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>
template <typename PreJoin, 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,
static_check_t<is_pre_join_t<PreJoin>::value, assert_join_consist_of_pre_join_and_on_t>,
static_check_t<is_on_t<On>::value, assert_join_consist_of_pre_join_and_on_t>,
static_check_t<required_tables_of<PreJoin>::size::value == 0, assert_join_no_table_dependencies_t>,
static_check_t<detail::is_subset_of<required_tables_of<On>, provided_tables_of<PreJoin>>::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 PreJoin, typename On>
using check_join_t = typename check_join<PreJoin, On>::type;
template <typename CrossJoin, typename Expr>
template <typename PreJoin, typename Expr>
struct check_join_on
{
using type = static_combined_check_t<check_on_t<Expr>, check_join_t<CrossJoin, on_t<Expr>>>;
using type = static_combined_check_t<check_on_t<Expr>, check_join_t<PreJoin, on_t<Expr>>>;
};
template <typename CrossJoin, typename Expr>
using check_join_on_t = typename check_join_on<CrossJoin, Expr>::type;
template <typename PreJoin, typename Expr>
using check_join_on_t = typename check_join_on<PreJoin, Expr>::type;
template <typename CrossJoin, typename On>
template <typename PreJoin, typename On>
struct join_t;
template <typename JoinType, typename Lhs, typename Rhs>
struct cross_join_t
struct pre_join_t
{
using _traits = make_traits<no_value_t, tag::is_cross_join>;
using _traits = make_traits<no_value_t, tag::is_pre_join>;
using _nodes = detail::type_vector<Lhs, Rhs>;
using _can_be_null = std::false_type;
@ -99,32 +99,27 @@ namespace sqlpp
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");
static_assert(required_tables_of<pre_join_t>::size::value == 0, "joined tables must not depend on other tables");
template <typename Expr>
auto on(Expr expr) const -> typename std::conditional<check_join_on_t<cross_join_t, Expr>::value,
join_t<cross_join_t, on_t<Expr>>,
auto on(Expr expr) const -> typename std::conditional<check_join_on_t<pre_join_t, Expr>::value,
join_t<pre_join_t, on_t<Expr>>,
bad_statement>::type
{
check_join_on_t<cross_join_t, Expr>::_();
check_join_on_t<pre_join_t, Expr>::_();
return {*this, {expr}};
}
auto unconditionally() -> join_t<cross_join_t, on_t<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>>
struct serializer_t<Context, pre_join_t<JoinType, Lhs, Rhs>>
{
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
using T = cross_join_t<JoinType, Lhs, Rhs>;
using T = pre_join_t<JoinType, Lhs, Rhs>;
static Context& _(const T& t, Context& context)
{
@ -137,54 +132,65 @@ namespace sqlpp
};
template <typename Lhs, typename Rhs>
auto join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_cross_join_t<Lhs, Rhs>::value,
cross_join_t<inner_join_t, Lhs, Rhs>,
auto join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
pre_join_t<inner_join_t, Lhs, Rhs>,
bad_statement>::type
{
check_cross_join_t<Lhs, Rhs>::_();
check_pre_join_t<Lhs, Rhs>::_();
return {lhs, rhs};
}
template <typename Lhs, typename Rhs>
auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_cross_join_t<Lhs, Rhs>::value,
cross_join_t<inner_join_t, Lhs, Rhs>,
auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
pre_join_t<inner_join_t, Lhs, Rhs>,
bad_statement>::type
{
check_cross_join_t<Lhs, Rhs>::_();
check_pre_join_t<Lhs, Rhs>::_();
return {lhs, rhs};
}
template <typename Lhs, typename Rhs>
auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_cross_join_t<Lhs, Rhs>::value,
cross_join_t<left_outer_join_t, Lhs, Rhs>,
auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
pre_join_t<left_outer_join_t, Lhs, Rhs>,
bad_statement>::type
{
check_cross_join_t<Lhs, Rhs>::_();
check_pre_join_t<Lhs, Rhs>::_();
return {lhs, rhs};
}
template <typename Lhs, typename Rhs>
auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_cross_join_t<Lhs, Rhs>::value,
cross_join_t<right_outer_join_t, Lhs, Rhs>,
auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
pre_join_t<right_outer_join_t, Lhs, Rhs>,
bad_statement>::type
{
check_cross_join_t<Lhs, Rhs>::_();
check_pre_join_t<Lhs, Rhs>::_();
return {lhs, rhs};
}
template <typename Lhs, typename Rhs>
auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_cross_join_t<Lhs, Rhs>::value,
cross_join_t<right_outer_join_t, Lhs, Rhs>,
auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
pre_join_t<right_outer_join_t, Lhs, Rhs>,
bad_statement>::type
{
check_cross_join_t<Lhs, Rhs>::_();
check_pre_join_t<Lhs, Rhs>::_();
return {lhs, rhs};
}
template <typename Lhs, typename Rhs>
auto cross_join(Lhs lhs, Rhs rhs) ->
typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
join_t<pre_join_t<cross_join_t, Lhs, Rhs>, on_t<unconditional_t>>,
bad_statement>::type
{
check_pre_join_t<Lhs, Rhs>::_();
return {pre_join_t<cross_join_t, Lhs, Rhs>{lhs, rhs}, {}};
}
}
#endif

View File

@ -97,6 +97,12 @@ namespace sqlpp
return {*static_cast<const Table*>(this)};
}
template <typename T>
auto cross_join(T t) const -> decltype(::sqlpp::cross_join(std::declval<Table>(), t))
{
return ::sqlpp::cross_join(*static_cast<const Table*>(this), t);
}
const Table& ref() const
{
return *static_cast<const Table*>(this);

View File

@ -90,6 +90,12 @@ namespace sqlpp
return ::sqlpp::outer_join(*this, t);
}
template <typename T>
auto cross_join(T t) const -> decltype(::sqlpp::cross_join(*this, t))
{
return ::sqlpp::cross_join(*this, t);
}
Table _table;
};

View File

@ -169,9 +169,9 @@ namespace sqlpp
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_cross_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_pre_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_cross_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_pre_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_column)

View File

@ -79,7 +79,7 @@ namespace
{
// 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.cross_join(f));
from_static_check<sqlpp::consistent_t>(t.join(f).on(t.alpha > f.omega));
// Try a bunch of non-tables
@ -90,14 +90,14 @@ namespace
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));
from_static_check<sqlpp::assert_from_not_pre_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.cross_join(f));
from_dynamic_check<sqlpp::consistent_t>(t.join(f).on(t.alpha > f.omega));
// Try a bunch of non-tables
@ -108,7 +108,7 @@ namespace
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));
from_dynamic_check<sqlpp::assert_from_not_pre_join_t>(t.join(f));
}
}

View File

@ -47,7 +47,7 @@ namespace
template <typename Assert, typename Lhs, typename Rhs>
void join_static_check(const Lhs& lhs, const Rhs& rhs)
{
using CheckResult = sqlpp::check_cross_join_t<Lhs, Rhs>;
using CheckResult = sqlpp::check_pre_join_t<Lhs, Rhs>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
@ -57,20 +57,23 @@ namespace
using LeftOuterJoinType = decltype(sqlpp::left_outer_join(lhs, rhs));
using RightOuterJoinType = decltype(sqlpp::right_outer_join(lhs, rhs));
using OuterJoinType = decltype(sqlpp::outer_join(lhs, rhs));
using CrossJoinType = decltype(sqlpp::cross_join(lhs, rhs));
using ExpectedReturnType = sqlpp::logic::all_t<
(Assert::value and sqlpp::is_cross_join_t<JoinType>::value and sqlpp::is_cross_join_t<InnerJoinType>::value and
sqlpp::is_cross_join_t<LeftOuterJoinType>::value and sqlpp::is_cross_join_t<RightOuterJoinType>::value and
sqlpp::is_cross_join_t<OuterJoinType>::value) xor
(Assert::value and sqlpp::is_pre_join_t<JoinType>::value and sqlpp::is_pre_join_t<InnerJoinType>::value and
sqlpp::is_pre_join_t<LeftOuterJoinType>::value and sqlpp::is_pre_join_t<RightOuterJoinType>::value and
sqlpp::is_pre_join_t<OuterJoinType>::value and sqlpp::is_join_t<CrossJoinType>::value) xor
(std::is_same<JoinType, sqlpp::bad_statement>::value and
std::is_same<InnerJoinType, sqlpp::bad_statement>::value and
std::is_same<LeftOuterJoinType, sqlpp::bad_statement>::value and
std::is_same<RightOuterJoinType, sqlpp::bad_statement>::value and
std::is_same<OuterJoinType, sqlpp::bad_statement>::value)>;
std::is_same<OuterJoinType, sqlpp::bad_statement>::value and
std::is_same<CrossJoinType, sqlpp::bad_statement>::value)>;
print_type_on_error<JoinType>(ExpectedReturnType{});
print_type_on_error<InnerJoinType>(ExpectedReturnType{});
print_type_on_error<LeftOuterJoinType>(ExpectedReturnType{});
print_type_on_error<RightOuterJoinType>(ExpectedReturnType{});
print_type_on_error<OuterJoinType>(ExpectedReturnType{});
print_type_on_error<CrossJoinType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
@ -108,7 +111,7 @@ namespace
join_static_check<sqlpp::consistent_t>(ta, t);
// Prepare a join for tests:
const auto j = join(ta, tb).unconditionally();
const auto j = cross_join(ta, tb);
// OK: Add a third table
join_static_check<sqlpp::consistent_t>(j, f);
@ -116,35 +119,35 @@ namespace
join_static_check<sqlpp::consistent_t>(j, t);
// Try a bunch of non-tables
join_static_check<sqlpp::assert_cross_join_rhs_table_t>(t, 7);
join_static_check<sqlpp::assert_cross_join_rhs_table_t>(t, t.alpha);
join_static_check<sqlpp::assert_cross_join_rhs_table_t>(t, t.beta);
join_static_check<sqlpp::assert_cross_join_rhs_table_t>(t, t.gamma);
join_static_check<sqlpp::assert_cross_join_rhs_table_t>(t, t.delta);
join_static_check<sqlpp::assert_pre_join_rhs_table_t>(t, 7);
join_static_check<sqlpp::assert_pre_join_rhs_table_t>(t, t.alpha);
join_static_check<sqlpp::assert_pre_join_rhs_table_t>(t, t.beta);
join_static_check<sqlpp::assert_pre_join_rhs_table_t>(t, t.gamma);
join_static_check<sqlpp::assert_pre_join_rhs_table_t>(t, t.delta);
join_static_check<sqlpp::assert_cross_join_lhs_table_t>(7, t);
join_static_check<sqlpp::assert_cross_join_lhs_table_t>(t.alpha, t);
join_static_check<sqlpp::assert_cross_join_lhs_table_t>(t.beta, t);
join_static_check<sqlpp::assert_cross_join_lhs_table_t>(t.gamma, t);
join_static_check<sqlpp::assert_cross_join_lhs_table_t>(t.delta, t);
join_static_check<sqlpp::assert_pre_join_lhs_table_t>(7, t);
join_static_check<sqlpp::assert_pre_join_lhs_table_t>(t.alpha, t);
join_static_check<sqlpp::assert_pre_join_lhs_table_t>(t.beta, t);
join_static_check<sqlpp::assert_pre_join_lhs_table_t>(t.gamma, t);
join_static_check<sqlpp::assert_pre_join_lhs_table_t>(t.delta, t);
// Try to join with join (rhs)
join_static_check<sqlpp::assert_cross_join_rhs_no_join_t>(t, j);
join_static_check<sqlpp::assert_cross_join_rhs_no_join_t>(f, j);
join_static_check<sqlpp::assert_cross_join_rhs_no_join_t>(t.as(sqlpp::alias::left), j);
join_static_check<sqlpp::assert_pre_join_rhs_no_join_t>(t, j);
join_static_check<sqlpp::assert_pre_join_rhs_no_join_t>(f, j);
join_static_check<sqlpp::assert_pre_join_rhs_no_join_t>(t.as(sqlpp::alias::left), j);
// Try to join identical table names
join_static_check<sqlpp::assert_cross_join_unique_names_t>(t, t);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(f, f);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(t.as(f), f);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(t, f.as(t));
join_static_check<sqlpp::assert_cross_join_unique_names_t>(ta, fa);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(j, fa);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(j, fb);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(j, ta);
join_static_check<sqlpp::assert_cross_join_unique_names_t>(j, tb);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(t, t);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(f, f);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(t.as(f), f);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(t, f.as(t));
join_static_check<sqlpp::assert_pre_join_unique_names_t>(ta, fa);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(j, fa);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(j, fb);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(j, ta);
join_static_check<sqlpp::assert_pre_join_unique_names_t>(j, tb);
// Prepare a cross_joins for tests:
// Prepare a pre_joins for tests:
const auto t_f = join(t, f);
const auto f_t = join(f, t);
const auto t_t = join(ta, tb);
@ -176,7 +179,7 @@ namespace
template <typename Assert, typename Table>
void join_dynamic_check(const Table& table)
{
using CheckResult = sqlpp::check_dynamic_cross_join_t<Table>;
using CheckResult = sqlpp::check_dynamic_pre_join_t<Table>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
@ -186,22 +189,25 @@ namespace
using LeftOuterJoinType = decltype(sqlpp::dynamic_left_outer_join(table));
using RightOuterJoinType = decltype(sqlpp::dynamic_right_outer_join(table));
using OuterJoinType = decltype(sqlpp::dynamic_outer_join(table));
using ExpectedReturnType =
sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_cross_join_t<JoinType>::value and
sqlpp::is_dynamic_cross_join_t<InnerJoinType>::value and
sqlpp::is_dynamic_cross_join_t<LeftOuterJoinType>::value and
sqlpp::is_dynamic_cross_join_t<RightOuterJoinType>::value and
sqlpp::is_dynamic_cross_join_t<OuterJoinType>::value) xor
(std::is_same<JoinType, sqlpp::bad_statement>::value and
std::is_same<InnerJoinType, sqlpp::bad_statement>::value and
std::is_same<LeftOuterJoinType, sqlpp::bad_statement>::value and
std::is_same<RightOuterJoinType, sqlpp::bad_statement>::value and
std::is_same<OuterJoinType, sqlpp::bad_statement>::value)>;
using CrossJoinType = decltype(sqlpp::dynamic_cross_join(table));
using ExpectedReturnType = sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_pre_join_t<JoinType>::value and
sqlpp::is_dynamic_pre_join_t<InnerJoinType>::value and
sqlpp::is_dynamic_pre_join_t<LeftOuterJoinType>::value and
sqlpp::is_dynamic_pre_join_t<RightOuterJoinType>::value and
sqlpp::is_dynamic_pre_join_t<OuterJoinType>::value and
sqlpp::is_dynamic_join_t<CrossJoinType>::value) xor
(std::is_same<JoinType, sqlpp::bad_statement>::value and
std::is_same<InnerJoinType, sqlpp::bad_statement>::value and
std::is_same<LeftOuterJoinType, sqlpp::bad_statement>::value and
std::is_same<RightOuterJoinType, sqlpp::bad_statement>::value and
std::is_same<OuterJoinType, sqlpp::bad_statement>::value and
std::is_same<CrossJoinType, sqlpp::bad_statement>::value)>;
print_type_on_error<JoinType>(ExpectedReturnType{});
print_type_on_error<InnerJoinType>(ExpectedReturnType{});
print_type_on_error<LeftOuterJoinType>(ExpectedReturnType{});
print_type_on_error<RightOuterJoinType>(ExpectedReturnType{});
print_type_on_error<OuterJoinType>(ExpectedReturnType{});
print_type_on_error<CrossJoinType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
@ -233,17 +239,17 @@ namespace
join_dynamic_check<sqlpp::consistent_t>(fa);
// Try a bunch of non-tables
join_dynamic_check<sqlpp::assert_dynamic_cross_join_table_t>(7);
join_dynamic_check<sqlpp::assert_dynamic_cross_join_table_t>(t.alpha);
join_dynamic_check<sqlpp::assert_dynamic_cross_join_table_t>(t.beta);
join_dynamic_check<sqlpp::assert_dynamic_cross_join_table_t>(t.gamma);
join_dynamic_check<sqlpp::assert_dynamic_cross_join_table_t>(t.delta);
join_dynamic_check<sqlpp::assert_dynamic_pre_join_table_t>(7);
join_dynamic_check<sqlpp::assert_dynamic_pre_join_table_t>(t.alpha);
join_dynamic_check<sqlpp::assert_dynamic_pre_join_table_t>(t.beta);
join_dynamic_check<sqlpp::assert_dynamic_pre_join_table_t>(t.gamma);
join_dynamic_check<sqlpp::assert_dynamic_pre_join_table_t>(t.delta);
// Try (cross) joins
join_dynamic_check<sqlpp::assert_dynamic_cross_join_table_t>(t.join(f));
join_dynamic_check<sqlpp::assert_dynamic_cross_join_no_join_t>(t.join(f).unconditionally());
// Try (pre) joins
join_dynamic_check<sqlpp::assert_dynamic_pre_join_table_t>(t.join(f));
join_dynamic_check<sqlpp::assert_dynamic_pre_join_no_join_t>(t.cross_join(f));
// Prepare a dynamic_cross_joins for tests:
// Prepare a dynamic_pre_joins for tests:
const auto tj = dynamic_join(t);
const auto fj = dynamic_join(f);

View File

@ -146,7 +146,7 @@ int Select(int, char* [])
.dynamic_offset();
s.select_flags.add(sqlpp::distinct);
s.selected_columns.add(f.omega);
s.from.add(dynamic_join(f).unconditionally());
s.from.add(dynamic_cross_join(f));
s.where.add(t.alpha > 7);
s.having.add(t.alpha > 7);
s.limit.set(3);

View File

@ -376,7 +376,7 @@ int SelectType(int, char* [])
auto s1 = sqlpp::select()
.flags(sqlpp::distinct, sqlpp::straight_join)
.columns(l.gamma, r.a)
.from(r.join(t).unconditionally().join(l).unconditionally())
.from(r.cross_join(t).cross_join(l))
.where(t.beta == "hello world" and select(t.gamma).from(t)) // .as(alias::right))
.group_by(l.gamma, r.a)
.having(r.a != true)