Skip to content

Commit

Permalink
Added the "unary minus" operator
Browse files Browse the repository at this point in the history
  • Loading branch information
trueqbit committed Jul 23, 2024
1 parent 766861e commit dd2040e
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 17 deletions.
5 changes: 5 additions & 0 deletions dev/column_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ namespace sqlite_orm {
using type = std::string;
};

template<class DBOs, class T>
struct column_result_t<DBOs, unary_minus_t<T>, void> {
using type = double;
};

template<class DBOs, class L, class R>
struct column_result_t<DBOs, add_t<L, R>, void> {
using type = double;
Expand Down
8 changes: 8 additions & 0 deletions dev/core_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<polyfill::disjunction<std::is_base_of<arithmetic_t, T>, is_operator_argument<T>>::value,
bool> = true>
constexpr unary_minus_t<unwrap_expression_t<T>> operator-(T arg) {
return {get_from_expression(std::forward<T>(arg))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
Expand Down
3 changes: 3 additions & 0 deletions dev/node_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ namespace sqlite_orm {
template<class C>
struct node_tuple<negated_condition_t<C>, void> : node_tuple<C> {};

template<class T>
struct node_tuple<unary_minus_t<T>, void> : node_tuple<T> {};

template<class T>
struct node_tuple<bitwise_not_t<T>, void> : node_tuple<T> {};

Expand Down
25 changes: 24 additions & 1 deletion dev/operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ namespace sqlite_orm {
template<class L, class R>
using conc_t = binary_operator<L, R, conc_string>;

struct unary_minus_string {
serialize_result_type serialize() const {
return "-";
}
};

/**
* Result of unary minus - operator
*/
template<class T>
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 "+";
Expand All @@ -60,7 +78,7 @@ namespace sqlite_orm {
};

/**
* Result of substitute - operator
* Result of substraction - operator
*/
template<class L, class R>
using sub_t = binary_operator<L, R, sub_string, arithmetic_t, negatable_t>;
Expand Down Expand Up @@ -201,6 +219,11 @@ namespace sqlite_orm {
return {std::move(l), std::move(r)};
}

template<class T>
constexpr internal::unary_minus_t<T> minus(T t) {
return {std::move(t)};
}

/**
* Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users
*/
Expand Down
7 changes: 5 additions & 2 deletions dev/statement_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,11 @@ namespace sqlite_orm {
};

template<class T>
struct statement_serializer<bitwise_not_t<T>, void> {
using statement_type = bitwise_not_t<T>;
struct statement_serializer<
T,
std::enable_if_t<polyfill::disjunction<polyfill::is_specialization_of<T, unary_minus_t>,
polyfill::is_specialization_of<T, bitwise_not_t>>::value>> {
using statement_type = T;

template<class Ctx>
std::string operator()(const statement_type& expression, const Ctx& context) const {
Expand Down
48 changes: 45 additions & 3 deletions include/sqlite_orm/sqlite_orm.h
Original file line number Diff line number Diff line change
Expand Up @@ -4168,6 +4168,24 @@ namespace sqlite_orm {
template<class L, class R>
using conc_t = binary_operator<L, R, conc_string>;

struct unary_minus_string {
serialize_result_type serialize() const {
return "-";
}
};

/**
* Result of unary minus - operator
*/
template<class T>
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 "+";
Expand All @@ -4187,7 +4205,7 @@ namespace sqlite_orm {
};

/**
* Result of substitute - operator
* Result of substraction - operator
*/
template<class L, class R>
using sub_t = binary_operator<L, R, sub_string, arithmetic_t, negatable_t>;
Expand Down Expand Up @@ -4328,6 +4346,11 @@ namespace sqlite_orm {
return {std::move(l), std::move(r)};
}

template<class T>
constexpr internal::unary_minus_t<T> minus(T t) {
return {std::move(t)};
}

/**
* Public interface for + operator. Example: `select(add(&User::age, 100));` => SELECT age + 100 FROM users
*/
Expand Down Expand Up @@ -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<polyfill::disjunction<std::is_base_of<arithmetic_t, T>, is_operator_argument<T>>::value,
bool> = true>
constexpr unary_minus_t<unwrap_expression_t<T>> operator-(T arg) {
return {get_from_expression(std::forward<T>(arg))};
}

template<class L,
class R,
std::enable_if_t<polyfill::disjunction<std::is_base_of<arithmetic_t, L>,
Expand Down Expand Up @@ -11474,6 +11505,11 @@ namespace sqlite_orm {
using type = std::string;
};

template<class DBOs, class T>
struct column_result_t<DBOs, unary_minus_t<T>, void> {
using type = double;
};

template<class DBOs, class L, class R>
struct column_result_t<DBOs, add_t<L, R>, void> {
using type = double;
Expand Down Expand Up @@ -19941,8 +19977,11 @@ namespace sqlite_orm {
};

template<class T>
struct statement_serializer<bitwise_not_t<T>, void> {
using statement_type = bitwise_not_t<T>;
struct statement_serializer<
T,
std::enable_if_t<polyfill::disjunction<polyfill::is_specialization_of<T, unary_minus_t>,
polyfill::is_specialization_of<T, bitwise_not_t>>::value>> {
using statement_type = T;

template<class Ctx>
std::string operator()(const statement_type& expression, const Ctx& context) const {
Expand Down Expand Up @@ -24287,6 +24326,9 @@ namespace sqlite_orm {
template<class C>
struct node_tuple<negated_condition_t<C>, void> : node_tuple<C> {};

template<class T>
struct node_tuple<unary_minus_t<T>, void> : node_tuple<T> {};

template<class T>
struct node_tuple<bitwise_not_t<T>, void> : node_tuple<T> {};

Expand Down
17 changes: 13 additions & 4 deletions tests/statement_serializer_tests/arithmetic_operators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ TEST_CASE("statement_serializer arithmetic operators") {
internal::serializer_context<internal::db_objects_tuple<>> 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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions tests/static_tests/column_result_t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ TEST_CASE("column_result_of_t") {
runTest<db_objects_t, std::string>(all(&User::name));
runTest<db_objects_t, std::string>(conc(&User::name, &User::id));
runTest<db_objects_t, std::string>(c(&User::name) || &User::id);
runTest<db_objects_t, double>(minus(&User::id));
runTest<db_objects_t, double>(-c(&User::id));
runTest<db_objects_t, double>(add(&User::id, 5));
runTest<db_objects_t, double>(c(&User::id) + 5);
runTest<db_objects_t, double>(sub(&User::id, 5));
Expand Down
17 changes: 10 additions & 7 deletions tests/static_tests/node_tuple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,25 +189,28 @@ TEST_CASE("Node tuple") {
using namespace internal;

using CondTuple = node_tuple_t<conc_t<std::string, decltype(&User::name)>>;
static_assert(is_same<CondTuple, tuple<std::string, decltype(&User::name)>>::value, "conc_t");
STATIC_REQUIRE(is_same<CondTuple, tuple<std::string, decltype(&User::name)>>::value);

using MinusTuple = node_tuple_t<unary_minus_t<decltype(&User::id)>>;
STATIC_REQUIRE(is_same<MinusTuple, tuple<decltype(&User::id)>>::value);

using AddTuple = node_tuple_t<add_t<int, decltype(&User::id)>>;
static_assert(is_same<AddTuple, tuple<int, decltype(&User::id)>>::value, "add_t");
STATIC_REQUIRE(is_same<AddTuple, tuple<int, decltype(&User::id)>>::value);

using SubTuple = node_tuple_t<sub_t<float, double>>;
static_assert(is_same<SubTuple, tuple<float, double>>::value, "sub_t");
STATIC_REQUIRE(is_same<SubTuple, tuple<float, double>>::value);

using MulTuple = node_tuple_t<mul_t<double, decltype(&User::id)>>;
static_assert(is_same<MulTuple, tuple<double, decltype(&User::id)>>::value, "mul_t");
STATIC_REQUIRE(is_same<MulTuple, tuple<double, decltype(&User::id)>>::value);

using DivTuple = node_tuple_t<sqlite_orm::internal::div_t<int, float>>;
static_assert(is_same<DivTuple, tuple<int, float>>::value, "div_t");
STATIC_REQUIRE(is_same<DivTuple, tuple<int, float>>::value);

using ModTuple = node_tuple_t<mod_t<decltype(&User::id), int>>;
static_assert(is_same<ModTuple, tuple<decltype(&User::id), int>>::value, "mod_t");
STATIC_REQUIRE(is_same<ModTuple, tuple<decltype(&User::id), int>>::value);

using AssignTuple = node_tuple_t<assign_t<decltype(&User::name), std::string>>;
static_assert(is_same<AssignTuple, tuple<decltype(&User::name), std::string>>::value, "assign_t");
STATIC_REQUIRE(is_same<AssignTuple, tuple<decltype(&User::name), std::string>>::value);
}
SECTION("bitwise operator") {
using namespace internal;
Expand Down
5 changes: 5 additions & 0 deletions tests/static_tests/operators_adl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<class E>
Expand Down Expand Up @@ -68,6 +69,10 @@ void runTests(E expression) {
STATIC_REQUIRE(is_specialization_of_v<decltype(42 || (expression || 42)), binary_operator>);
STATIC_REQUIRE(is_specialization_of_v<decltype(c(42) || (expression || 42)), binary_operator>);

STATIC_REQUIRE(is_specialization_of_v<decltype(-expression), unary_minus_t>);
STATIC_REQUIRE(is_specialization_of_v<decltype(-(expression + expression)), unary_minus_t>);
STATIC_REQUIRE(is_specialization_of_v<decltype(-expression + expression), binary_operator>);

STATIC_REQUIRE(is_specialization_of_v<decltype(expression + 42), binary_operator>);
STATIC_REQUIRE(is_specialization_of_v<decltype(42 + expression), binary_operator>);
STATIC_REQUIRE(is_specialization_of_v<decltype(expression + expression), binary_operator>);
Expand Down

0 comments on commit dd2040e

Please sign in to comment.