Implement Range function
Reviewers: teon.banek, buda Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D358
This commit is contained in:
parent
aeacdfc631
commit
f82bda6c0c
@ -282,6 +282,39 @@ TypedValue Labels(const std::vector<TypedValue> &args,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypedValue Range(const std::vector<TypedValue> &args, GraphDbAccessor &) {
|
||||||
|
if (args.size() != 2U && args.size() != 3U) {
|
||||||
|
throw QueryRuntimeException("range requires two or three arguments");
|
||||||
|
}
|
||||||
|
bool has_null = false;
|
||||||
|
auto check_type = [&](const TypedValue &t) {
|
||||||
|
if (t.IsNull()) {
|
||||||
|
has_null = true;
|
||||||
|
} else if (t.type() != TypedValue::Type::Int) {
|
||||||
|
throw QueryRuntimeException("range called with incompatible type");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::for_each(args.begin(), args.end(), check_type);
|
||||||
|
if (has_null) return TypedValue::Null;
|
||||||
|
auto lbound = args[0].Value<int64_t>();
|
||||||
|
auto rbound = args[1].Value<int64_t>();
|
||||||
|
int64_t step = args.size() == 3U ? args[2].Value<int64_t>() : 1;
|
||||||
|
if (step == 0) {
|
||||||
|
throw QueryRuntimeException("step argument in range can't be zero");
|
||||||
|
}
|
||||||
|
std::vector<TypedValue> list;
|
||||||
|
if (lbound <= rbound && step > 0) {
|
||||||
|
for (auto i = lbound; i <= rbound; i += step) {
|
||||||
|
list.push_back(i);
|
||||||
|
}
|
||||||
|
} else if (lbound >= rbound && step < 0) {
|
||||||
|
for (auto i = lbound; i >= rbound; i += step) {
|
||||||
|
list.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
TypedValue Tail(const std::vector<TypedValue> &args, GraphDbAccessor &) {
|
TypedValue Tail(const std::vector<TypedValue> &args, GraphDbAccessor &) {
|
||||||
if (args.size() != 1U) {
|
if (args.size() != 1U) {
|
||||||
throw QueryRuntimeException("tail requires one argument");
|
throw QueryRuntimeException("tail requires one argument");
|
||||||
@ -421,6 +454,7 @@ NameToFunction(const std::string &function_name) {
|
|||||||
if (function_name == "TYPE") return Type;
|
if (function_name == "TYPE") return Type;
|
||||||
if (function_name == "KEYS") return Keys;
|
if (function_name == "KEYS") return Keys;
|
||||||
if (function_name == "LABELS") return Labels;
|
if (function_name == "LABELS") return Labels;
|
||||||
|
if (function_name == "RANGE") return Range;
|
||||||
if (function_name == "TAIL") return Tail;
|
if (function_name == "TAIL") return Tail;
|
||||||
if (function_name == "ABS") return Abs;
|
if (function_name == "ABS") return Abs;
|
||||||
if (function_name == "CEIL") return Ceil;
|
if (function_name == "CEIL") return Ceil;
|
||||||
|
@ -820,6 +820,38 @@ TEST(ExpressionEvaluator, FunctionLabels) {
|
|||||||
ASSERT_THROW(EvaluateFunction("LABELS", {2}), QueryRuntimeException);
|
ASSERT_THROW(EvaluateFunction("LABELS", {2}), QueryRuntimeException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ExpressionEvaluator, FunctionRange) {
|
||||||
|
EXPECT_THROW(EvaluateFunction("RANGE", {}), QueryRuntimeException);
|
||||||
|
EXPECT_TRUE(EvaluateFunction("RANGE", {1, 2, TypedValue::Null}).IsNull());
|
||||||
|
EXPECT_THROW(EvaluateFunction("RANGE", {1, TypedValue::Null, 1.3}),
|
||||||
|
QueryRuntimeException);
|
||||||
|
auto to_int_list = [](const TypedValue &t) {
|
||||||
|
std::vector<int64_t> list;
|
||||||
|
for (auto x : t.Value<std::vector<TypedValue>>()) {
|
||||||
|
list.push_back(x.Value<int64_t>());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
EXPECT_THROW(EvaluateFunction("RANGE", {1, 2, 0}), QueryRuntimeException);
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {1, 3})),
|
||||||
|
ElementsAre(1, 2, 3));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {-1, 5, 2})),
|
||||||
|
ElementsAre(-1, 1, 3, 5));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {2, 10, 3})),
|
||||||
|
ElementsAre(2, 5, 8));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {2, 2, 2})),
|
||||||
|
ElementsAre(2));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {3, 0, 5})), ElementsAre());
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {5, 1, -2})),
|
||||||
|
ElementsAre(5, 3, 1));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {6, 1, -2})),
|
||||||
|
ElementsAre(6, 4, 2));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {2, 2, -3})),
|
||||||
|
ElementsAre(2));
|
||||||
|
EXPECT_THAT(to_int_list(EvaluateFunction("RANGE", {-2, 4, -1})),
|
||||||
|
ElementsAre());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ExpressionEvaluator, FunctionKeys) {
|
TEST(ExpressionEvaluator, FunctionKeys) {
|
||||||
ASSERT_THROW(EvaluateFunction("KEYS", {}), QueryRuntimeException);
|
ASSERT_THROW(EvaluateFunction("KEYS", {}), QueryRuntimeException);
|
||||||
ASSERT_EQ(EvaluateFunction("KEYS", {TypedValue::Null}).type(),
|
ASSERT_EQ(EvaluateFunction("KEYS", {TypedValue::Null}).type(),
|
||||||
|
Loading…
Reference in New Issue
Block a user