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

more tests and more clarity for group_by

This commit is contained in:
Roland Bock 2024-08-16 14:15:08 +02:00
parent 843e39b3d0
commit fc0632e0b0
15 changed files with 647 additions and 288 deletions

View File

@ -85,6 +85,11 @@ namespace sqlpp
}
};
template<typename Table, typename ColumnSpec>
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>>
{

View File

@ -30,15 +30,16 @@
#include <sqlpp11/core/logic.h>
#include <sqlpp11/core/query/policy_update.h>
#include <sqlpp11/core/type_traits.h>
#include <sqlpp11/core/group_by_column.h>
#include <tuple>
namespace sqlpp
{
// GROUP BY DATA
template <typename... Expressions>
template <typename... Columns>
struct group_by_data_t
{
group_by_data_t(Expressions... expressions) : _expressions(expressions...)
group_by_data_t(Columns... columns) : _columns(columns...)
{
}
@ -48,7 +49,7 @@ namespace sqlpp
group_by_data_t& operator=(group_by_data_t&&) = default;
~group_by_data_t() = default;
std::tuple<Expressions...> _expressions;
std::tuple<Columns...> _columns;
};
SQLPP_PORTABLE_STATIC_ASSERT(
@ -56,13 +57,13 @@ namespace sqlpp
"at least one group-by expression requires a table which is otherwise not known in the statement");
// GROUP BY
template <typename... Expressions>
template <typename... Columns>
struct group_by_t
{
using _traits = make_traits<no_value_t, tag::is_group_by>;
using _nodes = detail::type_vector<Expressions...>;
using _nodes = detail::type_vector<Columns...>;
using _data_t = group_by_data_t<Expressions...>;
using _data_t = group_by_data_t<Columns...>;
// Base template to be inherited by the statement
template <typename Policies>
@ -80,22 +81,22 @@ namespace sqlpp
};
};
template <typename... Expressions>
struct known_aggregate_expressions_of<group_by_t<Expressions...>>
template <typename... Columns>
struct known_aggregate_columns_of<group_by_t<Columns...>>
{
using type = detail::type_vector<Expressions...>;
using type = detail::type_vector<Columns...>;
};
SQLPP_PORTABLE_STATIC_ASSERT(assert_group_by_args_have_values_t, "all arguments for group_by() must have values");
SQLPP_PORTABLE_STATIC_ASSERT(assert_group_by_args_are_columns_t, "all arguments for group_by() must be columns");
template <typename... Exprs>
template <typename... Columns>
struct check_group_by
{
using type = static_combined_check_t<
static_check_t<logic::all_t<has_value_type<Exprs>::value...>::value, assert_group_by_args_have_values_t>>;
static_check_t<logic::all_t<is_group_by_column<Columns>::value...>::value, assert_group_by_args_are_columns_t>>;
};
template <typename... Exprs>
using check_group_by_t = typename check_group_by<Exprs...>::type;
template <typename... Columns>
using check_group_by_t = typename check_group_by<Columns...>::type;
// NO GROUP BY YET
struct no_group_by_t
@ -122,44 +123,43 @@ namespace sqlpp
using _consistency_check = consistent_t;
#warning: Arguments should not be constants and not contain aggregate functions
template <typename... Expressions>
auto group_by(Expressions... expressions) const
-> _new_statement_t<check_group_by_t<Expressions...>, group_by_t<Expressions...>>
template <typename... Columns>
auto group_by(Columns... columns) const
-> _new_statement_t<check_group_by_t<remove_dynamic_t<Columns>...>, group_by_t<Columns...>>
{
static_assert(sizeof...(Expressions), "at least one expression (e.g. a column) required in group_by()");
static_assert(sizeof...(Columns), "at least one column required in group_by()");
return _group_by_impl(check_group_by_t<Expressions...>{}, expressions...);
return _group_by_impl(check_group_by_t<Columns...>{}, columns...);
}
private:
template <typename Check, typename... Expressions>
auto _group_by_impl(Check, Expressions... expressions) const -> inconsistent<Check>;
template <typename Check, typename... Columns>
auto _group_by_impl(Check, Columns... columns) const -> inconsistent<Check>;
template <typename... Expressions>
auto _group_by_impl(consistent_t /*unused*/, Expressions... expressions) const
-> _new_statement_t<consistent_t, group_by_t<Expressions...>>
template <typename... Columns>
auto _group_by_impl(consistent_t /*unused*/, Columns... columns) const
-> _new_statement_t<consistent_t, group_by_t<Columns...>>
{
static_assert(not detail::has_duplicates<Expressions...>::value,
static_assert(not detail::has_duplicates<Columns...>::value,
"at least one duplicate argument detected in group_by()");
return {static_cast<const derived_statement_t<Policies>&>(*this),
group_by_data_t<Expressions...>{expressions...}};
group_by_data_t<Columns...>{columns...}};
}
};
};
// Interpreters
template <typename Context, typename... Expressions>
auto to_sql_string(Context& context, const group_by_data_t<Expressions...>& t) -> std::string
template <typename Context, typename... Columns>
auto to_sql_string(Context& context, const group_by_data_t<Columns...>& t) -> std::string
{
return " GROUP BY " + interpret_tuple(t._expressions, ',', context);
return " GROUP BY " + interpret_tuple(t._columns, ',', context);
}
template <typename... T>
auto group_by(T&&... t) -> decltype(statement_t<no_group_by_t>().group_by(std::forward<T>(t)...))
auto group_by(T... t) -> decltype(statement_t<no_group_by_t>().group_by(std::move(t)...))
{
return statement_t<no_group_by_t>().group_by(std::forward<T>(t)...);
return statement_t<no_group_by_t>().group_by(std::move(t)...);
}
} // namespace sqlpp

