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

More type tests

This commit is contained in:
Roland Bock 2024-07-21 19:33:33 +02:00
parent 25faf6c4bb
commit 4630bf7f0c
6 changed files with 207 additions and 131 deletions

View File

@ -78,22 +78,6 @@ namespace sqlpp
template <typename T> template <typename T>
using remove_dynamic_t = typename remove_dynamic<T>::type; using remove_dynamic_t = typename remove_dynamic<T>::type;
#warning: Should not turn Expr to into optional, but just the value type
template <typename T>
struct dynamic_to_optional
{
using type = T;
};
template <typename Expr>
struct dynamic_to_optional<dynamic_t<Expr>>
{
using type = force_optional_t<Expr>;
};
template <typename T>
using dynamic_to_optional_t = typename dynamic_to_optional<T>::type;
template <typename Context, typename Select> template <typename Context, typename Select>
Context& serialize(Context& context, const dynamic_t<Select>& t) Context& serialize(Context& context, const dynamic_t<Select>& t)
{ {

View File

@ -26,17 +26,16 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sqlpp11/type_traits.h>
#include <type_traits> #include <type_traits>
#include <sqlpp11/compat/optional.h> #include <sqlpp11/type_traits.h>
#include <sqlpp11/dynamic.h>
namespace sqlpp namespace sqlpp
{ {
#warning: Do we need this? It should be possible to use name_tag_of_t and value_type_of_t somehow #warning: Do we need this? It should be possible to use name_tag_of_t and value_type_of_t somehow
template <typename NameType, typename ValueType> template <typename NameType, typename ValueType>
struct field_spec_t struct field_spec_t : public name_tag_base
{ {
using _alias_t = NameType; using _alias_t = NameType;
@ -77,17 +76,22 @@ namespace sqlpp
template <typename Select, typename NamedExpr> template <typename Select, typename NamedExpr>
struct make_field_spec_impl struct make_field_spec_impl
{ {
#warning: required_tables_of_t and obtaining the alias should handle optional. using ValueType = value_type_of_t<NamedExpr>;
#warning: remove_optional should not be necessary at all, since we are using dynamic instead
using RawNamedExpr = remove_optional_t<NamedExpr>;
static constexpr bool _depends_on_outer_table = static constexpr bool _depends_on_outer_table =
detail::make_intersect_set_t<required_tables_of_t<RawNamedExpr>, detail::make_intersect_set_t<required_tables_of_t<NamedExpr>,
typename Select::_used_outer_tables>::size::value > 0; typename Select::_used_outer_tables>::size::value > 0;
using ValueType = typename std::conditional<_depends_on_outer_table,
sqlpp::force_optional_t<value_type_of_t<NamedExpr>>,
value_type_of_t<NamedExpr>>::type;
using type = field_spec_t<name_tag_of_t<RawNamedExpr>, using type = field_spec_t<
name_tag_of_t<NamedExpr>,
typename std::conditional<_depends_on_outer_table, sqlpp::force_optional_t<ValueType>, ValueType>::type>;
};
template <typename Select, typename NamedExpr>
struct make_field_spec_impl<Select, dynamic_t<NamedExpr>>
{
using ValueType = force_optional_t<value_type_of_t<NamedExpr>>;
using type = field_spec_t<name_tag_of_t<NamedExpr>,
ValueType>; ValueType>;
}; };
} // namespace detail } // namespace detail

View File

@ -155,7 +155,7 @@ namespace sqlpp
using _field_t = typename _deferred_field_t<Db, Column>::type; using _field_t = typename _deferred_field_t<Db, Column>::type;
template <typename Db> template <typename Db>
using _result_row_t = result_row_t<Db, _field_t<Db, dynamic_to_optional_t<Columns>>...>; using _result_row_t = result_row_t<Db, _field_t<Db, Columns>...>;
template <typename AliasProvider> template <typename AliasProvider>
struct _deferred_table_t struct _deferred_table_t
@ -212,25 +212,42 @@ namespace sqlpp
}; };
}; };
template <typename Column> template <typename Column>
struct value_type_of<select_column_list_t<Column>> : public value_type_of<Column> {}; struct value_type_of<select_column_list_t<Column>> : public value_type_of<Column>
{
template<typename Column> };
struct name_tag_of<select_column_list_t<Column>> :public name_tag_of<Column>{}; template <typename Column>
struct value_type_of<select_column_list_t<dynamic_t<Column>>>
{
using type = force_optional_t<value_type_of_t<Column>>;
};
template <typename Column>
struct name_tag_of<select_column_list_t<Column>> : public name_tag_of<Column>
{
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_selected_colums_are_selectable_t, "selected columns must be selectable"); SQLPP_PORTABLE_STATIC_ASSERT(assert_selected_colums_are_selectable_t, "selected columns must be selectable");
template <typename T> template <typename T>
struct check_selected_columns; struct check_selected_column : std::integral_constant<bool, has_value_type<T>::value and has_name<T>::value>
template <typename... T>
struct check_selected_columns<std::tuple<T...>>
{ {
using type = };
static_combined_check_t<static_check_t<logic::all_t<is_selectable_t<remove_dynamic_t<T>>::value...>::value, template <typename T>
struct check_selected_column<dynamic_t<T>> : check_selected_column<T>
{
};
template <typename T>
struct check_selected_tuple;
template <typename... T>
struct check_selected_tuple<std::tuple<T...>>
{
using type = static_combined_check_t<
static_check_t<logic::all_t<check_selected_column<T>::value...>::value,
assert_selected_colums_are_selectable_t>>; assert_selected_colums_are_selectable_t>>;
}; };
template <typename T> template <typename T>
using check_selected_columns_t = typename check_selected_columns<T>::type; using check_selected_tuple_t = typename check_selected_tuple<T>::type;
template <typename T> template <typename T>
struct make_select_column_list; struct make_select_column_list;
@ -270,11 +287,11 @@ namespace sqlpp
using _consistency_check = consistent_t; using _consistency_check = consistent_t;
template <typename... Args> template <typename... Args>
auto columns(Args... args) const -> _new_statement_t<check_selected_columns_t<detail::flat_tuple_t<Args...>>, auto columns(Args... args) const -> _new_statement_t<check_selected_tuple_t<detail::flat_tuple_t<Args...>>,
make_select_column_list_t<detail::flat_tuple_t<Args...>>> make_select_column_list_t<detail::flat_tuple_t<Args...>>>
{ {
static_assert(sizeof...(Args), "at least one selectable expression (e.g. a column) required in columns()"); static_assert(sizeof...(Args), "at least one selectable expression (e.g. a column) required in columns()");
using check = check_selected_columns_t<detail::flat_tuple_t<Args...>>; using check = check_selected_tuple_t<detail::flat_tuple_t<Args...>>;
static_assert(check::value, static_assert(check::value,
"at least one argument is not a selectable expression in columns()"); "at least one argument is not a selectable expression in columns()");

View File

@ -36,6 +36,7 @@ endfunction()
test_compile(any) test_compile(any)
test_compile(aggregate_functions) test_compile(aggregate_functions)
test_compile(arithmetic_expression)
test_compile(comparison_expression) test_compile(comparison_expression)
test_compile(dynamic) test_compile(dynamic)
test_compile(in_expression) test_compile(in_expression)

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2016-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 "MockDb.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h"
namespace
{
template<typename A, typename B>
constexpr bool is_same_type()
{
return std::is_same<A, B>::value;
}
}
SQLPP_ALIAS_PROVIDER(r_not_null);
SQLPP_ALIAS_PROVIDER(r_maybe_null);
SQLPP_ALIAS_PROVIDER(r_opt_not_null);
SQLPP_ALIAS_PROVIDER(r_opt_maybe_null);
template<typename Value>
void test_arithmetic_expressions(Value v)
{
using ValueType = sqlpp::numeric;
using OptValueType = sqlpp::compat::optional<sqlpp::numeric>;
auto value = sqlpp::value(v);
auto opt_value = sqlpp::value(sqlpp::compat::make_optional(v));
// Arithmetically combining non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + value)>, ValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value - value)>, ValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value * value)>, ValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value / value)>, ValueType>(), "");
// Arithmetically combining non-optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value - opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value * opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value / opt_value)>, OptValueType>(), "");
// Arithmetically combining optional with non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value - value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value * value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value / value)>, OptValueType>(), "");
// Arithmetically combining optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value - opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value * opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value / opt_value)>, OptValueType>(), "");
// Same with negate.
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(-value)>, ValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(-opt_value)>, OptValueType>(), "");
}
template<typename Value>
void test_modulus_expressions(Value v)
{
using ValueType = sqlpp::numeric;
using OptValueType = sqlpp::compat::optional<sqlpp::numeric>;
auto value = sqlpp::value(v);
auto opt_value = sqlpp::value(sqlpp::compat::make_optional(v));
// Modulus combining non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value % value)>, ValueType>(), "");
// Modulus combining non-optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value % opt_value)>, OptValueType>(), "");
// Modulus combining optional with non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value % value)>, OptValueType>(), "");
// Modulus combining optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value % opt_value)>, OptValueType>(), "");
}
template<typename Value>
void test_concatenation_expressions(Value v)
{
using ValueType = sqlpp::text;
using OptValueType = sqlpp::compat::optional<sqlpp::text>;
auto value = sqlpp::value(v);
auto opt_value = sqlpp::value(sqlpp::compat::make_optional(v));
// Concatenating non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + value)>, ValueType>(), "");
// Concatenating non-optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + opt_value)>, OptValueType>(), "");
// Concatenating optional with non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + value)>, OptValueType>(), "");
// Concatenating optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + opt_value)>, OptValueType>(), "");
}
int main()
{
// integral
test_arithmetic_expressions(int8_t{7});
test_arithmetic_expressions(int16_t{7});
test_arithmetic_expressions(int32_t{7});
test_arithmetic_expressions(int64_t{7});
test_modulus_expressions(int8_t{7});
test_modulus_expressions(int16_t{7});
test_modulus_expressions(int32_t{7});
test_modulus_expressions(int64_t{7});
// unsigned integral
test_arithmetic_expressions(uint8_t{7});
test_arithmetic_expressions(uint16_t{7});
test_arithmetic_expressions(uint32_t{7});
test_arithmetic_expressions(uint64_t{7});
test_modulus_expressions(uint8_t{7});
test_modulus_expressions(uint16_t{7});
test_modulus_expressions(uint32_t{7});
test_modulus_expressions(uint64_t{7});
// floating point
test_arithmetic_expressions(float{7.7});
test_arithmetic_expressions(double{7.7});
// text
test_concatenation_expressions('7');
test_concatenation_expressions("seven");
test_concatenation_expressions(std::string("seven"));
test_concatenation_expressions(sqlpp::compat::string_view("seven"));
}

View File

@ -110,34 +110,6 @@ int main()
// time_of_day // time_of_day
test_result_row<std::chrono::microseconds>(std::chrono::microseconds{}); test_result_row<std::chrono::microseconds>(std::chrono::microseconds{});
// Arithmetically combining optional value with non-optional value yields optional boolean.
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::value(sqlpp::compat::make_optional(7)) + 8)>,
sqlpp::compat::optional<sqlpp::numeric>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::value(8) - sqlpp::compat::make_optional(7))>,
sqlpp::compat::optional<sqlpp::numeric>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::value(sqlpp::compat::make_optional(7)) / sqlpp::compat::make_optional(7))>,
sqlpp::compat::optional<sqlpp::numeric>>::value,
"");
// Same with negate.
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(-sqlpp::value(sqlpp::compat::make_optional(7)))>,
sqlpp::compat::optional<sqlpp::numeric>>::value,
"");
// Arithmetically combining non-optional value with non-optional value yields optional boolean.
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::value(7) + 8)>,
sqlpp::numeric>::value,
"");
// Same with negate.
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(-sqlpp::value(7))>,
sqlpp::numeric>::value,
"");
// Bit shifting combining optional value with non-optional value yields optional boolean. // Bit shifting combining optional value with non-optional value yields optional boolean.
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::value(sqlpp::compat::make_optional(7)) << 8)>, static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::value(sqlpp::compat::make_optional(7)) << 8)>,
sqlpp::compat::optional<sqlpp::integral>>::value, sqlpp::compat::optional<sqlpp::integral>>::value,
@ -147,30 +119,6 @@ int main()
sqlpp::compat::optional<sqlpp::integral>>::value, sqlpp::compat::optional<sqlpp::integral>>::value,
""); "");
// In expression with and without optional
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(in(sqlpp::value(7), 7, 8, 9))>,
sqlpp::boolean>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(in(sqlpp::value(7), std::vector<int>{7, 8, 9}))>,
sqlpp::boolean>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(in(sqlpp::value(sqlpp::compat::make_optional(7)), 7, 8, 9))>,
sqlpp::compat::optional<sqlpp::boolean>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(in(sqlpp::value(sqlpp::compat::make_optional(7)), std::vector<int>{7, 8, 9}))>,
sqlpp::compat::optional<sqlpp::boolean>>::value,
"");
// in expression
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(in(sqlpp::value(7), sqlpp::compat::make_optional(7), 8, 9))>,
sqlpp::compat::optional<sqlpp::boolean>>::value,
"");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(in(sqlpp::value(7), std::vector<sqlpp::compat::optional<int>>{7, 8, 9}))>,
sqlpp::compat::optional<sqlpp::boolean>>::value,
"");
// assignment is no value // assignment is no value
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(assign(bar.intN, sqlpp::compat::nullopt))>, sqlpp::no_value_t>::value, ""); static_assert(std::is_same<sqlpp::value_type_of_t<decltype(assign(bar.intN, sqlpp::compat::nullopt))>, sqlpp::no_value_t>::value, "");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(assign(bar.intN, sqlpp::default_value))>, sqlpp::no_value_t>::value, ""); static_assert(std::is_same<sqlpp::value_type_of_t<decltype(assign(bar.intN, sqlpp::default_value))>, sqlpp::no_value_t>::value, "");
@ -180,45 +128,8 @@ int main()
sqlpp::as(bar.intN, bar.textN); sqlpp::as(bar.intN, bar.textN);
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(bar.intN.as(bar.textN))>, sqlpp::value_type_of_t<decltype(bar.intN)>>::value, ""); static_assert(std::is_same<sqlpp::value_type_of_t<decltype(bar.intN.as(bar.textN))>, sqlpp::value_type_of_t<decltype(bar.intN)>>::value, "");
// max can yield NULL if there are no results.
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(max(bar.intN))>, sqlpp::compat::optional<sqlpp::integral>>::value, "");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(max(foo.textNnD))>, sqlpp::compat::optional<sqlpp::text>>::value, "");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(sqlpp::max(7))>, sqlpp::compat::optional<sqlpp::integral>>::value, "");
#if 0 #if 0
{
// result fields are as nullable as the expressions they represent
const auto rows = db(select(bar.id, bar.boolNn, bar.intN, seven).from(bar).unconditionally());
auto& x = rows.front();
#warning: test with nullable columns, too.
#warning: test with all kinds of functions as well.
#warning: We should actually test for the exact type!
static_assert(not is_optional<decltype(x.id)>::value, "");
static_assert(not is_optional<decltype(x.boolNn)>::value, "");
static_assert(is_optional<decltype(x.intN)>::value, "");
static_assert(not is_optional<decltype(x.s)>::value, "");
}
}
void optional_columns()
{
{
// result fields are as nullable as the expressions they represent
#warning: add `if_` to other expressions, too
#warning: test with nullable columns, too.
#warning: test with all kinds of functions as well.
#warning: We should actually test for the exact type!
const auto rows = db(select(bar.id.if_(true), bar.boolNn.if_(true), bar.intN.if_(true) /*, seven*/).from(bar).unconditionally());
auto& x = rows.front();
static_assert(is_optional<decltype(x.id)>::value, "");
static_assert(is_optional<decltype(x.boolNn)>::value, "");
static_assert(is_optional<decltype(x.intN)>::value, "");
}
}
void join() void join()
{ {
// Join // Join