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

Reorganized join and added a first set of serialize tests

This commit is contained in:
Roland Bock 2024-08-24 20:00:16 +02:00
parent 151af17bbc
commit 8caea01d0a
13 changed files with 341 additions and 432 deletions

View File

@ -37,6 +37,10 @@ They must not be mixed in a select.
If group_by is specified in the select, then all columns have to be aggregate expressions. If group_by is specified in the select, then all columns have to be aggregate expressions.
# Join
unconditional joins are cross joins. The "unconditional" function is dropped.
Added join tables (other than the left-most) can be dynamic.
# Dynamic queries # Dynamic queries
We don't always have a completely fixed structure for our queries. For instance, there might columns that we only want to select under certain circumstances. In version 1.0, this was handled by dynamic queries. Now we introduce conditional query parts that may or may not be used at runtime: We don't always have a completely fixed structure for our queries. For instance, there might columns that we only want to select under certain circumstances. In version 1.0, this was handled by dynamic queries. Now we introduce conditional query parts that may or may not be used at runtime:

View File

@ -27,7 +27,7 @@
*/ */
#include <sqlpp11/core/type_traits.h> #include <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/basic/join.h> #include <sqlpp11/core/basic/join_fwd.h>
namespace sqlpp namespace sqlpp
{ {
@ -64,10 +64,11 @@ namespace sqlpp
return ::sqlpp::right_outer_join(this->derived(), t); return ::sqlpp::right_outer_join(this->derived(), t);
} }
#warning: There is no full_outer_join in mysql?
template <typename T> template <typename T>
auto outer_join(T t) const -> decltype(::sqlpp::outer_join(this->derived(), t)) auto full_outer_join(T t) const -> decltype(::sqlpp::full_outer_join(this->derived(), t))
{ {
return ::sqlpp::outer_join(this->derived(), t); return ::sqlpp::full_outer_join(this->derived(), t);
} }
template <typename T> template <typename T>

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/* /*
* Copyright (c) 2013, Roland Bock * Copyright (c) 2024, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
@ -26,79 +26,147 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sqlpp11/core/basic/join_types.h> #include <sqlpp11/core/basic/join_fwd.h>
#include <sqlpp11/core/basic/pre_join.h> #include <sqlpp11/core/basic/enable_join.h>
#include <sqlpp11/core/basic/on.h>
namespace sqlpp namespace sqlpp
{ {
template <typename PreJoin, typename On> // Join representation including condition
struct join_t template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct join_t : enable_join<join_t<Lhs, JoinType, Rhs, Condition>>
{ {
using _traits = make_traits<no_value_t, tag::is_join>; join_t(Lhs lhs, Rhs rhs, Condition condition)
using _nodes = detail::type_vector<PreJoin, On>; : _lhs(std::move(lhs)), _rhs(std::move(rhs)), _condition(std::move(condition))
using _can_be_null = std::false_type;
using _provided_tables = provided_tables_of_t<PreJoin>;
using _required_tables = detail::make_difference_set_t<required_tables_of_t<On>, _provided_tables>;
template <typename T>
auto join(T t) const -> decltype(::sqlpp::join(*this, t))
{ {
return ::sqlpp::join(*this, t);
} }
template <typename T> join_t(const join_t&) = default;
auto inner_join(T t) const -> decltype(::sqlpp::inner_join(*this, t)) join_t(join_t&&) = default;
{ join_t& operator=(const join_t&) = default;
return ::sqlpp::inner_join(*this, t); join_t& operator=(join_t&&) = default;
} ~join_t() = default;
template <typename T> Lhs _lhs;
auto left_outer_join(T t) const -> decltype(::sqlpp::left_outer_join(*this, t)) Rhs _rhs;
{ Condition _condition;
return ::sqlpp::left_outer_join(*this, t);
}
template <typename T>
auto right_outer_join(T t) const -> decltype(::sqlpp::right_outer_join(*this, t))
{
return ::sqlpp::right_outer_join(*this, t);
}
template <typename T>
auto outer_join(T t) const -> decltype(::sqlpp::outer_join(*this, t))
{
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);
}
PreJoin _pre_join;
On _on;
}; };
template<typename PreJoin, typename On> template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct nodes_of<join_t<PreJoin, On>> struct nodes_of<join_t<Lhs, JoinType, Rhs, Condition>>
{
using type = sqlpp::detail::type_vector<PreJoin, On>;
};
template<typename PreJoin, typename On>
struct provided_outer_tables_of<join_t<PreJoin, On>>
{
using type = provided_outer_tables_of_t<PreJoin>;
};
template<typename PreJoin, typename On>
struct is_table<join_t<PreJoin, On>> : public std::true_type{};
template <typename Context, typename PreJoin, typename On>
auto to_sql_string(Context& context, const join_t<PreJoin, On>& t) -> std::string
{ {
return to_sql_string(context, t._pre_join) + to_sql_string(context, t._on); using type = sqlpp::detail::type_vector<Lhs, Rhs, Condition>;
};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct provided_outer_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
{
using type = typename std::conditional<
std::is_same<JoinType, left_outer_join_t>::value,
sqlpp::detail::type_set<Rhs>,
typename std::conditional<
std::is_same<JoinType, right_outer_join_t>::value,
sqlpp::detail::type_set<Lhs>,
typename std::conditional<std::is_same<JoinType, full_outer_join_t>::value,
detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>,
detail::type_set<>>::type>::type>::type;
};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct is_table<join_t<Lhs, JoinType, Rhs, Condition>> : public std::true_type
{
};
template <typename Context, typename Lhs, typename JoinType, typename Rhs, typename Condition>
auto to_sql_string(Context& context, const join_t<Lhs, JoinType, Rhs, Condition>& t) -> std::string
{
static_assert(not std::is_same<JoinType, cross_join_t>::value, "");
return to_sql_string(context, t._lhs) + JoinType::_name + to_sql_string(context, t._rhs) + " ON " +
to_sql_string(context, t._condition);
} }
template <typename Context, typename Lhs, typename JoinType, typename Rhs, typename Condition>
auto to_sql_string(Context& context, const join_t<Lhs, JoinType, dynamic_t<Rhs>, Condition>& t) -> std::string
{
static_assert(not std::is_same<JoinType, cross_join_t>::value, "");
if (t._rhs._condition)
{
return to_sql_string(context, t._lhs) + JoinType::_name + to_sql_string(context, t._rhs) + " ON " +
to_sql_string(context, t._condition);
}
return to_sql_string(context, t._lhs);
}
template <typename Context, typename Lhs, typename Rhs>
auto to_sql_string(Context& context, const join_t<Lhs, cross_join_t, Rhs, unconditional_t>& t) -> std::string
{
return to_sql_string(context, t._lhs) + cross_join_t::_name + to_sql_string(context, t._rhs);
}
template <typename Context, typename Lhs, typename Rhs>
auto to_sql_string(Context& context, const join_t<Lhs, cross_join_t, dynamic_t<Rhs>, unconditional_t>& t) -> std::string
{
if (t._rhs._condition)
{
return to_sql_string(context, t._lhs) + cross_join_t::_name + to_sql_string(context, t._rhs);
}
return to_sql_string(context, t._lhs);
}
#warning: Verify that the Expr does not require tables other than Lhs, Rhs
//and detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>::is_superset_of<required_tables_of_t<Expr>::value
template <typename Lhs, typename Rhs, typename Expr>
using check_on_args = sqlpp::enable_if_t<sqlpp::is_boolean<Expr>::value>;
template <typename Lhs, typename JoinType, typename Rhs>
struct pre_join_t
{
template <typename Expr, typename = check_on_args<Lhs, Rhs, Expr>>
auto on(Expr expr) const -> join_t<Lhs, JoinType, Rhs, Expr>
{
return {_lhs, _rhs, std::move(expr)};
}
Lhs _lhs;
Rhs _rhs;
};
// Note: See sqlpp11/core/basic/join_fwd.h for forward declarations including check_join_args.
template <typename Lhs, typename Rhs, typename /* = check_join_args<Lhs, Rhs> */>
auto join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, inner_join_t, Rhs>
{
#warning: What is the point of from_table? rename to make_table_ref?
return {from_table(std::move(lhs)), from_table(std::move(rhs))};
}
template <typename Lhs, typename Rhs, typename /* = check_join_args<Lhs, Rhs> */>
auto inner_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, inner_join_t, Rhs>
{
return {from_table(std::move(lhs)), from_table(std::move(rhs))};
}
template <typename Lhs, typename Rhs, typename /* = check_join_args<Lhs, Rhs> */>
auto left_outer_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, left_outer_join_t, Rhs>
{
return {from_table(std::move(lhs)), from_table(std::move(rhs))};
}
template <typename Lhs, typename Rhs, typename /* = check_join_args<Lhs, Rhs> */>
auto right_outer_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, right_outer_join_t, Rhs>
{
return {from_table(std::move(lhs)), from_table(std::move(rhs))};
}
template <typename Lhs, typename Rhs, typename /* = check_join_args<Lhs, Rhs> */>
auto full_outer_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, full_outer_join_t, Rhs>
{
return {from_table(std::move(lhs)), from_table(std::move(rhs))};
}
template <typename Lhs, typename Rhs, typename /* = check_join_args<Lhs, Rhs> */>
auto cross_join(Lhs lhs, Rhs rhs) -> join_t<Lhs, cross_join_t, Rhs, unconditional_t>
{
return {from_table(std::move(lhs)), from_table(std::move(rhs)), {}};
}
} // namespace sqlpp } // namespace sqlpp