View File

@ -35,6 +35,7 @@
#include <sqlpp11/core/query/result_row.h>
#include <sqlpp11/core/clause/select_as.h>
#include <sqlpp11/core/clause/select_column_traits.h>
#include <sqlpp11/core/group_by_column.h>
#include <sqlpp11/core/basic/table.h>
#include <tuple>

View File

@ -0,0 +1,73 @@
#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.
*/
#include <sqlpp11/core/type_traits/group_by_column.h>
#include <sqlpp11/core/type_traits/value_type.h>
#include <sqlpp11/core/operator/enable_as.h>
namespace sqlpp
{
// `group_by` takes columns as parameters.
// If you really, really want to, you can pass something else, but you have to tell the library that you are really certain by wrapping it in `declare_group_by_column`.
template <typename Expr>
struct group_by_column : public enable_as<group_by_column<Expr>>
{
group_by_column(Expr expr) : _expr(std::move(expr)) {}
group_by_column(const group_by_column&) = default;
group_by_column(group_by_column&&) = default;
group_by_column& operator=(const group_by_column&) = default;
group_by_column& operator=(group_by_column&&) = default;
~group_by_column() = default;
Expr _expr;
};
template <typename Expr>
struct is_group_by_column<group_by_column<Expr>> : public std::true_type
{
};
template <typename Expr>
struct value_type_of<group_by_column<Expr>> : public value_type_of<Expr>
{
};
template<typename Expr>
using check_declare_group_by_column_args = ::sqlpp::enable_if_t<has_value_type<Expr>::value and not is_group_by_column<Expr>::value>;
template <typename Expr, typename = check_declare_group_by_column_args<Expr>>
auto declare_group_by_column(Expr expr) -> group_by_column<Expr>
{
return {std::move(expr)};
}
#warning Add tests
} // namespace sqlpp11

View File

@ -273,6 +273,12 @@ namespace sqlpp
using type = typename detail::type_vector<Policies...>;
};
template <typename... Policies>
struct known_aggregate_columns_of<statement_t<Policies...>>
{
using type = detail::type_vector_cat_t<known_aggregate_columns_of_t<Policies>...>;
};
template <typename... Policies>
struct requires_parentheses<statement_t<Policies...>> : public std::true_type {};

View File

