Simplify using identifiers in RETURN/WITH test macros
Reviewers: florijan, mislav.bradac Reviewed By: mislav.bradac Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D414
This commit is contained in:
parent
1356fd5391
commit
2951b6bdcf
@ -194,44 +194,75 @@ auto GetQuery(AstTreeStorage &storage, Clause *clause, T *... clauses) {
|
||||
}
|
||||
|
||||
// Helper functions for constructing RETURN and WITH clauses.
|
||||
void FillReturnBody(ReturnBody &body, NamedExpression *named_expr) {
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body,
|
||||
NamedExpression *named_expr) {
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
void FillReturnBody(ReturnBody &body, Limit limit) {
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body,
|
||||
const std::string &name) {
|
||||
auto *ident = storage.Create<query::Identifier>(name);
|
||||
auto *named_expr = storage.Create<query::NamedExpression>(name, ident);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body, Limit limit) {
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(ReturnBody &body, Skip skip, Limit limit = Limit{}) {
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body, Skip skip,
|
||||
Limit limit = Limit{}) {
|
||||
body.skip = skip.expression;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(ReturnBody &body, OrderBy order_by, Limit limit = Limit{}) {
|
||||
body.order_by = order_by.expressions;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(ReturnBody &body, OrderBy order_by, Skip skip,
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body, OrderBy order_by,
|
||||
Limit limit = Limit{}) {
|
||||
body.order_by = order_by.expressions;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body, OrderBy order_by,
|
||||
Skip skip, Limit limit = Limit{}) {
|
||||
body.order_by = order_by.expressions;
|
||||
body.skip = skip.expression;
|
||||
body.limit = limit.expression;
|
||||
}
|
||||
void FillReturnBody(ReturnBody &body, Expression *expr,
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body, Expression *expr,
|
||||
NamedExpression *named_expr) {
|
||||
// This overload supports `RETURN(expr, AS(name))` construct, since
|
||||
// NamedExpression does not inherit Expression.
|
||||
named_expr->expression_ = expr;
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body,
|
||||
const std::string &name, NamedExpression *named_expr) {
|
||||
named_expr->expression_ = storage.Create<query::Identifier>(name);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(ReturnBody &body, Expression *expr,
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body, Expression *expr,
|
||||
NamedExpression *named_expr, T... rest) {
|
||||
named_expr->expression_ = expr;
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(body, rest...);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(ReturnBody &body, NamedExpression *named_expr, T... rest) {
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body,
|
||||
NamedExpression *named_expr, T... rest) {
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(body, rest...);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body,
|
||||
const std::string &name, NamedExpression *named_expr,
|
||||
T... rest) {
|
||||
named_expr->expression_ = storage.Create<query::Identifier>(name);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
template <class... T>
|
||||
void FillReturnBody(AstTreeStorage &storage, ReturnBody &body,
|
||||
const std::string &name, T... rest) {
|
||||
auto *ident = storage.Create<query::Identifier>(name);
|
||||
auto *named_expr = storage.Create<query::NamedExpression>(name, ident);
|
||||
body.named_expressions.emplace_back(named_expr);
|
||||
FillReturnBody(storage, body, rest...);
|
||||
}
|
||||
|
||||
///
|
||||
@ -239,18 +270,20 @@ void FillReturnBody(ReturnBody &body, NamedExpression *named_expr, T... rest) {
|
||||
///
|
||||
/// The supported expression combination of arguments is:
|
||||
///
|
||||
/// (NamedExpression | (Expression NamedExpression))+ [OrderBy] [Skip] [Limit]
|
||||
/// (String | NamedExpression | (Expression NamedExpression))+
|
||||
/// [OrderBy] [Skip] [Limit]
|
||||
///
|
||||
/// When the pair (Expression NamedExpression) is given, the Expression will be
|
||||
/// moved inside the NamedExpression. This is done, so that the constructs like
|
||||
/// RETURN(expr, AS("name"), ...) are supported.
|
||||
/// RETURN(expr, AS("name"), ...) are supported. Taking a String is a shorthand
|
||||
/// for RETURN(IDENT(string), AS(string), ....).
|
||||
///
|
||||
/// @sa GetWith
|
||||
template <class... T>
|
||||
auto GetReturn(AstTreeStorage &storage, bool distinct, T... exprs) {
|
||||
auto ret = storage.Create<Return>();
|
||||
ret->body_.distinct = distinct;
|
||||
FillReturnBody(ret->body_, exprs...);
|
||||
FillReturnBody(storage, ret->body_, exprs...);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -264,7 +297,7 @@ template <class... T>
|
||||
auto GetWith(AstTreeStorage &storage, bool distinct, T... exprs) {
|
||||
auto with = storage.Create<With>();
|
||||
with->body_.distinct = distinct;
|
||||
FillReturnBody(with->body_, exprs...);
|
||||
FillReturnBody(storage, with->body_, exprs...);
|
||||
return with;
|
||||
}
|
||||
|
||||
|
@ -227,9 +227,9 @@ auto CheckPlan(AstTreeStorage &storage, TChecker... checker) {
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchNodeReturn) {
|
||||
// Test MATCH (n) RETURN n AS n
|
||||
// Test MATCH (n) RETURN n
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), RETURN(IDENT("n"), AS("n")));
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), RETURN("n"));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectProduce());
|
||||
}
|
||||
|
||||
@ -288,36 +288,35 @@ TEST(TestLogicalPlanner, MatchCreateExpand) {
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchLabeledNodes) {
|
||||
// Test MATCH (n :label) RETURN n AS n
|
||||
// Test MATCH (n :label) RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->label("label");
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))), RETURN(IDENT("n"), AS("n")));
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))), RETURN("n"));
|
||||
CheckPlan(storage, ExpectScanAllByLabel(), ExpectFilter(), ExpectProduce());
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchPathReturn) {
|
||||
// Test MATCH (n) -[r :relationship]- (m) RETURN n AS n
|
||||
// Test MATCH (n) -[r :relationship]- (m) RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->edge_type("relationship");
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r", relationship), NODE("m"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectFilter(),
|
||||
ExpectProduce());
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWhereReturn) {
|
||||
// Test MATCH (n) WHERE n.property < 42 RETURN n AS n
|
||||
// Test MATCH (n) WHERE n.property < 42 RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto property = dba->property("property");
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", property), LITERAL(42))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", property), LITERAL(42))), RETURN("n"));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectFilter(), ExpectProduce());
|
||||
}
|
||||
|
||||
@ -359,7 +358,7 @@ TEST(TestLogicalPlanner, MatchMultiPattern) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m")),
|
||||
PATTERN(NODE("j"), EDGE("e"), NODE("i"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
// We expect the expansions after the first to have a uniqueness filter in a
|
||||
// single MATCH clause.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectScanAll(),
|
||||
@ -371,7 +370,7 @@ TEST(TestLogicalPlanner, MatchMultiPatternSameStart) {
|
||||
// Test MATCH (n), (n) -[e]- (m) RETURN n
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n")), PATTERN(NODE("n"), EDGE("e"), NODE("m"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
// We expect the second pattern to generate only an Expand, since another
|
||||
// ScanAll would be redundant.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectProduce());
|
||||
@ -382,7 +381,7 @@ TEST(TestLogicalPlanner, MatchMultiPatternSameExpandStart) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m")),
|
||||
PATTERN(NODE("m"), EDGE("e"), NODE("l"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
// We expect the second pattern to generate only an Expand. Another
|
||||
// ScanAll would be redundant, as it would generate the nodes obtained from
|
||||
// expansion. Additionally, a uniqueness filter is expected.
|
||||
@ -395,7 +394,7 @@ TEST(TestLogicalPlanner, MultiMatch) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
MATCH(PATTERN(NODE("j"), EDGE("e"), NODE("i"), EDGE("f"), NODE("h"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
// Multiple MATCH clauses form a Cartesian product, so the uniqueness should
|
||||
// not cross MATCH boundaries.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectScanAll(),
|
||||
@ -407,8 +406,7 @@ TEST(TestLogicalPlanner, MultiMatchSameStart) {
|
||||
// Test MATCH (n) MATCH (n) -[r]- (m) RETURN n
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))), RETURN("n"));
|
||||
// Similar to MatchMultiPatternSameStart, we expect only Expand from second
|
||||
// MATCH clause.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectProduce());
|
||||
@ -418,7 +416,7 @@ TEST(TestLogicalPlanner, MatchExistingEdge) {
|
||||
// Test MATCH (n) -[r]- (m) -[r]- (j) RETURN n
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"), EDGE("r"), NODE("j"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
// There is no ExpandUniquenessFilter for referencing the same edge.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectExpand(),
|
||||
ExpectProduce());
|
||||
@ -429,7 +427,7 @@ TEST(TestLogicalPlanner, MultiMatchExistingEdgeOtherEdge) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
MATCH(PATTERN(NODE("m"), EDGE("r"), NODE("j"), EDGE("e"), NODE("l"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
// We need ExpandUniquenessFilter for edge `e` against `r` in second MATCH.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectExpand(), ExpectExpand(),
|
||||
ExpectExpand(), ExpectExpandUniquenessFilter<EdgeAccessor>(),
|
||||
@ -437,23 +435,21 @@ TEST(TestLogicalPlanner, MultiMatchExistingEdgeOtherEdge) {
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWithReturn) {
|
||||
// Test MATCH (old) WITH old AS new RETURN new AS new
|
||||
// Test MATCH (old) WITH old AS new RETURN new
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH(IDENT("old"), AS("new")),
|
||||
RETURN(IDENT("new"), AS("new")));
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH("old", AS("new")), RETURN("new"));
|
||||
// No accumulation since we only do reads.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectProduce(), ExpectProduce());
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWithWhereReturn) {
|
||||
// Test MATCH (old) WITH old AS new WHERE new.prop < 42 RETURN new AS new
|
||||
// Test MATCH (old) WITH old AS new WHERE new.prop < 42 RETURN new
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH(IDENT("old"), AS("new")),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("new", prop), LITERAL(42))),
|
||||
RETURN(IDENT("new"), AS("new")));
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH("old", AS("new")),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("new", prop), LITERAL(42))), RETURN("new"));
|
||||
// No accumulation since we only do reads.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectProduce(), ExpectFilter(),
|
||||
ExpectProduce());
|
||||
@ -482,8 +478,7 @@ TEST(TestLogicalPlanner, MatchWithSumWhereReturn) {
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop));
|
||||
auto literal = LITERAL(42);
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), WITH(ADD(sum, literal), AS("sum")),
|
||||
WHERE(LESS(IDENT("sum"), LITERAL(42))),
|
||||
RETURN(IDENT("sum"), AS("result")));
|
||||
WHERE(LESS(IDENT("sum"), LITERAL(42))), RETURN("sum", AS("result")));
|
||||
auto aggr = ExpectAggregate({sum}, {literal});
|
||||
CheckPlan(storage, ExpectScanAll(), aggr, ExpectProduce(), ExpectFilter(),
|
||||
ExpectProduce());
|
||||
@ -530,7 +525,7 @@ TEST(TestLogicalPlanner, MatchWithCreate) {
|
||||
auto r_type = dba->edge_type("r");
|
||||
AstTreeStorage storage;
|
||||
QUERY(
|
||||
MATCH(PATTERN(NODE("n"))), WITH(IDENT("n"), AS("a")),
|
||||
MATCH(PATTERN(NODE("n"))), WITH("n", AS("a")),
|
||||
CREATE(PATTERN(NODE("a"), EDGE("r", r_type, Direction::OUT), NODE("b"))));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectProduce(), ExpectCreateExpand());
|
||||
}
|
||||
@ -539,7 +534,7 @@ TEST(TestLogicalPlanner, MatchReturnSkipLimit) {
|
||||
// Test MATCH (n) RETURN n SKIP 2 LIMIT 1
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
RETURN(IDENT("n"), AS("n"), SKIP(LITERAL(2)), LIMIT(LITERAL(1))));
|
||||
RETURN("n", SKIP(LITERAL(2)), LIMIT(LITERAL(1))));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectProduce(), ExpectSkip(),
|
||||
ExpectLimit());
|
||||
}
|
||||
@ -550,7 +545,7 @@ TEST(TestLogicalPlanner, CreateWithSkipReturnLimit) {
|
||||
auto ident_n = IDENT("n");
|
||||
auto query = QUERY(CREATE(PATTERN(NODE("n"))),
|
||||
WITH(ident_n, AS("m"), SKIP(LITERAL(2))),
|
||||
RETURN(IDENT("m"), AS("m"), LIMIT(LITERAL(1))));
|
||||
RETURN("m", LIMIT(LITERAL(1))));
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*ident_n)});
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(storage, symbol_table);
|
||||
@ -587,7 +582,7 @@ TEST(TestLogicalPlanner, MatchReturnOrderBy) {
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto ret = RETURN(IDENT("n"), AS("n"), ORDER_BY(PROPERTY_LOOKUP("n", prop)));
|
||||
auto ret = RETURN("n", ORDER_BY(PROPERTY_LOOKUP("n", prop)));
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), ret);
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectProduce(), ExpectOrderBy());
|
||||
}
|
||||
@ -670,8 +665,7 @@ TEST(TestLogicalPlanner, MatchOptionalMatchWhereReturn) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
OPTIONAL_MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("m", prop), LITERAL(42))),
|
||||
RETURN(IDENT("r"), AS("r")));
|
||||
WHERE(LESS(PROPERTY_LOOKUP("m", prop), LITERAL(42))), RETURN("r"));
|
||||
std::list<BaseOpChecker *> optional{new ExpectScanAll(), new ExpectExpand(),
|
||||
new ExpectFilter()};
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectOptional(optional),
|
||||
@ -679,11 +673,11 @@ TEST(TestLogicalPlanner, MatchOptionalMatchWhereReturn) {
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchUnwindReturn) {
|
||||
// Test MATCH (n) UNWIND [1,2,3] AS x RETURN n AS n, x AS x
|
||||
// Test MATCH (n) UNWIND [1,2,3] AS x RETURN n, x
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
UNWIND(LIST(LITERAL(1), LITERAL(2), LITERAL(3)), AS("x")),
|
||||
RETURN(IDENT("n"), AS("n"), IDENT("x"), AS("x")));
|
||||
RETURN("n", "x"));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectUnwind(), ExpectProduce());
|
||||
}
|
||||
|
||||
@ -704,9 +698,8 @@ TEST(TestLogicalPlanner, CreateWithDistinctSumWhereReturn) {
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop));
|
||||
auto query =
|
||||
QUERY(CREATE(PATTERN(node_n)), WITH_DISTINCT(sum, AS("s")),
|
||||
WHERE(LESS(IDENT("s"), LITERAL(42))), RETURN(IDENT("s"), AS("s")));
|
||||
auto query = QUERY(CREATE(PATTERN(node_n)), WITH_DISTINCT(sum, AS("s")),
|
||||
WHERE(LESS(IDENT("s"), LITERAL(42))), RETURN("s"));
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*node_n->identifier_)});
|
||||
auto aggr = ExpectAggregate({sum}, {});
|
||||
@ -727,7 +720,7 @@ TEST(TestLogicalPlanner, MatchCrossReferenceVariable) {
|
||||
auto node_m = NODE("m");
|
||||
auto n_prop = PROPERTY_LOOKUP("n", prop);
|
||||
node_m->properties_[prop] = n_prop;
|
||||
QUERY(MATCH(PATTERN(node_n), PATTERN(node_m)), RETURN(IDENT("n"), AS("n")));
|
||||
QUERY(MATCH(PATTERN(node_n), PATTERN(node_m)), RETURN("n"));
|
||||
// We expect both ScanAll to come before filters (2 are joined into one),
|
||||
// because they need to populate the symbol values.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectScanAll(), ExpectFilter(),
|
||||
@ -741,8 +734,7 @@ TEST(TestLogicalPlanner, MatchWhereBeforeExpand) {
|
||||
auto prop = dba->property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))), RETURN("n"));
|
||||
// We expect Fitler to come immediately after ScanAll, since it only uses `n`.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectFilter(), ExpectExpand(),
|
||||
ExpectProduce());
|
||||
@ -756,8 +748,7 @@ TEST(TestLogicalPlanner, MultiMatchWhere) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
MATCH(PATTERN(NODE("l"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))), RETURN("n"));
|
||||
// Even though WHERE is in the second MATCH clause, we expect Filter to come
|
||||
// before second ScanAll, since it only uses the value from first ScanAll.
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectFilter(), ExpectExpand(),
|
||||
@ -772,8 +763,7 @@ TEST(TestLogicalPlanner, MatchOptionalMatchWhere) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
OPTIONAL_MATCH(PATTERN(NODE("l"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))), RETURN("n"));
|
||||
// Even though WHERE is in the second MATCH clause, and it uses the value from
|
||||
// first ScanAll, it must remain part of the Optional. It should come before
|
||||
// optional ScanAll.
|
||||
@ -852,7 +842,7 @@ TEST(TestLogicalPlanner, MultipleOptionalMatchReturn) {
|
||||
// Test OPTIONAL MATCH (n) OPTIONAL MATCH (m) RETURN n
|
||||
AstTreeStorage storage;
|
||||
QUERY(OPTIONAL_MATCH(PATTERN(NODE("n"))), OPTIONAL_MATCH(PATTERN(NODE("m"))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
RETURN("n"));
|
||||
std::list<BaseOpChecker *> optional{new ExpectScanAll()};
|
||||
CheckPlan(storage, ExpectOptional(optional), ExpectOptional(optional),
|
||||
ExpectProduce());
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#include "dbms/dbms.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
|
||||
#include "query_common.hpp"
|
||||
|
||||
@ -16,9 +16,9 @@ namespace {
|
||||
TEST(TestSymbolGenerator, MatchNodeReturn) {
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
// MATCH (node_atom_1) RETURN node_atom_1 AS node_atom_1
|
||||
auto query_ast = QUERY(MATCH(PATTERN(NODE("node_atom_1"))),
|
||||
RETURN(IDENT("node_atom_1"), AS("node_atom_1")));
|
||||
// MATCH (node_atom_1) RETURN node_atom_1
|
||||
auto query_ast =
|
||||
QUERY(MATCH(PATTERN(NODE("node_atom_1"))), RETURN("node_atom_1"));
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
query_ast->Accept(symbol_generator);
|
||||
EXPECT_EQ(symbol_table.max_position(), 2);
|
||||
@ -42,10 +42,9 @@ TEST(TestSymbolGenerator, MatchUnboundMultiReturn) {
|
||||
AstTreeStorage storage;
|
||||
// AST using variable in return bound by naming the previous return
|
||||
// expression. This is treated as an unbound variable.
|
||||
// MATCH (node_atom_1) RETURN node_atom_1 AS n, n AS n
|
||||
auto query_ast =
|
||||
QUERY(MATCH(PATTERN(NODE("node_atom_1"))),
|
||||
RETURN(IDENT("node_atom_1"), AS("n"), IDENT("n"), AS("n")));
|
||||
// MATCH (node_atom_1) RETURN node_atom_1 AS n, n
|
||||
auto query_ast = QUERY(MATCH(PATTERN(NODE("node_atom_1"))),
|
||||
RETURN("node_atom_1", AS("n"), "n"));
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query_ast->Accept(symbol_generator), UnboundVariableError);
|
||||
}
|
||||
@ -53,9 +52,8 @@ TEST(TestSymbolGenerator, MatchUnboundMultiReturn) {
|
||||
TEST(TestSymbolGenerator, MatchNodeUnboundReturn) {
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
// AST with unbound variable in return: MATCH (n) RETURN x AS x
|
||||
auto query_ast =
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), RETURN(IDENT("x"), AS("x")));
|
||||
// AST with unbound variable in return: MATCH (n) RETURN x
|
||||
auto query_ast = QUERY(MATCH(PATTERN(NODE("n"))), RETURN("x"));
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query_ast->Accept(symbol_generator), UnboundVariableError);
|
||||
}
|
||||
@ -64,11 +62,11 @@ TEST(TestSymbolGenerator, MatchSameEdge) {
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
// AST with match pattern referencing an edge multiple times:
|
||||
// MATCH (n) -[r]- (n) -[r]- (n) RETURN r AS r
|
||||
// MATCH (n) -[r]- (n) -[r]- (n) RETURN r
|
||||
// This usually throws a redeclaration error, but we support it.
|
||||
auto query_ast = QUERY(
|
||||
MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("n"), EDGE("r"), NODE("n"))),
|
||||
RETURN(IDENT("r"), AS("r")));
|
||||
RETURN("r"));
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
query_ast->Accept(symbol_generator);
|
||||
EXPECT_EQ(symbol_table.max_position(), 3);
|
||||
@ -120,8 +118,7 @@ TEST(TestSymbolGenerator, CreateNodeReturn) {
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
// Simple AST returning a created node: CREATE (n) RETURN n
|
||||
auto query_ast =
|
||||
QUERY(CREATE(PATTERN(NODE("n"))), RETURN(IDENT("n"), AS("n")));
|
||||
auto query_ast = QUERY(CREATE(PATTERN(NODE("n"))), RETURN("n"));
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
query_ast->Accept(symbol_generator);
|
||||
EXPECT_EQ(symbol_table.max_position(), 2);
|
||||
@ -238,11 +235,10 @@ TEST(TestSymbolGenerator, CreateBidirectionalEdge) {
|
||||
}
|
||||
|
||||
TEST(TestSymbolGenerator, MatchWhereUnbound) {
|
||||
// Test MATCH (n) WHERE missing < 42 RETURN n AS n
|
||||
// Test MATCH (n) WHERE missing < 42 RETURN n
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
WHERE(LESS(IDENT("missing"), LITERAL(42))),
|
||||
RETURN(IDENT("n"), AS("n")));
|
||||
WHERE(LESS(IDENT("missing"), LITERAL(42))), RETURN("n"));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), UnboundVariableError);
|
||||
@ -299,10 +295,10 @@ TEST(TestSymbolGenerator, MatchWithReturn) {
|
||||
}
|
||||
|
||||
TEST(TestSymbolGenerator, MatchWithReturnUnbound) {
|
||||
// Test MATCH (old) WITH old AS n RETURN old AS old
|
||||
// Test MATCH (old) WITH old AS n RETURN old
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("old"))), WITH(IDENT("old"), AS("n")),
|
||||
RETURN(IDENT("old"), AS("old")));
|
||||
auto query =
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH("old", AS("n")), RETURN("old"));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), UnboundVariableError);
|
||||
@ -520,7 +516,7 @@ TEST(TestSymbolGenerator, MatchWithCreate) {
|
||||
auto node_2 = NODE("m");
|
||||
auto edge = EDGE("r", r_type, EdgeAtom::Direction::OUT);
|
||||
auto node_3 = NODE("m");
|
||||
auto query = QUERY(MATCH(PATTERN(node_1)), WITH(IDENT("n"), AS("m")),
|
||||
auto query = QUERY(MATCH(PATTERN(node_1)), WITH("n", AS("m")),
|
||||
CREATE(PATTERN(node_2, edge, node_3)));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
@ -539,8 +535,8 @@ TEST(TestSymbolGenerator, SameResults) {
|
||||
// Test MATCH (n) WITH n AS m, n AS m
|
||||
{
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
WITH(IDENT("n"), AS("m"), IDENT("n"), AS("m")));
|
||||
auto query =
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), WITH("n", AS("m"), "n", AS("m")));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
@ -548,8 +544,7 @@ TEST(TestSymbolGenerator, SameResults) {
|
||||
// Test MATCH (n) RETURN n, n
|
||||
{
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
RETURN(IDENT("n"), AS("n"), IDENT("n"), AS("n")));
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))), RETURN("n", "n"));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
@ -561,7 +556,7 @@ TEST(TestSymbolGenerator, SkipUsingIdentifier) {
|
||||
{
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("old"))),
|
||||
WITH(IDENT("old"), AS("new"), SKIP(IDENT("old"))));
|
||||
WITH("old", AS("new"), SKIP(IDENT("old"))));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
@ -570,7 +565,7 @@ TEST(TestSymbolGenerator, SkipUsingIdentifier) {
|
||||
{
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("old"))),
|
||||
WITH(IDENT("old"), AS("new"), SKIP(IDENT("new"))));
|
||||
WITH("old", AS("new"), SKIP(IDENT("new"))));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
@ -580,8 +575,7 @@ TEST(TestSymbolGenerator, SkipUsingIdentifier) {
|
||||
TEST(TestSymbolGenerator, LimitUsingIdentifier) {
|
||||
// Test MATCH (n) RETURN n AS n LIMIT n
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
RETURN(IDENT("n"), AS("n"), LIMIT(IDENT("n"))));
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))), RETURN("n", LIMIT(IDENT("n"))));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
@ -590,9 +584,8 @@ TEST(TestSymbolGenerator, LimitUsingIdentifier) {
|
||||
TEST(TestSymbolGenerator, OrderByAggregation) {
|
||||
// Test MATCH (old) RETURN old AS new ORDER BY COUNT(1)
|
||||
AstTreeStorage storage;
|
||||
auto query =
|
||||
QUERY(MATCH(PATTERN(NODE("old"))),
|
||||
RETURN(IDENT("old"), AS("new"), ORDER_BY(COUNT(LITERAL(1)))));
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("old"))),
|
||||
RETURN("old", AS("new"), ORDER_BY(COUNT(LITERAL(1)))));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
@ -728,8 +721,7 @@ TEST(TestSymbolGenerator, WithUnwindRedeclareReturn) {
|
||||
// Test WITH [1, 2] AS list UNWIND list AS list RETURN list
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(WITH(LIST(LITERAL(1), LITERAL(2)), AS("list")),
|
||||
UNWIND(IDENT("list"), AS("list")),
|
||||
RETURN(IDENT("list"), AS("list")));
|
||||
UNWIND(IDENT("list"), AS("list")), RETURN("list"));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), RedeclareVariableError);
|
||||
@ -817,9 +809,9 @@ TEST(TestSymbolGenerator, MatchWithAsteriskReturnAsterisk) {
|
||||
}
|
||||
|
||||
TEST(TestSymbolGenerator, MatchReturnAsteriskSameResult) {
|
||||
// MATCH (n) RETURN *, n AS n
|
||||
// MATCH (n) RETURN *, n
|
||||
AstTreeStorage storage;
|
||||
auto ret = RETURN(IDENT("n"), AS("n"));
|
||||
auto ret = RETURN("n");
|
||||
ret->body_.all_identifiers = true;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))), ret);
|
||||
SymbolTable symbol_table;
|
||||
|
Loading…
Reference in New Issue
Block a user