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

Added type tests for join and fixed a few things to make them compile

This commit is contained in:
Roland Bock 2024-08-23 11:13:48 +02:00
parent 135dceeba3
commit 151af17bbc
13 changed files with 219 additions and 34 deletions

View File

@ -104,10 +104,13 @@ namespace sqlpp
{ {
}; };
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>>
{ {
using type = detail::type_set<Table>; using type = detail::type_set<table_t<Table>>;
}; };
template <typename Context, typename Table, typename ColumnSpec> template <typename Context, typename Table, typename ColumnSpec>

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/* /*
* Copyright (c) 2013-2016, Roland Bock * Copyright (c) 2013, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
@ -38,7 +38,7 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_join>; using _traits = make_traits<no_value_t, tag::is_join>;
using _nodes = detail::type_vector<PreJoin, On>; using _nodes = detail::type_vector<PreJoin, On>;
using _can_be_null = std::false_type; using _can_be_null = std::false_type;
using _provided_tables = provided_tables_of<PreJoin>; using _provided_tables = provided_tables_of_t<PreJoin>;
using _required_tables = detail::make_difference_set_t<required_tables_of_t<On>, _provided_tables>; using _required_tables = detail::make_difference_set_t<required_tables_of_t<On>, _provided_tables>;
template <typename T> template <typename T>
@ -81,6 +81,18 @@ namespace sqlpp
On _on; On _on;
}; };
template<typename PreJoin, typename On>
struct nodes_of<join_t<PreJoin, On>>
{
using type = sqlpp::detail::type_vector<PreJoin, On>;
};
template<typename PreJoin, typename On>
struct provided_outer_tables_of<join_t<PreJoin, On>>
{
using type = provided_outer_tables_of_t<PreJoin>;
};
template<typename PreJoin, typename On> template<typename PreJoin, typename On>
struct is_table<join_t<PreJoin, On>> : public std::true_type{}; struct is_table<join_t<PreJoin, On>> : public std::true_type{};

View File

@ -34,28 +34,28 @@ namespace sqlpp
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = using _provided_outer_tables =
detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_outer_tables_of<Rhs>>; detail::make_joined_set_t<provided_outer_tables_of_t<Lhs>, provided_outer_tables_of_t<Rhs>>;
static constexpr const char* _name = " INNER"; static constexpr const char* _name = " INNER";
}; };
struct outer_join_t struct outer_join_t
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_tables_of<Rhs>>; using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>;
static constexpr const char* _name = " OUTER"; static constexpr const char* _name = " OUTER";
}; };
struct left_outer_join_t struct left_outer_join_t
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_tables_of<Rhs>>; using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of_t<Lhs>, provided_tables_of_t<Rhs>>;
static constexpr const char* _name = " LEFT OUTER"; static constexpr const char* _name = " LEFT OUTER";
}; };
struct right_outer_join_t struct right_outer_join_t
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_outer_tables_of<Rhs>>; using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of_t<Lhs>, provided_outer_tables_of_t<Rhs>>;
static constexpr const char* _name = " RIGHT OUTER"; static constexpr const char* _name = " RIGHT OUTER";
}; };
@ -63,7 +63,7 @@ namespace sqlpp
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = using _provided_outer_tables =
detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_outer_tables_of<Rhs>>; detail::make_joined_set_t<provided_outer_tables_of_t<Lhs>, provided_outer_tables_of_t<Rhs>>;
static constexpr const char* _name = " CROSS"; static constexpr const char* _name = " CROSS";
}; };

View File

@ -60,6 +60,12 @@ namespace sqlpp
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
}; };
template<typename Expression>
struct nodes_of<on_t<Expression>>
{
using type = sqlpp::detail::type_vector<Expression>;
};
template <typename Context> template <typename Context>
auto to_sql_string(Context& , const on_t<unconditional_t>&) -> std::string auto to_sql_string(Context& , const on_t<unconditional_t>&) -> std::string
{ {

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/* /*
* Copyright (c) 2013-2016, Roland Bock * Copyright (c) 2013, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
@ -28,6 +28,7 @@
#include <sqlpp11/core/basic/join_types.h> #include <sqlpp11/core/basic/join_types.h>
#include <sqlpp11/core/noop.h> #include <sqlpp11/core/noop.h>
#include <sqlpp11/core/query/dynamic.h>
#include <sqlpp11/core/basic/on.h> #include <sqlpp11/core/basic/on.h>
#include <sqlpp11/core/basic/table_ref.h> #include <sqlpp11/core/basic/table_ref.h>
@ -45,8 +46,9 @@ namespace sqlpp
static_check_t<is_table<Lhs>::value, assert_pre_join_lhs_table_t>, static_check_t<is_table<Lhs>::value, assert_pre_join_lhs_table_t>,
static_check_t<is_table<Rhs>::value, assert_pre_join_rhs_table_t>, static_check_t<is_table<Rhs>::value, assert_pre_join_rhs_table_t>,
static_check_t<not is_join_t<Rhs>::value, assert_pre_join_rhs_no_join_t>, static_check_t<not is_join_t<Rhs>::value, assert_pre_join_rhs_no_join_t>,
static_check_t<detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of<Lhs>>, #warning: Since rhs is a table, we could also just get a type vector here.
detail::make_name_of_set_t<provided_tables_of<Rhs>>>::value, static_check_t<detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of_t<Lhs>>,
detail::make_name_of_set_t<provided_tables_of_t<Rhs>>>::value,
assert_pre_join_unique_names_t>>; assert_pre_join_unique_names_t>>;
}; };
@ -66,7 +68,7 @@ namespace sqlpp
static_check_t<is_pre_join_t<PreJoin>::value, assert_join_consist_of_pre_join_and_on_t>, static_check_t<is_pre_join_t<PreJoin>::value, assert_join_consist_of_pre_join_and_on_t>,
static_check_t<is_on_t<On>::value, assert_join_consist_of_pre_join_and_on_t>, static_check_t<is_on_t<On>::value, assert_join_consist_of_pre_join_and_on_t>,
static_check_t<required_tables_of_t<PreJoin>::size::value == 0, assert_join_no_table_dependencies_t>, static_check_t<required_tables_of_t<PreJoin>::size::value == 0, assert_join_no_table_dependencies_t>,
static_check_t<detail::is_subset_of<required_tables_of_t<On>, provided_tables_of<PreJoin>>::value, static_check_t<detail::is_subset_of<required_tables_of_t<On>, provided_tables_of_t<PreJoin>>::value,
assert_join_on_no_foreign_table_dependencies_t>>; assert_join_on_no_foreign_table_dependencies_t>>;
}; };
@ -93,13 +95,7 @@ namespace sqlpp
using _can_be_null = std::false_type; using _can_be_null = std::false_type;
using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>; using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>;
static_assert(is_table<Lhs>::value, "lhs argument for join() has to be a table or join"); #warning: Do we really need this?
static_assert(is_table<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_t<pre_join_t>::size::value == 0, "joined tables must not depend on other tables"); static_assert(required_tables_of_t<pre_join_t>::size::value == 0, "joined tables must not depend on other tables");
auto unconditionally() -> join_t<pre_join_t, on_t<unconditional_t>> auto unconditionally() -> join_t<pre_join_t, on_t<unconditional_t>>
@ -132,6 +128,19 @@ namespace sqlpp
Rhs _rhs; Rhs _rhs;
}; };
template <typename JoinType, typename Lhs, typename Rhs>
struct nodes_of<pre_join_t<JoinType, Lhs, Rhs>>
{
using type = sqlpp::detail::type_vector<Lhs, Rhs>;
};
template <typename JoinType, typename Lhs, typename Rhs>
struct provided_outer_tables_of<pre_join_t<JoinType, Lhs, Rhs>>
{
using type = typename JoinType::template _provided_outer_tables<Lhs, Rhs>;
};
template <typename Context, typename JoinType, typename Lhs, typename Rhs> template <typename Context, typename JoinType, typename Lhs, typename Rhs>
auto to_sql_string(Context& context, const pre_join_t<JoinType, Lhs, Rhs>& t) -> std::string auto to_sql_string(Context& context, const pre_join_t<JoinType, Lhs, Rhs>& t) -> std::string
{ {
@ -147,7 +156,7 @@ namespace sqlpp
auto join_impl(consistent_t, Lhs lhs, Rhs rhs) -> pre_join_t<JoinType, from_table_t<Lhs>, from_table_t<Rhs>>; auto join_impl(consistent_t, Lhs lhs, Rhs rhs) -> pre_join_t<JoinType, from_table_t<Lhs>, from_table_t<Rhs>>;
template <typename JoinType, typename Lhs, typename Rhs> template <typename JoinType, typename Lhs, typename Rhs>
auto join_impl(Lhs lhs, Rhs rhs) -> decltype(join_impl<JoinType>(check_pre_join_t<Lhs, Rhs>{}, lhs, rhs)); auto join_impl(Lhs lhs, Rhs rhs) -> decltype(join_impl<JoinType>(check_pre_join_t<Lhs, remove_dynamic_t<Rhs>>{}, lhs, rhs));
} // namespace detail } // namespace detail
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>

View File

@ -41,9 +41,6 @@ namespace sqlpp
{ {
using _traits = make_traits<no_value_t, tag::is_raw_table>; using _traits = make_traits<no_value_t, tag::is_raw_table>;
using _nodes = detail::type_vector<>;
using _provided_tables = detail::type_set<TableSpec>;
using _required_insert_columns = typename TableSpec::_required_insert_columns; using _required_insert_columns = typename TableSpec::_required_insert_columns;
#warning: Need to inherit? #warning: Need to inherit?
//using _column_tuple_t = std::tuple<column_t<Table, ColumnSpec>...>; //using _column_tuple_t = std::tuple<column_t<Table, ColumnSpec>...>;
@ -66,6 +63,12 @@ namespace sqlpp
template <typename TableSpec> template <typename TableSpec>
struct is_table<table_t<TableSpec>>: public std::true_type {}; struct is_table<table_t<TableSpec>>: public std::true_type {};
template <typename TableSpec>
struct provided_tables_of<table_t<TableSpec>>
{
using type = sqlpp::detail::type_set<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
{ {

View File

@ -85,8 +85,8 @@ namespace sqlpp
static_check_t<not is_pre_join_t<Table>::value, assert_from_not_pre_join_t>, static_check_t<not is_pre_join_t<Table>::value, assert_from_not_pre_join_t>,
static_check_t<is_table<Table>::value, assert_from_table_t>, static_check_t<is_table<Table>::value, assert_from_table_t>,
static_check_t<required_tables_of_t<Table>::size::value == 0, assert_from_dependency_free_t>, static_check_t<required_tables_of_t<Table>::size::value == 0, assert_from_dependency_free_t>,
static_check_t<provided_tables_of<Table>::size::value == static_check_t<provided_tables_of_t<Table>::size::value ==
detail::make_name_of_set_t<provided_tables_of<Table>>::size::value, detail::make_name_of_set_t<provided_tables_of_t<Table>>::size::value,
assert_from_no_duplicates_t>>; assert_from_no_duplicates_t>>;
}; };

View File

@ -27,6 +27,7 @@
*/ */
#include <sqlpp11/core/type_traits.h> #include <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/operator/assign_expression.h>
#include <sqlpp11/core/operator/sort_order_expression.h> #include <sqlpp11/core/operator/sort_order_expression.h>
#include <sqlpp11/core/operator/enable_as.h> #include <sqlpp11/core/operator/enable_as.h>
#include <sqlpp11/core/to_sql_string.h> #include <sqlpp11/core/to_sql_string.h>
@ -115,4 +116,13 @@ namespace sqlpp
{ {
return {condition, std::move(t)}; return {condition, std::move(t)};
} }
template <typename TableSpec>
struct table_t;
template <typename TableSpec>
auto dynamic(bool condition, table_t<TableSpec> t) -> dynamic_t<table_t<TableSpec>>
{
return {condition, std::move(t)};
}
} // namespace sqlpp } // namespace sqlpp

