Add temporal type arithmetic for queries (#214)
This commit is contained in:
parent
086fc47769
commit
8d87e38c64
@ -843,11 +843,71 @@ inline void EnsureArithmeticallyOk(const TypedValue &a, const TypedValue &b, boo
|
||||
// checked here because they are handled before this check is performed in
|
||||
// arithmetic op implementations.
|
||||
|
||||
// TODO(antonio2368): Introduce typed value arithmetic
|
||||
if (!is_legal(a) || !is_legal(b))
|
||||
throw TypedValueException("Invalid {} operand types {}, {}", op_name, a.type(), b.type());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<TypedValue> MaybeDoTemporalTypeAddition(const TypedValue &a, const TypedValue &b) {
|
||||
// Duration
|
||||
if (a.IsDuration() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueDuration() + b.ValueDuration());
|
||||
}
|
||||
// Date
|
||||
if (a.IsDate() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueDate() + b.ValueDuration());
|
||||
}
|
||||
if (a.IsDuration() && b.IsDate()) {
|
||||
return TypedValue(a.ValueDuration() + b.ValueDate());
|
||||
}
|
||||
// LocalTime
|
||||
if (a.IsLocalTime() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueLocalTime() + b.ValueDuration());
|
||||
}
|
||||
if (a.IsDuration() && b.IsLocalTime()) {
|
||||
return TypedValue(a.ValueDuration() + b.ValueLocalTime());
|
||||
}
|
||||
// LocalDateTime
|
||||
if (a.IsLocalDateTime() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueLocalDateTime() + b.ValueDuration());
|
||||
}
|
||||
if (a.IsDuration() && b.IsLocalDateTime()) {
|
||||
return TypedValue(a.ValueDuration() + b.ValueLocalDateTime());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypedValue> MaybeDoTemporalTypeSubtraction(const TypedValue &a, const TypedValue &b) {
|
||||
// Duration
|
||||
if (a.IsDuration() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueDuration() - b.ValueDuration());
|
||||
}
|
||||
// Date
|
||||
if (a.IsDate() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueDate() - b.ValueDuration());
|
||||
}
|
||||
if (a.IsDate() && b.IsDate()) {
|
||||
return TypedValue(a.ValueDate() - b.ValueDate());
|
||||
}
|
||||
// LocalTime
|
||||
if (a.IsLocalTime() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueLocalTime() - b.ValueDuration());
|
||||
}
|
||||
if (a.IsLocalTime() && b.IsLocalTime()) {
|
||||
return TypedValue(a.ValueLocalTime() - b.ValueLocalTime());
|
||||
}
|
||||
// LocalDateTime
|
||||
if (a.IsLocalDateTime() && b.IsDuration()) {
|
||||
return TypedValue(a.ValueLocalDateTime() - b.ValueDuration());
|
||||
}
|
||||
if (a.IsLocalDateTime() && b.IsLocalDateTime()) {
|
||||
return TypedValue(a.ValueLocalDateTime() - b.ValueLocalDateTime());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TypedValue operator+(const TypedValue &a, const TypedValue &b) {
|
||||
if (a.IsNull() || b.IsNull()) return TypedValue(a.GetMemoryResource());
|
||||
|
||||
@ -866,6 +926,10 @@ TypedValue operator+(const TypedValue &a, const TypedValue &b) {
|
||||
return TypedValue(std::move(list), a.GetMemoryResource());
|
||||
}
|
||||
|
||||
if (const auto maybe_add = MaybeDoTemporalTypeAddition(a, b); maybe_add) {
|
||||
return *maybe_add;
|
||||
}
|
||||
|
||||
EnsureArithmeticallyOk(a, b, true, "addition");
|
||||
// no more Bool nor Null, summing works on anything from here onward
|
||||
|
||||
@ -874,23 +938,21 @@ TypedValue operator+(const TypedValue &a, const TypedValue &b) {
|
||||
// at this point we only have int and double
|
||||
if (a.IsDouble() || b.IsDouble()) {
|
||||
return TypedValue(ToDouble(a) + ToDouble(b), a.GetMemoryResource());
|
||||
} else {
|
||||
return TypedValue(a.ValueInt() + b.ValueInt(), a.GetMemoryResource());
|
||||
}
|
||||
// TODO(antonio2368): Introduce typed value arithmetic
|
||||
return TypedValue(a.ValueInt() + b.ValueInt(), a.GetMemoryResource());
|
||||
}
|
||||
|
||||
TypedValue operator-(const TypedValue &a, const TypedValue &b) {
|
||||
if (a.IsNull() || b.IsNull()) return TypedValue(a.GetMemoryResource());
|
||||
EnsureArithmeticallyOk(a, b, false, "subtraction");
|
||||
|
||||
if (const auto maybe_sub = MaybeDoTemporalTypeSubtraction(a, b); maybe_sub) {
|
||||
return *maybe_sub;
|
||||
}
|
||||
EnsureArithmeticallyOk(a, b, true, "subraction");
|
||||
// at this point we only have int and double
|
||||
if (a.IsDouble() || b.IsDouble()) {
|
||||
return TypedValue(ToDouble(a) - ToDouble(b), a.GetMemoryResource());
|
||||
} else {
|
||||
return TypedValue(a.ValueInt() - b.ValueInt(), a.GetMemoryResource());
|
||||
}
|
||||
// TODO(antonio2368): Introduce typed value arithmetic
|
||||
return TypedValue(a.ValueInt() - b.ValueInt(), a.GetMemoryResource());
|
||||
}
|
||||
|
||||
TypedValue operator/(const TypedValue &a, const TypedValue &b) {
|
||||
|
@ -292,6 +292,22 @@ TEST_F(TypedValueArithmeticTest, Sum) {
|
||||
EXPECT_PROP_EQ(TypedValue(2) + TypedValue(in), TypedValue(out1));
|
||||
EXPECT_PROP_EQ(TypedValue(in) + TypedValue(2), TypedValue(out2));
|
||||
EXPECT_PROP_EQ(TypedValue(in) + TypedValue(in), TypedValue(out3));
|
||||
|
||||
// Temporal Types
|
||||
// Duration
|
||||
EXPECT_NO_THROW(TypedValue(utils::Duration(1)) + TypedValue(utils::Duration(1)));
|
||||
// Date
|
||||
EXPECT_NO_THROW(TypedValue(utils::Date(1)) + TypedValue(utils::Duration(1)));
|
||||
EXPECT_NO_THROW(TypedValue(utils::Duration(1)) + TypedValue(utils::Date(1)));
|
||||
EXPECT_THROW(TypedValue(utils::Date(1)) + TypedValue(utils::Date(1)), TypedValueException);
|
||||
// LocalTime
|
||||
EXPECT_NO_THROW(TypedValue(utils::LocalTime(1)) + TypedValue(utils::Duration(1)));
|
||||
EXPECT_NO_THROW(TypedValue(utils::Duration(1)) + TypedValue(utils::LocalTime(1)));
|
||||
EXPECT_THROW(TypedValue(utils::LocalTime(1)) + TypedValue(utils::LocalTime(1)), TypedValueException);
|
||||
// LocalDateTime
|
||||
EXPECT_NO_THROW(TypedValue(utils::LocalDateTime(1)) + TypedValue(utils::Duration(1)));
|
||||
EXPECT_NO_THROW(TypedValue(utils::Duration(1)) + TypedValue(utils::LocalDateTime(1)));
|
||||
EXPECT_THROW(TypedValue(utils::LocalDateTime(1)) + TypedValue(utils::LocalDateTime(1)), TypedValueException);
|
||||
}
|
||||
|
||||
TEST_F(TypedValueArithmeticTest, Difference) {
|
||||
@ -304,8 +320,25 @@ TEST_F(TypedValueArithmeticTest, Difference) {
|
||||
// implicit casting
|
||||
EXPECT_FLOAT_EQ((TypedValue(2) - TypedValue(0.5)).ValueDouble(), 1.5);
|
||||
EXPECT_FLOAT_EQ((TypedValue(2.5) - TypedValue(2)).ValueDouble(), 0.5);
|
||||
// Temporal Types
|
||||
// Duration
|
||||
EXPECT_NO_THROW(TypedValue(utils::Duration(1)) - TypedValue(utils::Duration(1)));
|
||||
// Date
|
||||
EXPECT_NO_THROW(TypedValue(utils::Date(1)) - TypedValue(utils::Duration(1)));
|
||||
EXPECT_NO_THROW(TypedValue(utils::Date(1)) - TypedValue(utils::Date(1)));
|
||||
EXPECT_THROW(TypedValue(utils::Duration(1)) - TypedValue(utils::Date(1)), TypedValueException);
|
||||
// LocalTime
|
||||
EXPECT_NO_THROW(TypedValue(utils::LocalTime(1)) - TypedValue(utils::Duration(1)));
|
||||
EXPECT_NO_THROW(TypedValue(utils::LocalTime(1)) - TypedValue(utils::LocalTime(1)));
|
||||
EXPECT_THROW(TypedValue(utils::Duration(1)) - TypedValue(utils::LocalTime(1)), TypedValueException);
|
||||
// LocalDateTime
|
||||
EXPECT_NO_THROW(TypedValue(utils::LocalDateTime(1)) - TypedValue(utils::Duration(1)));
|
||||
EXPECT_NO_THROW(TypedValue(utils::LocalDateTime(1)) - TypedValue(utils::LocalDateTime(1)));
|
||||
EXPECT_THROW(TypedValue(utils::Duration(1)) - TypedValue(utils::LocalDateTime(1)), TypedValueException);
|
||||
}
|
||||
|
||||
TEST_F(TypedValueArithmeticTest, Negate) { EXPECT_NO_THROW(-TypedValue(utils::Duration(1))); }
|
||||
|
||||
TEST_F(TypedValueArithmeticTest, Divison) {
|
||||
ExpectArithmeticThrowsAndNull(false, [](const TypedValue &a, const TypedValue &b) { return a / b; });
|
||||
EXPECT_THROW(TypedValue(1) / TypedValue(0), TypedValueException);
|
||||
|
Loading…
Reference in New Issue
Block a user