mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 12:51:13 +08:00
Prepared for advanced table checks
This commit is contained in:
parent
6e7d05d6db
commit
9349f56d68
@ -34,7 +34,7 @@
|
|||||||
#include <sqlpp11/core/default_value.h>
|
#include <sqlpp11/core/default_value.h>
|
||||||
#include <sqlpp11/core/type_traits.h>
|
#include <sqlpp11/core/type_traits.h>
|
||||||
#include <sqlpp11/core/wrong.h>
|
#include <sqlpp11/core/wrong.h>
|
||||||
#include <sqlpp11/core/detail/type_set.h>
|
#include <sqlpp11/core/detail/type_vector.h>
|
||||||
|
|
||||||
namespace sqlpp
|
namespace sqlpp
|
||||||
{
|
{
|
||||||
@ -104,13 +104,18 @@ namespace sqlpp
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Table>
|
template <typename Table>
|
||||||
struct table_t;
|
struct table_t;
|
||||||
|
|
||||||
template<typename Table, typename ColumnSpec>
|
template<typename Table, typename ColumnSpec>
|
||||||
struct required_tables_of<column_t<Table, ColumnSpec>>
|
struct required_tables_of<column_t<Table, ColumnSpec>>
|
||||||
{
|
{
|
||||||
using type = detail::type_set<table_t<Table>>;
|
using type = detail::type_vector<table_t<Table>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Table, typename ColumnSpec>
|
||||||
|
struct required_static_tables_of<column_t<Table, ColumnSpec>> : public required_tables_of<column_t<Table, ColumnSpec>>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Context, typename Table, typename ColumnSpec>
|
template <typename Context, typename Table, typename ColumnSpec>
|
||||||
|
@ -67,18 +67,36 @@ namespace sqlpp
|
|||||||
#warning: We should mix dynamic and optional into the provided_tables_of (instead of having separate traits for each).
|
#warning: We should mix dynamic and optional into the provided_tables_of (instead of having separate traits for each).
|
||||||
#warning: it might be great to search for missing tables and return something like `missing_table_for<column_t<SomeSpec>>`.
|
#warning: it might be great to search for missing tables and return something like `missing_table_for<column_t<SomeSpec>>`.
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_dynamic : public std::false_type {};
|
||||||
|
template<typename T>
|
||||||
|
struct is_dynamic<dynamic_t<T>> : public std::true_type {};
|
||||||
|
|
||||||
|
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
|
||||||
|
struct provided_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
|
||||||
|
{
|
||||||
|
using type = detail::type_vector_cat_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
|
||||||
|
struct provided_static_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
|
||||||
|
{
|
||||||
|
using type = typename std::conditional<
|
||||||
|
is_dynamic<Rhs>::value,
|
||||||
|
provided_static_tables_of<Lhs>,
|
||||||
|
detail::type_vector_cat_t<provided_static_tables_of<Lhs>, provided_static_tables_of<Rhs>>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
|
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
|
||||||
struct provided_optional_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
|
struct provided_optional_tables_of<join_t<Lhs, JoinType, Rhs, Condition>>
|
||||||
{
|
{
|
||||||
using type = typename std::conditional<
|
using type = detail::type_vector_cat_t<
|
||||||
std::is_same<JoinType, left_outer_join_t>::value,
|
typename std::conditional<detail::type_vector<right_outer_join_t, full_outer_join_t>::contains<JoinType>(),
|
||||||
sqlpp::detail::type_set<Rhs>,
|
provided_tables_of_t<Lhs>,
|
||||||
typename std::conditional<
|
detail::type_vector<>>::type,
|
||||||
std::is_same<JoinType, right_outer_join_t>::value,
|
typename std::conditional<detail::type_vector<left_outer_join_t, full_outer_join_t>::contains<JoinType>(),
|
||||||
sqlpp::detail::type_set<Lhs>,
|
provided_tables_of_t<Rhs>,
|
||||||
typename std::conditional<std::is_same<JoinType, full_outer_join_t>::value,
|
detail::type_vector<>>::type>;
|
||||||
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>
|
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
|
||||||
@ -124,8 +142,36 @@ namespace sqlpp
|
|||||||
|
|
||||||
#warning: Verify that the Expr does not require tables other than Lhs, Rhs
|
#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
|
//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 Expr, typename StaticTableTypeVector, typename AllTableTypeVector>
|
||||||
|
struct are_table_requirements_satisfied
|
||||||
|
: std::integral_constant<bool,
|
||||||
|
StaticTableTypeVector::contains_all(required_static_tables_of_t<Expr>{}) and
|
||||||
|
AllTableTypeVector::contains_all(required_tables_of_t<Expr>{})>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Lhs, typename Rhs, typename Expr>
|
template <typename Lhs, typename Rhs, typename Expr>
|
||||||
using check_on_args = sqlpp::enable_if_t<sqlpp::is_boolean<Expr>::value>;
|
struct are_join_table_requirements_satisfied
|
||||||
|
: public std::integral_constant<
|
||||||
|
bool,
|
||||||
|
is_dynamic<Rhs>::value ?
|
||||||
|
// In case of a dynamic join, we can use all tables in the ON expr.
|
||||||
|
are_table_requirements_satisfied<
|
||||||
|
Expr,
|
||||||
|
provided_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>,
|
||||||
|
provided_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>>::value
|
||||||
|
:
|
||||||
|
// In case of a static join, we can use static tables in the static part of the ON
|
||||||
|
// expression and dynamic tables in any potential dynamic part of the expression.
|
||||||
|
are_table_requirements_satisfied<
|
||||||
|
Expr,
|
||||||
|
provided_static_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>,
|
||||||
|
provided_tables_of_t<join_t<Lhs, cross_join_t, Rhs, unconditional_t>>>::value>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Lhs, typename Rhs, typename Expr>
|
||||||
|
using check_on_args = sqlpp::enable_if_t<sqlpp::is_boolean<Expr>::value and are_join_table_requirements_satisfied<Lhs, Rhs, Expr>::value>;
|
||||||
|
|
||||||
template <typename Lhs, typename JoinType, typename Rhs>
|
template <typename Lhs, typename JoinType, typename Rhs>
|
||||||
struct pre_join_t
|
struct pre_join_t
|
||||||
@ -133,7 +179,7 @@ namespace sqlpp
|
|||||||
template <typename Expr, typename = check_on_args<Lhs, Rhs, Expr>>
|
template <typename Expr, typename = check_on_args<Lhs, Rhs, Expr>>
|
||||||
auto on(Expr expr) const -> join_t<Lhs, JoinType, Rhs, Expr>
|
auto on(Expr expr) const -> join_t<Lhs, JoinType, Rhs, Expr>
|
||||||
{
|
{
|
||||||
return {_lhs, _rhs, std::move(expr)};
|
return {_lhs, _rhs, std::move(expr)};
|
||||||
}
|
}
|
||||||
|
|
||||||
Lhs _lhs;
|
Lhs _lhs;
|
||||||
|
@ -69,6 +69,16 @@ namespace sqlpp
|
|||||||
using type = sqlpp::detail::type_set<table_t<TableSpec>>;
|
using type = sqlpp::detail::type_set<table_t<TableSpec>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename TableSpec>
|
||||||
|
struct provided_static_tables_of<table_t<TableSpec>> : public provided_tables_of<table_t<TableSpec>>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TableSpec>
|
||||||
|
struct provided_optional_tables_of<table_t<TableSpec>> : public provided_tables_of<table_t<TableSpec>>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Context, typename TableSpec>
|
template <typename Context, typename TableSpec>
|
||||||
auto to_sql_string(Context& context, const table_t<TableSpec>& /*unused*/) -> std::string
|
auto to_sql_string(Context& context, const table_t<TableSpec>& /*unused*/) -> std::string
|
||||||
{
|
{
|
||||||
|
@ -159,7 +159,7 @@ namespace sqlpp
|
|||||||
using _new_statement_t = new_statement_t<Check, Policies, no_where_t, T>;
|
using _new_statement_t = new_statement_t<Check, Policies, no_where_t, T>;
|
||||||
|
|
||||||
using _consistency_check =
|
using _consistency_check =
|
||||||
typename std::conditional<WhereRequired and (Policies::_all_provided_tables::size::value > 0),
|
typename std::conditional<WhereRequired and (Policies::_all_provided_tables::size() > 0),
|
||||||
assert_where_or_unconditionally_called_t,
|
assert_where_or_unconditionally_called_t,
|
||||||
consistent_t>::type;
|
consistent_t>::type;
|
||||||
|
|
||||||
|
@ -36,16 +36,26 @@ namespace sqlpp
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
struct type_vector
|
struct type_vector
|
||||||
{
|
{
|
||||||
template<typename X>
|
template <typename X>
|
||||||
using contains = std::integral_constant<bool, ::sqlpp::logic::any<std::is_same<T, X>::value...>::value>;
|
static constexpr bool contains()
|
||||||
|
{
|
||||||
|
return ::sqlpp::logic::any<std::is_same<T, X>::value...>::value;
|
||||||
|
}
|
||||||
|
|
||||||
template <template <typename> class Transform>
|
template <typename... X>
|
||||||
using transform = type_vector<typename Transform<T>::type...>;
|
static constexpr bool contains_all(type_vector<X...>)
|
||||||
|
{
|
||||||
|
return ::sqlpp::logic::all<contains<X>()...>::value;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool size = sizeof...(T);
|
static constexpr size_t size()
|
||||||
|
{
|
||||||
|
return sizeof...(T);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool empty() {
|
static constexpr bool empty()
|
||||||
return size == 0;
|
{
|
||||||
|
return size() == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,5 +92,17 @@ namespace sqlpp
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
using type_vector_cat_t = typename type_vector_cat_impl<T...>::type;
|
using type_vector_cat_t = typename type_vector_cat_impl<T...>::type;
|
||||||
|
|
||||||
|
template <typename TypeVector, template <typename> class Transform>
|
||||||
|
struct transform;
|
||||||
|
|
||||||
|
template <template <typename> class Transform, typename... T>
|
||||||
|
struct transform<type_vector<T...>, Transform>
|
||||||
|
{
|
||||||
|
using type = type_vector<typename Transform<T>::type...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TypeVector, template <typename> class Transform>
|
||||||
|
using transform_t = typename transform<TypeVector, Transform>::type;
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace sqlpp
|
} // namespace sqlpp
|
||||||
|
@ -78,12 +78,15 @@ namespace sqlpp
|
|||||||
using _all_required_ctes = detail::make_joined_set_t<required_ctes_of<Policies>...>;
|
using _all_required_ctes = detail::make_joined_set_t<required_ctes_of<Policies>...>;
|
||||||
using _all_provided_ctes = detail::make_joined_set_t<provided_ctes_of<Policies>...>;
|
using _all_provided_ctes = detail::make_joined_set_t<provided_ctes_of<Policies>...>;
|
||||||
using _all_required_tables = detail::make_joined_set_t<required_tables_of_t<Policies>...>;
|
using _all_required_tables = detail::make_joined_set_t<required_tables_of_t<Policies>...>;
|
||||||
using _all_provided_tables = detail::make_joined_set_t<provided_tables_of_t<Policies>...>;
|
using _all_provided_tables = detail::type_vector_cat_t<provided_tables_of_t<Policies>...>;
|
||||||
using _all_provided_outer_tables = detail::make_joined_set_t<provided_optional_tables_of_t<Policies>...>;
|
//using _all_provided_outer_tables = detail::make_joined_set_t<provided_optional_tables_of_t<Policies>...>;
|
||||||
using _all_provided_aggregates = detail::make_joined_set_t<provided_aggregates_of<Policies>...>;
|
using _all_provided_aggregates = detail::make_joined_set_t<provided_aggregates_of<Policies>...>;
|
||||||
|
|
||||||
|
#warning reactivate
|
||||||
|
/*
|
||||||
template <typename Expression>
|
template <typename Expression>
|
||||||
using _no_unknown_tables = detail::is_subset_of<required_tables_of_t<Expression>, _all_provided_tables>;
|
using _no_unknown_tables = detail::is_subset_of<required_tables_of_t<Expression>, _all_provided_tables>;
|
||||||
|
*/
|
||||||
|
|
||||||
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2086629
|
// workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2086629
|
||||||
// template <typename... Expressions>
|
// template <typename... Expressions>
|
||||||
@ -109,7 +112,7 @@ namespace sqlpp
|
|||||||
using any_t = logic::any<Predicate<Policies>::value...>;
|
using any_t = logic::any<Predicate<Policies>::value...>;
|
||||||
|
|
||||||
// The tables not covered by the from.
|
// The tables not covered by the from.
|
||||||
using _required_tables = detail::make_difference_set_t<_all_required_tables, _all_provided_tables>;
|
//using _required_tables = detail::make_difference_set_t<_all_required_tables, _all_provided_tables>;
|
||||||
|
|
||||||
// The common table expressions not covered by the with.
|
// The common table expressions not covered by the with.
|
||||||
using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>;
|
using _required_ctes = detail::make_difference_set_t<_all_required_ctes, _all_provided_ctes>;
|
||||||
@ -125,7 +128,8 @@ namespace sqlpp
|
|||||||
// - the select is complete (leaks no table requirements or cte requirements)
|
// - the select is complete (leaks no table requirements or cte requirements)
|
||||||
static constexpr bool _can_be_used_as_table()
|
static constexpr bool _can_be_used_as_table()
|
||||||
{
|
{
|
||||||
return has_result_row_t<_statement_t>::value and _required_tables::size::value == 0 and
|
#warning: reactivate
|
||||||
|
return has_result_row_t<_statement_t>::value and /*_required_tables::size::value == 0 and*/
|
||||||
_required_ctes::size::value == 0;
|
_required_ctes::size::value == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,8 +151,9 @@ namespace sqlpp
|
|||||||
|
|
||||||
using _cte_check =
|
using _cte_check =
|
||||||
typename std::conditional<_required_ctes::size::value == 0, consistent_t, assert_no_unknown_ctes_t>::type;
|
typename std::conditional<_required_ctes::size::value == 0, consistent_t, assert_no_unknown_ctes_t>::type;
|
||||||
using _table_check =
|
#warning: reactivate
|
||||||
typename std::conditional<_required_tables::size::value == 0, consistent_t, assert_no_unknown_tables_t>::type;
|
using _table_check = std::true_type;
|
||||||
|
//typename std::conditional<_required_tables::size::value == 0, consistent_t, assert_no_unknown_tables_t>::type;
|
||||||
using _parameter_check = typename std::
|
using _parameter_check = typename std::
|
||||||
conditional<_parameters::empty(), consistent_t, assert_no_parameters_t>::type;
|
conditional<_parameters::empty(), consistent_t, assert_no_parameters_t>::type;
|
||||||
};
|
};
|
||||||
@ -206,7 +211,7 @@ namespace sqlpp
|
|||||||
>;
|
>;
|
||||||
using _name_tag_of = name_tag_of<_result_type_provider>;
|
using _name_tag_of = name_tag_of<_result_type_provider>;
|
||||||
using _nodes = detail::type_vector<_policies_t>;
|
using _nodes = detail::type_vector<_policies_t>;
|
||||||
using _used_outer_tables = typename _policies_t::_all_provided_outer_tables;
|
//using _used_outer_tables = typename _policies_t::_all_provided_outer_tables;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
statement_t() = default;
|
statement_t() = default;
|
||||||
|
@ -45,12 +45,27 @@ namespace sqlpp
|
|||||||
template<typename... T>
|
template<typename... T>
|
||||||
struct required_tables_of<detail::type_vector<T...>>
|
struct required_tables_of<detail::type_vector<T...>>
|
||||||
{
|
{
|
||||||
using type = detail::make_joined_set_t<typename required_tables_of<T>::type...>;
|
using type = detail::type_vector_cat_t<typename required_tables_of<T>::type...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using required_tables_of_t = typename required_tables_of<T>::type;
|
using required_tables_of_t = typename required_tables_of<T>::type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct required_static_tables_of
|
||||||
|
{
|
||||||
|
using type = typename required_static_tables_of<nodes_of_t<T>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
struct required_static_tables_of<detail::type_vector<T...>>
|
||||||
|
{
|
||||||
|
using type = detail::type_vector_cat_t<typename required_static_tables_of<T>::type...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using required_static_tables_of_t = typename required_static_tables_of<T>::type;
|
||||||
|
|
||||||
#warning: need type tests...
|
#warning: need type tests...
|
||||||
//static_assert(required_tables_of_t<int>::size::value == 0, "");
|
//static_assert(required_tables_of_t<int>::size::value == 0, "");
|
||||||
|
|
||||||
@ -66,16 +81,27 @@ namespace sqlpp
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
struct provided_tables_of<detail::type_vector<T...>>
|
struct provided_tables_of<detail::type_vector<T...>>
|
||||||
{
|
{
|
||||||
using type = detail::make_joined_set_t<typename provided_tables_of<T>::type...>;
|
using type = detail::type_vector_cat_t<typename provided_tables_of<T>::type...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using provided_tables_of_t = typename provided_tables_of<T>::type;
|
using provided_tables_of_t = typename provided_tables_of<T>::type;
|
||||||
|
|
||||||
static_assert(provided_tables_of_t<int>::size::value == 0, "");
|
template <typename T>
|
||||||
|
struct provided_static_tables_of
|
||||||
|
{
|
||||||
|
using type = typename provided_static_tables_of<nodes_of_t<T>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
struct provided_static_tables_of<detail::type_vector<T...>>
|
||||||
|
{
|
||||||
|
using type = detail::type_vector_cat_t<typename provided_static_tables_of<T>::type...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using provided_static_tables_of_t = typename provided_static_tables_of<T>::type;
|
||||||
|
|
||||||
// provided_optional_tables_of is similar to provided_tables_of but only references the tables that have optional
|
|
||||||
// rows in outer joins (e.g. the right hand side table in a LEFT OUTER JOIN).
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct provided_optional_tables_of
|
struct provided_optional_tables_of
|
||||||
{
|
{
|
||||||
@ -85,11 +111,13 @@ namespace sqlpp
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
struct provided_optional_tables_of<detail::type_vector<T...>>
|
struct provided_optional_tables_of<detail::type_vector<T...>>
|
||||||
{
|
{
|
||||||
using type = detail::make_joined_set_t<typename provided_optional_tables_of<T>::type...>;
|
using type = detail::type_vector_cat_t<typename provided_optional_tables_of<T>::type...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using provided_optional_tables_of_t = typename provided_optional_tables_of<T>::type;
|
using provided_optional_tables_of_t = typename provided_optional_tables_of<T>::type;
|
||||||
|
|
||||||
|
static_assert(provided_tables_of_t<int>::empty(), "");
|
||||||
|
|
||||||
} // namespace sqlpp
|
} // namespace sqlpp
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user