@ -1,7 +1,7 @@
#pragma once
/*
* Copyright (c) 2013-2017, Roland Bock, Aaron Bishop
* Copyright (c) 2013, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -26,13 +26,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdint>
#include <tuple>
#include <type_traits>
#include <array>
#include <vector>
#include <sqlpp11/core/chrono.h>
#include <sqlpp11/core/name/name_tag.h>
#include <sqlpp11/core/compat/optional.h>
#include <sqlpp11/core/compat/string_view.h>
@ -44,55 +42,13 @@
#include <sqlpp11/core/detail/type_set.h>
#include <sqlpp11/core/detail/get_first.h>
#include <sqlpp11/core/type_traits/aggregates.h>
#include <sqlpp11/core/type_traits/group_by_column.h>
#include <sqlpp11/core/type_traits/nodes_of.h>
#include <sqlpp11/core/type_traits/optional.h>
#include <sqlpp11/core/type_traits/value_type.h>
namespace sqlpp
{
template <typename T>
struct is_optional : public std::false_type
{
};
template <typename T>
struct is_optional<::sqlpp::optional<T>> : public std::true_type
{
};
template <>
struct is_optional<::sqlpp::nullopt_t> : public std::true_type
{
};
template <typename T>
struct remove_optional
{
using type = T;
};
template <typename T>
struct remove_optional<::sqlpp::optional<T>>
{
using type = T;
};
template <typename T>
using remove_optional_t = typename remove_optional<T>::type;
template <typename T>
struct force_optional
{
using type = ::sqlpp::optional<T>;
};
template <typename T>
struct force_optional<::sqlpp::optional<T>>
{
using type = ::sqlpp::optional<T>;
};
template <typename T>
using force_optional_t = typename force_optional<T>::type;
template <typename T>
const T& get_value(const T& t)
{
@ -117,26 +73,6 @@ namespace sqlpp
return t.has_value();
}
struct no_value_t;
template <typename T>
struct value_type_of
{
using type = no_value_t;
};
template <typename T>
using value_type_of_t = typename value_type_of<T>::type;
template<typename T>
struct value_type_of<::sqlpp::optional<T>>
{
using type = sqlpp::force_optional_t<value_type_of_t<remove_optional_t<T>>>;
};
template <typename T>
struct has_value_type : public std::integral_constant<bool, not std::is_same<value_type_of_t<T>, no_value_t>::value> {};
template <typename T>
struct has_default : public std::false_type
{
@ -153,186 +89,6 @@ namespace sqlpp
};
//
struct boolean{};
template<>
struct value_type_of<boolean> { using type = boolean; };
template<>
struct value_type_of<bool> { using type = boolean; };
struct integral{};
template<>
struct value_type_of<integral> { using type = integral; };
template<>
struct value_type_of<int8_t> { using type = integral; };
template<>
struct value_type_of<int16_t> { using type = integral; };
template<>
struct value_type_of<int32_t> { using type = integral; };
template<>
struct value_type_of<int64_t> { using type = integral; };
struct unsigned_integral{};
template<>
struct value_type_of<unsigned_integral> { using type = unsigned_integral; };
template<>
struct value_type_of<uint8_t> { using type = unsigned_integral; };
template<>
struct value_type_of<uint16_t> { using type = unsigned_integral; };
template<>
struct value_type_of<uint32_t> { using type = unsigned_integral; };
template<>
struct value_type_of<uint64_t> { using type = unsigned_integral; };
struct floating_point{};
template<>
struct value_type_of<floating_point> { using type = floating_point; };
template<>
struct value_type_of<float> { using type = floating_point; };
template<>
struct value_type_of<double> { using type = floating_point; };
template<>
struct value_type_of<long double> { using type = floating_point; };
struct text{};
template <>
struct value_type_of<text> { using type = text; };
template <>
struct value_type_of<char> { using type = text; };
template <>
struct value_type_of<const char*> { using type = text; };
template <>
struct value_type_of<std::string> { using type = text; };
template <>
struct value_type_of<::sqlpp::string_view> { using type = text; };
struct blob{};
template <>
struct value_type_of<blob> { using type = blob; };
template <std::size_t N>
struct value_type_of<std::array<std::uint8_t, N>> { using type = blob; };
template <>
struct value_type_of<std::vector<std::uint8_t>> { using type = blob; };
template <>
struct value_type_of<::sqlpp::span<std::uint8_t>> { using type = blob; };
struct day_point{};
template <>
struct value_type_of<day_point> { using type = day_point; };
template <>
struct value_type_of<std::chrono::time_point<std::chrono::system_clock, sqlpp::chrono::days>> { using type = day_point; };
struct time_of_day{};
template <>
struct value_type_of<time_of_day> { using type = time_of_day; };
template <typename Rep, typename Period>
struct value_type_of<std::chrono::duration<Rep, Period>> { using type = time_of_day; };
struct time_point{};
template <>
struct value_type_of<time_point> { using type = time_point; };
template <typename Period>
struct value_type_of<std::chrono::time_point<std::chrono::system_clock, Period>> { using type = time_point; };
template <typename T>
struct is_boolean : public std::is_same<remove_optional_t<value_type_of_t<T>>, boolean>
{
};
template <>
struct is_boolean<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_integral : public std::is_same<remove_optional_t<value_type_of_t<T>>, integral>
{
};
template <>
struct is_integral<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_unsigned_integral : public std::is_same<remove_optional_t<value_type_of_t<T>>, unsigned_integral>
{
};
template <>
struct is_unsigned_integral<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_floating_point : public std::is_same<remove_optional_t<value_type_of_t<T>>, floating_point>
{
};
template <>
struct is_floating_point<::sqlpp::nullopt_t> : public std::true_type {
};
// A generic numeric type which could be (unsigned) integral or floating point.
struct numeric{};
template <typename T>
struct is_numeric
: public std::integral_constant<bool,
is_boolean<T>::value or is_integral<T>::value or is_unsigned_integral<T>::value or
is_floating_point<T>::value or
std::is_same<remove_optional_t<value_type_of_t<T>>, numeric>::value>
{
};
template <>
struct is_numeric<::sqlpp::nullopt_t> : public std::true_type{};
template <typename T>
struct is_text : public std::is_same<remove_optional_t<value_type_of_t<T>>, text>
{
};
template <>
struct is_text<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_blob : public std::is_same<remove_optional_t<value_type_of_t<T>>, blob>
{
};
template <>
struct is_blob<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_day_point : public std::is_same<remove_optional_t<value_type_of_t<T>>, day_point>
{
};
template <>
struct is_day_point<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_time_point : public std::is_same<remove_optional_t<value_type_of_t<T>>, time_point>
{
};
template <>
struct is_time_point<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_day_or_time_point : public std::integral_constant<bool, is_day_point<T>::value or is_time_point<T>::value> {
};
template <typename T>
struct is_time_of_day : public std::is_same<remove_optional_t<value_type_of_t<T>>, time_of_day>
{
};
template <>
struct is_time_of_day<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename L, typename R>
struct values_are_comparable
: public std::integral_constant<bool,
@ -579,6 +335,7 @@ namespace sqlpp
;
};
#warning: This should go away
namespace detail
{
template <typename KnownAggregates, typename T, typename Leaf = void>

View File

@ -34,7 +34,7 @@ namespace sqlpp
{
// We don't want to mix aggregate and non-aggregate expressions as the results are unspecified.
// Aggregates are either results of aggregate functions or GROUP BY columns.
// Non-aggregates are columns (unless they are aggregate expressions).
// Non-aggregates are columns (unless they are aggregate columns).
// Constant values are neutral.
template <typename T>
@ -60,23 +60,23 @@ namespace sqlpp
{
};
// Obtain known aggregate expressions, i.e. GROUP BY columns.
// Obtain known aggregate columns, i.e. GROUP BY columns.
template <typename T>
struct known_aggregate_expressions_of
struct known_aggregate_columns_of
{
using type = detail::type_vector<>;
};
template <typename T>
using known_aggregate_expressions_of_t = typename known_aggregate_expressions_of<T>::type;
using known_aggregate_columns_of_t = typename known_aggregate_columns_of<T>::type;
// Checks if T is an aggregate expression (either an aggregate function or a known aggregate).
// @KnownAggregateExpressions: type_vector as obtained through known_aggregate_expressions_of_t
template <typename KnownAggregateExpressions, typename T>
// @KnownAggregateColumns: type_vector as obtained through known_aggregate_columns_of_t
template <typename KnownAggregateColumns, typename T>
struct is_aggregate_expression
: public std::integral_constant<bool,
is_aggregate_function<T>::value or
KnownAggregateExpressions::template contains<T>::value>
KnownAggregateColumns::template contains<T>::value>
{
};

View File

@ -0,0 +1,46 @@
#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.
*/
#include <sqlpp11/core/detail/type_vector.h>
#include <sqlpp11/core/type_traits/value_type.h>
#include <sqlpp11/core/logic.h>
namespace sqlpp
{
// `group_by` takes columns as parameters.
// If you really, really want to, you can pass something else, but you have to tell the library that you are really certain by wrapping it in `declare_group_by_column`.
template <typename T>
struct is_group_by_column : public std::false_type
{
};
#warning Add tests
} // namespace sqlpp11

