Remove support for iso duration and fix bolt (#235)
This commit is contained in:
parent
da68f86fc9
commit
8ea281649a
@ -192,8 +192,11 @@ class BaseEncoder {
|
||||
void WriteDuration(const utils::Duration &duration) {
|
||||
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct4));
|
||||
WriteRAW(utils::UnderlyingCast(Signature::Duration));
|
||||
WriteInt(duration.Months());
|
||||
WriteInt(duration.SubMonthsAsDays());
|
||||
// This shall always be zero because internally we store microseconds
|
||||
// and converting months to microseconds is an approximation. However,
|
||||
// for the encoder, we implement ReadInt() to support the neo4j driver.
|
||||
WriteInt(0);
|
||||
WriteInt(duration.Days());
|
||||
WriteInt(duration.SubDaysAsSeconds());
|
||||
WriteInt(duration.SubSecondsAsNanoseconds());
|
||||
}
|
||||
|
@ -61,22 +61,22 @@ void DumpPreciseDouble(std::ostream *os, double value) {
|
||||
namespace {
|
||||
void DumpDate(std::ostream &os, const storage::TemporalData &value) {
|
||||
utils::Date date(value.microseconds);
|
||||
os << fmt::format("DATE(\"{}\")", date);
|
||||
os << "DATE(\"" << date << "\")";
|
||||
}
|
||||
|
||||
void DumpLocalTime(std::ostream &os, const storage::TemporalData &value) {
|
||||
utils::LocalTime lt(value.microseconds);
|
||||
os << fmt::format("LOCALTIME(\"{}\")", lt);
|
||||
os << "LOCALTIME(\"" << lt << "\")";
|
||||
}
|
||||
|
||||
void DumpLocalDateTime(std::ostream &os, const storage::TemporalData &value) {
|
||||
utils::LocalDateTime ldt(value.microseconds);
|
||||
os << fmt::format("LOCALDATETIME(\"{}\")", ldt);
|
||||
os << "LOCALDATETIME(\"" << ldt << "\")";
|
||||
}
|
||||
|
||||
void DumpDuration(std::ostream &os, const storage::TemporalData &value) {
|
||||
utils::Duration dur(value.microseconds);
|
||||
os << fmt::format("DURATION(\"{}\")", dur);
|
||||
os << "DURATION(\"" << dur << "\")";
|
||||
}
|
||||
|
||||
void DumpTemporalData(std::ostream &os, const storage::TemporalData &value) {
|
||||
|
@ -1154,9 +1154,7 @@ TypedValue Duration(const TypedValue *args, int64_t nargs, const FunctionContext
|
||||
|
||||
utils::DurationParameters duration_parameters;
|
||||
using namespace std::literals;
|
||||
std::unordered_map parameter_mappings{std::pair{"year"sv, &duration_parameters.years},
|
||||
std::pair{"month"sv, &duration_parameters.months},
|
||||
std::pair{"day"sv, &duration_parameters.days},
|
||||
std::unordered_map parameter_mappings{std::pair{"day"sv, &duration_parameters.days},
|
||||
std::pair{"hour"sv, &duration_parameters.hours},
|
||||
std::pair{"minute"sv, &duration_parameters.minutes},
|
||||
std::pair{"second"sv, &duration_parameters.seconds},
|
||||
|
@ -279,14 +279,8 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
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);
|
||||
return TypedValue(dur.Days(), ctx_->memory);
|
||||
}
|
||||
if (prop_name == "hours") {
|
||||
return TypedValue(dur.SubDaysAsHours(), ctx_->memory);
|
||||
|
@ -503,7 +503,7 @@ size_t LocalDateTimeHash::operator()(const LocalDateTime &local_date_time) const
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::optional<DurationParameters> TryParseIsoDurationString(std::string_view string) {
|
||||
std::optional<DurationParameters> TryParseDurationString(std::string_view string) {
|
||||
DurationParameters duration_parameters;
|
||||
|
||||
if (string.empty()) {
|
||||
@ -554,26 +554,7 @@ std::optional<DurationParameters> TryParseIsoDurationString(std::string_view str
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto parse_duration_date_part = [&](auto date_string) {
|
||||
if (!std::isdigit(date_string.front())) {
|
||||
return false;
|
||||
throw utils::BasicException("Invalid format of duration string");
|
||||
}
|
||||
|
||||
if (!parse_and_assign(date_string, 'Y', duration_parameters.years)) {
|
||||
return false;
|
||||
}
|
||||
if (date_string.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!parse_and_assign(date_string, 'M', duration_parameters.months)) {
|
||||
return false;
|
||||
}
|
||||
if (date_string.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto parse_duration_days_part = [&](auto date_string) {
|
||||
if (!parse_and_assign(date_string, 'D', duration_parameters.days)) {
|
||||
return false;
|
||||
}
|
||||
@ -582,10 +563,6 @@ std::optional<DurationParameters> TryParseIsoDurationString(std::string_view str
|
||||
};
|
||||
|
||||
const auto parse_duration_time_part = [&](auto time_string) {
|
||||
if (!std::isdigit(time_string.front())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_and_assign(time_string, 'H', duration_parameters.hours)) {
|
||||
return false;
|
||||
}
|
||||
@ -610,7 +587,7 @@ std::optional<DurationParameters> TryParseIsoDurationString(std::string_view str
|
||||
auto t_position = string.find('T');
|
||||
|
||||
const auto date_string = string.substr(0, t_position);
|
||||
if (!date_string.empty() && !parse_duration_date_part(date_string)) {
|
||||
if (!date_string.empty() && !parse_duration_days_part(date_string)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@ -631,15 +608,11 @@ std::optional<DurationParameters> TryParseIsoDurationString(std::string_view str
|
||||
const auto kSupportedDurationFormatsHelpMessage = fmt::format(R"help(
|
||||
"String representing duration should be in the following format:
|
||||
|
||||
P[nY][nM][nD]T[nH][nM][nS]
|
||||
P[nD]T[nH][nM][nS]
|
||||
|
||||
Symbol table:
|
||||
|---|---------|
|
||||
| Y | YEAR |
|
||||
|---|---------|
|
||||
| M | MONTH |
|
||||
|---|---------|
|
||||
| D | DAY |
|
||||
| D | DAYS |
|
||||
|---|---------|
|
||||
| H | HOURS |
|
||||
|---|---------|
|
||||
@ -650,46 +623,21 @@ Symbol table:
|
||||
|
||||
'n' represents a number that can be an integer of ANY value, or a fraction IF it's the last value in the string.
|
||||
All the fields are optional.
|
||||
|
||||
Alternatively, the string can contain LocalDateTime format:
|
||||
P<local_date_time_string>
|
||||
{}
|
||||
)help", kSupportedLocalDateTimeFormatsHelpMessage);
|
||||
// clang-format on
|
||||
|
||||
DurationParameters ParseDurationParameters(std::string_view string) {
|
||||
// https://en.wikipedia.org/wiki/ISO_8601#Durations
|
||||
// The string needs to start with P followed by one of the two options:
|
||||
// - string in a duration specific format
|
||||
// - string in a combined date and time format (LocalDateTime string format)
|
||||
if (string.empty() || string.front() != 'P') {
|
||||
throw utils::BasicException("Duration string is empty.");
|
||||
}
|
||||
|
||||
if (auto maybe_duration_parameters = TryParseIsoDurationString(string); maybe_duration_parameters) {
|
||||
if (auto maybe_duration_parameters = TryParseDurationString(string); maybe_duration_parameters) {
|
||||
return *maybe_duration_parameters;
|
||||
}
|
||||
|
||||
DurationParameters duration_parameters;
|
||||
// remove P and try to parse local date time
|
||||
string.remove_prefix(1);
|
||||
|
||||
try {
|
||||
const auto [date_parameters, local_time_parameters] = ParseLocalDateTimeParameters(string);
|
||||
|
||||
duration_parameters.years = static_cast<double>(date_parameters.years);
|
||||
duration_parameters.months = static_cast<double>(date_parameters.months);
|
||||
duration_parameters.days = static_cast<double>(date_parameters.days);
|
||||
duration_parameters.hours = static_cast<double>(local_time_parameters.hours);
|
||||
duration_parameters.minutes = static_cast<double>(local_time_parameters.minutes);
|
||||
duration_parameters.seconds = static_cast<double>(local_time_parameters.seconds);
|
||||
duration_parameters.milliseconds = static_cast<double>(local_time_parameters.milliseconds);
|
||||
duration_parameters.microseconds = static_cast<double>(local_time_parameters.microseconds);
|
||||
|
||||
return duration_parameters;
|
||||
} catch (const utils::BasicException &e) {
|
||||
throw utils::BasicException("Invalid duration string. {}", kSupportedDurationFormatsHelpMessage);
|
||||
}
|
||||
throw utils::BasicException("Invalid duration string. {}", kSupportedDurationFormatsHelpMessage);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -702,9 +650,7 @@ constexpr To CastChronoDouble(const double value) {
|
||||
Duration::Duration(int64_t microseconds) { this->microseconds = microseconds; }
|
||||
|
||||
Duration::Duration(const DurationParameters ¶meters) {
|
||||
microseconds = (CastChronoDouble<std::chrono::years, std::chrono::microseconds>(parameters.years) +
|
||||
CastChronoDouble<std::chrono::months, std::chrono::microseconds>(parameters.months) +
|
||||
CastChronoDouble<std::chrono::days, std::chrono::microseconds>(parameters.days) +
|
||||
microseconds = (CastChronoDouble<std::chrono::days, std::chrono::microseconds>(parameters.days) +
|
||||
CastChronoDouble<std::chrono::hours, std::chrono::microseconds>(parameters.hours) +
|
||||
CastChronoDouble<std::chrono::minutes, std::chrono::microseconds>(parameters.minutes) +
|
||||
CastChronoDouble<std::chrono::seconds, std::chrono::microseconds>(parameters.seconds) +
|
||||
@ -713,34 +659,14 @@ 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();
|
||||
}
|
||||
|
||||
int64_t Duration::Days() const {
|
||||
std::chrono::microseconds ms(microseconds);
|
||||
return std::chrono::duration_cast<std::chrono::days>(ms).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubMonthsAsDays() const {
|
||||
namespace chrono = std::chrono;
|
||||
const auto months = chrono::months(Months());
|
||||
const auto micros = chrono::microseconds(microseconds);
|
||||
return chrono::duration_cast<chrono::days>(micros - months).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsSeconds() 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::seconds>(micros - months - days).count();
|
||||
return chrono::duration_cast<chrono::seconds>(chrono::microseconds(SubDaysAsMicroseconds())).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsHours() const {
|
||||
@ -755,10 +681,7 @@ int64_t Duration::SubDaysAsMinutes() const {
|
||||
|
||||
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();
|
||||
return chrono::duration_cast<chrono::milliseconds>(chrono::microseconds(SubDaysAsMicroseconds())).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubDaysAsNanoseconds() const {
|
||||
@ -768,19 +691,16 @@ int64_t Duration::SubDaysAsNanoseconds() const {
|
||||
|
||||
int64_t Duration::SubDaysAsMicroseconds() const {
|
||||
namespace chrono = std::chrono;
|
||||
const auto months = chrono::months(Months());
|
||||
const auto days = chrono::days(SubMonthsAsDays());
|
||||
const auto days = chrono::days(Days());
|
||||
const auto micros = chrono::microseconds(microseconds);
|
||||
return (micros - months - days).count();
|
||||
return (micros - days).count();
|
||||
}
|
||||
|
||||
int64_t Duration::SubSecondsAsNanoseconds() const {
|
||||
namespace chrono = std::chrono;
|
||||
const auto months = chrono::months(Months());
|
||||
const auto days = chrono::days(SubMonthsAsDays());
|
||||
const auto micros = chrono::microseconds(SubDaysAsMicroseconds());
|
||||
const auto secs = chrono::seconds(SubDaysAsSeconds());
|
||||
const auto micros = chrono::microseconds(microseconds);
|
||||
return chrono::duration_cast<chrono::nanoseconds>(micros - months - days - secs).count();
|
||||
return chrono::duration_cast<chrono::nanoseconds>(micros - secs).count();
|
||||
}
|
||||
|
||||
Duration Duration::operator-() const {
|
||||
|
@ -41,8 +41,6 @@ bool Underflows(const TType &lhs, const TType &rhs) {
|
||||
}
|
||||
|
||||
struct DurationParameters {
|
||||
double years{0};
|
||||
double months{0};
|
||||
double days{0};
|
||||
double hours{0};
|
||||
double minutes{0};
|
||||
@ -63,10 +61,7 @@ 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;
|
||||
@ -76,16 +71,14 @@ struct Duration {
|
||||
int64_t SubSecondsAsNanoseconds() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Duration &dur) {
|
||||
// ISO 8601 extended format: P[YYYY]-[MM]-[DD]T[hh]:[mm]:[ss].
|
||||
// Format [DD]T[hh]:[mm]:[ss].
|
||||
namespace chrono = std::chrono;
|
||||
auto micros = chrono::microseconds(dur.microseconds);
|
||||
const auto y = GetAndSubtractDuration<chrono::years>(micros);
|
||||
const auto mo = GetAndSubtractDuration<chrono::months>(micros);
|
||||
const auto dd = GetAndSubtractDuration<chrono::days>(micros);
|
||||
const auto h = GetAndSubtractDuration<chrono::hours>(micros);
|
||||
const auto m = GetAndSubtractDuration<chrono::minutes>(micros);
|
||||
const auto s = GetAndSubtractDuration<chrono::seconds>(micros);
|
||||
return os << fmt::format("P{:0>4}-{:0>2}-{:0>2}T{:0>2}:{:0>2}:{:0>2}.{:0>6}", y, mo, dd, h, m, s, micros.count());
|
||||
return os << fmt::format("P{:0>9}DT{:0>2}H{:0>2}M{:0>2}.{:0>6}S", dd, h, m, s, micros.count());
|
||||
}
|
||||
|
||||
Duration operator-() const;
|
||||
|
@ -505,8 +505,7 @@ TEST_F(BoltDecoder, DurationOneSec) {
|
||||
const auto value = Value(utils::Duration(1));
|
||||
const auto &dur = value.ValueDuration();
|
||||
const auto nanos = dur.SubSecondsAsNanoseconds();
|
||||
ASSERT_EQ(dur.Months(), 0);
|
||||
ASSERT_EQ(dur.SubMonthsAsDays(), 0);
|
||||
ASSERT_EQ(dur.Days(), 0);
|
||||
ASSERT_EQ(dur.SubDaysAsSeconds(), 0);
|
||||
ASSERT_EQ(nanos, 1000);
|
||||
const auto *n_bytes = std::bit_cast<const uint8_t *>(&nanos);
|
||||
@ -535,8 +534,7 @@ TEST_F(BoltDecoder, DurationMinusOneSec) {
|
||||
const auto value = Value(utils::Duration(-1));
|
||||
const auto &dur = value.ValueDuration();
|
||||
const auto nanos = dur.SubSecondsAsNanoseconds();
|
||||
ASSERT_EQ(dur.Months(), 0);
|
||||
ASSERT_EQ(dur.SubMonthsAsDays(), 0);
|
||||
ASSERT_EQ(dur.Days(), 0);
|
||||
ASSERT_EQ(dur.SubDaysAsSeconds(), 0);
|
||||
ASSERT_EQ(nanos, -1000);
|
||||
const auto *n_bytes = std::bit_cast<const uint8_t *>(&nanos);
|
||||
@ -562,15 +560,14 @@ TEST_F(BoltDecoder, ArbitraryDuration) {
|
||||
TestDecoderBuffer buffer;
|
||||
DecoderT decoder(buffer);
|
||||
Value dv;
|
||||
const auto value = Value(utils::Duration({1, 1, 1, 1, 1, 1, 1, 0}));
|
||||
const auto value = Value(utils::Duration({15, 1, 2, 3, 5, 0}));
|
||||
const auto &dur = value.ValueDuration();
|
||||
ASSERT_EQ(dur.Months(), 13);
|
||||
ASSERT_EQ(dur.SubMonthsAsDays(), 1);
|
||||
ASSERT_EQ(dur.Days(), 15);
|
||||
const auto secs = dur.SubDaysAsSeconds();
|
||||
ASSERT_EQ(secs, 3661);
|
||||
ASSERT_EQ(secs, 3723);
|
||||
const auto *sec_bytes = std::bit_cast<const uint8_t *>(&secs);
|
||||
const auto nanos = dur.SubSecondsAsNanoseconds();
|
||||
ASSERT_EQ(nanos, 1000000);
|
||||
ASSERT_EQ(nanos, 5000000);
|
||||
const auto *nano_bytes = std::bit_cast<const uint8_t *>(&nanos);
|
||||
using Marker = communication::bolt::Marker;
|
||||
using Sig = communication::bolt::Signature;
|
||||
@ -578,8 +575,8 @@ TEST_F(BoltDecoder, ArbitraryDuration) {
|
||||
std::array<uint8_t, 12> data = {
|
||||
Cast(Marker::TinyStruct4),
|
||||
Cast(Sig::Duration),
|
||||
0xD,
|
||||
0x1,
|
||||
0x0,
|
||||
0xF,
|
||||
Cast(Marker::Int16),
|
||||
sec_bytes[1],
|
||||
sec_bytes[0],
|
||||
|
@ -323,8 +323,7 @@ TEST_F(BoltEncoder, DurationOneSec) {
|
||||
vals.push_back(value);
|
||||
ASSERT_EQ(bolt_encoder.MessageRecord(vals), true);
|
||||
const auto &dur = value.ValueDuration();
|
||||
ASSERT_EQ(dur.Months(), 0);
|
||||
ASSERT_EQ(dur.SubMonthsAsDays(), 0);
|
||||
ASSERT_EQ(dur.Days(), 0);
|
||||
ASSERT_EQ(dur.SubDaysAsSeconds(), 0);
|
||||
const auto nanos = dur.SubSecondsAsNanoseconds();
|
||||
ASSERT_EQ(nanos, 1000);
|
||||
@ -357,8 +356,7 @@ TEST_F(BoltEncoder, DurationMinusOneSec) {
|
||||
vals.push_back(value);
|
||||
ASSERT_EQ(bolt_encoder.MessageRecord(vals), true);
|
||||
const auto &dur = value.ValueDuration();
|
||||
ASSERT_EQ(dur.Months(), 0);
|
||||
ASSERT_EQ(dur.SubMonthsAsDays(), 0);
|
||||
ASSERT_EQ(dur.Days(), 0);
|
||||
ASSERT_EQ(dur.SubDaysAsSeconds(), 0);
|
||||
const auto nanos = dur.SubSecondsAsNanoseconds();
|
||||
const auto *d_bytes = std::bit_cast<const uint8_t *>(&nanos);
|
||||
@ -387,17 +385,17 @@ TEST_F(BoltEncoder, DurationMinusOneSec) {
|
||||
TEST_F(BoltEncoder, ArbitraryDuration) {
|
||||
output.clear();
|
||||
std::vector<Value> vals;
|
||||
const auto value = Value(utils::Duration({1, 1, 1, 1, 1, 1, 1, 0}));
|
||||
const auto value = Value(utils::Duration({15, 1, 2, 3, 5, 0}));
|
||||
vals.push_back(value);
|
||||
ASSERT_EQ(bolt_encoder.MessageRecord(vals), true);
|
||||
const auto &dur = value.ValueDuration();
|
||||
ASSERT_EQ(dur.Months(), 13);
|
||||
ASSERT_EQ(dur.SubMonthsAsDays(), 1);
|
||||
// This is an approximation because of chrono::months to days conversion
|
||||
ASSERT_EQ(dur.Days(), 15);
|
||||
const auto secs = dur.SubDaysAsSeconds();
|
||||
ASSERT_EQ(secs, 3661);
|
||||
ASSERT_EQ(secs, 3723);
|
||||
const auto *sec_bytes = std::bit_cast<const uint8_t *>(&secs);
|
||||
const auto nanos = dur.SubSecondsAsNanoseconds();
|
||||
ASSERT_EQ(nanos, 1000000);
|
||||
ASSERT_EQ(nanos, 5000000);
|
||||
const auto *nano_bytes = std::bit_cast<const uint8_t *>(&nanos);
|
||||
// 0x91 denotes the size of vals (it's 0x91 because it's anded -- see
|
||||
// WriteTypeSize in base_encoder.hpp).
|
||||
@ -410,8 +408,8 @@ TEST_F(BoltEncoder, ArbitraryDuration) {
|
||||
0x91,
|
||||
Cast(Marker::TinyStruct4),
|
||||
Cast(Sig::Duration),
|
||||
0xD,
|
||||
0x1,
|
||||
0x0,
|
||||
0xF,
|
||||
Cast(Marker::Int16),
|
||||
sec_bytes[1],
|
||||
sec_bytes[0],
|
||||
|
@ -396,8 +396,8 @@ TEST(DumpTest, PropertyValue) {
|
||||
auto ldt = storage::PropertyValue(
|
||||
storage::TemporalData(storage::TemporalType::LocalDateTime,
|
||||
utils::LocalDateTime({1994, 12, 7}, {14, 10, 44, 99, 99}).MicrosecondsSinceEpoch()));
|
||||
auto dur = storage::PropertyValue(storage::TemporalData(storage::TemporalType::Duration,
|
||||
utils::Duration({1, 2, 3, 4, 5, 6, 10, 11}).microseconds));
|
||||
auto dur = storage::PropertyValue(
|
||||
storage::TemporalData(storage::TemporalType::Duration, utils::Duration({3, 4, 5, 6, 10, 11}).microseconds));
|
||||
auto list_value = storage::PropertyValue({map_value, null_value, double_value, dt, lt, ldt, dur});
|
||||
CreateVertex(&dba, {}, {{"p1", list_value}, {"p2", str_value}}, false);
|
||||
ASSERT_FALSE(dba.Commit().HasError());
|
||||
@ -415,7 +415,7 @@ TEST(DumpTest, PropertyValue) {
|
||||
"CREATE (:__mg_vertex__ {__mg_id__: 0, `p1`: [{`prop 1`: 13, "
|
||||
"`prop``2```: true}, Null, -1.2, DATE(\"1994-12-07\"), "
|
||||
"LOCALTIME(\"14:10:44.099099\"), LOCALDATETIME(\"1994-12-07T14:10:44.099099\"), "
|
||||
"DURATION(\"P0001-02-03T04:05:06.010011\")"
|
||||
"DURATION(\"P000000003DT04H05M06.010011S\")"
|
||||
"], `p2`: \"hello \\'world\\'\"});",
|
||||
kDropInternalIndex, kRemoveInternalLabelProperty);
|
||||
}
|
||||
@ -658,10 +658,9 @@ TEST(DumpTest, CheckStateSimpleGraph) {
|
||||
{{"time", storage::PropertyValue(storage::TemporalData(
|
||||
storage::TemporalType::LocalDateTime,
|
||||
utils::LocalDateTime({1994, 12, 7}, {14, 10, 44, 99, 99}).MicrosecondsSinceEpoch()))}});
|
||||
CreateEdge(
|
||||
&dba, &w, &z, "Duration",
|
||||
{{"time", storage::PropertyValue(storage::TemporalData(
|
||||
storage::TemporalType::Duration, utils::Duration({1, 2, 3, 4, 5, 6, 10, 11}).microseconds))}});
|
||||
CreateEdge(&dba, &w, &z, "Duration",
|
||||
{{"time", storage::PropertyValue(storage::TemporalData(
|
||||
storage::TemporalType::Duration, utils::Duration({3, 4, 5, 6, 10, 11}).microseconds))}});
|
||||
ASSERT_FALSE(dba.Commit().HasError());
|
||||
}
|
||||
{
|
||||
|
@ -982,18 +982,8 @@ TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) {
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, Duration) {
|
||||
const utils::Duration dur({1994, 2, 10, 1, 30, 2, 22, 45});
|
||||
const utils::Duration dur({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);
|
||||
@ -1980,19 +1970,14 @@ TEST_F(FunctionTest, LocalDateTime) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, Duration) {
|
||||
constexpr size_t microseconds_in_a_year = 31556952000000;
|
||||
const auto dur = utils::Duration(microseconds_in_a_year);
|
||||
EXPECT_EQ(EvaluateFunction("DURATION", "P1Y").ValueDuration(), dur);
|
||||
const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"year", TypedValue(1972)},
|
||||
{"month", TypedValue(2)},
|
||||
{"day", TypedValue(3)},
|
||||
const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(3)},
|
||||
{"hour", TypedValue(4)},
|
||||
{"minute", TypedValue(5)},
|
||||
{"second", TypedValue(6)},
|
||||
{"millisecond", TypedValue(7)},
|
||||
{"microsecond", TypedValue(8)}});
|
||||
|
||||
EXPECT_EQ(EvaluateFunction("DURATION", map_param).ValueDuration(), utils::Duration({1972, 2, 3, 4, 5, 6, 7, 8}));
|
||||
EXPECT_EQ(EvaluateFunction("DURATION", map_param).ValueDuration(), utils::Duration({3, 4, 5, 6, 7, 8}));
|
||||
EXPECT_THROW(EvaluateFunction("DURATION", "{}"), utils::BasicException);
|
||||
EXPECT_THROW(EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"hours", TypedValue(1970)}})),
|
||||
QueryRuntimeException);
|
||||
|
@ -54,7 +54,7 @@ TEST_F(ExpressionPrettyPrinterTest, Literals) {
|
||||
storage::PropertyValue(storage::TemporalData(storage::TemporalType::LocalDateTime, 3)),
|
||||
storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 4))};
|
||||
EXPECT_EQ(ToString(LITERAL(storage::PropertyValue(tt_vec))),
|
||||
"[DURATION(\"P0000-00-00T00:00:00.000001\"), LOCALTIME(\"00:00:00.000002\"), "
|
||||
"[DURATION(\"P000000000DT00H00M00.000001S\"), LOCALTIME(\"00:00:00.000002\"), "
|
||||
"LOCALDATETIME(\"1970-01-01T00:00:00.000003\"), DATE(\"1970-01-01\")]");
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
#include "utils/temporal.hpp"
|
||||
|
||||
namespace {
|
||||
@ -148,20 +149,6 @@ TEST(TemporalTest, LocalDateTimeMicrosecondsSinceEpochConversion) {
|
||||
}
|
||||
|
||||
TEST(TemporalTest, DurationConversion) {
|
||||
{
|
||||
utils::Duration duration{{.years = 2.5}};
|
||||
const auto microseconds = duration.microseconds;
|
||||
utils::LocalDateTime local_date_time{microseconds};
|
||||
ASSERT_EQ(local_date_time.date.years, 2 + 1970);
|
||||
ASSERT_EQ(local_date_time.date.months, 6 + 1);
|
||||
};
|
||||
{
|
||||
utils::Duration duration{{.months = 26}};
|
||||
const auto microseconds = duration.microseconds;
|
||||
utils::LocalDateTime local_date_time{microseconds};
|
||||
ASSERT_EQ(local_date_time.date.years, 2 + 1970);
|
||||
ASSERT_EQ(local_date_time.date.months, 2 + 1);
|
||||
};
|
||||
{
|
||||
utils::Duration duration{{.minutes = 123.25}};
|
||||
const auto microseconds = duration.microseconds;
|
||||
@ -255,19 +242,24 @@ TEST(TemporalTest, LocalDateTimeParsing) {
|
||||
}
|
||||
|
||||
void CheckDurationParameters(const auto &values, const auto &expected) {
|
||||
ASSERT_NEAR(values.years, expected.years, 0.01);
|
||||
ASSERT_NEAR(values.months, expected.months, 0.01);
|
||||
ASSERT_NEAR(values.days, expected.days, 0.01);
|
||||
ASSERT_NEAR(values.hours, expected.hours, 0.01);
|
||||
ASSERT_NEAR(values.minutes, expected.minutes, 0.01);
|
||||
ASSERT_NEAR(values.seconds, expected.seconds, 0.01);
|
||||
ASSERT_EQ(values.days, expected.days);
|
||||
ASSERT_EQ(values.hours, expected.hours);
|
||||
ASSERT_EQ(values.minutes, expected.minutes);
|
||||
ASSERT_EQ(values.seconds, expected.seconds);
|
||||
ASSERT_EQ(values.milliseconds, expected.milliseconds);
|
||||
ASSERT_EQ(values.microseconds, expected.microseconds);
|
||||
}
|
||||
|
||||
TEST(TemporalTest, DurationParsing) {
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P12Y"), utils::DurationParameters{.years = 12.0});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P12Y32DT2M"),
|
||||
utils::DurationParameters{.years = 12.0, .days = 32.0, .minutes = 2.0});
|
||||
ASSERT_THROW(utils::ParseDurationParameters("P12Y"), utils::BasicException);
|
||||
ASSERT_THROW(utils::ParseDurationParameters("P12Y32DT2M"), utils::BasicException);
|
||||
|
||||
CheckDurationParameters(utils::ParseDurationParameters("PT26H"), utils::DurationParameters{.hours = 26});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("PT2M"), utils::DurationParameters{.minutes = 2.0});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("PT22S"), utils::DurationParameters{.seconds = 22});
|
||||
|
||||
CheckDurationParameters(utils::ParseDurationParameters("PT.33S"), utils::DurationParameters{.seconds = 0.33});
|
||||
|
||||
CheckDurationParameters(utils::ParseDurationParameters("PT2M3S"),
|
||||
utils::DurationParameters{.minutes = 2.0, .seconds = 3.0});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("PT2.5H"), utils::DurationParameters{.hours = 2.5});
|
||||
@ -285,13 +277,14 @@ TEST(TemporalTest, DurationParsing) {
|
||||
ASSERT_THROW(utils::ParseDurationParameters("PT2M3S32"), utils::BasicException);
|
||||
ASSERT_THROW(utils::ParseDurationParameters("PT2.5M3S"), utils::BasicException);
|
||||
ASSERT_THROW(utils::ParseDurationParameters("PT2.5M3.5S"), utils::BasicException);
|
||||
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P20201122T192032"),
|
||||
utils::DurationParameters{2020, 11, 22, 19, 20, 32});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P20201122T192032.333"),
|
||||
utils::DurationParameters{2020, 11, 22, 19, 20, 32, 333});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P2020-11-22T19:20:32"),
|
||||
utils::DurationParameters{2020, 11, 22, 19, 20, 32});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P1256.5D"), utils::DurationParameters{1256.5});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P1222DT2H"), utils::DurationParameters{1222, 2});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P1222DT2H44M"), utils::DurationParameters{1222, 2, 44});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P22DT1H9M20S"), utils::DurationParameters{22, 1, 9, 20});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P22DT1H9M20.100S"),
|
||||
utils::DurationParameters{22, 1, 9, 20.100, 0, 0});
|
||||
CheckDurationParameters(utils::ParseDurationParameters("P22DT1H9M20.1000S"),
|
||||
utils::DurationParameters{22, 1, 9, 20.100, 0, 0});
|
||||
}
|
||||
|
||||
TEST(TemporalTest, PrintDate) {
|
||||
@ -311,17 +304,17 @@ TEST(TemporalTest, PrintLocalTime) {
|
||||
}
|
||||
|
||||
TEST(TemporalTest, PrintDuration) {
|
||||
const auto dur = utils::Duration({1, 0, 0, 0, 0, 0, 0, 0});
|
||||
const auto dur = utils::Duration({1, 0, 0, 0, 0, 0});
|
||||
std::ostringstream stream;
|
||||
stream << dur;
|
||||
ASSERT_TRUE(stream);
|
||||
ASSERT_EQ(stream.view(), "P0001-00-00T00:00:00.000000");
|
||||
ASSERT_EQ(stream.view(), "P000000001DT00H00M00.000000S");
|
||||
stream.str("");
|
||||
stream.clear();
|
||||
const auto complex_dur = utils::Duration({1, 5, 10, 3, 30, 33, 100, 50});
|
||||
const auto complex_dur = utils::Duration({10, 3, 30, 33, 100, 50});
|
||||
stream << complex_dur;
|
||||
ASSERT_TRUE(stream);
|
||||
ASSERT_EQ(stream.view(), "P0001-05-10T03:30:33.100050");
|
||||
ASSERT_EQ(stream.view(), "P000000010DT03H30M33.100050S");
|
||||
/// stream.str("");
|
||||
/// stream.clear();
|
||||
/// TODO (kostasrim)
|
||||
@ -420,14 +413,14 @@ TEST(TemporalTest, DurationSubtraction) {
|
||||
|
||||
TEST(TemporalTest, LocalTimeAndDurationAddition) {
|
||||
const auto half_past_one = utils::LocalTime({1, 30, 10});
|
||||
const auto three = half_past_one + utils::Duration({1994, 2, 10, 1, 30, 2, 22, 45});
|
||||
const auto three_symmetrical = utils::Duration({1994, 2, 10, 1, 30, 2, 22, 45}) + half_past_one;
|
||||
const auto three = half_past_one + utils::Duration({10, 1, 30, 2, 22, 45});
|
||||
const auto three_symmetrical = utils::Duration({10, 1, 30, 2, 22, 45}) + half_past_one;
|
||||
ASSERT_EQ(three, utils::LocalTime({3, 0, 12, 22, 45}));
|
||||
ASSERT_EQ(three_symmetrical, utils::LocalTime({3, 0, 12, 22, 45}));
|
||||
|
||||
const auto half_an_hour_before_midnight = utils::LocalTime({23, 30, 10});
|
||||
{
|
||||
const auto half_past_midnight = half_an_hour_before_midnight + utils::Duration({1994, 1, 10, 1});
|
||||
const auto half_past_midnight = half_an_hour_before_midnight + utils::Duration({1, 1, 0, 0});
|
||||
ASSERT_EQ(half_past_midnight, utils::LocalTime({.minutes = 30, .seconds = 10}));
|
||||
}
|
||||
const auto identity = half_an_hour_before_midnight + utils::Duration({.days = 1});
|
||||
@ -436,36 +429,36 @@ TEST(TemporalTest, LocalTimeAndDurationAddition) {
|
||||
const auto an_hour_and_a_half_before_midnight = utils::LocalTime({22, 30, 10});
|
||||
ASSERT_EQ(half_an_hour_before_midnight + utils::Duration({.hours = 23}), an_hour_and_a_half_before_midnight);
|
||||
|
||||
const auto minus_one_hour = utils::Duration({-1994, -2, -10, -1, 0, 0, -20, -20});
|
||||
const auto minus_one_hour_exact = utils::Duration({-1994, -2, -10, -1});
|
||||
const auto minus_one_hour = utils::Duration({-10, -1, 0, 0, -20, -20});
|
||||
const auto minus_one_hour_exact = utils::Duration({.days = -10, .hours = -1});
|
||||
{
|
||||
const auto half_past_midnight = half_past_one + minus_one_hour;
|
||||
ASSERT_EQ(half_past_midnight, utils::LocalTime({0, 30, 9, 979, 980}));
|
||||
ASSERT_EQ(half_past_midnight + minus_one_hour_exact, utils::LocalTime({23, 30, 9, 979, 980}));
|
||||
|
||||
const auto minus_two_hours_thirty_mins = utils::Duration({-1994, -2, -10, -2, -30, -9});
|
||||
const auto minus_two_hours_thirty_mins = utils::Duration({-10, -2, -30, -9});
|
||||
ASSERT_EQ(half_past_midnight + minus_two_hours_thirty_mins, utils::LocalTime({22, 0, 0, 979, 980}));
|
||||
|
||||
ASSERT_NO_THROW(half_past_midnight + (utils::Duration(std::numeric_limits<int64_t>::max())));
|
||||
ASSERT_EQ(half_past_midnight + (utils::Duration(std::numeric_limits<int64_t>::max())),
|
||||
utils::LocalTime({0, 22, 40, 755, 787}));
|
||||
utils::LocalTime({4, 31, 4, 755, 787}));
|
||||
ASSERT_NO_THROW(half_past_midnight + (utils::Duration(std::numeric_limits<int64_t>::min())));
|
||||
ASSERT_EQ(half_past_midnight + (utils::Duration(std::numeric_limits<int64_t>::min())),
|
||||
utils::LocalTime({0, 37, 39, 204, 172}));
|
||||
utils::LocalTime({20, 29, 15, 204, 172}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TemporalTest, LocalTimeAndDurationSubtraction) {
|
||||
const auto half_past_one = utils::LocalTime({1, 30, 10});
|
||||
const auto midnight = half_past_one - utils::Duration({1994, 2, 10, 1, 30, 10});
|
||||
const auto midnight = half_past_one - utils::Duration({10, 1, 30, 10});
|
||||
ASSERT_EQ(midnight, utils::LocalTime());
|
||||
ASSERT_EQ(midnight - utils::Duration({-1994, -2, -10, -1, -30, -10}), utils::LocalTime({1, 30, 10}));
|
||||
ASSERT_EQ(midnight - utils::Duration({-10, -1, -30, -10}), utils::LocalTime({1, 30, 10}));
|
||||
|
||||
const auto almost_an_hour_and_a_half_before_midnight = midnight - utils::Duration({1994, 2, 10, 1, 30, 1, 20, 20});
|
||||
const auto almost_an_hour_and_a_half_before_midnight = midnight - utils::Duration({10, 1, 30, 1, 20, 20});
|
||||
ASSERT_EQ(almost_an_hour_and_a_half_before_midnight, utils::LocalTime({22, 29, 58, 979, 980}));
|
||||
|
||||
ASSERT_NO_THROW(midnight - (utils::Duration(std::numeric_limits<int64_t>::max())));
|
||||
ASSERT_EQ(midnight - (utils::Duration(std::numeric_limits<int64_t>::max())), utils::LocalTime({0, 7, 29, 224, 193}));
|
||||
ASSERT_EQ(midnight - (utils::Duration(std::numeric_limits<int64_t>::max())), utils::LocalTime({19, 59, 5, 224, 193}));
|
||||
ASSERT_THROW(midnight - utils::Duration(std::numeric_limits<int64_t>::min()), utils::BasicException);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user