View File

@ -0,0 +1,94 @@
#pragma once
/*
* Copyright (c) 2024, 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 <sqlpp11/core/unconditional.h>
#include <sqlpp11/core/query/dynamic.h>
#include <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/compat/type_traits.h>
#include <sqlpp11/core/detail/type_set.h>
namespace sqlpp
{
// Join types.
struct cross_join_t
{
static constexpr const char* _name = " CROSS JOIN ";
};
struct inner_join_t
{
static constexpr const char* _name = " INNER JOIN ";
};
struct left_outer_join_t
{
static constexpr const char* _name = " LEFT OUTER JOIN ";
};
struct right_outer_join_t
{
static constexpr const char* _name = " RIGHT OUTER JOIN ";
};
struct full_outer_join_t
{
static constexpr const char* _name = " FULL OUTER JOIN ";
};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
struct join_t;
template <typename Lhs, typename JoinType, typename Rhs>
struct pre_join_t;
template <typename Lhs, typename Rhs>
using check_join_args =
sqlpp::enable_if_t<is_table<Lhs>::value and is_table<remove_dynamic_t<Rhs>>::value and
required_tables_of_t<Lhs>::size::value == 0 and required_tables_of_t<Rhs>::size::value == 0 and
detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of_t<Lhs>>,
detail::make_name_of_set_t<provided_tables_of_t<Rhs>>>::value>;
template <typename Lhs, typename Rhs, typename = check_join_args<Lhs, Rhs>>
auto join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, inner_join_t, Rhs>;
template <typename Lhs, typename Rhs, typename = check_join_args<Lhs, Rhs>>
auto inner_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, inner_join_t, Rhs>;
template <typename Lhs, typename Rhs, typename = check_join_args<Lhs, Rhs>>
auto left_outer_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, left_outer_join_t, Rhs>;
template <typename Lhs, typename Rhs, typename = check_join_args<Lhs, Rhs>>
auto right_outer_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, right_outer_join_t, Rhs>;
template <typename Lhs, typename Rhs, typename = check_join_args<Lhs, Rhs>>
auto full_outer_join(Lhs lhs, Rhs rhs) -> pre_join_t<Lhs, full_outer_join_t, Rhs>;
template <typename Lhs, typename Rhs, typename = check_join_args<Lhs, Rhs>>
auto cross_join(Lhs lhs, Rhs rhs) -> join_t<Lhs, cross_join_t, Rhs, unconditional_t>;
} // namespace sqlpp

View File

@ -1,70 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <sqlpp11/core/type_traits.h>
namespace sqlpp
{
struct inner_join_t
{
template <typename Lhs, typename Rhs>
using _provided_outer_tables =
detail::make_joined_set_t<provided_outer_tables_of_t<Lhs>, provided_outer_tables_of_t<Rhs>>;
static constexpr const char* _name = " INNER";
};
struct outer_join_t
{
template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>;
static constexpr const char* _name = " OUTER";
};
struct left_outer_join_t
{
template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>;
static constexpr const char* _name = " LEFT OUTER";
};
struct right_outer_join_t
{
template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_outer_tables_of_t<Rhs>>;
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_t<Lhs>, provided_outer_tables_of_t<Rhs>>;
static constexpr const char* _name = " CROSS";
};
} // namespace sqlpp

View File

@ -1,80 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2015, 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 <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/unconditional.h>
#include <sqlpp11/core/logic.h>
namespace sqlpp
{
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_boolean<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>;
Expression _expression;
};
template <>
struct on_t<unconditional_t>
{
using _traits = make_traits<no_value_t, tag::is_on>;
using _nodes = detail::type_vector<>;
};
template<typename Expression>
struct nodes_of<on_t<Expression>>
{
using type = sqlpp::detail::type_vector<Expression>;
};
template <typename Context>
auto to_sql_string(Context& , const on_t<unconditional_t>&) -> std::string
{
return {};
}
template <typename Context, typename Expression>
auto to_sql_string(Context& context, const on_t<Expression>& t) -> std::string
{
return " ON " + to_sql_string(context, t._expression);
}
} // namespace sqlpp

View File

@ -1,213 +0,0 @@
#pragma once
/*
* 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.
*/
#include <sqlpp11/core/basic/join_types.h>
#include <sqlpp11/core/noop.h>
#include <sqlpp11/core/query/dynamic.h>
#include <sqlpp11/core/basic/on.h>
#include <sqlpp11/core/basic/table_ref.h>
namespace sqlpp
{
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_pre_join
{
using type = static_combined_check_t<
static_check_t<is_table<Lhs>::value, assert_pre_join_lhs_table_t>,
static_check_t<is_table<Rhs>::value, assert_pre_join_rhs_table_t>,
static_check_t<not is_join_t<Rhs>::value, assert_pre_join_rhs_no_join_t>,
#warning: Since rhs is a table, we could also just get a type vector here.
static_check_t<detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of_t<Lhs>>,
detail::make_name_of_set_t<provided_tables_of_t<Rhs>>>::value,
assert_pre_join_unique_names_t>>;
};
template <typename Lhs, typename Rhs>
using check_pre_join_t = typename check_pre_join<Lhs, Rhs>::type;
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 PreJoin, typename On>
struct check_join
{
using type = static_combined_check_t<
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_t<PreJoin>::size::value == 0, assert_join_no_table_dependencies_t>,
static_check_t<detail::is_subset_of<required_tables_of_t<On>, provided_tables_of_t<PreJoin>>::value,
assert_join_on_no_foreign_table_dependencies_t>>;
};
template <typename PreJoin, typename On>
using check_join_t = typename check_join<PreJoin, On>::type;
template <typename PreJoin, typename Expr>
struct check_join_on
{
using type = static_combined_check_t<check_on_t<Expr>, check_join_t<PreJoin, on_t<Expr>>>;
};
template <typename PreJoin, typename Expr>
using check_join_on_t = typename check_join_on<PreJoin, Expr>::type;
template <typename PreJoin, typename On>
struct join_t;
template <typename JoinType, typename Lhs, typename Rhs>
struct pre_join_t
{
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;
using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>;
#warning: Do we really need this?
static_assert(required_tables_of_t<pre_join_t>::size::value == 0, "joined tables must not depend on other tables");
auto unconditionally() -> join_t<pre_join_t, on_t<unconditional_t>>
{
return {*this, {}};
}
template <typename 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>>,
check_join_on_t<pre_join_t, Expr>>::type
{
using Check = check_join_on_t<pre_join_t, Expr>;
return on_impl(Check{}, expr);
}
private:
template <typename Check, typename Expr>
auto on_impl(Check, const Expr&) const -> inconsistent<Check>;
template <typename Expr>
auto on_impl(consistent_t /*unused*/, const Expr& expr) const -> join_t<pre_join_t, on_t<Expr>>
{
return {*this, {expr}};
}
public:
Lhs _lhs;
Rhs _rhs;
};
template <typename JoinType, typename Lhs, typename Rhs>
struct nodes_of<pre_join_t<JoinType, Lhs, Rhs>>
{
using type = sqlpp::detail::type_vector<Lhs, Rhs>;
};
template <typename JoinType, typename Lhs, typename Rhs>
struct provided_outer_tables_of<pre_join_t<JoinType, Lhs, Rhs>>
{
using type = typename JoinType::template _provided_outer_tables<Lhs, Rhs>;
};
template <typename Context, typename JoinType, typename Lhs, typename Rhs>
auto to_sql_string(Context& context, const pre_join_t<JoinType, Lhs, Rhs>& t) -> std::string
{
return to_sql_string(context, t._lhs) + JoinType::_name + " JOIN " + to_sql_string(context, t._rhs);
}
namespace detail
{
template <typename JoinType, typename Check, typename Lhs, typename Rhs>
auto join_impl(Check, Lhs lhs, Rhs rhs) -> inconsistent<Check>;
template <typename JoinType, typename Lhs, typename Rhs>
auto join_impl(consistent_t, Lhs lhs, Rhs rhs) -> pre_join_t<JoinType, from_table_t<Lhs>, from_table_t<Rhs>>;
template <typename JoinType, typename Lhs, typename Rhs>
auto join_impl(Lhs lhs, Rhs rhs) -> decltype(join_impl<JoinType>(check_pre_join_t<Lhs, remove_dynamic_t<Rhs>>{}, lhs, rhs));
} // namespace detail
template <typename Lhs, typename Rhs>
auto join(Lhs lhs, Rhs rhs) -> decltype(detail::join_impl<inner_join_t>(lhs, rhs))
{
return {from_table(lhs), from_table(rhs)};
}
template <typename Lhs, typename Rhs>
auto inner_join(Lhs lhs, Rhs rhs) -> decltype(detail::join_impl<inner_join_t>(lhs, rhs))
{
return {from_table(lhs), from_table(rhs)};
}
template <typename Lhs, typename Rhs>
auto left_outer_join(Lhs lhs, Rhs rhs) -> decltype(detail::join_impl<left_outer_join_t>(lhs, rhs))
{
return {from_table(lhs), from_table(rhs)};
}
template <typename Lhs, typename Rhs>
auto right_outer_join(Lhs lhs, Rhs rhs) -> decltype(detail::join_impl<right_outer_join_t>(lhs, rhs))
{
check_pre_join_t<Lhs, Rhs>::verify();
return {from_table(lhs), from_table(rhs)};
}
template <typename Lhs, typename Rhs>
auto outer_join(Lhs lhs, Rhs rhs) -> decltype(detail::join_impl<outer_join_t>(lhs, rhs))
{
return {from_table(lhs), from_table(rhs)};
}
namespace detail
{
template <typename Check, typename Lhs, typename Rhs>
auto cross_join_impl(Check, Lhs lhs, Rhs rhs) -> inconsistent<Check>;
template <typename Lhs, typename Rhs>
auto cross_join_impl(consistent_t, Lhs lhs, Rhs rhs)
-> join_t<pre_join_t<cross_join_t, Lhs, Rhs>, on_t<unconditional_t>>;
template <typename Lhs, typename Rhs>
auto cross_join_impl(Lhs lhs, Rhs rhs)
-> decltype(cross_join_impl(check_pre_join_t<from_table_t<Lhs>, from_table_t<Rhs>>{}, lhs, rhs));
} // namespace detail
template <typename Lhs, typename Rhs>
auto cross_join(Lhs lhs, Rhs rhs) -> decltype(detail::cross_join_impl(lhs, rhs))
{
return {pre_join_t<cross_join_t, from_table_t<Lhs>, from_table_t<Rhs>>{from_table(lhs), from_table(rhs)}, {}};
}
} // namespace sqlpp

