Implement valueType openCypher function

Reviewers: buda

Reviewed By: buda

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2818
This commit is contained in:
Matej Ferencevic 2020-09-05 13:05:30 +02:00
parent fb7025a716
commit 04ceb8d4b1
2 changed files with 71 additions and 1 deletions

View File

@ -74,6 +74,7 @@ struct Integer {};
struct PositiveInteger {};
struct NonZeroInteger {};
struct NonNegativeInteger {};
struct Double {};
struct Number {};
struct List {};
struct String {};
@ -96,6 +97,8 @@ bool ArgIsType(const TypedValue &arg) {
return arg.IsInt() && arg.ValueInt() != 0;
} else if constexpr (std::is_same_v<ArgType, NonNegativeInteger>) {
return arg.IsInt() && arg.ValueInt() >= 0;
} else if constexpr (std::is_same_v<ArgType, Double>) {
return arg.IsDouble();
} else if constexpr (std::is_same_v<ArgType, Number>) {
return arg.IsNumeric();
} else if constexpr (std::is_same_v<ArgType, List>) {
@ -120,6 +123,8 @@ bool ArgIsType(const TypedValue &arg) {
template <class ArgType>
constexpr const char *ArgTypeName() {
// The type names returned should be standardized openCypher type names.
// https://github.com/opencypher/openCypher/blob/master/docs/openCypher9.pdf
if constexpr (std::is_same_v<ArgType, Null>) {
return "null";
} else if constexpr (std::is_same_v<ArgType, Bool>) {
@ -132,6 +137,8 @@ constexpr const char *ArgTypeName() {
return "non-zero integer";
} else if constexpr (std::is_same_v<ArgType, NonNegativeInteger>) {
return "non-negative integer";
} else if constexpr (std::is_same_v<ArgType, Double>) {
return "float";
} else if constexpr (std::is_same_v<ArgType, Number>) {
return "number";
} else if constexpr (std::is_same_v<ArgType, List>) {
@ -143,7 +150,7 @@ constexpr const char *ArgTypeName() {
} else if constexpr (std::is_same_v<ArgType, Vertex>) {
return "node";
} else if constexpr (std::is_same_v<ArgType, Edge>) {
return "edge";
return "relationship";
} else if constexpr (std::is_same_v<ArgType, Path>) {
return "path";
} else if constexpr (std::is_same_v<ArgType, void>) {
@ -548,6 +555,36 @@ TypedValue Type(const TypedValue *args, int64_t nargs,
ctx.memory);
}
TypedValue ValueType(const TypedValue *args, int64_t nargs,
const FunctionContext &ctx) {
FType<Or<Null, Bool, Integer, Double, String, List, Map, Vertex, Edge, Path>>(
"type", args, nargs);
// The type names returned should be standardized openCypher type names.
// https://github.com/opencypher/openCypher/blob/master/docs/openCypher9.pdf
switch (args[0].type()) {
case TypedValue::Type::Null:
return TypedValue("NULL", ctx.memory);
case TypedValue::Type::Bool:
return TypedValue("BOOLEAN", ctx.memory);
case TypedValue::Type::Int:
return TypedValue("INTEGER", ctx.memory);
case TypedValue::Type::Double:
return TypedValue("FLOAT", ctx.memory);
case TypedValue::Type::String:
return TypedValue("STRING", ctx.memory);
case TypedValue::Type::List:
return TypedValue("LIST", ctx.memory);
case TypedValue::Type::Map:
return TypedValue("MAP", ctx.memory);
case TypedValue::Type::Vertex:
return TypedValue("NODE", ctx.memory);
case TypedValue::Type::Edge:
return TypedValue("RELATIONSHIP", ctx.memory);
case TypedValue::Type::Path:
return TypedValue("PATH", ctx.memory);
}
}
// TODO: How is Keys different from Properties function?
TypedValue Keys(const TypedValue *args, int64_t nargs,
const FunctionContext &ctx) {
@ -1088,6 +1125,7 @@ NameToFunction(const std::string &function_name) {
if (function_name == "TOFLOAT") return ToFloat;
if (function_name == "TOINTEGER") return ToInteger;
if (function_name == "TYPE") return Type;
if (function_name == "VALUETYPE") return ValueType;
// List functions
if (function_name == "KEYS") return Keys;

View File

@ -1418,6 +1418,38 @@ TEST_F(FunctionTest, Type) {
ASSERT_THROW(EvaluateFunction("TYPE", 2), QueryRuntimeException);
}
TEST_F(FunctionTest, ValueType) {
ASSERT_THROW(EvaluateFunction("VALUETYPE"), QueryRuntimeException);
ASSERT_THROW(EvaluateFunction("VALUETYPE", TypedValue(), TypedValue()),
QueryRuntimeException);
ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue()).ValueString(), "NULL");
ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(true)).ValueString(),
"BOOLEAN");
ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(1)).ValueString(),
"INTEGER");
ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(1.1)).ValueString(),
"FLOAT");
ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue("test")).ValueString(),
"STRING");
ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(std::vector<TypedValue>{
TypedValue(1), TypedValue(2)}))
.ValueString(),
"LIST");
ASSERT_EQ(EvaluateFunction("VALUETYPE",
TypedValue(std::map<std::string, TypedValue>{
{"test", TypedValue(1)}}))
.ValueString(),
"MAP");
auto v1 = dba.InsertVertex();
auto v2 = dba.InsertVertex();
ASSERT_EQ(EvaluateFunction("VALUETYPE", v1).ValueString(), "NODE");
auto e = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("type1"));
ASSERT_TRUE(e.HasValue());
ASSERT_EQ(EvaluateFunction("VALUETYPE", *e).ValueString(), "RELATIONSHIP");
Path p(v1, *e, v2);
ASSERT_EQ(EvaluateFunction("VALUETYPE", p).ValueString(), "PATH");
}
TEST_F(FunctionTest, Labels) {
ASSERT_THROW(EvaluateFunction("LABELS"), QueryRuntimeException);
ASSERT_TRUE(EvaluateFunction("LABELS", TypedValue()).IsNull());