View File

@ -0,0 +1,79 @@
#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.
*/
#include <sqlpp11/core/compat/optional.h>
namespace sqlpp
{
template <typename T>
struct is_optional : public std::false_type
{
};
template <typename T>
struct is_optional<::sqlpp::optional<T>> : public std::true_type
{
};
template <>
struct is_optional<::sqlpp::nullopt_t> : public std::true_type
{
};
template <typename T>
struct remove_optional
{
using type = T;
};
template <typename T>
struct remove_optional<::sqlpp::optional<T>>
{
using type = T;
};
template <typename T>
using remove_optional_t = typename remove_optional<T>::type;
template <typename T>
struct force_optional
{
using type = ::sqlpp::optional<T>;
};
template <typename T>
struct force_optional<::sqlpp::optional<T>>
{
using type = ::sqlpp::optional<T>;
};
template <typename T>
using force_optional_t = typename force_optional<T>::type;
}

View File

@ -0,0 +1,237 @@
#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.
*/
#include <cstdint>
#include <sqlpp11/core/chrono.h>
#include <sqlpp11/core/compat/optional.h>
#include <sqlpp11/core/type_traits/optional.h>
namespace sqlpp
{
struct no_value_t;
template <typename T>
struct value_type_of
{
using type = no_value_t;
};
template <typename T>
using value_type_of_t = typename value_type_of<T>::type;
template<typename T>
struct value_type_of<::sqlpp::optional<T>>
{
using type = sqlpp::optional<value_type_of_t<remove_optional_t<T>>>;
};
template <typename T>
struct has_value_type : public std::integral_constant<bool, not std::is_same<value_type_of_t<T>, no_value_t>::value> {};
struct boolean{};
template<>
struct value_type_of<boolean> { using type = boolean; };
template<>
struct value_type_of<bool> { using type = boolean; };
struct integral{};
template<>
struct value_type_of<integral> { using type = integral; };
template<>
struct value_type_of<int8_t> { using type = integral; };
template<>
struct value_type_of<int16_t> { using type = integral; };
template<>
struct value_type_of<int32_t> { using type = integral; };
template<>
struct value_type_of<int64_t> { using type = integral; };
struct unsigned_integral{};
template<>
struct value_type_of<unsigned_integral> { using type = unsigned_integral; };
template<>
struct value_type_of<uint8_t> { using type = unsigned_integral; };
template<>
struct value_type_of<uint16_t> { using type = unsigned_integral; };
template<>
struct value_type_of<uint32_t> { using type = unsigned_integral; };
template<>
struct value_type_of<uint64_t> { using type = unsigned_integral; };
struct floating_point{};
template<>
struct value_type_of<floating_point> { using type = floating_point; };
template<>
struct value_type_of<float> { using type = floating_point; };
template<>
struct value_type_of<double> { using type = floating_point; };
template<>
struct value_type_of<long double> { using type = floating_point; };
struct text{};
template <>
struct value_type_of<text> { using type = text; };
template <>
struct value_type_of<char> { using type = text; };
template <>
struct value_type_of<const char*> { using type = text; };
template <>
struct value_type_of<std::string> { using type = text; };
template <>
struct value_type_of<::sqlpp::string_view> { using type = text; };
struct blob{};
template <>
struct value_type_of<blob> { using type = blob; };
template <std::size_t N>
struct value_type_of<std::array<std::uint8_t, N>> { using type = blob; };
template <>
struct value_type_of<std::vector<std::uint8_t>> { using type = blob; };
template <>
struct value_type_of<::sqlpp::span<std::uint8_t>> { using type = blob; };
struct day_point{};
template <>
struct value_type_of<day_point> { using type = day_point; };
template <>
struct value_type_of<std::chrono::time_point<std::chrono::system_clock, sqlpp::chrono::days>> { using type = day_point; };
struct time_of_day{};
template <>
struct value_type_of<time_of_day> { using type = time_of_day; };
template <typename Rep, typename Period>
struct value_type_of<std::chrono::duration<Rep, Period>> { using type = time_of_day; };
struct time_point{};
template <>
struct value_type_of<time_point> { using type = time_point; };
template <typename Period>
struct value_type_of<std::chrono::time_point<std::chrono::system_clock, Period>> { using type = time_point; };
template <typename T>
struct is_boolean : public std::is_same<remove_optional_t<value_type_of_t<T>>, boolean>
{
};
template <>
struct is_boolean<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_integral : public std::is_same<remove_optional_t<value_type_of_t<T>>, integral>
{
};
template <>
struct is_integral<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_unsigned_integral : public std::is_same<remove_optional_t<value_type_of_t<T>>, unsigned_integral>
{
};
template <>
struct is_unsigned_integral<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_floating_point : public std::is_same<remove_optional_t<value_type_of_t<T>>, floating_point>
{
};
template <>
struct is_floating_point<::sqlpp::nullopt_t> : public std::true_type {
};
// A generic numeric type which could be (unsigned) integral or floating point.
struct numeric{};
template <typename T>
struct is_numeric
: public std::integral_constant<bool,
is_boolean<T>::value or is_integral<T>::value or is_unsigned_integral<T>::value or
is_floating_point<T>::value or
std::is_same<remove_optional_t<value_type_of_t<T>>, numeric>::value>
{
};
template <>
struct is_numeric<::sqlpp::nullopt_t> : public std::true_type{};
template <typename T>
struct is_text : public std::is_same<remove_optional_t<value_type_of_t<T>>, text>
{
};
template <>
struct is_text<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_blob : public std::is_same<remove_optional_t<value_type_of_t<T>>, blob>
{
};
template <>
struct is_blob<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_day_point : public std::is_same<remove_optional_t<value_type_of_t<T>>, day_point>
{
};
template <>
struct is_day_point<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_time_point : public std::is_same<remove_optional_t<value_type_of_t<T>>, time_point>
{
};
template <>
struct is_time_point<::sqlpp::nullopt_t> : public std::true_type {
};
template <typename T>
struct is_day_or_time_point : public std::integral_constant<bool, is_day_point<T>::value or is_time_point<T>::value> {
};
template <typename T>
struct is_time_of_day : public std::is_same<remove_optional_t<value_type_of_t<T>>, time_of_day>
{
};
template <>
struct is_time_of_day<::sqlpp::nullopt_t> : public std::true_type {
};
}

