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

More tests for provided_tables_of

This commit is contained in:
Roland Bock 2024-11-15 17:13:04 +01:00
parent c52a60cabd
commit 841ed273b9
21 changed files with 310 additions and 76 deletions

View File

@ -67,10 +67,8 @@ namespace sqlpp
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_t<Lhs>,
detail::type_vector_cat_t<provided_static_tables_of_t<Lhs>, provided_static_tables_of_t<Rhs>>>::type;
using type =
detail::type_vector_cat_t<provided_static_tables_of_t<Lhs>, provided_static_tables_of_t<Rhs>>;
};
template <typename Lhs, typename JoinType, typename Rhs, typename Condition>
@ -79,10 +77,10 @@ namespace sqlpp
using type = detail::type_vector_cat_t<
typename std::conditional<detail::type_vector<right_outer_join_t, full_outer_join_t>::contains<JoinType>::value,
provided_tables_of_t<Lhs>,
detail::type_vector<>>::type,
provided_optional_tables_of_t<Lhs>>::type,
typename std::conditional<detail::type_vector<left_outer_join_t, full_outer_join_t>::contains<JoinType>::value,
provided_tables_of_t<Rhs>,
detail::type_vector<>>::type>;
provided_optional_tables_of_t<Rhs>>::type>;
};
#warning: Need to make extra sure that ON does not require on extra tables.

View File

@ -41,7 +41,7 @@ namespace sqlpp
return name_to_sql_string(context, t._name);
}
auto schema(std::string name) -> schema_t
inline auto schema(std::string name) -> schema_t
{
return schema_t{std::move(name)};
};

View File

@ -64,11 +64,6 @@ namespace sqlpp
using type = sqlpp::detail::type_vector<table_t<TableSpec>>;
};
template <typename TableSpec>
struct provided_static_tables_of<table_t<TableSpec>> : public provided_tables_of<table_t<TableSpec>>
{
};
template <typename Context, typename TableSpec>
auto to_sql_string(Context& context, const table_t<TableSpec>& /*unused*/) -> std::string
{

View File

@ -59,16 +59,6 @@ namespace sqlpp
using type = sqlpp::detail::type_vector<table_as_t<TableSpec, NameTag>>;
};
template <typename TableSpec, typename NameTag>
struct provided_static_tables_of<table_as_t<TableSpec, NameTag>> : public provided_tables_of<table_as_t<TableSpec, NameTag>>
{
};
template <typename TableSpec, typename NameTag>
struct provided_optional_tables_of<table_as_t<TableSpec, NameTag>> : public provided_tables_of<table_as_t<TableSpec, NameTag>>
{
};
template <typename Context, typename TableSpec, typename NameTag>
auto to_sql_string(Context& context, const table_as_t<TableSpec, NameTag>&) -> std::string
{

View File

@ -289,11 +289,6 @@ namespace sqlpp
using type = sqlpp::detail::type_vector<cte_ref_t<NameTagProvider>>;
};
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct provided_static_tables_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>> : public provided_tables_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
{
};
#warning: Should enough if with_t provides ctes?
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct provided_ctes_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
@ -301,11 +296,6 @@ namespace sqlpp
using type = detail::type_vector<cte_ref_t<NameTagProvider>>;
};
template <typename NameTagProvider, typename Statement, typename... ColumnSpecs>
struct provided_static_ctes_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>> : public provided_ctes_of<cte_t<NameTagProvider, Statement, ColumnSpecs...>>
{
};
template <typename Context, typename NameTagProvider, typename Statement, typename... ColumnSpecs>
auto to_sql_string(Context& context, const cte_t<NameTagProvider, Statement, ColumnSpecs...>& t) -> std::string
{
@ -341,11 +331,6 @@ namespace sqlpp
using type = sqlpp::detail::type_vector<cte_ref_t<NameTagProvider>>;
};
template<typename NameTagProvider>
struct provided_static_tables_of<cte_ref_t<NameTagProvider>> : public provided_tables_of<cte_ref_t<NameTagProvider>>
{
};
template<typename NameTagProvider>
struct required_ctes_of<cte_ref_t<NameTagProvider>>
{

View File

@ -71,6 +71,16 @@ namespace sqlpp
using type = detail::type_vector<Table>;
};
template<typename Table>
struct provided_tables_of<from_t<Table>> : public provided_tables_of<Table>
{
};
template<typename Table>
struct provided_optional_tables_of<from_t<Table>> : public provided_optional_tables_of<Table>
{
};
SQLPP_PORTABLE_STATIC_ASSERT(
assert_from_not_pre_join_t,
"from() argument is a pre join, please use an explicit on() condition or unconditionally()");

