Add SET conversion from low to highlevel ast
Reviewers: teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D192
This commit is contained in:
parent
7c36529aec
commit
e40bd83636
src/query/frontend
ast
opencypher/grammar
tests/unit
@ -593,6 +593,7 @@ class SetProperties : public Clause {
|
||||
}
|
||||
Identifier *identifier_ = nullptr;
|
||||
Expression *expression_ = nullptr;
|
||||
bool update_ = false;
|
||||
|
||||
protected:
|
||||
SetProperties(int uid) : Clause(uid) {}
|
||||
|
@ -22,7 +22,14 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery(
|
||||
CypherParser::SingleQueryContext *ctx) {
|
||||
query_ = storage_.query();
|
||||
for (auto *child : ctx->clause()) {
|
||||
query_->clauses_.push_back(child->accept(this));
|
||||
antlrcpp::Any got = child->accept(this);
|
||||
if (got.is<Clause *>()) {
|
||||
query_->clauses_.push_back(got.as<Clause *>());
|
||||
} else {
|
||||
auto child_clauses = got.as<std::vector<Clause *>>();
|
||||
query_->clauses_.insert(query_->clauses_.end(), child_clauses.begin(),
|
||||
child_clauses.end());
|
||||
}
|
||||
}
|
||||
// Construct unique names for anonymous identifiers;
|
||||
int id = 1;
|
||||
@ -54,6 +61,10 @@ antlrcpp::Any CypherMainVisitor::visitClause(CypherParser::ClauseContext *ctx) {
|
||||
return static_cast<Clause *>(
|
||||
ctx->cypherDelete()->accept(this).as<Delete *>());
|
||||
}
|
||||
if (ctx->set()) {
|
||||
// Different return type!!!
|
||||
return ctx->set()->accept(this).as<std::vector<Clause *>>();
|
||||
}
|
||||
// TODO: implement other clauses.
|
||||
throw NotYetImplemented();
|
||||
return 0;
|
||||
@ -690,5 +701,57 @@ antlrcpp::Any CypherMainVisitor::visitWhere(CypherParser::WhereContext *ctx) {
|
||||
where->expression_ = ctx->expression()->accept(this);
|
||||
return where;
|
||||
}
|
||||
|
||||
antlrcpp::Any CypherMainVisitor::visitSet(CypherParser::SetContext *ctx) {
|
||||
std::vector<Clause *> set_items;
|
||||
for (auto *set_item : ctx->setItem()) {
|
||||
set_items.push_back(set_item->accept(this));
|
||||
}
|
||||
return set_items;
|
||||
}
|
||||
|
||||
antlrcpp::Any CypherMainVisitor::visitSetItem(
|
||||
CypherParser::SetItemContext *ctx) {
|
||||
// SetProperty
|
||||
if (ctx->propertyExpression()) {
|
||||
auto *set_property = storage_.Create<SetProperty>();
|
||||
set_property->property_lookup_ = ctx->propertyExpression()->accept(this);
|
||||
set_property->expression_ = ctx->expression()->accept(this);
|
||||
return static_cast<Clause *>(set_property);
|
||||
}
|
||||
|
||||
// SetProperties either assignment or update
|
||||
if (ctx->getTokens(kPropertyAssignmentTokenId).size() ||
|
||||
ctx->getTokens(kPropertyUpdateTokenId).size()) {
|
||||
auto *set_properties = storage_.Create<SetProperties>();
|
||||
set_properties->identifier_ = storage_.Create<Identifier>(
|
||||
ctx->variable()->accept(this).as<std::string>());
|
||||
set_properties->expression_ = ctx->expression()->accept(this);
|
||||
if (ctx->getTokens(kPropertyUpdateTokenId).size()) {
|
||||
set_properties->update_ = true;
|
||||
}
|
||||
return static_cast<Clause *>(set_properties);
|
||||
}
|
||||
|
||||
// SetLabels
|
||||
auto *set_labels = storage_.Create<SetLabels>();
|
||||
set_labels->identifier_ = storage_.Create<Identifier>(
|
||||
ctx->variable()->accept(this).as<std::string>());
|
||||
set_labels->labels_ =
|
||||
ctx->nodeLabels()->accept(this).as<std::vector<GraphDb::Label>>();
|
||||
return static_cast<Clause *>(set_labels);
|
||||
}
|
||||
|
||||
antlrcpp::Any CypherMainVisitor::visitPropertyExpression(
|
||||
CypherParser::PropertyExpressionContext *ctx) {
|
||||
Expression *expression = ctx->atom()->accept(this);
|
||||
for (auto *lookup : ctx->propertyLookup()) {
|
||||
auto property_lookup =
|
||||
storage_.Create<PropertyLookup>(expression, lookup->accept(this));
|
||||
expression = property_lookup;
|
||||
}
|
||||
// It is guaranteed by grammar that there is at least one propertyLookup.
|
||||
return dynamic_cast<PropertyLookup *>(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
|
||||
CypherParser::SingleQueryContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return Clause*
|
||||
* @return Clause* or vector<Clause*>!!!
|
||||
*/
|
||||
antlrcpp::Any visitClause(CypherParser::ClauseContext *ctx) override;
|
||||
|
||||
@ -389,8 +389,8 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
|
||||
CypherParser::NumberLiteralContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return int64_t
|
||||
*/
|
||||
* @return int64_t
|
||||
*/
|
||||
antlrcpp::Any visitIntegerLiteral(
|
||||
CypherParser::IntegerLiteralContext *ctx) override;
|
||||
|
||||
@ -411,6 +411,22 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
|
||||
*/
|
||||
antlrcpp::Any visitWhere(CypherParser::WhereContext *ctx) override;
|
||||
|
||||
/**
|
||||
* return vector<Clause*>
|
||||
*/
|
||||
antlrcpp::Any visitSet(CypherParser::SetContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return Clause*
|
||||
*/
|
||||
antlrcpp::Any visitSetItem(CypherParser::SetItemContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return PropertyLookup*
|
||||
*/
|
||||
antlrcpp::Any visitPropertyExpression(
|
||||
CypherParser::PropertyExpressionContext *ctx) override;
|
||||
|
||||
public:
|
||||
Query *query() { return query_; }
|
||||
const static std::string kAnonPrefix;
|
||||
|
@ -7,19 +7,21 @@ using antlropencypher::CypherParser;
|
||||
// List of unnamed tokens visitor needs to use. This should be reviewed on every
|
||||
// grammar change since even changes in ordering of rules will cause antlr to
|
||||
// generate different constants for unnamed tokens.
|
||||
const auto kReturnAllTokenId = CypherParser::T__4; // *
|
||||
const auto kDotsTokenId = CypherParser::T__11; // ..
|
||||
const auto kEqTokenId = CypherParser::T__2; // =
|
||||
const auto kNeTokenId1 = CypherParser::T__18; // <>
|
||||
const auto kNeTokenId2 = CypherParser::T__19; // !=
|
||||
const auto kLtTokenId = CypherParser::T__20; // <
|
||||
const auto kGtTokenId = CypherParser::T__21; // >
|
||||
const auto kLeTokenId = CypherParser::T__22; // <=
|
||||
const auto kGeTokenId = CypherParser::T__23; // >=
|
||||
const auto kPlusTokenId = CypherParser::T__12; // +
|
||||
const auto kMinusTokenId = CypherParser::T__13; // -
|
||||
const auto kMultTokenId = CypherParser::T__4; // *
|
||||
const auto kDivTokenId = CypherParser::T__14; // /
|
||||
const auto kModTokenId = CypherParser::T__15; // %
|
||||
const auto kUnaryPlusTokenId = CypherParser::T__12; // +
|
||||
const auto kUnaryMinusTokenId = CypherParser::T__13; // -
|
||||
const auto kReturnAllTokenId = CypherParser::T__4; // *
|
||||
const auto kDotsTokenId = CypherParser::T__11; // ..
|
||||
const auto kEqTokenId = CypherParser::T__2; // =
|
||||
const auto kNeTokenId1 = CypherParser::T__18; // <>
|
||||
const auto kNeTokenId2 = CypherParser::T__19; // !=
|
||||
const auto kLtTokenId = CypherParser::T__20; // <
|
||||
const auto kGtTokenId = CypherParser::T__21; // >
|
||||
const auto kLeTokenId = CypherParser::T__22; // <=
|
||||
const auto kGeTokenId = CypherParser::T__23; // >=
|
||||
const auto kPlusTokenId = CypherParser::T__12; // +
|
||||
const auto kMinusTokenId = CypherParser::T__13; // -
|
||||
const auto kMultTokenId = CypherParser::T__4; // *
|
||||
const auto kDivTokenId = CypherParser::T__14; // /
|
||||
const auto kModTokenId = CypherParser::T__15; // %
|
||||
const auto kUnaryPlusTokenId = CypherParser::T__12; // +
|
||||
const auto kUnaryMinusTokenId = CypherParser::T__13; // -
|
||||
const auto kPropertyAssignmentTokenId = CypherParser::T__2; // =
|
||||
const auto kPropertyUpdateTokenId = CypherParser::T__3; // +=
|
||||
|
@ -53,7 +53,7 @@ mergeAction : ( ON SP MATCH SP set )
|
||||
|
||||
create : CREATE SP? pattern ;
|
||||
|
||||
set : SET SP? setItem ( ',' setItem )* ;
|
||||
set : SET SP? setItem ( SP? ',' SP? setItem )* ;
|
||||
|
||||
setItem : ( propertyExpression SP? '=' SP? expression )
|
||||
| ( variable SP? '=' SP? expression )
|
||||
|
@ -615,4 +615,58 @@ TEST(Visitor, MatchWhere) {
|
||||
ASSERT_TRUE(identifier);
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
}
|
||||
|
||||
TEST(Visitor, Set) {
|
||||
AstGenerator ast_generator("SET a.x = b, c = d, e += f, g : h : i ");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 4U);
|
||||
|
||||
{
|
||||
auto *set_property = dynamic_cast<SetProperty *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(set_property);
|
||||
ASSERT_TRUE(set_property->property_lookup_);
|
||||
auto *identifier1 =
|
||||
dynamic_cast<Identifier *>(set_property->property_lookup_->expression_);
|
||||
ASSERT_TRUE(identifier1);
|
||||
ASSERT_EQ(identifier1->name_, "a");
|
||||
ASSERT_EQ(set_property->property_lookup_->property_,
|
||||
ast_generator.db_accessor_->property("x"));
|
||||
auto *identifier2 = dynamic_cast<Identifier *>(set_property->expression_);
|
||||
ASSERT_EQ(identifier2->name_, "b");
|
||||
}
|
||||
|
||||
{
|
||||
auto *set_properties_assignment =
|
||||
dynamic_cast<SetProperties *>(query->clauses_[1]);
|
||||
ASSERT_TRUE(set_properties_assignment);
|
||||
ASSERT_FALSE(set_properties_assignment->update_);
|
||||
ASSERT_TRUE(set_properties_assignment->identifier_);
|
||||
ASSERT_EQ(set_properties_assignment->identifier_->name_, "c");
|
||||
auto *identifier =
|
||||
dynamic_cast<Identifier *>(set_properties_assignment->expression_);
|
||||
ASSERT_EQ(identifier->name_, "d");
|
||||
}
|
||||
|
||||
{
|
||||
auto *set_properties_update =
|
||||
dynamic_cast<SetProperties *>(query->clauses_[2]);
|
||||
ASSERT_TRUE(set_properties_update);
|
||||
ASSERT_TRUE(set_properties_update->update_);
|
||||
ASSERT_TRUE(set_properties_update->identifier_);
|
||||
ASSERT_EQ(set_properties_update->identifier_->name_, "e");
|
||||
auto *identifier =
|
||||
dynamic_cast<Identifier *>(set_properties_update->expression_);
|
||||
ASSERT_EQ(identifier->name_, "f");
|
||||
}
|
||||
|
||||
{
|
||||
auto *set_labels = dynamic_cast<SetLabels *>(query->clauses_[3]);
|
||||
ASSERT_TRUE(set_labels);
|
||||
ASSERT_TRUE(set_labels->identifier_);
|
||||
ASSERT_EQ(set_labels->identifier_->name_, "g");
|
||||
ASSERT_THAT(set_labels->labels_,
|
||||
UnorderedElementsAre(ast_generator.db_accessor_->label("h"),
|
||||
ast_generator.db_accessor_->label("i")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user