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 &) {
|
||||
if (args.size() != 1U) {
|
||||
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 == "KEYS") return Keys;
|
||||
if (function_name == "LABELS") return Labels;
|
||||
if (function_name == "RANGE") return Range;
|
||||
if (function_name == "TAIL") return Tail;
|
||||
if (function_name == "ABS") return Abs;
|
||||
if (function_name == "CEIL") return Ceil;
|
||||
|
@ -820,6 +820,38 @@ TEST(ExpressionEvaluator, FunctionLabels) {
|
||||
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) {
|
||||
ASSERT_THROW(EvaluateFunction("KEYS", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("KEYS", {TypedValue::Null}).type(),
|
||||
|
Loading…
Reference in New Issue
Block a user