Skip to content

Commit

Permalink
Rewrite attribute expresion to labeltagprop for unwind.
Browse files Browse the repository at this point in the history
  • Loading branch information
xtcyclist committed Dec 15, 2022
1 parent c3866b3 commit 0a07d8c
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 49 deletions.
9 changes: 2 additions & 7 deletions src/common/expression/AttributeExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,8 @@ const Value &AttributeExpression::eval(ExpressionContext &ctx) {
result_ = lvalue.getVertex().vid;
return result_;
}
for (auto &tag : lvalue.getVertex().tags) {
auto iter = tag.props.find(rvalue.getStr());
if (iter != tag.props.end()) {
return iter->second;
}
}
return Value::kNullValue;
LOG(ERROR) << "Var.tar.prop cannot be evaluated as an attribute expression.";
return Value::kNullBadType;
}
case Value::Type::EDGE: {
DCHECK(!rvalue.getStr().empty());
Expand Down
53 changes: 34 additions & 19 deletions src/common/expression/test/AttributeExpressionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* This source code is licensed under Apache 2.0 License.
*/
#include "common/expression/test/TestBase.h"
#include "graph/util/ExpressionUtils.h"
#include <unordered_map>

namespace nebula {

Expand Down Expand Up @@ -82,44 +84,57 @@ TEST_F(AttributeExpressionTest, VertexAttribute) {
Vertex vertex;
vertex.vid = "vid";
vertex.tags.resize(2);
vertex.tags[0].name = "tag0";
vertex.tags[1].name = "tag1";
vertex.tags[0].props = {
{"Venus", "Mars"},
{"Mull", "Kintyre"},
{"Venus", Value("Mars")},
{"Mull", Value("Kintyre")},
};
vertex.tags[1].props = {
{"Bip", "Bop"},
{"Tug", "War"},
{"Venus", "RocksShow"},
{"Bip", Value("Bop")},
{"Tug", Value("War")},
{"Venus", Value("RocksShow")},
};
{
auto *left = ConstantExpression::make(&pool, Value(vertex));
auto *right = LabelExpression::make(&pool, "Mull");
auto expr = AttributeExpression::make(&pool, left, right);
auto value = Expression::eval(expr, gExpCtxt);
std::unordered_map<std::string, graph::AliasType> aliasTypeMap = {
{"v", graph::AliasType::kNode}
};
ExpressionContextMock expContext;
expContext.setVar("v", Value(vertex));
{
auto *left = LabelExpression::make(&pool, "v");
auto *right = ConstantExpression::make(&pool, "tag0");
auto *labelAttribute = LabelAttributeExpression::make(&pool, left, right);
auto expr = AttributeExpression::make(&pool, labelAttribute, ConstantExpression::make(&pool, "Mull"));
auto rewriteExpr = graph::ExpressionUtils::rewriteAttr2LabelTagProp(expr->clone(), aliasTypeMap);
auto value = Expression::eval(rewriteExpr, expContext);
ASSERT_TRUE(value.isStr());
ASSERT_EQ("Kintyre", value.getStr());
}
{
auto *left = ConstantExpression::make(&pool, Value(vertex));
auto *right = LabelExpression::make(&pool, "Bip");
auto expr = AttributeExpression::make(&pool, left, right);
auto value = Expression::eval(expr, gExpCtxt);
auto *left = LabelExpression::make(&pool, "v");
auto *right = ConstantExpression::make(&pool, "tag1");
auto *labelAttribute = LabelAttributeExpression::make(&pool, left, right);
auto expr = AttributeExpression::make(&pool, labelAttribute, ConstantExpression::make(&pool, "Bip"));
auto rewriteExpr = graph::ExpressionUtils::rewriteAttr2LabelTagProp(expr->clone(), aliasTypeMap);
auto value = Expression::eval(rewriteExpr, expContext);
ASSERT_TRUE(value.isStr());
ASSERT_EQ("Bop", value.getStr());
}
{
auto *left = ConstantExpression::make(&pool, Value(vertex));
auto *right = LabelExpression::make(&pool, "Venus");
auto expr = AttributeExpression::make(&pool, left, right);
auto value = Expression::eval(expr, gExpCtxt);
auto *left = LabelExpression::make(&pool, "v");
auto *right = ConstantExpression::make(&pool, "tag0");
auto *labelAttribute = LabelAttributeExpression::make(&pool, left, right);
auto expr = AttributeExpression::make(&pool, labelAttribute, ConstantExpression::make(&pool, "Venus"));
auto rewriteExpr = graph::ExpressionUtils::rewriteAttr2LabelTagProp(expr->clone(), aliasTypeMap);
auto value = Expression::eval(rewriteExpr, expContext);
ASSERT_TRUE(value.isStr());
ASSERT_EQ("Mars", value.getStr());
}
{
auto *left = ConstantExpression::make(&pool, Value(vertex));
auto *right = LabelExpression::make(&pool, "_vid");
auto expr = AttributeExpression::make(&pool, left, right);
auto value = Expression::eval(expr, gExpCtxt);
auto value = Expression::eval(expr, expContext);
ASSERT_TRUE(value.isStr());
ASSERT_EQ("vid", value.getStr());
}
Expand Down
13 changes: 11 additions & 2 deletions src/common/expression/test/ExpressionContextMock.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ class ExpressionContextMock final : public ExpressionContext {
}

void setInnerVar(const std::string& var, Value val) override {
exprValueMap_[var] = std::move(val);
if (var == "xxx") {
if (vals_.empty()) {
vals_.emplace_back(val);
indices_[var] = vals_.size() - 1;
} else {
vals_[indices_[var]] = val;
}
} else {
exprValueMap_[var] = std::move(val);
}
}

const Value& getInnerVar(const std::string& var) const override {
Expand Down Expand Up @@ -143,7 +152,7 @@ class ExpressionContextMock final : public ExpressionContext {

void setVar(const std::string& var, Value val) override {
// used by tests of list comprehesion, predicate or reduce
if (var == "n" || var == "p" || var == "totalNum") {
if (var == "n" || var == "p" || var == "totalNum" || var == "v") {
vals_.emplace_back(val);
indices_[var] = vals_.size() - 1;
}
Expand Down
33 changes: 24 additions & 9 deletions src/common/expression/test/ListComprehensionExpressionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ TEST_F(ListComprehensionExpressionTest, ListComprehensionEvaluate) {
ASSERT_EQ(expected, value.getList());
}
{
// [n IN nodes(p) | n.age + 5]
// [n IN nodes(p) | n.player.age + 5]
auto v1 = Vertex("101", {Tag("player", {{"name", "joe"}, {"age", 18}})});
auto v2 = Vertex("102", {Tag("player", {{"name", "amber"}, {"age", 19}})});
auto v3 = Vertex("103", {Tag("player", {{"name", "shawdan"}, {"age", 20}})});
Expand All @@ -46,19 +46,26 @@ TEST_F(ListComprehensionExpressionTest, ListComprehensionEvaluate) {
path.steps.emplace_back(Step(v2, 1, "like", 0, {}));
path.steps.emplace_back(Step(v3, 1, "like", 0, {}));
gExpCtxt.setVar("p", path);

std::unordered_map<std::string, graph::AliasType> aliasTypeMap = {
{"xxx", graph::AliasType::kNode}
};
ArgumentList *argList = ArgumentList::make(&pool);
argList->addArgument(VariableExpression::make(&pool, "p"));
auto expr = ListComprehensionExpression::make(
&pool,
"n",
"xxx",
FunctionCallExpression::make(&pool, "nodes", argList),
nullptr,
ArithmeticExpression::makeAdd(
&pool,
AttributeExpression::make(&pool,
VariableExpression::makeInner(&pool, "n"),
ConstantExpression::make(&pool, "age")),
graph::ExpressionUtils::rewriteAttr2LabelTagProp(
AttributeExpression::make(
&pool,
LabelAttributeExpression::make(&pool,
LabelExpression::make(&pool, "xxx"),
ConstantExpression::make(&pool, "player")),
ConstantExpression::make(&pool, "age")),
aliasTypeMap),
ConstantExpression::make(&pool, 5)));

auto value = Expression::eval(expr, gExpCtxt);
Expand Down Expand Up @@ -88,17 +95,25 @@ TEST_F(ListComprehensionExpressionTest, ListComprehensionExprToString) {
{
ArgumentList *argList = ArgumentList::make(&pool);
argList->addArgument(LabelExpression::make(&pool, "p"));
std::unordered_map<std::string, graph::AliasType> aliasTypeMap = {
{"n", graph::AliasType::kNode}};
auto expr = ListComprehensionExpression::make(
&pool,
"n",
FunctionCallExpression::make(&pool, "nodes", argList),
nullptr,
ArithmeticExpression::makeAdd(
&pool,
LabelAttributeExpression::make(
&pool, LabelExpression::make(&pool, "n"), ConstantExpression::make(&pool, "age")),
graph::ExpressionUtils::rewriteAttr2LabelTagProp(
AttributeExpression::make(
&pool,
LabelAttributeExpression::make(&pool,
LabelExpression::make(&pool, "n"),
ConstantExpression::make(&pool, "player")),
ConstantExpression::make(&pool, "age")),
aliasTypeMap),
ConstantExpression::make(&pool, 10)));
ASSERT_EQ("[n IN nodes(p) | (n.age+10)]", expr->toString());
ASSERT_EQ("[n IN nodes(p) | (n.player.age+10)]", expr->toString());
}
{
auto listItems = ExpressionList::make(&pool);
Expand Down
34 changes: 23 additions & 11 deletions src/common/expression/test/PredicateExpressionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ TEST_F(PredicateExpressionTest, PredicateEvaluate) {
ASSERT_EQ(false, value.getBool());
}
{
// any(n IN nodes(p) WHERE n.age >= 19)
// any(xxx IN nodes(p) WHERE xxx.player.age >= 19)
auto v1 = Vertex("101", {Tag("player", {{"name", "joe"}, {"age", 18}})});
auto v2 = Vertex("102", {Tag("player", {{"name", "amber"}, {"age", 19}})});
auto v3 = Vertex("103", {Tag("player", {{"name", "shawdan"}, {"age", 20}})});
Expand All @@ -40,19 +40,25 @@ TEST_F(PredicateExpressionTest, PredicateEvaluate) {
path.steps.emplace_back(Step(v2, 1, "like", 0, {}));
path.steps.emplace_back(Step(v3, 1, "like", 0, {}));
gExpCtxt.setVar("p", path);

std::unordered_map<std::string, graph::AliasType> aliasTypeMap = {
{"xxx", graph::AliasType::kNode}};
ArgumentList *argList = ArgumentList::make(&pool);
argList->addArgument(VariableExpression::make(&pool, "p"));
auto expr = PredicateExpression::make(
&pool,
"any",
"n",
"xxx",
FunctionCallExpression::make(&pool, "nodes", argList),
RelationalExpression::makeGE(
&pool,
AttributeExpression::make(&pool,
VariableExpression::makeInner(&pool, "n"),
ConstantExpression::make(&pool, "age")),
graph::ExpressionUtils::rewriteAttr2LabelTagProp(
AttributeExpression::make(
&pool,
LabelAttributeExpression::make(&pool,
LabelExpression::make(&pool, "xxx"),
ConstantExpression::make(&pool, "player")),
ConstantExpression::make(&pool, "age")),
aliasTypeMap),
ConstantExpression::make(&pool, 19)));

auto value = Expression::eval(expr, gExpCtxt);
Expand Down Expand Up @@ -90,19 +96,25 @@ TEST_F(PredicateExpressionTest, PredicateEvaluate) {
path.steps.emplace_back(Step(v2, 1, "like", 0, {}));
path.steps.emplace_back(Step(v3, 1, "like", 0, {}));
gExpCtxt.setVar("p", path);

std::unordered_map<std::string, graph::AliasType> aliasTypeMap = {
{"xxx", graph::AliasType::kNode}};
ArgumentList *argList = ArgumentList::make(&pool);
argList->addArgument(VariableExpression::make(&pool, "p"));
auto expr = PredicateExpression::make(
&pool,
"none",
"n",
"xxx",
FunctionCallExpression::make(&pool, "nodes", argList),
RelationalExpression::makeGE(
&pool,
AttributeExpression::make(&pool,
VariableExpression::makeInner(&pool, "n"),
ConstantExpression::make(&pool, "age")),
graph::ExpressionUtils::rewriteAttr2LabelTagProp(
AttributeExpression::make(
&pool,
LabelAttributeExpression::make(&pool,
LabelExpression::make(&pool, "xxx"),
ConstantExpression::make(&pool, "player")),
ConstantExpression::make(&pool, "age")),
aliasTypeMap),
ConstantExpression::make(&pool, 19)));

auto value = Expression::eval(expr, gExpCtxt);
Expand Down
3 changes: 2 additions & 1 deletion src/graph/validator/MatchValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,8 @@ Status MatchValidator::validateUnwind(const UnwindClause *unwindClause,
return Status::SemanticError("Expression in UNWIND must be aliased (use AS)");
}
unwindCtx.alias = unwindClause->alias();
unwindCtx.unwindExpr = unwindClause->expr()->clone();
unwindCtx.unwindExpr = ExpressionUtils::rewriteAttr2LabelTagProp(unwindClause->expr()->clone(),
unwindCtx.aliasesAvailable);
if (ExpressionUtils::hasAny(unwindCtx.unwindExpr, {Expression::Kind::kAggregate})) {
return Status::SemanticError("Can't use aggregating expressions in unwind clause, `%s'",
unwindCtx.unwindExpr->toString().c_str());
Expand Down
33 changes: 33 additions & 0 deletions tests/tck/features/match/Unwind.feature
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,36 @@ Feature: Unwind clause
RETURN num
"""
Then a SemanticError should be raised at runtime: Can't use aggregating expressions in unwind clause, `count(b)'
Scenario: unwind vtp edge expression
When executing query:
"""
match (v:player)
where v.player.name in ["Tim Duncan"]
unwind v.player.age as age
return age;
"""
Then the result should be, in any order:
| age |
| 42 |
When executing query:
"""
match (v:player)-[e:like]-()
where v.player.name in ["Tim Duncan"]
unwind e.likeness as age
return age, e
"""
Then the result should be, in any order:
| age | e |
| 55 | [:like "Marco Belinelli"->"Tim Duncan" @0 {likeness: 55}] |
| 70 | [:like "Danny Green"->"Tim Duncan" @0 {likeness: 70}] |
| 80 | [:like "Tiago Splitter"->"Tim Duncan" @0 {likeness: 80}] |
| 90 | [:like "Manu Ginobili"->"Tim Duncan" @0 {likeness: 90}] |
| 95 | [:like "Tim Duncan"->"Manu Ginobili" @0 {likeness: 95}] |
| 80 | [:like "Boris Diaw"->"Tim Duncan" @0 {likeness: 80}] |
| 75 | [:like "LaMarcus Aldridge"->"Tim Duncan" @0 {likeness: 75}] |
| 80 | [:like "Aron Baynes"->"Tim Duncan" @0 {likeness: 80}] |
| 95 | [:like "Tony Parker"->"Tim Duncan" @0 {likeness: 95}] |
| 95 | [:like "Tim Duncan"->"Tony Parker" @0 {likeness: 95}] |
| 99 | [:like "Dejounte Murray"->"Tim Duncan" @0 {likeness: 99}] |
| 80 | [:like "Shaquille O'Neal"->"Tim Duncan" @0 {likeness: 80}] |

0 comments on commit 0a07d8c

Please sign in to comment.