View File

@ -40,7 +40,7 @@
namespace sqlpp namespace sqlpp
{ {
template <typename Context, typename X = void> template <typename Context, typename X = void>
auto to_sql_string(Context& context, ...) -> std::string auto to_sql_string(Context& , ...) -> std::string
{ {
static_assert(wrong_t<X>::value, "Missing specialization"); static_assert(wrong_t<X>::value, "Missing specialization");
return {}; return {};

View File

@ -54,6 +54,7 @@ foreach(test_file IN LISTS test_files)
endforeach() endforeach()
add_subdirectory(aggregate_function) add_subdirectory(aggregate_function)
add_subdirectory(basic)
add_subdirectory(clause) add_subdirectory(clause)
add_subdirectory(operator) add_subdirectory(operator)
add_subdirectory(query) add_subdirectory(query)

View File

@ -0,0 +1,33 @@
# Copyright (c) 2024, 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.
function(create_test name)
set(target sqlpp11_core_serialize_basic_${name})
add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing)
add_test(NAME ${target} COMMAND ${target})
endfunction()
create_test(join)

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2024, 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 "Sample.h"
#include "../compare.h"
#include <sqlpp11/sqlpp11.h>
SQLPP_ALIAS_PROVIDER(v);
int main(int, char* [])
{
const auto val = sqlpp::value(17);
const auto expr = sqlpp::value(17) + 4;
const auto foo = test::TabFoo{};
const auto bar = test::TabBar{};
// Join with two tables
SQLPP_COMPARE(foo.join(bar).on(foo.id == bar.id), "tab_foo INNER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.inner_join(bar).on(foo.id == bar.id), "tab_foo INNER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.left_outer_join(bar).on(foo.id == bar.id), "tab_foo LEFT OUTER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.right_outer_join(bar).on(foo.id == bar.id), "tab_foo RIGHT OUTER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.full_outer_join(bar).on(foo.id == bar.id), "tab_foo FULL OUTER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.cross_join(bar), "tab_foo CROSS JOIN tab_bar");
// Join with dynamic table
SQLPP_COMPARE(foo.join(dynamic(true, bar)).on(foo.id == bar.id), "tab_foo INNER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.inner_join(dynamic(true, bar)).on(foo.id == bar.id), "tab_foo INNER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.left_outer_join(dynamic(true, bar)).on(foo.id == bar.id), "tab_foo LEFT OUTER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.right_outer_join(dynamic(true, bar)).on(foo.id == bar.id), "tab_foo RIGHT OUTER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.full_outer_join(dynamic(true, bar)).on(foo.id == bar.id), "tab_foo FULL OUTER JOIN tab_bar ON tab_foo.id = tab_bar.id");
SQLPP_COMPARE(foo.cross_join(dynamic(true, bar)), "tab_foo CROSS JOIN tab_bar");
SQLPP_COMPARE(foo.join(dynamic(false, bar)).on(foo.id == bar.id), "tab_foo");
SQLPP_COMPARE(foo.inner_join(dynamic(false, bar)).on(foo.id == bar.id), "tab_foo");
SQLPP_COMPARE(foo.left_outer_join(dynamic(false, bar)).on(foo.id == bar.id), "tab_foo");
SQLPP_COMPARE(foo.right_outer_join(dynamic(false, bar)).on(foo.id == bar.id), "tab_foo");
SQLPP_COMPARE(foo.full_outer_join(dynamic(false, bar)).on(foo.id == bar.id), "tab_foo");
SQLPP_COMPARE(foo.cross_join(dynamic(false, bar)), "tab_foo");
#warning: Need to add tests with 3 tables
#warning: Need to add tests with CTEs
return 0;
}

View File

@ -23,7 +23,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function(test_compile name) function(test_compile name)
set(target sqlpp11_core_types_clause_${name}) set(target sqlpp11_core_types_basic_${name})
add_executable(${target} ${name}.cpp) add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing) target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing)
endfunction() endfunction()

View File

@ -69,6 +69,7 @@ void test_group_by()
} }
#warning: Need to add tests all join types!
#warning: Need to add tests with 3 tables #warning: Need to add tests with 3 tables
#warning: Need to add tests with CTEs #warning: Need to add tests with CTEs