From dd2040efdfbc3c71d337f21db57bd832357a1031 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 23 Jul 2024 18:22:57 +0200 Subject: [PATCH] Added the "unary minus" operator --- dev/column_result.h | 5 ++ dev/core_functions.h | 8 ++++ dev/node_tuple.h | 3 ++ dev/operators.h | 25 +++++++++- dev/statement_serializer.h | 7 ++- include/sqlite_orm/sqlite_orm.h | 48 +++++++++++++++++-- .../arithmetic_operators.cpp | 17 +++++-- tests/static_tests/column_result_t.cpp | 2 + tests/static_tests/node_tuple.cpp | 17 ++++--- tests/static_tests/operators_adl.cpp | 5 ++ 10 files changed, 120 insertions(+), 17 deletions(-) diff --git a/dev/column_result.h b/dev/column_result.h index 6bf9ad7d..725546b3 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -149,6 +149,11 @@ namespace sqlite_orm { using type = std::string; }; + template + struct column_result_t, void> { + using type = double; + }; + template struct column_result_t, void> { using type = double; diff --git a/dev/core_functions.h b/dev/core_functions.h index 3c4136b5..918135ca 100644 --- a/dev/core_functions.h +++ b/dev/core_functions.h @@ -2041,6 +2041,14 @@ namespace sqlite_orm { // Intentionally place operators for types classified as arithmetic or general operator arguments in the internal namespace // to facilitate ADL (Argument Dependent Lookup) namespace internal { + template< + class T, + std::enable_if_t, is_operator_argument>::value, + bool> = true> + constexpr unary_minus_t> operator-(T arg) { + return {get_from_expression(std::forward(arg))}; + } + template, diff --git a/dev/node_tuple.h b/dev/node_tuple.h index d82825af..e551b04b 100644 --- a/dev/node_tuple.h +++ b/dev/node_tuple.h @@ -199,6 +199,9 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; + template + struct node_tuple, void> : node_tuple {}; + template struct node_tuple, void> : node_tuple {}; diff --git a/dev/operators.h b/dev/operators.h index 85d0e349..d656a0ec 100644 --- a/dev/operators.h +++ b/dev/operators.h @@ -41,6 +41,24 @@ namespace sqlite_orm { template using conc_t = binary_operator; + struct unary_minus_string { + serialize_result_type serialize() const { + return "-"; + } + }; + + /** + * Result of unary minus - operator + */ + template + struct unary_minus_t : unary_minus_string, arithmetic_t, negatable_t { + using argument_type = T; + + argument_type argument; + + unary_minus_t(argument_type argument_) : argument(std::move(argument_)) {} + }; + struct add_string { serialize_result_type serialize() const { return "+"; @@ -60,7 +78,7 @@ namespace sqlite_orm { }; /** - * Result of substitute - operator + * Result of substraction - operator */ template using sub_t = binary_operator; @@ -201,6 +219,11 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } + template + constexpr internal::unary_minus_t minus(T t) { + return {std::move(t)}; + } + /** * Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users */ diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 60cf5586..c616d906 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -718,8 +718,11 @@ namespace sqlite_orm { }; template - struct statement_serializer, void> { - using statement_type = bitwise_not_t; + struct statement_serializer< + T, + std::enable_if_t, + polyfill::is_specialization_of>::value>> { + using statement_type = T; template std::string operator()(const statement_type& expression, const Ctx& context) const { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ff4507de..dc32f84f 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -4168,6 +4168,24 @@ namespace sqlite_orm { template using conc_t = binary_operator; + struct unary_minus_string { + serialize_result_type serialize() const { + return "-"; + } + }; + + /** + * Result of unary minus - operator + */ + template + struct unary_minus_t : unary_minus_string, arithmetic_t, negatable_t { + using argument_type = T; + + argument_type argument; + + unary_minus_t(argument_type argument_) : argument(std::move(argument_)) {} + }; + struct add_string { serialize_result_type serialize() const { return "+"; @@ -4187,7 +4205,7 @@ namespace sqlite_orm { }; /** - * Result of substitute - operator + * Result of substraction - operator */ template using sub_t = binary_operator; @@ -4328,6 +4346,11 @@ namespace sqlite_orm { return {std::move(l), std::move(r)}; } + template + constexpr internal::unary_minus_t minus(T t) { + return {std::move(t)}; + } + /** * Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users */ @@ -8091,6 +8114,14 @@ namespace sqlite_orm { // Intentionally place operators for types classified as arithmetic or general operator arguments in the internal namespace // to facilitate ADL (Argument Dependent Lookup) namespace internal { + template< + class T, + std::enable_if_t, is_operator_argument>::value, + bool> = true> + constexpr unary_minus_t> operator-(T arg) { + return {get_from_expression(std::forward(arg))}; + } + template, @@ -11474,6 +11505,11 @@ namespace sqlite_orm { using type = std::string; }; + template + struct column_result_t, void> { + using type = double; + }; + template struct column_result_t, void> { using type = double; @@ -19941,8 +19977,11 @@ namespace sqlite_orm { }; template - struct statement_serializer, void> { - using statement_type = bitwise_not_t; + struct statement_serializer< + T, + std::enable_if_t, + polyfill::is_specialization_of>::value>> { + using statement_type = T; template std::string operator()(const statement_type& expression, const Ctx& context) const { @@ -24287,6 +24326,9 @@ namespace sqlite_orm { template struct node_tuple, void> : node_tuple {}; + template + struct node_tuple, void> : node_tuple {}; + template struct node_tuple, void> : node_tuple {}; diff --git a/tests/statement_serializer_tests/arithmetic_operators.cpp b/tests/statement_serializer_tests/arithmetic_operators.cpp index 764b062b..842f9ec2 100644 --- a/tests/statement_serializer_tests/arithmetic_operators.cpp +++ b/tests/statement_serializer_tests/arithmetic_operators.cpp @@ -8,6 +8,15 @@ TEST_CASE("statement_serializer arithmetic operators") { internal::serializer_context> context{storage}; std::string value; decltype(value) expected; + SECTION("unary minus") { + SECTION("func") { + value = serialize(minus(20), context); + } + SECTION("operator") { + value = serialize(-c(20), context); + } + expected = "-20"; + } SECTION("add") { SECTION("func") { value = serialize(add(3, 5), context); @@ -55,12 +64,12 @@ TEST_CASE("statement_serializer arithmetic operators") { } SECTION("parentheses keeping order of precedence") { SECTION("1") { - value = serialize(c(4) + 5 + 3, context); - expected = "(4 + 5) + 3"; + value = serialize(c(4) + 5 + -c(3), context); + expected = "(4 + 5) + -3"; } SECTION("2") { - value = serialize(4 + (c(5) + 3), context); - expected = "4 + (5 + 3)"; + value = serialize(4 + -(c(5) + 3), context); + expected = "4 + -(5 + 3)"; } SECTION("3") { value = serialize(4 + c(5) * 3 + 1, context); diff --git a/tests/static_tests/column_result_t.cpp b/tests/static_tests/column_result_t.cpp index 25b19491..cbfef385 100644 --- a/tests/static_tests/column_result_t.cpp +++ b/tests/static_tests/column_result_t.cpp @@ -95,6 +95,8 @@ TEST_CASE("column_result_of_t") { runTest(all(&User::name)); runTest(conc(&User::name, &User::id)); runTest(c(&User::name) || &User::id); + runTest(minus(&User::id)); + runTest(-c(&User::id)); runTest(add(&User::id, 5)); runTest(c(&User::id) + 5); runTest(sub(&User::id, 5)); diff --git a/tests/static_tests/node_tuple.cpp b/tests/static_tests/node_tuple.cpp index 9f10491d..4a9a07bc 100644 --- a/tests/static_tests/node_tuple.cpp +++ b/tests/static_tests/node_tuple.cpp @@ -189,25 +189,28 @@ TEST_CASE("Node tuple") { using namespace internal; using CondTuple = node_tuple_t>; - static_assert(is_same>::value, "conc_t"); + STATIC_REQUIRE(is_same>::value); + + using MinusTuple = node_tuple_t>; + STATIC_REQUIRE(is_same>::value); using AddTuple = node_tuple_t>; - static_assert(is_same>::value, "add_t"); + STATIC_REQUIRE(is_same>::value); using SubTuple = node_tuple_t>; - static_assert(is_same>::value, "sub_t"); + STATIC_REQUIRE(is_same>::value); using MulTuple = node_tuple_t>; - static_assert(is_same>::value, "mul_t"); + STATIC_REQUIRE(is_same>::value); using DivTuple = node_tuple_t>; - static_assert(is_same>::value, "div_t"); + STATIC_REQUIRE(is_same>::value); using ModTuple = node_tuple_t>; - static_assert(is_same>::value, "mod_t"); + STATIC_REQUIRE(is_same>::value); using AssignTuple = node_tuple_t>; - static_assert(is_same>::value, "assign_t"); + STATIC_REQUIRE(is_same>::value); } SECTION("bitwise operator") { using namespace internal; diff --git a/tests/static_tests/operators_adl.cpp b/tests/static_tests/operators_adl.cpp index cdfdb63c..111358ab 100644 --- a/tests/static_tests/operators_adl.cpp +++ b/tests/static_tests/operators_adl.cpp @@ -28,6 +28,7 @@ using sqlite_orm::internal::less_or_equal_t; using sqlite_orm::internal::less_than_t; using sqlite_orm::internal::negated_condition_t; using sqlite_orm::internal::or_condition_t; +using sqlite_orm::internal::unary_minus_t; using sqlite_orm::polyfill::is_specialization_of_v; template @@ -68,6 +69,10 @@ void runTests(E expression) { STATIC_REQUIRE(is_specialization_of_v); STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); + STATIC_REQUIRE(is_specialization_of_v); STATIC_REQUIRE(is_specialization_of_v); STATIC_REQUIRE(is_specialization_of_v);