View File

@ -78,8 +78,8 @@ 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<Policies>...>; using _all_provided_tables = detail::make_joined_set_t<provided_tables_of_t<Policies>...>;
using _all_provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Policies>...>; using _all_provided_outer_tables = detail::make_joined_set_t<provided_outer_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>...>;
template <typename Expression> template <typename Expression>

View File

@ -285,8 +285,6 @@ namespace sqlpp
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(required_ctes) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(required_ctes)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_ctes) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_ctes)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_tables)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_outer_tables)
SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates) SQLPP_RECURSIVE_TRAIT_SET_GENERATOR(provided_aggregates)
template <typename T> template <typename T>
@ -325,6 +323,40 @@ namespace sqlpp
static_assert(required_tables_of_t<int>::size::value == 0, ""); static_assert(required_tables_of_t<int>::size::value == 0, "");
template <typename T>
struct provided_tables_of
{
using type = typename provided_tables_of<nodes_of_t<T>>::type;
};
template <typename... T>
struct provided_tables_of<detail::type_vector<T...>>
{
using type = detail::make_joined_set_t<typename provided_tables_of<T>::type...>;
};
template <typename T>
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_outer_tables_of
{
using type = typename provided_outer_tables_of<nodes_of_t<T>>::type;
};
template <typename... T>
struct provided_outer_tables_of<detail::type_vector<T...>>
{
using type = detail::make_joined_set_t<typename provided_outer_tables_of<T>::type...>;
};
template <typename T>
using provided_outer_tables_of_t = typename provided_outer_tables_of<T>::type;
static_assert(provided_outer_tables_of_t<int>::size::value == 0, "");
template <typename ValueType, typename T> template <typename ValueType, typename T>
struct is_valid_operand struct is_valid_operand
{ {

View File

@ -33,8 +33,4 @@ test_compile(result_row)
test_compile(select_as) test_compile(select_as)
test_compile(value) test_compile(value)
add_subdirectory(aggregate_function) add_subdirectory(basic)
add_subdirectory(operator)
add_subdirectory(clause)
add_subdirectory(detail)
add_subdirectory(type_traits)

View File

@ -0,0 +1,32 @@
# Copyright (c) 2024, Roland Bock
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function(test_compile name)
set(target sqlpp11_core_types_clause_${name})
add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing)
endfunction()
test_compile(join)

View File

@ -0,0 +1,82 @@
/*
* 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_group_by()
{
auto v = sqlpp::value(17);
auto foo = test::TabFoo{};
auto bar = test::TabBar{};
// Pre-join
static_assert(not sqlpp::is_table<decltype(foo.join(bar))>::value, "");
// Join
{
using J = decltype(foo.join(bar).on(foo.id == bar.id));
static_assert(sqlpp::is_table<J>::value, "");
static_assert(
std::is_same<sqlpp::provided_tables_of_t<J>, sqlpp::detail::type_set<test::TabFoo, test::TabBar>>::value, "");
static_assert(
std::is_same<sqlpp::provided_outer_tables_of_t<J>, sqlpp::detail::type_set<>>::value, "");
#warning: test the provided dynamic tables of?
}
{
using J = decltype(foo.outer_join(bar).on(foo.id == bar.id));
static_assert(sqlpp::is_table<J>::value, "");
static_assert(
std::is_same<sqlpp::provided_tables_of_t<J>, sqlpp::detail::type_set<test::TabFoo, test::TabBar>>::value, "");
static_assert(
std::is_same<sqlpp::provided_outer_tables_of_t<J>, sqlpp::detail::type_set<test::TabFoo, test::TabBar>>::value, "");
#warning: test the provided dynamic tables of?
}
// Join with dynamic table
{
using J = decltype(foo.join(dynamic(true, bar)).on(foo.id == bar.id));
static_assert(sqlpp::is_table<J>::value, "");
static_assert(
std::is_same<sqlpp::provided_tables_of_t<J>, sqlpp::detail::type_set<test::TabFoo, test::TabBar>>::value, "");
#warning: OUTER is the wrong term. In a left-outer join, the *right* table is the one with optional rows.
static_assert(
std::is_same<sqlpp::provided_outer_tables_of_t<J>, sqlpp::detail::type_set<>>::value, "");
#warning: test the provided dynamic tables of?
}
#warning: Need to add tests with 3 tables
#warning: Need to add tests with CTEs
}
int main()
{
void test_group_by();
}