View File

@ -77,6 +77,11 @@ namespace sqlpp
using type = detail::type_vector<Table>;
};
template<typename Table>
struct provided_tables_of<into_t<Table>> : public provided_tables_of<Table>
{
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_into_t, "into() required");
SQLPP_PORTABLE_STATIC_ASSERT(assert_into_arg_is_table, "argument for into() must be a table");

View File

@ -83,7 +83,7 @@ namespace sqlpp
template <typename Select, typename NameTagProvider, typename... FieldSpecs>
struct provided_tables_of<select_as_t<Select, NameTagProvider, FieldSpecs...>>
: public std::conditional<Select::_can_be_used_as_table(),
sqlpp::detail::type_vector<select_as_t<Select, NameTagProvider, FieldSpecs...>>,
sqlpp::detail::type_vector<select_ref_t<NameTagProvider>>,
sqlpp::detail::type_vector<>>
{
};
@ -94,14 +94,9 @@ namespace sqlpp
{
};
template <typename Select, typename NameTagProvider, typename... FieldSpecs>
struct provided_optional_tables_of<select_as_t<Select, NameTagProvider, FieldSpecs...>>
: public provided_tables_of<select_as_t<Select, NameTagProvider, FieldSpecs...>>
{
};
#warning: V1.0 has empty nodes. Is that correct? In either case document the decision here.
#warning: Need to add required tables of
#warning: Need to add nodes to allow for parameters to be used.
template <typename Context, typename Select, typename NameTagProvider, typename... FieldSpecs>
auto to_sql_string(Context& context, const select_as_t<Select, NameTagProvider, FieldSpecs...>& t) -> std::string

View File

@ -80,6 +80,11 @@ namespace sqlpp
using type = detail::type_vector<Table>;
};
template<typename Table>
struct provided_tables_of<single_table_t<Table>> : public provided_tables_of<Table>
{
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_update_table_arg_is_table_t, "argument for update() must be a table");
template <typename Table>
struct check_update_table

View File

