mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 04:47:18 +08:00
Made from() testable with portable static asserts, added tests
Added cross_join_t, simplifying join a lot
This commit is contained in:
parent
d7a29fac97
commit
3461918d88
91
include/sqlpp11/cross_join.h
Normal file
91
include/sqlpp11/cross_join.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SQLPP_CROSS_JOIN_H
|
||||||
|
#define SQLPP_CROSS_JOIN_H
|
||||||
|
|
||||||
|
#include <sqlpp11/join_types.h>
|
||||||
|
#include <sqlpp11/on.h>
|
||||||
|
#include <sqlpp11/noop.h>
|
||||||
|
|
||||||
|
namespace sqlpp
|
||||||
|
{
|
||||||
|
template <typename CrossJoin, typename On>
|
||||||
|
struct join_t;
|
||||||
|
|
||||||
|
template <typename JoinType, typename Lhs, typename Rhs>
|
||||||
|
struct cross_join_t
|
||||||
|
{
|
||||||
|
using _traits = make_traits<no_value_t, tag::is_cross_join>;
|
||||||
|
using _nodes = detail::type_vector<Lhs, Rhs>;
|
||||||
|
using _can_be_null = std::false_type;
|
||||||
|
|
||||||
|
static_assert(is_table_t<Lhs>::value, "lhs argument for join() has to be a table or join");
|
||||||
|
static_assert(is_table_t<Rhs>::value, "rhs argument for join() has to be a table");
|
||||||
|
static_assert(not is_join_t<Rhs>::value, "rhs argument for join must not be a join");
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
template <typename Expr>
|
||||||
|
auto on(Expr expr) -> join_t<cross_join_t, on_t<void, Expr>>
|
||||||
|
{
|
||||||
|
static_assert(is_expression_t<Expr>::value, "argument is not an expression in on()");
|
||||||
|
|
||||||
|
static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
|
||||||
|
|
||||||
|
return {*this, {expr, {}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unconditionally() -> join_t<cross_join_t, on_t<void, 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>>
|
||||||
|
{
|
||||||
|
using _serialize_check = serialize_check_of<Context, Lhs, Rhs>;
|
||||||
|
using T = cross_join_t<JoinType, Lhs, Rhs>;
|
||||||
|
|
||||||
|
static Context& _(const T& t, Context& context)
|
||||||
|
{
|
||||||
|
serialize(t._lhs, context);
|
||||||
|
context << JoinType::_name;
|
||||||
|
context << " JOIN ";
|
||||||
|
serialize(t._rhs, context);
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -50,14 +50,14 @@ namespace sqlpp
|
|||||||
template <typename OnT>
|
template <typename OnT>
|
||||||
using set_on_t = dynamic_join_t<JoinType, Rhs, OnT>;
|
using set_on_t = dynamic_join_t<JoinType, Rhs, OnT>;
|
||||||
|
|
||||||
template <typename... Expr>
|
template <typename Expr>
|
||||||
auto on(Expr... expr) -> set_on_t<on_t<void, Expr...>>
|
auto on(Expr expr) -> set_on_t<on_t<void, Expr>>
|
||||||
{
|
{
|
||||||
static_assert(is_noop<On>::value, "cannot call on() twice for a single join()");
|
static_assert(is_noop<On>::value, "cannot call on() twice for a single join()");
|
||||||
static_assert(logic::all_t<is_expression_t<Expr>::value...>::value,
|
static_assert(is_expression_t<Expr>::value, "argument is not a boolean expression in on()");
|
||||||
"at least one argument is not an expression in on()");
|
static_assert(is_boolean_t<Expr>::value, "argument is not a boolean expression in on()");
|
||||||
|
|
||||||
return {_rhs, {std::tuple<Expr...>{expr...}, {}}};
|
return {_rhs, {expr, {}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unconditionally() -> set_on_t<on_t<void, unconditional_t>>
|
auto unconditionally() -> set_on_t<on_t<void, unconditional_t>>
|
||||||
|
@ -147,6 +147,39 @@ 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()");
|
||||||
|
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()");
|
||||||
|
|
||||||
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dynamic_statement_dynamic_t,
|
||||||
|
"dynamic_from must not be called in a static statement");
|
||||||
|
|
||||||
|
template <typename Table>
|
||||||
|
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<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 ==
|
||||||
|
detail::make_name_of_set_t<provided_tables_of<Table>>::size::value,
|
||||||
|
assert_from_no_duplicates_t>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Table>
|
||||||
|
using check_from_t = typename check_from<Table>::type;
|
||||||
|
|
||||||
|
template <typename Table>
|
||||||
|
using check_from_static_t = check_from_t<Table>;
|
||||||
|
|
||||||
|
template <typename Database, typename Table>
|
||||||
|
using check_from_dynamic_t = static_combined_check_t<
|
||||||
|
static_check_t<not std::is_same<Database, void>::value, assert_from_dynamic_statement_dynamic_t>,
|
||||||
|
check_from_t<Table>>;
|
||||||
|
|
||||||
struct no_from_t
|
struct no_from_t
|
||||||
{
|
{
|
||||||
using _traits = make_traits<no_value_t, tag::is_noop>;
|
using _traits = make_traits<no_value_t, tag::is_noop>;
|
||||||
@ -199,33 +232,26 @@ namespace sqlpp
|
|||||||
|
|
||||||
using _database_t = typename Policies::_database_t;
|
using _database_t = typename Policies::_database_t;
|
||||||
|
|
||||||
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
|
|
||||||
// template <typename... T>
|
|
||||||
// using _check = logic::all_t<is_table_t<T>::value...>;
|
|
||||||
template <typename... T>
|
|
||||||
struct _check : logic::all_t<is_table_t<T>::value...>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Check, typename T>
|
template <typename Check, typename T>
|
||||||
using _new_statement_t = new_statement_t<Check::value, Policies, no_from_t, T>;
|
using _new_statement_t = new_statement_t<Check::value, Policies, no_from_t, T>;
|
||||||
|
|
||||||
using _consistency_check = consistent_t;
|
using _consistency_check = consistent_t;
|
||||||
|
|
||||||
template <typename Table>
|
template <typename Table>
|
||||||
auto from(Table table) const -> _new_statement_t<_check<Table>, from_t<void, from_table_t<Table>>>
|
auto from(Table table) const -> _new_statement_t<check_from_static_t<Table>, from_t<void, from_table_t<Table>>>
|
||||||
{
|
{
|
||||||
static_assert(_check<Table>::value, "argument is not a table or join in from()");
|
using Check = check_from_static_t<Table>;
|
||||||
return _from_impl<void>(_check<Table>{}, table);
|
Check{}._();
|
||||||
|
return _from_impl<void>(Check{}, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Table>
|
template <typename Table>
|
||||||
auto dynamic_from(Table table) const -> _new_statement_t<_check<Table>, from_t<_database_t, from_table_t<Table>>>
|
auto dynamic_from(Table table) const
|
||||||
|
-> _new_statement_t<check_from_dynamic_t<_database_t, Table>, from_t<_database_t, from_table_t<Table>>>
|
||||||
{
|
{
|
||||||
static_assert(not std::is_same<_database_t, void>::value,
|
using Check = check_from_dynamic_t<_database_t, Table>;
|
||||||
"dynamic_from must not be called in a static statement");
|
Check{}._();
|
||||||
static_assert(_check<Table>::value, "argument is not a table or join in from()");
|
return _from_impl<_database_t>(Check{}, table);
|
||||||
return _from_impl<_database_t>(_check<Table>{}, table);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -236,17 +262,6 @@ namespace sqlpp
|
|||||||
auto _from_impl(const std::true_type&, Table table) const
|
auto _from_impl(const std::true_type&, Table table) const
|
||||||
-> _new_statement_t<std::true_type, from_t<Database, from_table_t<Table>>>
|
-> _new_statement_t<std::true_type, from_t<Database, from_table_t<Table>>>
|
||||||
{
|
{
|
||||||
static_assert(required_tables_of<from_t<Database, Table>>::size::value == 0,
|
|
||||||
"at least one table depends on another table in from()");
|
|
||||||
|
|
||||||
static constexpr std::size_t _number_of_tables = detail::sum(provided_tables_of<Table>::size::value);
|
|
||||||
using _unique_tables = provided_tables_of<Table>;
|
|
||||||
using _unique_table_names = detail::make_name_of_set_t<_unique_tables>;
|
|
||||||
static_assert(_number_of_tables == _unique_tables::size::value,
|
|
||||||
"at least one duplicate table detected in from()");
|
|
||||||
static_assert(_number_of_tables == _unique_table_names::size::value,
|
|
||||||
"at least one duplicate table name detected in from()");
|
|
||||||
|
|
||||||
return {static_cast<const derived_statement_t<Policies>&>(*this),
|
return {static_cast<const derived_statement_t<Policies>&>(*this),
|
||||||
from_data_t<Database, from_table_t<Table>>{from_table(table)}};
|
from_data_t<Database, from_table_t<Table>>{from_table(table)}};
|
||||||
}
|
}
|
||||||
|
@ -28,99 +28,70 @@
|
|||||||
#define SQLPP_JOIN_H
|
#define SQLPP_JOIN_H
|
||||||
|
|
||||||
#include <sqlpp11/join_types.h>
|
#include <sqlpp11/join_types.h>
|
||||||
|
#include <sqlpp11/cross_join.h>
|
||||||
#include <sqlpp11/on.h>
|
#include <sqlpp11/on.h>
|
||||||
#include <sqlpp11/noop.h>
|
|
||||||
|
|
||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
template <typename JoinType, typename Lhs, typename Rhs, typename On = noop>
|
template <typename CrossJoin, typename On>
|
||||||
struct join_t
|
struct join_t
|
||||||
{
|
{
|
||||||
using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>;
|
using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>;
|
||||||
using _nodes = detail::type_vector<Lhs, Rhs>;
|
using _nodes = detail::type_vector<CrossJoin, On>;
|
||||||
using _can_be_null = std::false_type;
|
using _can_be_null = std::false_type;
|
||||||
|
using _provided_tables = provided_tables_of<CrossJoin>;
|
||||||
|
using _required_tables = detail::make_difference_set_t<required_tables_of<On>, _provided_tables>;
|
||||||
|
|
||||||
static_assert(is_table_t<Lhs>::value, "lhs argument for join() has to be a table or join");
|
static_assert(is_cross_join_t<CrossJoin>::value, "lhs argument for join() has to be a table or join");
|
||||||
static_assert(is_table_t<Rhs>::value, "rhs argument for join() has to be a table");
|
static_assert(is_on_t<On>::value, "invalid on expression in join().on()");
|
||||||
static_assert(not is_join_t<Rhs>::value, "rhs argument for join must not be a join");
|
|
||||||
static_assert(is_noop<On>::value or is_on_t<On>::value, "invalid on expression in join().on()");
|
|
||||||
|
|
||||||
static_assert(detail::is_disjunct_from<provided_tables_of<Lhs>, provided_tables_of<Rhs>>::value,
|
static_assert(required_tables_of<CrossJoin>::size::value == 0, "joined tables must not depend on other tables");
|
||||||
"joined tables must not be identical");
|
static_assert(detail::is_subset_of<required_tables_of<On>, provided_tables_of<CrossJoin>>::value,
|
||||||
|
"on() condition must not depend on other tables");
|
||||||
|
|
||||||
static_assert(required_tables_of<join_t>::size::value == 0, "joined tables must not depend on other tables");
|
template <typename T>
|
||||||
|
cross_join_t<inner_join_t, join_t, T> join(T t)
|
||||||
template <typename OnT>
|
|
||||||
using set_on_t = join_t<JoinType, Lhs, Rhs, OnT>;
|
|
||||||
|
|
||||||
template <typename... Expr>
|
|
||||||
auto on(Expr... expr) -> set_on_t<on_t<void, Expr...>>
|
|
||||||
{
|
{
|
||||||
static_assert(is_noop<On>::value, "cannot call on() twice for a single join()");
|
return {*this, t};
|
||||||
static_assert(logic::all_t<is_expression_t<Expr>::value...>::value,
|
|
||||||
"at least one argument is not an expression in on()");
|
|
||||||
|
|
||||||
return {_lhs, _rhs, {std::tuple<Expr...>{expr...}, {}}};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto unconditionally() -> set_on_t<on_t<void, unconditional_t>>
|
|
||||||
{
|
|
||||||
return {_lhs, _rhs, {}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<inner_join_t, join_t, T> join(T t)
|
cross_join_t<inner_join_t, join_t, T> inner_join(T t)
|
||||||
{
|
{
|
||||||
static_assert(not is_noop<On>::value, "join type requires on()");
|
return {*this, t};
|
||||||
return {*this, t, {}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<inner_join_t, join_t, T> inner_join(T t)
|
cross_join_t<outer_join_t, join_t, T> outer_join(T t)
|
||||||
{
|
{
|
||||||
static_assert(not is_noop<On>::value, "join type requires on()");
|
return {*this, t};
|
||||||
return {*this, t, {}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<outer_join_t, join_t, T> outer_join(T t)
|
cross_join_t<left_outer_join_t, join_t, T> left_outer_join(T t)
|
||||||
{
|
{
|
||||||
static_assert(not is_noop<On>::value, "join type requires on()");
|
return {*this, t};
|
||||||
return {*this, t, {}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<left_outer_join_t, join_t, T> left_outer_join(T t)
|
cross_join_t<right_outer_join_t, join_t, T> right_outer_join(T t)
|
||||||
{
|
{
|
||||||
static_assert(not is_noop<On>::value, "join type requires on()");
|
return {*this, t};
|
||||||
return {*this, t, {}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
CrossJoin _cross_join;
|
||||||
join_t<right_outer_join_t, join_t, T> right_outer_join(T t)
|
|
||||||
{
|
|
||||||
static_assert(not is_noop<On>::value, "join type requires on()");
|
|
||||||
return {*this, t, {}};
|
|
||||||
}
|
|
||||||
|
|
||||||
Lhs _lhs;
|
|
||||||
Rhs _rhs;
|
|
||||||
On _on;
|
On _on;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Context, typename JoinType, typename Lhs, typename Rhs, typename On>
|
template <typename Context, typename CrossJoin, typename On>
|
||||||
struct serializer_t<Context, join_t<JoinType, Lhs, Rhs, On>>
|
struct serializer_t<Context, join_t<CrossJoin, On>>
|
||||||
{
|
{
|
||||||
using _serialize_check = serialize_check_of<Context, Lhs, Rhs, On>;
|
using _serialize_check = serialize_check_of<Context, CrossJoin, On>;
|
||||||
using T = join_t<JoinType, Lhs, Rhs, On>;
|
using T = join_t<CrossJoin, On>;
|
||||||
|
|
||||||
static Context& _(const T& t, Context& context)
|
static Context& _(const T& t, Context& context)
|
||||||
{
|
{
|
||||||
static_assert(not is_noop<On>::value, "joined tables require on()");
|
serialize(t._cross_join, context);
|
||||||
serialize(t._lhs, context);
|
|
||||||
context << JoinType::_name;
|
|
||||||
context << " JOIN ";
|
|
||||||
serialize(t._rhs, context);
|
|
||||||
serialize(t._on, context);
|
serialize(t._on, context);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -28,23 +28,20 @@
|
|||||||
#define SQLPP_ON_H
|
#define SQLPP_ON_H
|
||||||
|
|
||||||
#include <sqlpp11/type_traits.h>
|
#include <sqlpp11/type_traits.h>
|
||||||
#include <sqlpp11/interpret_tuple.h>
|
|
||||||
#include <sqlpp11/interpretable_list.h>
|
#include <sqlpp11/interpretable_list.h>
|
||||||
#include <sqlpp11/unconditional.h>
|
#include <sqlpp11/unconditional.h>
|
||||||
#include <sqlpp11/logic.h>
|
#include <sqlpp11/logic.h>
|
||||||
|
|
||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
template <typename Database, typename... Expressions>
|
template <typename Database, typename Expression>
|
||||||
struct on_t
|
struct on_t
|
||||||
{
|
{
|
||||||
using _traits = make_traits<no_value_t, tag::is_on>;
|
using _traits = make_traits<no_value_t, tag::is_on>;
|
||||||
using _nodes = detail::type_vector<Expressions...>;
|
using _nodes = detail::type_vector<Expression>;
|
||||||
|
|
||||||
using _is_dynamic = is_database<Database>;
|
using _is_dynamic = is_database<Database>;
|
||||||
|
|
||||||
static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in on()");
|
|
||||||
|
|
||||||
template <typename Expr>
|
template <typename Expr>
|
||||||
void add(Expr expr)
|
void add(Expr expr)
|
||||||
{
|
{
|
||||||
@ -69,7 +66,7 @@ namespace sqlpp
|
|||||||
void _add_impl(Expr expr, const std::false_type&);
|
void _add_impl(Expr expr, const std::false_type&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::tuple<Expressions...> _expressions;
|
Expression _expression;
|
||||||
interpretable_list_t<Database> _dynamic_expressions;
|
interpretable_list_t<Database> _dynamic_expressions;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,8 +100,8 @@ namespace sqlpp
|
|||||||
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
|
if (sizeof...(Expressions) == 0 and t._dynamic_expressions.empty())
|
||||||
return context;
|
return context;
|
||||||
context << " ON (";
|
context << " ON (";
|
||||||
interpret_tuple(t._expressions, " AND ", context);
|
serialize(t._expression, context);
|
||||||
if (sizeof...(Expressions) and not t._dynamic_expressions.empty())
|
if (not t._dynamic_expressions.empty())
|
||||||
context << " AND ";
|
context << " AND ";
|
||||||
interpret_list(t._dynamic_expressions, " AND ", context);
|
interpret_list(t._dynamic_expressions, " AND ", context);
|
||||||
context << " )";
|
context << " )";
|
||||||
|
@ -62,33 +62,33 @@ namespace sqlpp
|
|||||||
using _alias_t = table_alias_t<AliasProvider, Table, ColumnSpec...>;
|
using _alias_t = table_alias_t<AliasProvider, Table, ColumnSpec...>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<inner_join_t, Table, T> join(T t) const
|
cross_join_t<inner_join_t, Table, T> join(T t) const
|
||||||
{
|
{
|
||||||
return {*static_cast<const Table*>(this), t, {}};
|
return {*static_cast<const Table*>(this), t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<inner_join_t, Table, T> inner_join(T t) const
|
cross_join_t<inner_join_t, Table, T> inner_join(T t) const
|
||||||
{
|
{
|
||||||
return {*static_cast<const Table*>(this), t, {}};
|
return {*static_cast<const Table*>(this), t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<outer_join_t, Table, T> outer_join(T t) const
|
cross_join_t<outer_join_t, Table, T> outer_join(T t) const
|
||||||
{
|
{
|
||||||
return {*static_cast<const Table*>(this), t, {}};
|
return {*static_cast<const Table*>(this), t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<left_outer_join_t, Table, T> left_outer_join(T t) const
|
cross_join_t<left_outer_join_t, Table, T> left_outer_join(T t) const
|
||||||
{
|
{
|
||||||
return {*static_cast<const Table*>(this), t, {}};
|
return {*static_cast<const Table*>(this), t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<right_outer_join_t, Table, T> right_outer_join(T t) const
|
cross_join_t<right_outer_join_t, Table, T> right_outer_join(T t) const
|
||||||
{
|
{
|
||||||
return {*static_cast<const Table*>(this), t, {}};
|
return {*static_cast<const Table*>(this), t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename AliasProvider>
|
template <typename AliasProvider>
|
||||||
|
@ -61,33 +61,33 @@ namespace sqlpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<inner_join_t, table_alias_t, T> join(T t) const
|
cross_join_t<inner_join_t, table_alias_t, T> join(T t) const
|
||||||
{
|
{
|
||||||
return {*this, t, {}};
|
return {*this, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<inner_join_t, table_alias_t, T> inner_join(T t) const
|
cross_join_t<inner_join_t, table_alias_t, T> inner_join(T t) const
|
||||||
{
|
{
|
||||||
return {*this, t, {}};
|
return {*this, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<outer_join_t, table_alias_t, T> outer_join(T t) const
|
cross_join_t<outer_join_t, table_alias_t, T> outer_join(T t) const
|
||||||
{
|
{
|
||||||
return {*this, t, {}};
|
return {*this, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<left_outer_join_t, table_alias_t, T> left_outer_join(T t) const
|
cross_join_t<left_outer_join_t, table_alias_t, T> left_outer_join(T t) const
|
||||||
{
|
{
|
||||||
return {*this, t, {}};
|
return {*this, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
join_t<right_outer_join_t, table_alias_t, T> right_outer_join(T t) const
|
cross_join_t<right_outer_join_t, table_alias_t, T> right_outer_join(T t) const
|
||||||
{
|
{
|
||||||
return {*this, t, {}};
|
return {*this, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
Table _table;
|
Table _table;
|
||||||
|
@ -56,6 +56,12 @@ namespace sqlpp
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using value_type_of = typename detail::value_type_of_impl<T>::type;
|
using value_type_of = typename detail::value_type_of_impl<T>::type;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_not_cpp_bool_t
|
||||||
|
{
|
||||||
|
static constexpr bool value = not std::is_same<T, bool>::value;
|
||||||
|
};
|
||||||
|
|
||||||
// data types
|
// data types
|
||||||
struct boolean;
|
struct boolean;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -163,6 +169,7 @@ namespace sqlpp
|
|||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_table)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_table)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table)
|
||||||
|
SQLPP_VALUE_TRAIT_GENERATOR(is_cross_join)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_join)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_join)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_dynamic_join)
|
||||||
SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table)
|
SQLPP_VALUE_TRAIT_GENERATOR(is_pseudo_table)
|
||||||
@ -374,6 +381,7 @@ namespace sqlpp
|
|||||||
using serialize_check_of =
|
using serialize_check_of =
|
||||||
detail::get_first_if<is_inconsistent_t, consistent_t, typename serializer_t<Context, T>::_serialize_check...>;
|
detail::get_first_if<is_inconsistent_t, consistent_t, typename serializer_t<Context, T>::_serialize_check...>;
|
||||||
|
|
||||||
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_sqlpp_type_t, "expression is not an sqlpp type, consistency cannot be verified");
|
||||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_run_statement_or_prepared_t,
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_run_statement_or_prepared_t,
|
||||||
"connection cannot run something that is neither statement nor prepared statement");
|
"connection cannot run something that is neither statement nor prepared statement");
|
||||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_prepare_statement_t,
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_prepare_statement_t,
|
||||||
@ -382,12 +390,11 @@ namespace sqlpp
|
|||||||
template <typename T, typename Enable = void>
|
template <typename T, typename Enable = void>
|
||||||
struct consistency_check
|
struct consistency_check
|
||||||
{
|
{
|
||||||
using type = assert_run_statement_or_prepared_t;
|
using type = assert_sqlpp_type_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct consistency_check<T,
|
struct consistency_check<T, detail::void_t<typename T::_consistency_check>>
|
||||||
typename std::enable_if<is_statement_t<T>::value or is_prepared_statement_t<T>::value>::type>
|
|
||||||
{
|
{
|
||||||
using type = typename T::_consistency_check;
|
using type = typename T::_consistency_check;
|
||||||
};
|
};
|
||||||
|
@ -93,6 +93,7 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
static_assert(_is_dynamic::value, "where::add() can only be called for dynamic_where");
|
static_assert(_is_dynamic::value, "where::add() can only be called for dynamic_where");
|
||||||
static_assert(is_expression_t<Expression>::value, "invalid expression argument in where::add()");
|
static_assert(is_expression_t<Expression>::value, "invalid expression argument in where::add()");
|
||||||
|
static_assert(is_boolean_t<Expression>::value, "invalid expression argument in where::add()");
|
||||||
static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables<Expression>::value,
|
static_assert(not TableCheckRequired::value or Policies::template _no_unknown_tables<Expression>::value,
|
||||||
"expression uses tables unknown to this statement in where::add()");
|
"expression uses tables unknown to this statement in where::add()");
|
||||||
static_assert(not contains_aggregate_function_t<Expression>::value,
|
static_assert(not contains_aggregate_function_t<Expression>::value,
|
||||||
@ -217,9 +218,11 @@ namespace sqlpp
|
|||||||
|
|
||||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "calling where() or uncontionally() required");
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_t, "calling where() or uncontionally() required");
|
||||||
|
|
||||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_expression_t,
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_not_cpp_bool_t,
|
||||||
"at least one argument is not a sqlpp::boolean expression in where(). Please use "
|
"where() argument has to be an sqlpp boolean expression. Please use "
|
||||||
".unconditionally() instead of .where(true), or sqlpp::value(bool)");
|
".unconditionally() instead of .where(true), or sqlpp::value(bool)");
|
||||||
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_boolean_expression_t,
|
||||||
|
"where() argument has to be an sqlpp boolean expression.");
|
||||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_no_aggregate_functions_t,
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_no_aggregate_functions_t,
|
||||||
"at least one aggregate function used in where()");
|
"at least one aggregate function used in where()");
|
||||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_static_count_args_t, "missing argument in where()");
|
SQLPP_PORTABLE_STATIC_ASSERT(assert_where_static_count_args_t, "missing argument in where()");
|
||||||
@ -230,6 +233,8 @@ namespace sqlpp
|
|||||||
// https://connect.microsoft.com/VisualStudio/feedback/details/2173198
|
// https://connect.microsoft.com/VisualStudio/feedback/details/2173198
|
||||||
// template <typename... Expressions>
|
// template <typename... Expressions>
|
||||||
// using check_where_t = static_combined_check_t<
|
// using check_where_t = static_combined_check_t<
|
||||||
|
// static_check_t<logic::all_t<is_not_cpp_bool_t<Expressions>::value...>::value,
|
||||||
|
// assert_where_not_cpp_bool_t>,
|
||||||
// static_check_t<logic::all_t<is_expression_t<Expressions>::value...>::value,
|
// static_check_t<logic::all_t<is_expression_t<Expressions>::value...>::value,
|
||||||
// assert_where_boolean_expressions_t>,
|
// assert_where_boolean_expressions_t>,
|
||||||
// static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>,
|
// static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>,
|
||||||
@ -239,6 +244,7 @@ namespace sqlpp
|
|||||||
struct check_where
|
struct check_where
|
||||||
{
|
{
|
||||||
using type = static_combined_check_t<
|
using type = static_combined_check_t<
|
||||||
|
static_check_t<logic::all_t<is_not_cpp_bool_t<Expressions>::value...>::value, assert_where_not_cpp_bool_t>,
|
||||||
static_check_t<logic::all_t<detail::is_expression_impl<Expressions>::type::value...>::value,
|
static_check_t<logic::all_t<detail::is_expression_impl<Expressions>::type::value...>::value,
|
||||||
assert_where_boolean_expression_t>,
|
assert_where_boolean_expression_t>,
|
||||||
static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>,
|
static_check_t<logic::all_t<is_boolean_t<Expressions>::value...>::value, assert_where_boolean_expression_t>,
|
||||||
@ -313,14 +319,6 @@ namespace sqlpp
|
|||||||
|
|
||||||
using _database_t = typename Policies::_database_t;
|
using _database_t = typename Policies::_database_t;
|
||||||
|
|
||||||
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269
|
|
||||||
// template <typename... T>
|
|
||||||
// using _check = logic::all_t<is_expression_t<T>::value...>;
|
|
||||||
template <typename... T>
|
|
||||||
struct _check : logic::all_t<is_expression_t<T>::value...>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Check, typename T>
|
template <typename Check, typename T>
|
||||||
using _new_statement_t = new_statement_t<Check::value, Policies, no_where_t, T>;
|
using _new_statement_t = new_statement_t<Check::value, Policies, no_where_t, T>;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ endfunction()
|
|||||||
|
|
||||||
test_compile(aggregates)
|
test_compile(aggregates)
|
||||||
test_compile(case)
|
test_compile(case)
|
||||||
|
test_compile(from)
|
||||||
test_compile(where)
|
test_compile(where)
|
||||||
test_compile(insert)
|
test_compile(insert)
|
||||||
test_compile(date)
|
test_compile(date)
|
||||||
|
119
test_static_asserts/from.cpp
Normal file
119
test_static_asserts/from.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* 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 <iostream>
|
||||||
|
#include "MockDb.h"
|
||||||
|
#include "Sample.h"
|
||||||
|
#include <sqlpp11/sqlpp11.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr auto t = test::TabBar{};
|
||||||
|
constexpr auto f = test::TabFoo{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_type_on_error(std::true_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print_type_on_error(std::false_type)
|
||||||
|
{
|
||||||
|
T::_print_me_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Assert, typename Expression>
|
||||||
|
void from_static_check(const Expression& expression)
|
||||||
|
{
|
||||||
|
using CheckResult = sqlpp::check_from_static_t<Expression>;
|
||||||
|
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
|
||||||
|
print_type_on_error<CheckResult>(ExpectedCheckResult{});
|
||||||
|
static_assert(ExpectedCheckResult::value, "Unexpected check result");
|
||||||
|
|
||||||
|
using ReturnType = decltype(select(t.alpha).from(expression));
|
||||||
|
using ExpectedReturnType =
|
||||||
|
sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, sqlpp::bad_statement>::value>;
|
||||||
|
print_type_on_error<ReturnType>(ExpectedReturnType{});
|
||||||
|
static_assert(ExpectedReturnType::value, "Unexpected return type");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Assert, typename Expression>
|
||||||
|
void from_dynamic_check(const Expression& expression)
|
||||||
|
{
|
||||||
|
static auto db = MockDb{};
|
||||||
|
using CheckResult = sqlpp::check_from_dynamic_t<decltype(db), Expression>;
|
||||||
|
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
|
||||||
|
print_type_on_error<CheckResult>(ExpectedCheckResult{});
|
||||||
|
static_assert(ExpectedCheckResult::value, "Unexpected check result");
|
||||||
|
|
||||||
|
using ReturnType = decltype(dynamic_select(db, t.alpha).dynamic_from(expression));
|
||||||
|
using ExpectedReturnType =
|
||||||
|
sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, sqlpp::bad_statement>::value>;
|
||||||
|
print_type_on_error<ReturnType>(ExpectedReturnType{});
|
||||||
|
static_assert(ExpectedReturnType::value, "Unexpected return type");
|
||||||
|
}
|
||||||
|
|
||||||
|
void static_from()
|
||||||
|
{
|
||||||
|
// 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.join(f).on(t.alpha > f.omega));
|
||||||
|
|
||||||
|
// Try a bunch of non-tables
|
||||||
|
from_static_check<sqlpp::assert_from_table_t>(7);
|
||||||
|
from_static_check<sqlpp::assert_from_table_t>(t.alpha);
|
||||||
|
from_static_check<sqlpp::assert_from_table_t>(t.beta);
|
||||||
|
from_static_check<sqlpp::assert_from_table_t>(t.gamma);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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.join(f).on(t.alpha > f.omega));
|
||||||
|
|
||||||
|
// Try a bunch of non-tables
|
||||||
|
from_dynamic_check<sqlpp::assert_from_table_t>(7);
|
||||||
|
from_dynamic_check<sqlpp::assert_from_table_t>(t.alpha);
|
||||||
|
from_dynamic_check<sqlpp::assert_from_table_t>(t.beta);
|
||||||
|
from_dynamic_check<sqlpp::assert_from_table_t>(t.gamma);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char* [])
|
||||||
|
{
|
||||||
|
static_from();
|
||||||
|
dynamic_from();
|
||||||
|
}
|
@ -89,6 +89,10 @@ namespace
|
|||||||
// Try non-boolean expression
|
// Try non-boolean expression
|
||||||
where_static_check<sqlpp::assert_where_boolean_expression_t>(t.alpha);
|
where_static_check<sqlpp::assert_where_boolean_expression_t>(t.alpha);
|
||||||
|
|
||||||
|
// Try builtin bool
|
||||||
|
where_static_check<sqlpp::assert_where_not_cpp_bool_t>(true);
|
||||||
|
where_static_check<sqlpp::assert_where_not_cpp_bool_t>(17 > 3);
|
||||||
|
|
||||||
// Try some other types as expressions
|
// Try some other types as expressions
|
||||||
where_static_check<sqlpp::assert_where_boolean_expression_t>("true");
|
where_static_check<sqlpp::assert_where_boolean_expression_t>("true");
|
||||||
where_static_check<sqlpp::assert_where_boolean_expression_t>(17);
|
where_static_check<sqlpp::assert_where_boolean_expression_t>(17);
|
||||||
@ -116,6 +120,10 @@ namespace
|
|||||||
// Try non-boolean expression
|
// Try non-boolean expression
|
||||||
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(t.alpha);
|
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(t.alpha);
|
||||||
|
|
||||||
|
// Try builtin bool
|
||||||
|
where_dynamic_check<sqlpp::assert_where_not_cpp_bool_t>(true);
|
||||||
|
where_dynamic_check<sqlpp::assert_where_not_cpp_bool_t>(17 > 3);
|
||||||
|
|
||||||
// Try some other types as expressions
|
// Try some other types as expressions
|
||||||
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>("true");
|
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>("true");
|
||||||
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(17);
|
where_dynamic_check<sqlpp::assert_where_boolean_expression_t>(17);
|
||||||
|
Loading…
Reference in New Issue
Block a user