Define functions that return a specific field of each temporal type (#221)

This commit is contained in:
Kostas Kyrimis 2021-09-03 16:48:30 +03:00 committed by Antonio Andelic
parent 8d87e38c64
commit d744711e5e
4 changed files with 281 additions and 1 deletions

View File

@ -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 &lt, 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 &lt = 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.");
}
}

View File

@ -713,6 +713,11 @@ Duration::Duration(const DurationParameters &parameters) {
.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());

View File

@ -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) {

View File

@ -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();