0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 12:51:13 +08:00

Add type tests for table and table_as and column

This commit is contained in:
Roland Bock 2024-09-05 07:27:59 +02:00
parent 3c36b1d025
commit 64163be810
9 changed files with 318 additions and 37 deletions

View File

@ -85,28 +85,20 @@ namespace sqlpp
} }
}; };
template<typename Table, typename ColumnSpec>
struct has_default<column_t<Table, ColumnSpec>> : public ColumnSpec::has_default
{
};
// Can be used in group_by
template<typename Table, typename ColumnSpec> template<typename Table, typename ColumnSpec>
struct is_group_by_column<column_t<Table, ColumnSpec>> : public std::true_type struct is_group_by_column<column_t<Table, ColumnSpec>> : public std::true_type
{ {
}; };
template<typename Table, typename ColumnSpec>
struct value_type_of<column_t<Table, ColumnSpec>>
{
using type = typename ColumnSpec::value_type;
};
template<typename Table, typename ColumnSpec> template<typename Table, typename ColumnSpec>
struct name_tag_of<column_t<Table, ColumnSpec>> : public name_tag_of<ColumnSpec>{}; struct name_tag_of<column_t<Table, ColumnSpec>> : public name_tag_of<ColumnSpec>{};
template<typename Table, typename ColumnSpec>
struct has_default<column_t<Table, ColumnSpec>> : public ColumnSpec::has_default
{
};
template <typename Table>
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>>
{ {
@ -118,6 +110,12 @@ namespace sqlpp
{ {
}; };
template<typename Table, typename ColumnSpec>
struct value_type_of<column_t<Table, ColumnSpec>>
{
using type = typename ColumnSpec::value_type;
};
template <typename Context, typename Table, typename ColumnSpec> template <typename Context, typename Table, typename ColumnSpec>
auto to_sql_string(Context& context, const column_t<Table, ColumnSpec>&) -> std::string auto to_sql_string(Context& context, const column_t<Table, ColumnSpec>&) -> std::string
{ {

View File

@ -46,11 +46,9 @@ namespace sqlpp
//using _column_tuple_t = std::tuple<column_t<Table, ColumnSpec>...>; //using _column_tuple_t = std::tuple<column_t<Table, ColumnSpec>...>;
template <typename NameTagProvider, typename T> template <typename NameTagProvider, typename T>
using _foreign_table_as_t = table_as_t<NameTagProvider, T>; using _foreign_table_as_t = table_as_t<NameTagProvider, T>;
template <typename NameTagProvider>
using _sqlpp_name_tag = table_as_t<NameTagProvider, TableSpec>;
template <typename NameTagProvider> template <typename NameTagProvider>
_sqlpp_name_tag<NameTagProvider> as(const NameTagProvider& /*unused*/) const constexpr auto as(const NameTagProvider& /*unused*/) const -> table_as_t<TableSpec, name_tag_of_t<NameTagProvider>>
{ {
return {}; return {};
} }

View File

@ -35,13 +35,12 @@
namespace sqlpp namespace sqlpp
{ {
template <typename NameTagProvider, typename TableSpec> template <typename TableSpec, typename NameTag>
struct table_as_t : public TableSpec::_table_columns<table_as_t<NameTagProvider, TableSpec>>, struct table_as_t : public TableSpec::_table_columns<table_as_t<TableSpec, NameTag>>,
public enable_join<table_as_t<NameTagProvider, TableSpec>> public enable_join<table_as_t<TableSpec, NameTag>>
{ {
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _required_ctes = required_ctes_of<TableSpec>; using _required_ctes = required_ctes_of<TableSpec>;
using _provided_tables = detail::type_set<NameTagProvider>;
static_assert(required_tables_of_t<TableSpec>::empty(), "table aliases must not depend on external tables"); static_assert(required_tables_of_t<TableSpec>::empty(), "table aliases must not depend on external tables");
@ -49,32 +48,35 @@ namespace sqlpp
//using _column_tuple_t = std::tuple<column_t<NameTagProvider, ColumnSpec>...>; //using _column_tuple_t = std::tuple<column_t<NameTagProvider, ColumnSpec>...>;
}; };
template<typename NameTagProvider, typename TableSpec> template<typename TableSpec, typename NameTag>
struct is_table<table_as_t<NameTagProvider, TableSpec>> : public std::true_type{}; struct is_table<table_as_t<TableSpec, NameTag>> : public std::true_type{};
template<typename NameTagProvider, typename TableSpec> template <typename TableSpec, typename NameTag>
struct name_tag_of<table_as_t<NameTagProvider, TableSpec>> : public name_tag_of<NameTagProvider>{}; struct name_tag_of<table_as_t<TableSpec, NameTag>>
template <typename NameTagProvider, typename TableSpec>
struct provided_tables_of<table_as_t<NameTagProvider, TableSpec>>
{ {
using type = sqlpp::detail::type_vector<table_as_t<NameTagProvider, TableSpec>>; using type = NameTag;
}; };
template <typename NameTagProvider, typename TableSpec> template <typename TableSpec, typename NameTag>
struct provided_static_tables_of<table_as_t<NameTagProvider, TableSpec>> : public provided_tables_of<table_as_t<NameTagProvider, TableSpec>> struct provided_tables_of<table_as_t<TableSpec, NameTag>>
{
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 NameTagProvider, typename TableSpec> template <typename TableSpec, typename NameTag>
struct provided_optional_tables_of<table_as_t<NameTagProvider, TableSpec>> : public provided_tables_of<table_as_t<NameTagProvider, TableSpec>> struct provided_optional_tables_of<table_as_t<TableSpec, NameTag>> : public provided_tables_of<table_as_t<TableSpec, NameTag>>
{ {
}; };
template <typename Context, typename NameTagProvider, typename TableSpec> template <typename Context, typename TableSpec, typename NameTag>
auto to_sql_string(Context& context, const table_as_t<NameTagProvider, TableSpec>&) -> std::string auto to_sql_string(Context& context, const table_as_t<TableSpec, NameTag>&) -> std::string
{ {
return name_to_sql_string(context, name_tag_of_t<TableSpec>::name) + " AS " + return name_to_sql_string(context, name_tag_of_t<TableSpec>::name) + " AS " +
name_to_sql_string(context, name_tag_of_t<NameTagProvider>::name); name_to_sql_string(context, NameTag::name);
} }
} // namespace sqlpp } // namespace sqlpp

View File

@ -102,7 +102,7 @@ namespace sqlpp
return {std::move(column), std::move(value)}; return {std::move(column), std::move(value)};
} }
#warning: need to add type tests and serialiaze tests #warning: need to add type tests and serialize tests
struct op_plus_assign struct op_plus_assign
{ {
static constexpr auto symbol = " += "; static constexpr auto symbol = " += ";

View File

@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace sqlpp namespace sqlpp
{ {
#warning: need type tests #warning: need type tests
#warning: Should only use NameTag, not NameTagProvider here!
template <typename Expression, typename NameTagProvider> template <typename Expression, typename NameTagProvider>
struct expression_as struct expression_as
{ {

View File

@ -28,5 +28,8 @@ function(test_compile name)
target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing) target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing)
endfunction() endfunction()
test_compile(column)
test_compile(join) test_compile(join)
test_compile(table)
test_compile(table_as)

View File

@ -0,0 +1,172 @@
/*
* 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_column()
{
{
// Column integer with default (auto-increment).
auto foo = test::TabFoo{};
using Foo = decltype(foo);
using Id = decltype(foo.id);
using Cheese = decltype(foo.id.as(cheese));
using BarId = decltype(foo.as(test::TabBar{}).id);
using BarCheese = decltype(foo.as(test::TabBar{}).id.as(cheese));
static_assert(not sqlpp::is_table<Id>::value, "");
static_assert(sqlpp::has_default<Id>::value, "");
static_assert(sqlpp::is_group_by_column<Id>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<Id>, test::TabFoo_::Id::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<Id>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<Id>, sqlpp::provided_tables_of_t<Id>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<Id>, sqlpp::provided_tables_of_t<Id>>::value, "");
static_assert(std::is_same<sqlpp::required_tables_of_t<Id>, sqlpp::detail::type_vector<Foo>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<Id>, sqlpp::required_tables_of_t<Id>>::value, "");
static_assert(std::is_same<sqlpp::value_type_of_t<Id>, sqlpp::integral>::value, "");
foo.as(test::TabBar{}).id = 7;
// tab_foo.id AS cheese
// This is only useful SELECT. It therefore exposes neither name nor value directly.
// It does require its table, though.
static_assert(not sqlpp::is_table<Cheese>::value, "");
static_assert(not sqlpp::has_default<Cheese>::value, "");
static_assert(not sqlpp::is_group_by_column<Cheese>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<Cheese>, sqlpp::no_name_t>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<Cheese>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<Cheese>, sqlpp::provided_tables_of_t<Cheese>>::value,
"");
static_assert(
std::is_same<sqlpp::provided_optional_tables_of_t<Cheese>, sqlpp::provided_tables_of_t<Cheese>>::value, "");
static_assert(std::is_same<sqlpp::required_tables_of_t<Cheese>, sqlpp::detail::type_vector<Foo>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<Cheese>, sqlpp::required_tables_of_t<Cheese>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<Cheese>, sqlpp::no_value_t>::value, "");
// (tab_foo AS bar).id
#warning : insert must not accept table_as!
static_assert(not sqlpp::is_table<BarId>::value, "");
static_assert(sqlpp::has_default<BarId>::value, "");
static_assert(sqlpp::is_group_by_column<BarId>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<BarId>, test::TabFoo_::Id::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<BarId>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<BarId>, sqlpp::provided_tables_of_t<BarId>>::value,
"");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<BarId>, sqlpp::provided_tables_of_t<BarId>>::value,
"");
static_assert(
std::is_same<
sqlpp::required_tables_of_t<BarId>,
sqlpp::detail::type_vector<sqlpp::table_as_t<test::TabFoo_, test::TabBar_::_sqlpp_name_tag>>>::value,
"");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<BarId>, sqlpp::required_tables_of_t<BarId>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<BarId>, sqlpp::integral>::value, "");
// (tab_foo as bar).id.as(cheese)
static_assert(not sqlpp::is_table<BarCheese>::value, "");
static_assert(not sqlpp::has_default<BarCheese>::value, "");
static_assert(not sqlpp::is_group_by_column<BarCheese>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<BarCheese>, sqlpp::no_name_t>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<BarCheese>, sqlpp::detail::type_vector<>>::value, "");
static_assert(
std::is_same<sqlpp::provided_static_tables_of_t<BarCheese>, sqlpp::provided_tables_of_t<BarCheese>>::value, "");
static_assert(
std::is_same<sqlpp::provided_optional_tables_of_t<BarCheese>, sqlpp::provided_tables_of_t<BarCheese>>::value,
"");
static_assert(
std::is_same<
sqlpp::required_tables_of_t<BarCheese>,
sqlpp::detail::type_vector<sqlpp::table_as_t<test::TabFoo_, test::TabBar_::_sqlpp_name_tag>>>::value,
"");
static_assert(
std::is_same<sqlpp::required_static_tables_of_t<BarCheese>, sqlpp::required_tables_of_t<BarCheese>>::value, "");
static_assert(std::is_same<sqlpp::value_type_of_t<BarCheese>, sqlpp::no_value_t>::value, "");
}
{
// Column optional (can be null) text with default.
auto bar = test::TabBar{};
using Bar = decltype(bar);
using TextN = decltype(bar.textN);
static_assert(not sqlpp::is_table<TextN>::value, "");
static_assert(sqlpp::has_default<TextN>::value, "");
static_assert(sqlpp::is_group_by_column<TextN>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<TextN>, test::TabBar_::TextN::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<TextN>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<TextN>, sqlpp::provided_tables_of_t<TextN>>::value,
"");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<TextN>, sqlpp::provided_tables_of_t<TextN>>::value,
"");
static_assert(std::is_same<sqlpp::required_tables_of_t<TextN>, sqlpp::detail::type_vector<Bar>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<TextN>, sqlpp::required_tables_of_t<TextN>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<TextN>, sqlpp::optional<sqlpp::text>>::value, "");
}
{
// Column bool without default.
auto bar = test::TabBar{};
using Bar = decltype(bar);
using BoolNn = decltype(bar.boolNn);
static_assert(not sqlpp::is_table<BoolNn>::value, "");
static_assert(not sqlpp::has_default<BoolNn>::value, "");
static_assert(sqlpp::is_group_by_column<BoolNn>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<BoolNn>, test::TabBar_::BoolNn::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<BoolNn>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<BoolNn>, sqlpp::provided_tables_of_t<BoolNn>>::value,
"");
static_assert(
std::is_same<sqlpp::provided_optional_tables_of_t<BoolNn>, sqlpp::provided_tables_of_t<BoolNn>>::value, "");
static_assert(std::is_same<sqlpp::required_tables_of_t<BoolNn>, sqlpp::detail::type_vector<Bar>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<BoolNn>, sqlpp::required_tables_of_t<BoolNn>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<BoolNn>, sqlpp::boolean>::value, "");
}
}
int main()
{
void test_column();
}

View File

@ -0,0 +1,47 @@
/*
* 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>
void test_table()
{
auto v = sqlpp::value(17);
auto foo = test::TabFoo{};
auto bar = test::TabBar{};
static_assert(sqlpp::is_table<test::TabFoo>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<test::TabFoo>, test::TabFoo_::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<test::TabFoo>, sqlpp::detail::type_vector<test::TabFoo>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<test::TabFoo>, sqlpp::provided_tables_of_t<test::TabFoo>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<test::TabFoo>, sqlpp::provided_tables_of_t<test::TabFoo>>::value, "");
}
int main()
{
void test_table();
}

View File

@ -0,0 +1,60 @@
/*
* 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>
void test_table()
{
auto v = sqlpp::value(17);
auto foo = test::TabFoo{};
auto bar = test::TabBar{};
using FooBar = decltype(foo.as(bar));
using Id = decltype(foo.as(bar).id);
static_assert(std::is_same<FooBar, sqlpp::table_as_t<test::TabFoo_, test::TabBar_::_sqlpp_name_tag>>::value, "");
static_assert(sqlpp::is_table<FooBar>::value, "");
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::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, "");
static_assert(not sqlpp::is_table<Id>::value, "");
static_assert(std::is_same<sqlpp::name_tag_of_t<Id>, test::TabFoo_::Id::_sqlpp_name_tag>::value, "");
static_assert(std::is_same<sqlpp::provided_tables_of_t<Id>, sqlpp::detail::type_vector<>>::value, "");
static_assert(std::is_same<sqlpp::provided_static_tables_of_t<Id>, sqlpp::provided_tables_of_t<Id>>::value, "");
static_assert(std::is_same<sqlpp::provided_optional_tables_of_t<Id>, sqlpp::provided_tables_of_t<Id>>::value, "");
static_assert(std::is_same<sqlpp::required_tables_of_t<Id>, sqlpp::detail::type_vector<FooBar>>::value, "");
static_assert(std::is_same<sqlpp::required_static_tables_of_t<Id>, sqlpp::required_tables_of_t<Id>>::value, "");
}
int main()
{
void test_table();
}