Skip to content
Snippets Groups Projects
Unverified Commit 63d3bb8d authored by cpw's avatar cpw Committed by GitHub
Browse files

Implement assign pattern to path (#401)

* Build path expr.

* Save path build to match ast context.

* Rewrite label expr to path expr.

* Test assign patten to path.
parent f93f3681
No related branches found
No related tags found
No related merge requests found
......@@ -20,21 +20,24 @@ Status MatchSolver::buildReturn(MatchAstContext* mctx, SubPlan& subPlan) {
for (auto *col : mctx->yieldColumns->columns()) {
auto kind = col->expr()->kind();
YieldColumn *newColumn = nullptr;
if (kind == Expression::Kind::kLabel) {
auto *label = static_cast<const LabelExpression*>(col->expr());
newColumn = new YieldColumn(rewrite(label));
} else if (kind == Expression::Kind::kLabelAttribute) {
auto *la = static_cast<const LabelAttributeExpression*>(col->expr());
newColumn = new YieldColumn(rewrite(la));
} else {
auto newExpr = col->expr()->clone();
auto rewriter = [] (const Expression *expr) {
if (expr->kind() == Expression::Kind::kLabel) {
return rewrite(static_cast<const LabelExpression*>(expr));
auto rewriter = [mctx] (const Expression *expr) {
if (expr->kind() == Expression::Kind::kLabel) {
auto* labelExpr = static_cast<const LabelExpression*>(expr);
auto alias = mctx->aliases.find(*labelExpr->name());
DCHECK(alias != mctx->aliases.end());
if (alias->second == MatchValidator::AliasType::kPath) {
return mctx->pathBuild->clone().release();
} else {
return rewrite(static_cast<const LabelAttributeExpression*>(expr));
return rewrite(labelExpr);
}
};
} else {
return rewrite(static_cast<const LabelAttributeExpression*>(expr));
}
};
if (kind == Expression::Kind::kLabel || kind == Expression::Kind::kLabelAttribute) {
newColumn = new YieldColumn(rewriter(col->expr()));
} else {
auto newExpr = col->expr()->clone();
RewriteMatchLabelVisitor visitor(std::move(rewriter));
newExpr->accept(&visitor);
newColumn = new YieldColumn(newExpr.release());
......
......@@ -5,8 +5,9 @@
*/
#include "validator/MatchValidator.h"
#include "visitor/RewriteMatchLabelVisitor.h"
#include "util/ExpressionUtils.h"
#include "visitor/RewriteMatchLabelVisitor.h"
namespace nebula {
namespace graph {
......@@ -46,19 +47,50 @@ Status MatchValidator::validateImpl() {
NG_RETURN_IF_ERROR(validateFilter(matchClause->where()->filter()));
}
NG_RETURN_IF_ERROR(validateReturn(sentence->ret()));
return analyzeStartPoint();
return Status::OK();
}
Status MatchValidator::validatePath(const MatchPath *path) {
auto *sm = qctx_->schemaMng();
auto steps = path->steps();
NG_RETURN_IF_ERROR(buildNodeInfo(path));
NG_RETURN_IF_ERROR(buildEdgeInfo(path));
NG_RETURN_IF_ERROR(buildPathExpr(path));
return Status::OK();
}
Status MatchValidator::buildPathExpr(const MatchPath *path) {
auto* pathAlias = path->alias();
if (pathAlias == nullptr) {
return Status::OK();
}
if (!matchCtx_->aliases.emplace(*pathAlias, kPath).second) {
return Status::SemanticError("`%s': Redefined alias", pathAlias->c_str());
}
auto& nodeInfos = matchCtx_->nodeInfos;
auto& edgeInfos = matchCtx_->edgeInfos;
auto pathBuild = std::make_unique<PathBuildExpression>();
for (size_t i = 0; i < edgeInfos.size(); ++i) {
pathBuild->add(std::make_unique<VariablePropertyExpression>(
new std::string(), new std::string(*nodeInfos[i].alias)));
pathBuild->add(std::make_unique<VariablePropertyExpression>(
new std::string(), new std::string(*edgeInfos[i].alias)));
}
pathBuild->add(std::make_unique<VariablePropertyExpression>(
new std::string(), new std::string(*nodeInfos.back().alias)));
matchCtx_->pathBuild = std::move(pathBuild);
return Status::OK();
}
Status MatchValidator::buildNodeInfo(const MatchPath *path) {
auto *sm = qctx_->schemaMng();
auto steps = path->steps();
auto& nodeInfos = matchCtx_->nodeInfos;
nodeInfos.resize(steps + 1);
edgeInfos.resize(steps);
for (auto i = 0u; i <= steps; i++) {
auto *node = path->node(i);
auto *label = node->label();
......@@ -68,7 +100,7 @@ Status MatchValidator::validatePath(const MatchPath *path) {
if (label != nullptr) {
auto tid = sm->toTagID(space_.id, *label);
if (!tid.ok()) {
return Status::Error("`%s': Unknown tag", label->c_str());
return Status::SemanticError("`%s': Unknown tag", label->c_str());
}
nodeInfos[i].tid = tid.value();
}
......@@ -77,7 +109,7 @@ Status MatchValidator::validatePath(const MatchPath *path) {
alias = saveObject(new std::string(vctx_->anonVarGen()->getVar()));
}
if (!matchCtx_->aliases.emplace(*alias, kNode).second) {
return Status::Error("`%s': Redefined alias", alias->c_str());
return Status::SemanticError("`%s': Redefined alias", alias->c_str());
}
Expression *filter = nullptr;
if (props != nullptr) {
......@@ -92,6 +124,15 @@ Status MatchValidator::validatePath(const MatchPath *path) {
nodeInfos[i].filter = filter;
}
return Status::OK();
}
Status MatchValidator::buildEdgeInfo(const MatchPath *path) {
auto *sm = qctx_->schemaMng();
auto steps = path->steps();
auto& edgeInfos = matchCtx_->edgeInfos;
edgeInfos.resize(steps);
for (auto i = 0u; i < steps; i++) {
auto *edge = path->edge(i);
auto &types = edge->types();
......@@ -306,10 +347,6 @@ Status MatchValidator::validateAliases(const std::vector<const Expression*> &exp
return Status::OK();
}
Status MatchValidator::analyzeStartPoint() {
return Status::OK();
}
StatusOr<Expression*>
MatchValidator::makeSubFilter(const std::string &alias,
......
......@@ -68,8 +68,6 @@ private:
Status validateAliases(const std::vector<const Expression*> &exprs) const;
Status analyzeStartPoint();
StatusOr<Expression*> makeSubFilter(const std::string &alias,
const MapExpression *map) const;
......@@ -78,6 +76,12 @@ private:
return qctx_->objPool()->add(obj);
}
Status buildNodeInfo(const MatchPath *path);
Status buildEdgeInfo(const MatchPath *path);
Status buildPathExpr(const MatchPath *path);
private:
std::unique_ptr<MatchAstContext> matchCtx_;
};
......@@ -86,6 +90,7 @@ struct MatchAstContext final : AstContext {
std::vector<MatchValidator::NodeInfo> nodeInfos;
std::vector<MatchValidator::EdgeInfo> edgeInfos;
std::unordered_map<std::string, MatchValidator::AliasType> aliases;
std::unique_ptr<PathBuildExpression> pathBuild;
std::unique_ptr<Expression> filter;
const YieldColumns *yieldColumns;
MatchValidator::ScanInfo scanInfo;
......
......@@ -34,6 +34,11 @@ T_NULL_UNKNOWN_PROP.set_nVal(CommonTtypes.NullType.UNKNOWN_PROP)
T_NULL_UNKNOWN_DIV_BY_ZERO = CommonTtypes.Value()
T_NULL_UNKNOWN_DIV_BY_ZERO.set_nVal(CommonTtypes.NullType.DIV_BY_ZERO)
class PathVal:
items = []
def __init__(self, items):
self.items = items
class NebulaTestSuite(object):
@classmethod
......@@ -353,6 +358,26 @@ class NebulaTestSuite(object):
ok = (expect[i] == result)
assert ok, "different column name, expect: {} vs. result: {}".format(expect[i], result)
@classmethod
def to_path_value(self, col):
path = CommonTtypes.Path()
path.steps = []
for col, j in zip(col.items, range(len(col.items))):
if j == 0:
path.src = col.get_vVal()
elif (j % 2) == 1:
edge = col[0].get_eVal()
step = CommonTtypes.Step()
step.name = edge.name
step.ranking = edge.ranking
step.type = col[1]
step.props = edge.props
path.steps.append(step)
else:
print("step: %d", len(path.steps))
path.steps[-1].dst = col.get_vVal()
return path
@classmethod
def to_value(self, col):
value = CommonTtypes.Value()
......@@ -389,6 +414,8 @@ class NebulaTestSuite(object):
return ok, temp
set_val.values.add(temp)
value.set_uVal(set_val)
elif isinstance(col, PathVal):
value.set_pVal(self.to_path_value(col))
else:
return False, 'Wrong val type'
return True, value
......
......@@ -7,7 +7,7 @@
import pytest
from tests.common.nebula_test_suite import NebulaTestSuite
from tests.common.nebula_test_suite import NebulaTestSuite, PathVal
@pytest.mark.usefixtures('set_vertices_and_edges')
......@@ -572,6 +572,117 @@ class TestMatch(NebulaTestSuite):
['Tony Parker', ['player']]]
self.check_out_of_order_result(resp, result)
def test_return_path(self):
VERTICES, EDGES = self.VERTEXS, self.EDGES
stmt = 'MATCH p = (n:player{name:"Tony Parker"}) return p,n'
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp);
columns_name = ['p', 'n']
self.check_column_names(resp, columns_name)
result = [
[PathVal([VERTICES["Tony Parker"]]), VERTICES["Tony Parker"]]
]
self.check_out_of_order_result(resp, result)
stmt = 'MATCH p = (n:player{name:"LeBron James"})-[:like]->(m) return p, n.name, m.name'
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
columns_name = ['p', 'n.name', 'm.name']
self.check_column_names(resp, columns_name)
result = [
[PathVal([VERTICES["LeBron James"],
(EDGES["LeBron James"+"Ray Allen"+"like"+"0"], 1),
VERTICES["Ray Allen"]]),
"LeBron James", "Ray Allen"]
]
self.check_out_of_order_result(resp, result)
stmt = 'MATCH p = (n:player{name:"LeBron James"})<-[:like]-(m) return p, n.name, m.name'
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
columns_name = ['p', 'n.name', 'm.name']
self.check_column_names(resp, columns_name)
result = [
[PathVal([VERTICES["LeBron James"],
(EDGES["Dejounte Murray"+"LeBron James"+"like"+"0"], -1),
VERTICES["Dejounte Murray"]]),
"LeBron James", "Dejounte Murray"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Carmelo Anthony"+"LeBron James"+"like"+"0"], -1),
VERTICES["Carmelo Anthony"]]),
"LeBron James", "Carmelo Anthony"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Kyrie Irving"+"LeBron James"+"like"+"0"], -1),
VERTICES["Kyrie Irving"]]),
"LeBron James", "Kyrie Irving"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Dwyane Wade"+"LeBron James"+"like"+"0"], -1),
VERTICES["Dwyane Wade"]]),
"LeBron James", "Dwyane Wade"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Danny Green"+"LeBron James"+"like"+"0"], -1),
VERTICES["Danny Green"]]),
"LeBron James", "Danny Green"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Chris Paul"+"LeBron James"+"like"+"0"], -1),
VERTICES["Chris Paul"]]),
"LeBron James", "Chris Paul"],
]
self.check_out_of_order_result(resp, result)
stmt = 'MATCH p = (n:player{name:"LeBron James"})-[:like]-(m) return p, n.name, m.name'
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
columns_name = ['p', 'n.name', 'm.name']
self.check_column_names(resp, columns_name)
result = [
[PathVal([VERTICES["LeBron James"],
(EDGES["LeBron James"+"Ray Allen"+"like"+"0"], 1),
VERTICES["Ray Allen"]]),
"LeBron James", "Ray Allen"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Dejounte Murray"+"LeBron James"+"like"+"0"], -1),
VERTICES["Dejounte Murray"]]),
"LeBron James", "Dejounte Murray"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Carmelo Anthony"+"LeBron James"+"like"+"0"], -1),
VERTICES["Carmelo Anthony"]]),
"LeBron James", "Carmelo Anthony"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Kyrie Irving"+"LeBron James"+"like"+"0"], -1),
VERTICES["Kyrie Irving"]]),
"LeBron James", "Kyrie Irving"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Dwyane Wade"+"LeBron James"+"like"+"0"], -1),
VERTICES["Dwyane Wade"]]),
"LeBron James", "Dwyane Wade"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Danny Green"+"LeBron James"+"like"+"0"], -1),
VERTICES["Danny Green"]]),
"LeBron James", "Danny Green"],
[PathVal([VERTICES["LeBron James"],
(EDGES["Chris Paul"+"LeBron James"+"like"+"0"], -1),
VERTICES["Chris Paul"]]),
"LeBron James", "Chris Paul"],
]
self.check_out_of_order_result(resp, result)
stmt = 'MATCH p = (n:player{name:"LeBron James"})-[:like]->(m)-[:like]->(k) return p, n.name, m.name, k.name'
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
columns_name = ['p', 'n.name', 'm.name', 'k.name']
self.check_column_names(resp, columns_name)
result = [
[PathVal([VERTICES["LeBron James"],
(EDGES["LeBron James"+"Ray Allen"+"like"+"0"], 1),
VERTICES["Ray Allen"],
(EDGES["Ray Allen"+"Rajon Rondo"+"like"+"0"], 1),
VERTICES["Rajon Rondo"]]),
"LeBron James", "Ray Allen", "Rajon Rondo"]
]
self.check_out_of_order_result(resp, result)
def test_failures(self):
# No RETURN
stmt = 'MATCH (v:player{name:"abc")'
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment