Define functions that return a specific field of each temporal type (#221)
This commit is contained in:
parent
8d87e38c64
commit
d744711e5e
@ -4,6 +4,7 @@
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
@ -247,6 +248,66 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
|
||||
TypedValue Visit(PropertyLookup &property_lookup) override {
|
||||
auto expression_result = property_lookup.expression_->Accept(*this);
|
||||
auto maybe_date = [this](const auto &date, const auto &prop_name) -> std::optional<TypedValue> {
|
||||
if (prop_name == "year") {
|
||||
return TypedValue(date.years, ctx_->memory);
|
||||
}
|
||||
if (prop_name == "month") {
|
||||
return TypedValue(date.months, ctx_->memory);
|
||||
}
|
||||
if (prop_name == "day") {
|
||||
return TypedValue(date.days, ctx_->memory);
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
auto maybe_local_time = [this](const auto <, const auto &prop_name) -> std::optional<TypedValue> {
|
||||
if (prop_name == "hour") {
|
||||
return TypedValue(lt.hours, ctx_->memory);
|
||||
}
|
||||
if (prop_name == "minute") {
|
||||
return TypedValue(lt.minutes, ctx_->memory);
|
||||
}
|
||||
if (prop_name == "seconds") {
|
||||
return TypedValue(lt.seconds, ctx_->memory);
|
||||
}
|
||||
if (prop_name == "milliseconds") {
|
||||
return TypedValue(lt.milliseconds, ctx_->memory);
|
||||
}
|
||||
if (prop_name == "microseconds") {
|
||||
return TypedValue(lt.microseconds, ctx_->memory);
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
auto maybe_duration = [this](const auto &dur, const auto &prop_name) -> std::optional<TypedValue> {
|
||||
if (prop_name == "years") {
|
||||
return TypedValue(dur.Years(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "months") {
|
||||
return TypedValue(dur.Months(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "days") {
|
||||
return TypedValue(dur.SubMonthsAsDays(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "hours") {
|
||||
return TypedValue(dur.SubDaysAsHours(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "minutes") {
|
||||
return TypedValue(dur.SubDaysAsMinutes(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "seconds") {
|
||||
return TypedValue(dur.SubDaysAsSeconds(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "milliseconds") {
|
||||
return TypedValue(dur.SubDaysAsMilliseconds(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "microseconds") {
|
||||
return TypedValue(dur.SubDaysAsMicroseconds(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "nanoseconds") {
|
||||
return TypedValue(dur.SubDaysAsNanoseconds(), ctx_->memory);
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
switch (expression_result.type()) {
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue(ctx_->memory);
|
||||
@ -264,8 +325,43 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
// value and preserve the correct MemoryResource.
|
||||
return std::move(found->second);
|
||||
}
|
||||
case TypedValue::Type::Duration: {
|
||||
const auto &prop_name = property_lookup.property_.name;
|
||||
const auto &dur = expression_result.ValueDuration();
|
||||
if (auto dur_field = maybe_duration(dur, prop_name); dur_field) {
|
||||
return std::move(*dur_field);
|
||||
}
|
||||
throw QueryRuntimeException("Invalid property name {} for Duration", prop_name);
|
||||
}
|
||||
case TypedValue::Type::Date: {
|
||||
const auto &prop_name = property_lookup.property_.name;
|
||||
const auto &date = expression_result.ValueDate();
|
||||
if (auto date_field = maybe_date(date, prop_name); date_field) {
|
||||
return std::move(*date_field);
|
||||
}
|
||||
throw QueryRuntimeException("Invalid property name {} for Date", prop_name);
|
||||
}
|
||||
case TypedValue::Type::LocalTime: {
|
||||
const auto &prop_name = property_lookup.property_.name;
|
||||
const auto < = expression_result.ValueLocalTime();
|
||||
if (auto lt_field = maybe_local_time(lt, prop_name); lt_field) {
|
||||
return std::move(*lt_field);
|
||||
}
|
||||
throw QueryRuntimeException("Invalid property name {} for LocalTime", prop_name);
|
||||
}
|
||||
case TypedValue::Type::LocalDateTime: {
|
||||
const auto &prop_name = property_lookup.property_.name;
|
||||
const auto &ldt = expression_result.ValueLocalDateTime();
|
||||
if (auto date_field = maybe_date(ldt.date, prop_name); date_field) {
|
||||
return std::move(*date_field);
|
||||
}
|
||||
if (auto lt_field = maybe_local_time(ldt.local_time, prop_name); lt_field) {
|
||||
return std::move(*lt_field);
|
||||
}
|
||||
throw QueryRuntimeException("Invalid property named {} for LocalDateTime", prop_name);
|
||||
}
|
||||
default:
|
||||
throw QueryRuntimeException("Only nodes, edges and maps have properties to be looked-up.");
|
||||
throw QueryRuntimeException("Only nodes, edges, maps and temporal types have properties to be looked-up.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -713,6 +713,11 @@ Duration::Duration(const DurationParameters ¶meters) {
|
||||
.count();
|
||||
}
|
||||
|
||||
int64_t Duration::Years() const {
|
||||
std::chrono::microseconds ms(microseconds);
|
||||
return std::chrono::duration_cast<std::chrono::years>(ms).count();
|
||||
}
|
||||
|
||||
int64_t Duration::Months() const {
|
||||
std::chrono::microseconds ms(microseconds);
|
||||
return std::chrono::duration_cast<std::chrono::months>(ms).count();
|
||||
@ -738,6 +743,29 @@ int64_t Duration::SubDaysAsSeconds() const {
|
||||
return chrono::duration_cast<chrono::seconds>(micros - months - days).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsHours() const {
|
||||
namespace chrono = std::chrono;
|
||||
return chrono::duration_cast<chrono::hours>(chrono::seconds(SubDaysAsSeconds())).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsMinutes() const {
|
||||
namespace chrono = std::chrono;
|
||||
return chrono::duration_cast<chrono::minutes>(chrono::seconds(SubDaysAsSeconds())).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsMilliseconds() const {
|
||||
namespace chrono = std::chrono;
|
||||
const auto months = chrono::months(Months());
|
||||
const auto days = chrono::days(SubMonthsAsDays());
|
||||
const auto micros = chrono::microseconds(microseconds);
|
||||
return chrono::duration_cast<chrono::milliseconds>(micros - months - days).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsNanoseconds() const {
|
||||
namespace chrono = std::chrono;
|
||||
return chrono::duration_cast<chrono::nanoseconds>(chrono::microseconds(SubDaysAsMicroseconds())).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsMicroseconds() const {
|
||||
namespace chrono = std::chrono;
|
||||
const auto months = chrono::months(Months());
|
||||
|
@ -63,11 +63,16 @@ struct Duration {
|
||||
|
||||
auto operator<=>(const Duration &) const = default;
|
||||
|
||||
int64_t Years() const;
|
||||
int64_t Months() const;
|
||||
int64_t Days() const;
|
||||
int64_t SubMonthsAsDays() const;
|
||||
int64_t SubDaysAsSeconds() const;
|
||||
int64_t SubDaysAsHours() const;
|
||||
int64_t SubDaysAsMinutes() const;
|
||||
int64_t SubDaysAsMilliseconds() const;
|
||||
int64_t SubDaysAsMicroseconds() const;
|
||||
int64_t SubDaysAsNanoseconds() const;
|
||||
int64_t SubSecondsAsNanoseconds() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Duration &dur) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
@ -980,6 +981,156 @@ TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) {
|
||||
EXPECT_TRUE(Value(prop_height).IsNull());
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, Duration) {
|
||||
const utils::Duration dur({1994, 2, 10, 1, 30, 2, 22, 45});
|
||||
frame[symbol] = TypedValue(dur);
|
||||
const std::pair years = std::make_pair("years", dba.NameToProperty("years"));
|
||||
|
||||
const auto total_years = Value(years);
|
||||
EXPECT_TRUE(total_years.IsInt());
|
||||
EXPECT_EQ(total_years.ValueInt(), 1994);
|
||||
|
||||
const std::pair months = std::make_pair("months", dba.NameToProperty("months"));
|
||||
const auto total_months = Value(months);
|
||||
EXPECT_TRUE(total_months.IsInt());
|
||||
EXPECT_EQ(total_months.ValueInt(), 1994 * 12 + 2);
|
||||
|
||||
const std::pair days = std::make_pair("days", dba.NameToProperty("days"));
|
||||
const auto total_days = Value(days);
|
||||
EXPECT_TRUE(total_days.IsInt());
|
||||
EXPECT_EQ(total_days.ValueInt(), 10);
|
||||
|
||||
const std::pair hours = std::make_pair("hours", dba.NameToProperty("hours"));
|
||||
const auto total_hours = Value(hours);
|
||||
EXPECT_TRUE(total_hours.IsInt());
|
||||
EXPECT_EQ(total_hours.ValueInt(), 1);
|
||||
|
||||
const std::pair mins = std::make_pair("minutes", dba.NameToProperty("minutes"));
|
||||
const auto total_mins = Value(mins);
|
||||
EXPECT_TRUE(total_mins.IsInt());
|
||||
|
||||
EXPECT_EQ(total_mins.ValueInt(), 1 * 60 + 30);
|
||||
|
||||
const std::pair secs = std::make_pair("seconds", dba.NameToProperty("seconds"));
|
||||
const auto total_secs = Value(secs);
|
||||
EXPECT_TRUE(total_secs.IsInt());
|
||||
const auto expected_secs = total_mins.ValueInt() * 60 + 2;
|
||||
EXPECT_EQ(total_secs.ValueInt(), expected_secs);
|
||||
|
||||
const std::pair milli = std::make_pair("milliseconds", dba.NameToProperty("milliseconds"));
|
||||
const auto total_milli = Value(milli);
|
||||
EXPECT_TRUE(total_milli.IsInt());
|
||||
const auto expected_milli = total_secs.ValueInt() * 1000 + 22;
|
||||
EXPECT_EQ(total_milli.ValueInt(), expected_milli);
|
||||
|
||||
const std::pair micro = std::make_pair("microseconds", dba.NameToProperty("microseconds"));
|
||||
const auto total_micros = Value(micro);
|
||||
EXPECT_TRUE(total_micros.IsInt());
|
||||
const auto expected_micros = expected_milli * 1000 + 45;
|
||||
EXPECT_EQ(total_micros.ValueInt(), expected_micros);
|
||||
|
||||
const std::pair nano = std::make_pair("nanoseconds", dba.NameToProperty("nanoseconds"));
|
||||
const auto total_nano = Value(nano);
|
||||
EXPECT_TRUE(total_nano.IsInt());
|
||||
const auto expected_nano = expected_micros * 1000;
|
||||
EXPECT_EQ(total_nano.ValueInt(), expected_nano);
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, Date) {
|
||||
const utils::Date date({1996, 11, 22});
|
||||
frame[symbol] = TypedValue(date);
|
||||
|
||||
const std::pair years = std::make_pair("year", dba.NameToProperty("year"));
|
||||
const auto y = Value(years);
|
||||
EXPECT_TRUE(y.IsInt());
|
||||
EXPECT_EQ(y.ValueInt(), 1996);
|
||||
|
||||
const std::pair months = std::make_pair("month", dba.NameToProperty("month"));
|
||||
const auto m = Value(months);
|
||||
EXPECT_TRUE(m.IsInt());
|
||||
EXPECT_EQ(m.ValueInt(), 11);
|
||||
|
||||
const std::pair days = std::make_pair("day", dba.NameToProperty("day"));
|
||||
const auto d = Value(days);
|
||||
EXPECT_TRUE(d.IsInt());
|
||||
EXPECT_EQ(d.ValueInt(), 22);
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, LocalTime) {
|
||||
const utils::LocalTime lt({1, 2, 3, 11, 22});
|
||||
frame[symbol] = TypedValue(lt);
|
||||
|
||||
const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour"));
|
||||
const auto h = Value(hour);
|
||||
EXPECT_TRUE(h.IsInt());
|
||||
EXPECT_EQ(h.ValueInt(), 1);
|
||||
|
||||
const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute"));
|
||||
const auto min = Value(minute);
|
||||
EXPECT_TRUE(min.IsInt());
|
||||
EXPECT_EQ(min.ValueInt(), 2);
|
||||
|
||||
const std::pair second = std::make_pair("seconds", dba.NameToProperty("seconds"));
|
||||
const auto sec = Value(second);
|
||||
EXPECT_TRUE(sec.IsInt());
|
||||
EXPECT_EQ(sec.ValueInt(), 3);
|
||||
|
||||
const std::pair millis = std::make_pair("milliseconds", dba.NameToProperty("milliseconds"));
|
||||
const auto mil = Value(millis);
|
||||
EXPECT_TRUE(mil.IsInt());
|
||||
EXPECT_EQ(mil.ValueInt(), 11);
|
||||
|
||||
const std::pair micros = std::make_pair("microseconds", dba.NameToProperty("microseconds"));
|
||||
const auto mic = Value(micros);
|
||||
EXPECT_TRUE(mic.IsInt());
|
||||
EXPECT_EQ(mic.ValueInt(), 22);
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, LocalDateTime) {
|
||||
const utils::LocalDateTime ldt({1993, 8, 6}, {2, 3, 4, 55, 40});
|
||||
frame[symbol] = TypedValue(ldt);
|
||||
|
||||
const std::pair years = std::make_pair("year", dba.NameToProperty("year"));
|
||||
const auto y = Value(years);
|
||||
EXPECT_TRUE(y.IsInt());
|
||||
EXPECT_EQ(y.ValueInt(), 1993);
|
||||
|
||||
const std::pair months = std::make_pair("month", dba.NameToProperty("month"));
|
||||
const auto m = Value(months);
|
||||
EXPECT_TRUE(m.IsInt());
|
||||
EXPECT_EQ(m.ValueInt(), 8);
|
||||
|
||||
const std::pair days = std::make_pair("day", dba.NameToProperty("day"));
|
||||
const auto d = Value(days);
|
||||
EXPECT_TRUE(d.IsInt());
|
||||
EXPECT_EQ(d.ValueInt(), 6);
|
||||
|
||||
const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour"));
|
||||
const auto h = Value(hour);
|
||||
EXPECT_TRUE(h.IsInt());
|
||||
EXPECT_EQ(h.ValueInt(), 2);
|
||||
|
||||
const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute"));
|
||||
const auto min = Value(minute);
|
||||
EXPECT_TRUE(min.IsInt());
|
||||
EXPECT_EQ(min.ValueInt(), 3);
|
||||
|
||||
const std::pair second = std::make_pair("seconds", dba.NameToProperty("seconds"));
|
||||
const auto sec = Value(second);
|
||||
EXPECT_TRUE(sec.IsInt());
|
||||
EXPECT_EQ(sec.ValueInt(), 4);
|
||||
|
||||
const std::pair millis = std::make_pair("milliseconds", dba.NameToProperty("milliseconds"));
|
||||
const auto mil = Value(millis);
|
||||
EXPECT_TRUE(mil.IsInt());
|
||||
EXPECT_EQ(mil.ValueInt(), 55);
|
||||
|
||||
const std::pair micros = std::make_pair("microseconds", dba.NameToProperty("microseconds"));
|
||||
const auto mic = Value(micros);
|
||||
EXPECT_TRUE(mic.IsInt());
|
||||
EXPECT_EQ(mic.ValueInt(), 40);
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, Edge) {
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
|
Loading…
Reference in New Issue
Block a user