From 5abcb5081d35065d4beb3803a3694069faf603da Mon Sep 17 00:00:00 2001
From: Kostas Kyrimis <kostaskyrim@gmail.com>
Date: Tue, 17 Aug 2021 13:10:03 +0300
Subject: [PATCH] Define timestamp function that return temporal types in
 microseconds since epoch representation (#205)

---
 .../interpret/awesome_memgraph_functions.cpp  | 27 ++++++++++++++++++-
 tests/unit/query_expression_evaluator.cpp     | 20 +++++++++++++-
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp
index ad9e34058..8913ce043 100644
--- a/src/query/interpret/awesome_memgraph_functions.cpp
+++ b/src/query/interpret/awesome_memgraph_functions.cpp
@@ -85,6 +85,9 @@ struct Map {};
 struct Edge {};
 struct Vertex {};
 struct Path {};
+struct Date {};
+struct LocalTime {};
+struct LocalDateTime {};
 
 template <class ArgType>
 bool ArgIsType(const TypedValue &arg) {
@@ -116,6 +119,12 @@ bool ArgIsType(const TypedValue &arg) {
     return arg.IsEdge();
   } else if constexpr (std::is_same_v<ArgType, Path>) {
     return arg.IsPath();
+  } else if constexpr (std::is_same_v<ArgType, Date>) {
+    return arg.IsDate();
+  } else if constexpr (std::is_same_v<ArgType, LocalTime>) {
+    return arg.IsLocalTime();
+  } else if constexpr (std::is_same_v<ArgType, LocalDateTime>) {
+    return arg.IsLocalDateTime();
   } else if constexpr (std::is_same_v<ArgType, void>) {
     return true;
   } else {
@@ -158,6 +167,12 @@ constexpr const char *ArgTypeName() {
     return "path";
   } else if constexpr (std::is_same_v<ArgType, void>) {
     return "void";
+  } else if constexpr (std::is_same_v<ArgType, Date>) {
+    return "Date";
+  } else if constexpr (std::is_same_v<ArgType, LocalTime>) {
+    return "LocalTime";
+  } else if constexpr (std::is_same_v<ArgType, LocalDateTime>) {
+    return "LocalDateTime";
   } else {
     static_assert(std::is_same_v<ArgType, Null>, "Unknown ArgType");
   }
@@ -866,7 +881,17 @@ TypedValue ToString(const TypedValue *args, int64_t nargs, const FunctionContext
 }
 
 TypedValue Timestamp(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
-  FType<void>("timestamp", args, nargs);
+  FType<Optional<Or<Date, LocalTime, LocalDateTime>>>("timestamp", args, nargs);
+  const auto &arg = *args;
+  if (arg.IsDate()) {
+    return TypedValue(arg.ValueDate().MicrosecondsSinceEpoch(), ctx.memory);
+  }
+  if (arg.IsLocalTime()) {
+    return TypedValue(arg.ValueLocalTime().MicrosecondsSinceEpoch(), ctx.memory);
+  }
+  if (arg.IsLocalDateTime()) {
+    return TypedValue(arg.ValueLocalDateTime().MicrosecondsSinceEpoch(), ctx.memory);
+  }
   return TypedValue(ctx.timestamp, ctx.memory);
 }
 
diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp
index 554236e78..1ce4d57e0 100644
--- a/tests/unit/query_expression_evaluator.cpp
+++ b/tests/unit/query_expression_evaluator.cpp
@@ -1588,11 +1588,29 @@ TEST_F(FunctionTest, ToStringBool) {
 
 TEST_F(FunctionTest, ToStringExceptions) { EXPECT_THROW(EvaluateFunction("TOSTRING", 1, 2, 3), QueryRuntimeException); }
 
-TEST_F(FunctionTest, Timestamp) {
+TEST_F(FunctionTest, TimestampVoid) {
   ctx.timestamp = 42;
   EXPECT_EQ(EvaluateFunction("TIMESTAMP").ValueInt(), 42);
 }
 
+TEST_F(FunctionTest, TimestampDate) {
+  ctx.timestamp = 42;
+  EXPECT_EQ(EvaluateFunction("TIMESTAMP", utils::Date({1970, 1, 1})).ValueInt(), 0);
+  EXPECT_EQ(EvaluateFunction("TIMESTAMP", utils::Date({1971, 1, 1})).ValueInt(), 31536000000000);
+}
+
+TEST_F(FunctionTest, TimestampLocalTime) {
+  ctx.timestamp = 42;
+  const utils::LocalTime time(10000);
+  EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 10000);
+}
+
+TEST_F(FunctionTest, TimestampLocalDateTime) {
+  ctx.timestamp = 42;
+  const utils::LocalDateTime time(20000);
+  EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000);
+}
+
 TEST_F(FunctionTest, TimestampExceptions) {
   ctx.timestamp = 42;
   EXPECT_THROW(EvaluateFunction("TIMESTAMP", 1).ValueInt(), QueryRuntimeException);