From cff18e917baab80c397f4806706de53078dab12f Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sat, 5 Oct 2013 17:35:40 +0200 Subject: [PATCH] Reworked join syntax --- include/sqlpp11/join.h | 71 +++++++++++++++++++--------- include/sqlpp11/on.h | 89 +++++++++++++++++++++++++++++++++++ include/sqlpp11/table_base.h | 24 ++++++++++ include/sqlpp11/type_traits.h | 1 + 4 files changed, 164 insertions(+), 21 deletions(-) create mode 100644 include/sqlpp11/on.h diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index bc88a735..4852c5c7 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -28,24 +28,29 @@ #define SQLPP_JOIN_H #include +#include namespace sqlpp { struct inner_join_t { - static constexpr const char* _name = "INNER"; + static constexpr bool _require_on = true; + static constexpr const char* _name = " INNER "; }; struct outer_join_t { - static constexpr const char* _name = "OUTER"; + static constexpr bool _require_on = true; + static constexpr const char* _name = " OUTER "; }; - struct left_join_t + struct left_outer_join_t { - static constexpr const char* _name = "LEFT OUTER"; + static constexpr bool _require_on = true; + static constexpr const char* _name = " LEFT OUTER "; }; - struct right_join_t + struct right_outer_join_t { - static constexpr const char* _name = "RIGHT OUTER"; + static constexpr bool _require_on = true; + static constexpr const char* _name = " RIGHT OUTER "; }; template @@ -53,42 +58,66 @@ namespace sqlpp { static_assert(is_table_t::value, "invalid lhs argument for join()"); static_assert(is_table_t::value, "invalid rhs argument for join()"); - static_assert(is_noop::value or is_expression_t::value, "invalid on expression in join().on()"); + static_assert(is_noop::value or is_on_t::value, "invalid on expression in join().on()"); static_assert(Lhs::_table_set::template is_disjunct_from::value, "joined tables must not be identical"); - using _is_table = typename std::conditional::value, - std::false_type, - std::true_type>::type; - using _table_set = typename std::conditional::value, - void, - typename Lhs::_table_set::template join::type>::type; + using _is_table = std::true_type; + using _table_set = typename Lhs::_table_set::template join::type; - template - using add_on_t = join_t::type>; + template + using set_on_t = join_t; template - add_on_t on(Expr&& expr) + set_on_t::type>> on(Expr&& expr) { - return { _lhs, _rhs, std::forward(expr) }; + return { _lhs, _rhs, {std::forward(expr)} }; } template join_t::type> join(T&& t) { + static_assert(not (JoinType::_require_on and is_noop::value), "join type requires on()"); + return { *this, std::forward(t) }; + } + + template + join_t::type> inner_join(T&& t) + { + static_assert(not (JoinType::_require_on and is_noop::value), "join type requires on()"); + return { *this, std::forward(t) }; + } + + template + join_t::type> outer_join(T&& t) + { + static_assert(not (JoinType::_require_on and is_noop::value), "join type requires on()"); + return { *this, std::forward(t) }; + } + + template + join_t::type> left_outer_join(T&& t) + { + static_assert(not (JoinType::_require_on and is_noop::value), "join type requires on()"); + return { *this, std::forward(t) }; + } + + template + join_t::type> right_outer_join(T&& t) + { + static_assert(not (JoinType::_require_on and is_noop::value), "join type requires on()"); return { *this, std::forward(t) }; } template void serialize(std::ostream& os, Db& db) const { - os << " ("; + static_assert(not (JoinType::_require_on and is_noop::value), "join type requires on()"); _lhs.serialize(os, db); - os << ") " << JoinType::_name << " JOIN ("; + os << JoinType::_name; + os << " JOIN "; _rhs.serialize(os, db); - os << ") ON ("; _on.serialize(os, db); - os << ")"; } Lhs _lhs; diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h new file mode 100644 index 00000000..a4c33bf9 --- /dev/null +++ b/include/sqlpp11/on.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef SQLPP_ON_H +#define SQLPP_ON_H + +#include +#include +#include +#include + +namespace sqlpp +{ + template + struct on_t + { + static_assert(is_expression_t::value, "invalid expression argument in on()"); + + using _is_on = std::true_type; + + template + void serialize(std::ostream& os, Db& db) const + { + os << " ON "; + _expr.serialize(os, db); + } + + Expr _expr; + }; + + template + struct dynamic_on_t + { + + using _is_on = std::true_type; + using _is_dynamic = std::true_type; + + template + void add(Expr&& expr) + { + static_assert(is_expression_t::type>::value, "invalid expression argument in on()"); + _conditions.push_back(std::forward(expr)); + } + + void serialize(std::ostream& os, Db& db) const + { + if (_conditions.empty()) + return; + + os << " ON "; + bool first = true; + for (const auto& condition : _conditions) + { + if (not first) + os << " AND "; + condition.serialize(os, db); + first = false; + } + } + + std::vector> _conditions; + }; + +} + +#endif diff --git a/include/sqlpp11/table_base.h b/include/sqlpp11/table_base.h index 6897d92e..0f832d25 100644 --- a/include/sqlpp11/table_base.h +++ b/include/sqlpp11/table_base.h @@ -54,6 +54,30 @@ namespace sqlpp return { *static_cast(this), std::forward(t) }; } + template + join_t::type> inner_join(T&& t) + { + return { *static_cast(this), std::forward(t) }; + } + + template + join_t::type> outer_join(T&& t) + { + return { *static_cast(this), std::forward(t) }; + } + + template + join_t::type> left_outer_join(T&& t) + { + return { *static_cast(this), std::forward(t) }; + } + + template + join_t::type> right_outer_join(T&& t) + { + return { *static_cast(this), std::forward(t) }; + } + template struct alias_t: public ColumnSpec::_name_t::template _member_t>... { diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 6fa08575..e852b0cd 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -96,6 +96,7 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(is_select_flag_list); SQLPP_TYPE_TRAIT_GENERATOR(is_select_expression_list); SQLPP_TYPE_TRAIT_GENERATOR(is_from); + SQLPP_TYPE_TRAIT_GENERATOR(is_on); SQLPP_TYPE_TRAIT_GENERATOR(is_dynamic); SQLPP_TYPE_TRAIT_GENERATOR(is_where); SQLPP_TYPE_TRAIT_GENERATOR(is_group_by);