@ -92,7 +92,7 @@ namespace sqlpp
template <typename L, typename R>
using check_arithmetic_args = ::sqlpp::enable_if_t<is_numeric<L>::value and is_numeric<R>::value>;
// L and R are expected to be numeric value types (boolen, integral, unsigned_integral, or floating_point).
// L and R are expected to be numeric value types (boolean, integral, unsigned_integral, or floating_point).
template <typename Operator, typename L, typename R>
struct arithmetic_value_type
{

View File

@ -26,6 +26,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sqlpp11/core/query/dynamic_fwd.h>
#include <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/operator/assign_expression.h>
#include <sqlpp11/core/operator/sort_order_expression.h>
@ -58,7 +59,7 @@ namespace sqlpp
template <typename Expr>
struct nodes_of<dynamic_t<Expr>>
{
using type = Expr;
using type = detail::type_vector<Expr>;
};
template <typename T>

View File

@ -0,0 +1,34 @@
#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.
*/
namespace sqlpp
{
template <typename Expr>
struct dynamic_t;
} // namespace sqlpp

View File

@ -28,13 +28,13 @@
#include <sqlpp11/core/type_traits/nodes_of.h>
#include <sqlpp11/core/detail/type_vector.h>
#include <sqlpp11/core/query/dynamic_fwd.h>
namespace sqlpp
{
// required_tables_of determines the type_vector of tables referenced by columns within within T.
// required_tables_of recursively determines the type_vector of tables referenced by columns within within T.
// column_t or other structs that might reference a table shall specialize this template to indicate their table
// requirement.
// Dynamic parts of a query shall wrap their required tables in dynamic_t.
template<typename T>
struct required_tables_of
{
@ -50,12 +50,23 @@ namespace sqlpp
template<typename T>
using required_tables_of_t = typename required_tables_of<T>::type;
// required_static_tables_of recursively determines the type_vector of tables statically referenced by columns within
// within T. column_t or other structs that might reference a table shall specialize this template to indicate their
// table requirement.
//
// Dynamic query parts are ignored.
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<dynamic_t<T>>
{
using type = detail::type_vector<>;
};
template<typename... T>
struct required_static_tables_of<detail::type_vector<T...>>
{
@ -66,57 +77,49 @@ namespace sqlpp
using required_static_tables_of_t = typename required_static_tables_of<T>::type;
#warning: need type tests...
//static_assert(required_tables_of_t<int>::size::value == 0, "");
// provided_tables_of determines the type_vector of tables provided by the query clause, e.g. by FROM.
// Provided tables can be wrapped in dynamic_t if they are provided through a dynamic join.
// provided_tables_of determines the type_vector of tables provided by a clause, e.g. by FROM.
// table_t, cte_ref_t, or other structs that might provide a table in a query need to specialize this template.
//
// Note: In contrast to `required_tables_of` above, this is non-recursive. This is important for instance to prevent
// `SELECT...AS` to leak from `select_column_list`.
template <typename T>
struct provided_tables_of
{
using type = typename provided_tables_of<nodes_of_t<T>>::type;
using type = detail::type_vector<>;
};
template <typename... T>
struct provided_tables_of<detail::type_vector<T...>>
template <typename T>
struct provided_tables_of<dynamic_t<T>> : public provided_tables_of<T>
{
using type = detail::type_vector_cat_t<typename provided_tables_of<T>::type...>;
};
template <typename T>
using provided_tables_of_t = typename provided_tables_of<T>::type;
// provided_tables_of determines the type_vector of non-dynamic tables provided by a clause, e.g. by FROM.
template <typename T>
struct provided_static_tables_of
struct provided_static_tables_of : public provided_tables_of<T>
{
using type = typename provided_static_tables_of<nodes_of_t<T>>::type;
};
template <typename... T>
struct provided_static_tables_of<detail::type_vector<T...>>
template <typename T>
struct provided_static_tables_of<dynamic_t<T>>
{
using type = detail::type_vector_cat_t<typename provided_static_tables_of<T>::type...>;
using type = detail::type_vector<>;
};
template <typename T>
using provided_static_tables_of_t = typename provided_static_tables_of<T>::type;
// provided_tables_of determines the type_vector of outer join tables provided by a clause, e.g. by FROM.
template <typename T>
struct provided_optional_tables_of
{
using type = typename provided_optional_tables_of<nodes_of_t<T>>::type;
};
template <typename... T>
struct provided_optional_tables_of<detail::type_vector<T...>>
{
using type = detail::type_vector_cat_t<typename provided_optional_tables_of<T>::type...>;
using type = detail::type_vector<>;
};
template <typename T>
using provided_optional_tables_of_t = typename provided_optional_tables_of<T>::type;
static_assert(provided_tables_of_t<int>::empty(), "");
} // namespace sqlpp

View File

@ -24,7 +24,6 @@
*/
#include "Sample.h"
#include "../compare.h"
#include <sqlpp11/sqlpp11.h>
int main(int, char* [])

View File

@ -40,7 +40,7 @@ void test_table()
static_assert(std::is_same<sqlpp::name_tag_of_t<FooBar>, test::TabBar_::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<FooBar>, sqlpp::detail::type_vector<FooBar>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<FooBar>, sqlpp::provided_tables_of_t<FooBar>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<FooBar>, sqlpp::provided_tables_of_t<FooBar>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<FooBar>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::required_tables_of_t<FooBar>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<FooBar>, sqlpp::required_tables_of_t<FooBar>>::value, "");

View File

@ -25,6 +25,7 @@
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
#include "../../../include/test_helpers.h"
void test_from()
{
@ -36,10 +37,11 @@ void test_from()
// FROM CTE
{
auto x = cte(sqlpp::alias::x).as(select(foo.id).from(foo).unconditionally());
auto f = from(x);
auto statement = from(x);
using R = decltype(make_table_ref(x));
using F = decltype(f);
using S = decltype(statement);
using F = extract_clause_t<S>;
static_assert(std::is_same<sqlpp::provided_tables_of_t<F>, sqlpp::detail::type_vector<R>>::value, "");
static_assert(std::is_same<sqlpp::required_ctes_of_t<F>, sqlpp::detail::type_vector<R>>::value, "");

View File

@ -25,6 +25,7 @@
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
#include "../../../include/test_helpers.h"
SQLPP_CREATE_NAME_TAG(cheese);
@ -45,7 +46,8 @@ void test_into()
// Valid into clause
{
using I = decltype(sqlpp::into(foo));
using S = decltype(sqlpp::into(foo));
using I = extract_clause_t<S>;
static_assert(std::is_same<sqlpp::provided_tables_of_t<I>, sqlpp::detail::type_vector<Foo>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<I>, sqlpp::provided_tables_of_t<I>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<I>, sqlpp::detail::type_vector<>>::value, "");

View File

@ -25,6 +25,7 @@
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
#include "../../../include/test_helpers.h"
SQLPP_CREATE_NAME_TAG(cheese);
@ -45,7 +46,8 @@ void test_single_table()
// Valid single table clause
{
using S = decltype(sqlpp::single_table(foo));
using Statement = decltype(sqlpp::single_table(foo));
using S = extract_clause_t<Statement>;
static_assert(std::is_same<sqlpp::provided_tables_of_t<S>, sqlpp::detail::type_vector<Foo>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<S>, sqlpp::provided_tables_of_t<S>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<S>, sqlpp::detail::type_vector<>>::value, "");

View File

@ -29,4 +29,5 @@ function(test_compile name)
endfunction()
test_compile(aggregates)
test_compile(tables_of)

View File

@ -0,0 +1,192 @@
/*
* 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 <sqlpp11/sqlpp11.h>
SQLPP_CREATE_NAME_TAG(cheese);
void test_required_tables_of()
{
// Columns require tables.
{
using T = decltype(test::TabFoo{}.id);
static_assert(std::is_same<sqlpp::required_tables_of_t<T>, sqlpp::detail::type_vector<test::TabFoo>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<T>, sqlpp::detail::type_vector<test::TabFoo>>::value,
"");
}
// Tables do not require tables.
{
using T = decltype(test::TabFoo{});
static_assert(sqlpp::required_tables_of_t<T>::empty(), "");
static_assert(sqlpp::required_static_tables_of_t<T>::empty(), "");
}
// Static expressions require collective tables.
{
using TF = test::TabFoo;
using TB = test::TabBar;
using TC = decltype(test::TabFoo{}.as(cheese));
using T = decltype(TF{}.id + TB{}.id + TC{}.id);
static_assert(std::is_same<sqlpp::required_tables_of_t<T>, sqlpp::detail::type_vector<TF, TB, TC>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<T>, sqlpp::detail::type_vector<TF, TB, TC>>::value, "");
}
// Dynamic expressions require all tables, but on the the static parts contribute to the statically required tables.
{
using TF = test::TabFoo;
using TB = test::TabBar;
using TC = decltype(test::TabFoo{}.as(cheese));
using T = decltype(TF{}.id < 17 and dynamic(true, TB{}.id < 17) and TC{}.id < 17);
static_assert(std::is_same<sqlpp::required_tables_of_t<T>, sqlpp::detail::type_vector<TF, TB, TC>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<T>, sqlpp::detail::type_vector<TF, TC>>::value, "");
}
}
void test_provided_tables_of()
{
// Columns do not provide tables.
{
using T = decltype(test::TabFoo{}.id);
static_assert(sqlpp::provided_tables_of_t<T>::empty(), "");
static_assert(sqlpp::provided_static_tables_of_t<T>::empty(),
"");
static_assert(sqlpp::provided_optional_tables_of_t<T>::empty(),
"");
}
// Tables provide tables.
{
using T = test::TabFoo;
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<T>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<T>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<>>::value, "");
}
// Schema-qualified tables provide tables.
{
using T = decltype(schema_qualified_table({"meme"}, test::TabFoo{}).as(cheese));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<T>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<T>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<>>::value, "");
}
// Tables AS provide tables.
{
using T = decltype(test::TabFoo{}.as(cheese));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<T>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<T>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<>>::value, "");
}
// SELECT AS provides tables.
{
using T = decltype(select(test::TabFoo{}.id).from(test::TabFoo{}).unconditionally().as(cheese));
using Ref = sqlpp::select_ref_t<cheese_t>;
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<Ref>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<Ref>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<>>::value, "");
}
// JOIN provides tables.
{
using F = test::TabFoo;
using B = test::TabBar;
using T = decltype(F{}.cross_join(B{}));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<>>::value, "");
}
// Dynamic JOIN provides non-static tables.
{
using F = test::TabFoo;
using B = test::TabBar;
using T = decltype(F{}.cross_join(dynamic(true, B{})));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<F>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<>>::value, "");
}
// Left outer join makes right-hand-side table "optional", i.e. columns can by NULL.
{
using F = test::TabFoo;
using B = test::TabBar;
using T = decltype(F{}.left_outer_join(dynamic(true, B{})).on(F{}.id == B{}.id));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<F>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<B>>::value, "");
}
// Right outer join makes left-hand-side table "optional", i.e. columns can by NULL.
{
using F = test::TabFoo;
using B = test::TabBar;
using T = decltype(F{}.right_outer_join(dynamic(true, B{})).on(F{}.id == B{}.id));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<F>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<F>>::value, "");
}
// Full outer join makes left-hand-side table "optional", i.e. columns can by NULL.
{
using F = test::TabFoo;
using B = test::TabBar;
using T = decltype(F{}.full_outer_join(dynamic(true, B{})).on(F{}.id == B{}.id));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<F>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<F, B>>::value, "");
}
// Nested joins propagate their provided tables.
{
using F = test::TabFoo;
using B = test::TabBar;
using C = decltype(test::TabFoo{}.as(cheese));
using T = decltype(C{}.cross_join(F{}.full_outer_join(dynamic(true, B{})).on(F{}.id == B{}.id)));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<C,F,B>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<C,F>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<F, B>>::value, "");
}
// Nested joins propagate their provided tables.
{
using F = test::TabFoo;
using B = test::TabBar;
using C = decltype(test::TabFoo{}.as(cheese));
using T = decltype(F{}.full_outer_join(dynamic(true, B{})).on(F{}.id == B{}.id).cross_join(C{}));
static_assert(std::is_same<sqlpp::provided_tables_of_t<T>, sqlpp::detail::type_vector<F,B,C>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<T>, sqlpp::detail::type_vector<F,C>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<T>, sqlpp::detail::type_vector<F, B>>::value, "");
}
}
int main()
{
void test_required_tables_of();
void test_provided_tables_of();
}

View File

@ -102,3 +102,18 @@ struct is_optional : public std::false_type{};
template <typename T>
struct is_optional<::sqlpp::optional<T>> : public std::true_type{};
// functions like `from(tab)` yield a statement with a single clause. This extracts the type of that clause.
template <typename Statement>
struct extract_clause;
template <typename Clause>
struct extract_clause<sqlpp::statement_t<Clause>>
{
using type = Clause;
};
template <typename Statement>
using extract_clause_t = typename extract_clause<Statement>::type;