View File

@ -37,4 +37,5 @@ test_compile(value)
add_subdirectory(aggregate_function)
add_subdirectory(operator)
add_subdirectory(clause)
add_subdirectory(type_traits)

View File

@ -0,0 +1,33 @@
# 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(group_by)
test_compile(select_columns)

View File

@ -0,0 +1,68 @@
/*
* 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>
namespace
{
template <typename... T>
auto known_aggregate_columns_as_expected(T... t)
-> std::is_same<sqlpp::known_aggregate_columns_of_t<decltype(group_by(std::move(t)...))>,
sqlpp::detail::type_vector<T...>>;
}
void test_group_by()
{
auto v = sqlpp::value(17);
auto col_int = test::TabFoo{}.id;
auto col_txt = test::TabFoo{}.textNnD;
// Constant values are neutral and therefore considered neither aggregate and non-aggregate.
static_assert(decltype(known_aggregate_columns_as_expected(col_int))::value, "");
static_assert(decltype(known_aggregate_columns_as_expected(col_int, col_txt))::value, "");
// Dynamic columns are listed as dynamic columns in known_aggregate_columns_of_t, since they need to be dynamic in
// select, too, and we need to check that there.
static_assert(decltype(known_aggregate_columns_as_expected(dynamic(true, col_int)))::value, "");
static_assert(decltype(known_aggregate_columns_as_expected(col_int, dynamic(true, col_txt)))::value, "");
// Declared columns are listed as declared columns in known_aggregate_columns_of_t, since they need to be declared in
// select, too, and we need to check that there.
static_assert(decltype(known_aggregate_columns_as_expected(declare_group_by_column(v)))::value, "");
static_assert(decltype(known_aggregate_columns_as_expected(col_int, declare_group_by_column(v)))::value, "");
// Declared columns can be dynamic, too.
static_assert(decltype(known_aggregate_columns_as_expected(dynamic(true, declare_group_by_column(v))))::value, "");
static_assert(decltype(known_aggregate_columns_as_expected(col_int, dynamic(true, declare_group_by_column(v))))::value, "");
#warning: need to test dynamic and declared columns in select, too
}
int main()
{
void test_group_by();
}

View File

@ -0,0 +1,53 @@
/*
* 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>
namespace
{
SQLPP_ALIAS_PROVIDER(cheese);
}
void test_select_columns()
{
auto v = sqlpp::value(17);
auto col_int = test::TabFoo{}.id;
auto col_txt = test::TabFoo{}.textNnD;
select_columns(col_int);
select_columns(dynamic(true, col_int));
select_columns(as(declare_group_by_column(v), cheese));
select_columns(dynamic(true, declare_group_by_column(v)).as(cheese));
#warning: add actual tests here
}
int main()
{
void test_group_by();
}

View File

@ -23,7 +23,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function(test_compile name)
set(target sqlpp11_core_types_operator_${name})
set(target sqlpp11_core_types_type_traits_${name})
add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11::sqlpp11 sqlpp11_testing)
endfunction()