diff --git a/include/sqlpp11/cross_join.h b/include/sqlpp11/cross_join.h index b5ea2a6f..3510cb0a 100644 --- a/include/sqlpp11/cross_join.h +++ b/include/sqlpp11/cross_join.h @@ -35,7 +35,7 @@ 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 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"); template @@ -102,9 +102,9 @@ namespace sqlpp static_assert(required_tables_of::size::value == 0, "joined tables must not depend on other tables"); template - auto on(Expr expr) -> typename std::conditional::value, - join_t>, - bad_statement>::type + auto on(Expr expr) const -> typename std::conditional::value, + join_t>, + bad_statement>::type { check_join_on_t::_(); diff --git a/include/sqlpp11/dynamic_cross_join.h b/include/sqlpp11/dynamic_cross_join.h index 3c2dfec4..2795417c 100644 --- a/include/sqlpp11/dynamic_cross_join.h +++ b/include/sqlpp11/dynamic_cross_join.h @@ -32,6 +32,20 @@ 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"); + + template + struct check_dynamic_cross_join + { + using type = + static_combined_check_t::value, assert_dynamic_cross_join_table_t>, + static_check_t::value, assert_dynamic_cross_join_no_join_t>>; + }; + + template + using check_dynamic_cross_join_t = typename check_dynamic_cross_join::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_no_table_dependencies_t, @@ -75,9 +89,9 @@ namespace sqlpp "joined tables must not depend on other tables"); template - auto on(Expr expr) -> typename std::conditional::value, - dynamic_join_t>, - bad_statement>::type + auto on(Expr expr) const -> typename std::conditional::value, + dynamic_join_t>, + bad_statement>::type { check_dynamic_join_on_t::_(); @@ -106,33 +120,43 @@ namespace sqlpp } }; + template + using make_dynamic_cross_join_t = typename std::conditional::value, + dynamic_cross_join_t, + bad_statement>::type; + template - dynamic_cross_join_t dynamic_join(Table table) + auto dynamic_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t dynamic_inner_join(Table table) + auto dynamic_inner_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t outer_join(Table table) + auto dynamic_left_outer_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t left_outer_join(Table table) + auto dynamic_right_outer_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } template - dynamic_cross_join_t right_outer_join(Table table) + auto dynamic_outer_join(Table table) -> make_dynamic_cross_join_t { + check_dynamic_cross_join_t
::_(); return {table}; } } diff --git a/test_static_asserts/join.cpp b/test_static_asserts/join.cpp index a9463448..ebaed7c6 100644 --- a/test_static_asserts/join.cpp +++ b/test_static_asserts/join.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, Roland Bock + * Copyright (c) 2016-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -52,17 +52,20 @@ namespace print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); - using JoinType = decltype(join(lhs, rhs)); - using InnerJoinType = decltype(inner_join(lhs, rhs)); - using LeftOuterJoinType = decltype(left_outer_join(lhs, rhs)); - using RightOuterJoinType = decltype(right_outer_join(lhs, rhs)); - using OuterJoinType = decltype(outer_join(lhs, rhs)); - using ExpectedReturnType = - sqlpp::logic::all_t::value and - std::is_same::value and - std::is_same::value and - std::is_same::value and - std::is_same::value)>; + using JoinType = decltype(sqlpp::join(lhs, rhs)); + using InnerJoinType = decltype(sqlpp::inner_join(lhs, rhs)); + 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 ExpectedReturnType = sqlpp::logic::all_t< + (Assert::value and sqlpp::is_cross_join_t::value and sqlpp::is_cross_join_t::value and + sqlpp::is_cross_join_t::value and sqlpp::is_cross_join_t::value and + sqlpp::is_cross_join_t::value) xor + (std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value)>; print_type_on_error(ExpectedReturnType{}); print_type_on_error(ExpectedReturnType{}); print_type_on_error(ExpectedReturnType{}); @@ -71,38 +74,41 @@ namespace static_assert(ExpectedReturnType::value, "Unexpected return type"); } - /* - template - void join_dynamic_check(const Expression& expression) + template + void on_static_check(const Lhs& lhs, const Rhs& rhs) { - static auto db = MockDb{}; - using CheckResult = sqlpp::check_join_dynamic_t; + using CheckResult = sqlpp::check_join_on_t; using ExpectedCheckResult = std::is_same; print_type_on_error(ExpectedCheckResult{}); static_assert(ExpectedCheckResult::value, "Unexpected check result"); - using ReturnType = decltype(dynamic_select(db, t.alpha).dynamic_join(expression)); - using ExpectedReturnType = - sqlpp::logic::all_t::value>; - print_type_on_error(ExpectedReturnType{}); + using ResultType = decltype(lhs.on(rhs)); + using ExpectedReturnType = sqlpp::logic::all_t<(Assert::value and sqlpp::is_join_t::value) xor + std::is_same::value>; + print_type_on_error(ExpectedReturnType{}); static_assert(ExpectedReturnType::value, "Unexpected return type"); } - */ void static_join() { + // Prepare a few table aliases for tests + const auto ta = t.as(sqlpp::alias::a); + const auto tb = t.as(sqlpp::alias::b); + const auto fa = f.as(sqlpp::alias::a); + const auto fb = f.as(sqlpp::alias::b); + // OK: Join two different tables join_static_check(t, f); - join_static_check(t, f.as(sqlpp::alias::a)); - join_static_check(t.as(sqlpp::alias::a), f.as(sqlpp::alias::b)); + join_static_check(t, fa); + join_static_check(ta, fb); // OK: Self join - join_static_check(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)); - join_static_check(t, t.as(sqlpp::alias::b)); - join_static_check(t.as(sqlpp::alias::a), t); + join_static_check(ta, tb); + join_static_check(t, tb); + join_static_check(ta, t); // Prepare a join for tests: - const auto j = join(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)).unconditionally(); + const auto j = join(ta, tb).unconditionally(); // OK: Add a third table join_static_check(j, f); @@ -132,31 +138,133 @@ namespace join_static_check(f, f); join_static_check(t.as(f), f); join_static_check(t, f.as(t)); - join_static_check(t.as(sqlpp::alias::a), f.as(sqlpp::alias::a)); - join_static_check(j, f.as(sqlpp::alias::a)); - join_static_check(j, f.as(sqlpp::alias::b)); - join_static_check(j, t.as(sqlpp::alias::a)); - join_static_check(j, t.as(sqlpp::alias::b)); + join_static_check(ta, fa); + join_static_check(j, fa); + join_static_check(j, fb); + join_static_check(j, ta); + join_static_check(j, tb); + + // Prepare a cross_joins for tests: + const auto t_f = join(t, f); + const auto f_t = join(f, t); + const auto t_t = join(ta, tb); + const auto f_f = join(fa, fb); + + // OK join.on() + on_static_check(t_f, t.alpha > f.omega); + on_static_check(f_t, t.alpha < f.omega); + on_static_check(f_f, fa.omega == fb.omega); + on_static_check(t_t, ta.alpha == tb.alpha); + on_static_check(t_f, t.gamma); + + // Try join.on(non-expression) + on_static_check(t_f, true); + on_static_check(t_f, 7); + on_static_check(t_f, t); + + // Try join.on(non-boolean) + on_static_check(t_f, t.alpha); + on_static_check(t_f, t.beta); + on_static_check(t_f, f.omega); + + // Try join.on(foreign-table) + on_static_check(t_f, ta.alpha != 0); + on_static_check(t_t, t.gamma); + on_static_check(f_f, f.omega > fa.omega); + } + + template + void join_dynamic_check(const Table& table) + { + using CheckResult = sqlpp::check_dynamic_cross_join_t
; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using JoinType = decltype(sqlpp::dynamic_join(table)); + using InnerJoinType = decltype(sqlpp::dynamic_inner_join(table)); + 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::value and + sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_join_t::value and + sqlpp::is_dynamic_cross_join_t::value) xor + (std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value and + std::is_same::value)>; + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + + template + void on_dynamic_check(const Lhs& lhs, const Rhs& rhs) + { + using CheckResult = sqlpp::check_dynamic_join_on_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ResultType = decltype(lhs.on(rhs)); + using ExpectedReturnType = sqlpp::logic::all_t<(Assert::value and sqlpp::is_dynamic_join_t::value) xor + std::is_same::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); } void dynamic_join() { - /* + // Prepare a few table aliases for tests + const auto ta = t.as(sqlpp::alias::a); + const auto fa = f.as(sqlpp::alias::a); + // OK join_dynamic_check(t); - join_dynamic_check(t.join(f).unconditionally()); - join_dynamic_check(t.join(f).on(t.alpha > f.omega)); + join_dynamic_check(f); + join_dynamic_check(ta); + join_dynamic_check(fa); // Try a bunch of non-tables - join_dynamic_check(7); - join_dynamic_check(t.alpha); - join_dynamic_check(t.beta); - join_dynamic_check(t.gamma); - join_dynamic_check(t.delta); + join_dynamic_check(7); + join_dynamic_check(t.alpha); + join_dynamic_check(t.beta); + join_dynamic_check(t.gamma); + join_dynamic_check(t.delta); - // Try cross joins (missing condition) - join_dynamic_check(t.join(f)); - */ + // Try (cross) joins + join_dynamic_check(t.join(f)); + join_dynamic_check(t.join(f).unconditionally()); + + // Prepare a dynamic_cross_joins for tests: + const auto tj = dynamic_join(t); + const auto fj = dynamic_join(f); + + // OK dynamic_join.on() + on_dynamic_check(tj, t.alpha > f.omega); + on_dynamic_check(fj, t.alpha < f.omega); + + // Try dynamic_join.on(non-expression) + on_dynamic_check(tj, true); + on_dynamic_check(tj, 7); + on_dynamic_check(tj, t); + + // Try dynamic_join.on(non-boolean) + on_dynamic_check(tj, t.alpha); + on_dynamic_check(tj, t.beta); + on_dynamic_check(tj, f.omega); + + // OK dynamic_join.on(foreign-table) + on_dynamic_check(tj, ta.alpha != 0); + on_dynamic_check(tj, t.gamma); + on_dynamic_check(tj, f.omega > fa.omega); } }