diff --git a/include/sqlpp11/core/operator/bit_expression.h b/include/sqlpp11/core/operator/bit_expression.h index 7b312958..559af420 100644 --- a/include/sqlpp11/core/operator/bit_expression.h +++ b/include/sqlpp11/core/operator/bit_expression.h @@ -52,10 +52,11 @@ namespace sqlpp template struct value_type_of> - : std::conditional>::value or sqlpp::is_optional>::value, - force_optional_t>, - value_type_of_t> { + using type = typename std::conditional>::value or + sqlpp::is_optional>::value, + ::sqlpp::optional, + integral>::type; }; template @@ -65,7 +66,10 @@ namespace sqlpp }; template - using check_bit_expression_args = ::sqlpp::enable_if_t::value and (is_integral::value or is_unsigned_integral::value)>; + using check_bit_expression_args = ::sqlpp::enable_if_t::value and is_integral::value>; + + template + using check_bit_shift_expression_args = ::sqlpp::enable_if_t::value and (is_integral::value or is_unsigned_integral::value)>; #if 0 template @@ -150,7 +154,7 @@ namespace sqlpp static constexpr auto symbol = " << "; }; - template > + template > constexpr auto operator<<(L l, R r) -> bit_expression { return {std::move(l), std::move(r)}; @@ -161,7 +165,7 @@ namespace sqlpp static constexpr auto symbol = " >> "; }; - template > + template > constexpr auto operator>>(L l, R r) -> bit_expression { return {std::move(l), std::move(r)}; diff --git a/include/sqlpp11/core/operator/case.h b/include/sqlpp11/core/operator/case.h index d4eaccaa..062c7b93 100644 --- a/include/sqlpp11/core/operator/case.h +++ b/include/sqlpp11/core/operator/case.h @@ -56,7 +56,6 @@ namespace sqlpp struct case_t : public enable_as>, public enable_comparison> { using _traits = make_traits, tag::is_expression>; - using _nodes = detail::type_vector; case_t(When when, Then then, Else else_) : _when(when), _then(then), _else(else_) { @@ -74,13 +73,18 @@ namespace sqlpp }; template - struct value_type_of> - { - using type = - typename std::conditional::value or can_be_null::value or can_be_null::value, - force_optional_t>, - value_type_of_t>::type; - }; + struct nodes_of> + { + using type = ::sqlpp::detail::type_vector; + }; + + template + struct value_type_of> + : public std::conditional::value or can_be_null::value or can_be_null::value, + force_optional_t>, + value_type_of_t> + { + }; template class case_then_t diff --git a/tests/core/types/operator/CMakeLists.txt b/tests/core/types/operator/CMakeLists.txt index be038df5..69375f45 100644 --- a/tests/core/types/operator/CMakeLists.txt +++ b/tests/core/types/operator/CMakeLists.txt @@ -38,6 +38,9 @@ test_compile(any) test_compile(arithmetic_expression) test_compile(as_expression) test_compile(assign_expression) +test_compile(between_expression) +test_compile(bit_expression) +test_compile(case_expression) test_compile(comparison_expression) test_compile(in_expression) test_compile(logical_expression) diff --git a/tests/core/types/operator/between_expression.cpp b/tests/core/types/operator/between_expression.cpp new file mode 100644 index 00000000..4291c899 --- /dev/null +++ b/tests/core/types/operator/between_expression.cpp @@ -0,0 +1,112 @@ +/* + * 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 "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + auto db = MockDb{}; + + template + using is_bool = std::is_same, sqlpp::boolean>; + + template + using is_maybe_bool = std::is_same, ::sqlpp::optional>; +} + +template +void test_between_expression(Value v) +{ + auto v_not_null = sqlpp::value(v); + auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v)); + + // Variations of nullable and non-nullable values + static_assert(is_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + static_assert(is_maybe_bool::value, ""); + + // Between expressions have the `as` member function. + static_assert(sqlpp::has_enabled_as::value, ""); + + // Between expressions do not enable comparison member functions. + static_assert(not sqlpp::has_enabled_comparison::value, ""); + + // Between expressions have their arguments as nodes. + using L = typename std::decay::type; + using M = Value; + using R = typename std::decay::type; + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); +} + +int main() +{ + // boolean + test_between_expression(bool{true}); + + // integral + test_between_expression(int8_t{7}); + test_between_expression(int16_t{7}); + test_between_expression(int32_t{7}); + test_between_expression(int64_t{7}); + + // unsigned integral + test_between_expression(uint8_t{7}); + test_between_expression(uint16_t{7}); + test_between_expression(uint32_t{7}); + test_between_expression(uint64_t{7}); + + // floating point + test_between_expression(float{7.7}); + test_between_expression(double{7.7}); + + // text + test_between_expression('7'); + test_between_expression("seven"); + test_between_expression(std::string("seven")); + test_between_expression(::sqlpp::string_view("seven")); + + // blob + test_between_expression(std::vector{}); + + // date + test_between_expression(::sqlpp::chrono::day_point{}); + + // timestamp + test_between_expression(::sqlpp::chrono::microsecond_point{}); + using minute_point = std::chrono::time_point; + test_between_expression(minute_point{}); + + // time_of_day + test_between_expression(std::chrono::microseconds{}); + +} + diff --git a/tests/core/types/operator/bit_expression.cpp b/tests/core/types/operator/bit_expression.cpp new file mode 100644 index 00000000..ecdbfa51 --- /dev/null +++ b/tests/core/types/operator/bit_expression.cpp @@ -0,0 +1,144 @@ +/* + * 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 "MockDb.h" +#include "Sample.h" +#include + +namespace +{ + auto db = MockDb{}; + + template + using is_integral = std::is_same, sqlpp::integral>; + + template + using is_maybe_integral = std::is_same, ::sqlpp::optional>; +} + +template +void test_bit_expression(Value v) +{ + auto v_not_null = sqlpp::value(v); + auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v)); + + // Compare non-nullable with non-nullable. + static_assert(is_integral::value, ""); + static_assert(is_integral> v_not_null)>::value, ""); + static_assert(is_integral::value, ""); + static_assert(is_integral::value, ""); + static_assert(is_integral::value, ""); + + // Compare non-nullable with nullable. + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral> v_maybe_null)>::value, ""); + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + + // Compare nullable with non-nullable. + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral> v_not_null)>::value, ""); + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + + // Compare nullable with nullable. + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral> v_maybe_null)>::value, ""); + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + + // Compare with null. + static_assert(is_integral::value, ""); + static_assert(is_maybe_integral::value, ""); + + // Comparison expressions have the `as` member function. + static_assert(sqlpp::has_enabled_as::value, ""); + static_assert(sqlpp::has_enabled_as::value, ""); + + // Comparison expressions do not enable comparison member functions. + static_assert(not sqlpp::has_enabled_comparison::value, ""); + + // Comparison expressions have their arguments as nodes. + using L = typename std::decay::type; + using R = typename std::decay::type; + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); +} + +template +void test_bit_shift_expression(Left l, Right r) +{ + auto l_not_null = sqlpp::value(l); + auto l_maybe_null = sqlpp::value(::sqlpp::make_optional(l)); + auto r_not_null = sqlpp::value(r); + auto r_maybe_null = sqlpp::value(::sqlpp::make_optional(r)); + + // Compare non-nullable with non-nullable. + static_assert(is_integral::value, ""); + static_assert(is_integral> r_not_null)>::value, ""); + + // Compare non-nullable with nullable. + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral> r_maybe_null)>::value, ""); + + // Compare nullable with non-nullable. + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral> r_not_null)>::value, ""); + + // Compare nullable with nullable. + static_assert(is_maybe_integral::value, ""); + static_assert(is_maybe_integral> r_maybe_null)>::value, ""); + + // Comparison expressions have the `as` member function. + static_assert(sqlpp::has_enabled_as::value, ""); + + // Comparison expressions do not enable comparison member functions. + static_assert(not sqlpp::has_enabled_comparison::value, ""); + + // Comparison expressions have their arguments as nodes. + using L = typename std::decay::type; + using R = typename std::decay::type; + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); +} + + +int main() +{ + // bit expression require integral operands + test_bit_expression(int8_t{7}); + test_bit_expression(int16_t{7}); + test_bit_expression(int32_t{7}); + test_bit_expression(int64_t{7}); + + // bit shift operations can have unsigned rhs operands + test_bit_shift_expression(int8_t{7}, uint8_t{7}); + test_bit_shift_expression(int8_t{7}, uint16_t{7}); + test_bit_shift_expression(int8_t{7}, uint32_t{7}); + test_bit_shift_expression(int8_t{7}, uint64_t{7}); +} + diff --git a/tests/core/types/operator/case_expression.cpp b/tests/core/types/operator/case_expression.cpp new file mode 100644 index 00000000..0687f2c0 --- /dev/null +++ b/tests/core/types/operator/case_expression.cpp @@ -0,0 +1,111 @@ +/* + * 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 + + template + using is_same_type = std::is_same, sqlpp::value_type_of_t>; + +template +void test_case_expression(Value v) +{ + auto c_not_null = sqlpp::value(true); + auto c_maybe_null = sqlpp::value(::sqlpp::make_optional(false)); + + auto v_not_null = sqlpp::value(v); + auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v)); + + using ValueType = sqlpp::value_type_of_t; + using OptValueType = sqlpp::value_type_of_t; + + // Variations of nullable and non-nullable values + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + static_assert(is_same_type::value, ""); + + // Incomplete case expressions have no value. + static_assert(not sqlpp::has_value_type::value, ""); + static_assert(not sqlpp::has_value_type::value, ""); + + // Case expressions have the `as` member function. + static_assert(sqlpp::has_enabled_as::value, ""); + + // Case expressions enable comparison member functions. + static_assert(sqlpp::has_enabled_comparison::value, ""); + + // Between expressions have their arguments as nodes. + using L = typename std::decay::type; + using M = typename std::decay::type; + using R = typename std::decay::type; + static_assert(std::is_same, sqlpp::detail::type_vector>::value, ""); +} + +int main() +{ + // boolean + test_case_expression(bool{true}); + + // integral + test_case_expression(int8_t{7}); + test_case_expression(int16_t{7}); + test_case_expression(int32_t{7}); + test_case_expression(int64_t{7}); + + // unsigned integral + test_case_expression(uint8_t{7}); + test_case_expression(uint16_t{7}); + test_case_expression(uint32_t{7}); + test_case_expression(uint64_t{7}); + + // floating point + test_case_expression(float{7.7}); + test_case_expression(double{7.7}); + + // text + test_case_expression('7'); + test_case_expression("seven"); + test_case_expression(std::string("seven")); + test_case_expression(::sqlpp::string_view("seven")); + + // blob + test_case_expression(std::vector{}); + + // date + test_case_expression(::sqlpp::chrono::day_point{}); + + // timestamp + test_case_expression(::sqlpp::chrono::microsecond_point{}); + using minute_point = std::chrono::time_point; + test_case_expression(minute_point{}); + + // time_of_day + test_case_expression(std::chrono::microseconds{}); +} +