diff --git a/include/sqlpp11/cross_join.h b/include/sqlpp11/cross_join.h index 77caa374..a0e97b74 100644 --- a/include/sqlpp11/cross_join.h +++ b/include/sqlpp11/cross_join.h @@ -33,6 +33,26 @@ 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_unique_names_t, "joined table names have to be unique"); + + template + struct check_cross_join + { + using type = static_combined_check_t< + static_check_t::value, assert_cross_join_lhs_table_t>, + static_check_t::value, assert_cross_join_rhs_table_t>, + static_check_t::value, assert_cross_join_rhs_no_join_t>, + static_check_t>, + detail::make_name_of_set_t>>::value, + assert_cross_join_unique_names_t>>; + }; + + template + using check_cross_join_t = typename check_cross_join::type; + template struct join_t; @@ -86,6 +106,56 @@ namespace sqlpp return context; } }; + + template + auto join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto inner_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto left_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto right_outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } + + template + auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional::value, + cross_join_t, + bad_statement>::type + { + check_cross_join_t::_(); + + return {lhs, rhs}; + } } #endif diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 86c92d1f..26198688 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Roland Bock + * Copyright (c) 2013-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -50,33 +50,33 @@ namespace sqlpp "on() condition must not depend on other tables"); template - cross_join_t join(T t) + auto join(T t) const -> decltype(::sqlpp::join(*this, t)) { - return {*this, t}; + return ::sqlpp::join(*this, t); } template - cross_join_t inner_join(T t) + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) { - return {*this, t}; + return ::sqlpp::inner_join(*this, t); } template - cross_join_t outer_join(T t) + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::left_outer_join(*this, t); } template - cross_join_t left_outer_join(T t) + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::right_outer_join(*this, t); } template - cross_join_t right_outer_join(T t) + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::outer_join(*this, t); } CrossJoin _cross_join; diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 029d44a6..61574e02 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -62,33 +62,33 @@ namespace sqlpp using _alias_t = table_alias_t; template - cross_join_t join(T t) const + auto join(T t) const -> decltype(::sqlpp::join(std::declval(), t)) { - return {*static_cast(this), t}; + return ::sqlpp::join(*static_cast(this), t); } template - cross_join_t inner_join(T t) const + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(std::declval
(), t)) { - return {*static_cast(this), t}; + return ::sqlpp::inner_join(*static_cast(this), t); } template - cross_join_t outer_join(T t) const + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(std::declval
(), t)) { - return {*static_cast(this), t}; + return ::sqlpp::left_outer_join(*static_cast(this), t); } template - cross_join_t left_outer_join(T t) const + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(std::declval
(), t)) { - return {*static_cast(this), t}; + return ::sqlpp::right_outer_join(*static_cast(this), t); } template - cross_join_t right_outer_join(T t) const + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(std::declval
(), t)) { - return {*static_cast(this), t}; + return ::sqlpp::outer_join(*static_cast(this), t); } template diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index a86d7915..06ffe23d 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -61,33 +61,33 @@ namespace sqlpp } template - cross_join_t join(T t) const + auto join(T t) const -> decltype(::sqlpp::join(*this, t)) { - return {*this, t}; + return ::sqlpp::join(*this, t); } template - cross_join_t inner_join(T t) const + auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) { - return {*this, t}; + return ::sqlpp::inner_join(*this, t); } template - cross_join_t outer_join(T t) const + auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::left_outer_join(*this, t); } template - cross_join_t left_outer_join(T t) const + auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::right_outer_join(*this, t); } template - cross_join_t right_outer_join(T t) const + auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t)) { - return {*this, t}; + return ::sqlpp::outer_join(*this, t); } Table _table; diff --git a/test_static_asserts/CMakeLists.txt b/test_static_asserts/CMakeLists.txt index 23b9ca67..0416116a 100644 --- a/test_static_asserts/CMakeLists.txt +++ b/test_static_asserts/CMakeLists.txt @@ -31,6 +31,7 @@ endfunction() test_compile(aggregates) test_compile(case) test_compile(from) +test_compile(join) test_compile(where) test_compile(insert) test_compile(date) diff --git a/test_static_asserts/join.cpp b/test_static_asserts/join.cpp new file mode 100644 index 00000000..a9463448 --- /dev/null +++ b/test_static_asserts/join.cpp @@ -0,0 +1,167 @@ +/* + * 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 +#include "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + constexpr auto t = test::TabBar{}; + constexpr auto f = test::TabFoo{}; + + template + void print_type_on_error(std::true_type) + { + } + + template + void print_type_on_error(std::false_type) + { + T::_print_me_; + } + + template + void join_static_check(const Lhs& lhs, const Rhs& rhs) + { + using CheckResult = sqlpp::check_cross_join_t; + using ExpectedCheckResult = std::is_same; + 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)>; + 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 join_dynamic_check(const Expression& expression) + { + static auto db = MockDb{}; + using CheckResult = sqlpp::check_join_dynamic_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{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + */ + + void static_join() + { + // 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)); + + // 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); + + // Prepare a join for tests: + const auto j = join(t.as(sqlpp::alias::a), t.as(sqlpp::alias::b)).unconditionally(); + + // OK: Add a third table + join_static_check(j, f); + join_static_check(j, t.as(sqlpp::alias::c)); + join_static_check(j, t); + + // Try a bunch of non-tables + join_static_check(t, 7); + join_static_check(t, t.alpha); + join_static_check(t, t.beta); + join_static_check(t, t.gamma); + join_static_check(t, t.delta); + + join_static_check(7, t); + join_static_check(t.alpha, t); + join_static_check(t.beta, t); + join_static_check(t.gamma, t); + join_static_check(t.delta, t); + + // Try to join with join (rhs) + join_static_check(t, j); + join_static_check(f, j); + join_static_check(t.as(sqlpp::alias::left), j); + + // Try to join identical table names + join_static_check(t, t); + 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)); + } + + void dynamic_join() + { + /* + // OK + join_dynamic_check(t); + join_dynamic_check(t.join(f).unconditionally()); + join_dynamic_check(t.join(f).on(t.alpha > f.omega)); + + // 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); + + // Try cross joins (missing condition) + join_dynamic_check(t.join(f)); + */ + } +} + +int main(int, char* []) +{ + static_join(); + dynamic_join(); +} diff --git a/tests/SelectType.cpp b/tests/SelectType.cpp index b733a636..968542df 100644 --- a/tests/SelectType.cpp +++ b/tests/SelectType.cpp @@ -326,7 +326,6 @@ int SelectType(int, char* []) { auto s = dynamic_select(db, all_of(t)).dynamic_from(t).dynamic_where().dynamic_limit().dynamic_offset(); -#warning : Need to test the deprecated stuff s.from.add(dynamic_join(f).on(f.omega > t.alpha)); s.where.add_ntc(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); s.limit.set(30);