Bug fixes in cypher_main_visitor and add create clause

Reviewers: teon.banek, florijan

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D143
This commit is contained in:
Mislav Bradac 2017-03-17 16:29:27 +01:00
parent 5e6aaf231d
commit 848d022c60
4 changed files with 268 additions and 177 deletions

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <map>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -13,6 +14,7 @@ class AstTreeStorage;
class Tree : public ::utils::Visitable<TreeVisitorBase> { class Tree : public ::utils::Visitable<TreeVisitorBase> {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
int uid() const { return uid_; } int uid() const { return uid_; }
@ -30,6 +32,7 @@ class Expression : public Tree {
class Identifier : public Expression { class Identifier : public Expression {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
DEFVISITABLE(TreeVisitorBase); DEFVISITABLE(TreeVisitorBase);
std::string name_; std::string name_;
@ -40,6 +43,7 @@ class Identifier : public Expression {
class PropertyLookup : public Expression { class PropertyLookup : public Expression {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
@ -57,13 +61,13 @@ class PropertyLookup : public Expression {
// between the two depending on Expression result // between the two depending on Expression result
protected: protected:
PropertyLookup(int uid, Expression* expression, PropertyLookup(int uid, Expression *expression, GraphDb::Property property)
GraphDb::Property property)
: Expression(uid), expression_(expression), property_(property) {} : Expression(uid), expression_(expression), property_(property) {}
}; };
class NamedExpression : public Tree { class NamedExpression : public Tree {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
@ -72,18 +76,20 @@ class NamedExpression : public Tree {
} }
std::string name_; std::string name_;
Expression* expression_ = nullptr; Expression *expression_ = nullptr;
protected: protected:
NamedExpression(int uid) : Tree(uid) {} NamedExpression(int uid) : Tree(uid) {}
NamedExpression(int uid, std::string name, Expression *expression) : NamedExpression(int uid, std::string name, Expression *expression)
Tree(uid), name_(name), expression_(expression) {} : Tree(uid), name_(name), expression_(expression) {}
}; };
class PatternAtom : public Tree { class PatternAtom : public Tree {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
Identifier* identifier_ = nullptr; Identifier *identifier_ = nullptr;
protected: protected:
PatternAtom(int uid) : Tree(uid) {} PatternAtom(int uid) : Tree(uid) {}
PatternAtom(int uid, Identifier *identifier) PatternAtom(int uid, Identifier *identifier)
@ -92,6 +98,7 @@ class PatternAtom : public Tree {
class NodeAtom : public PatternAtom { class NodeAtom : public PatternAtom {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
@ -100,7 +107,8 @@ class NodeAtom : public PatternAtom {
} }
std::vector<GraphDb::Label> labels_; std::vector<GraphDb::Label> labels_;
std::map<GraphDb::Property, Expression*> properties_; // TODO: change to unordered_map
std::map<GraphDb::Property, Expression *> properties_;
protected: protected:
using PatternAtom::PatternAtom; using PatternAtom::PatternAtom;
@ -108,6 +116,7 @@ class NodeAtom : public PatternAtom {
class EdgeAtom : public PatternAtom { class EdgeAtom : public PatternAtom {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
enum class Direction { LEFT, RIGHT, BOTH }; enum class Direction { LEFT, RIGHT, BOTH };
@ -119,6 +128,8 @@ class EdgeAtom : public PatternAtom {
Direction direction_ = Direction::BOTH; Direction direction_ = Direction::BOTH;
std::vector<GraphDb::EdgeType> types_; std::vector<GraphDb::EdgeType> types_;
// TODO: change to unordered_map
std::map<GraphDb::Property, Expression *> properties_;
protected: protected:
using PatternAtom::PatternAtom; using PatternAtom::PatternAtom;
@ -126,12 +137,14 @@ class EdgeAtom : public PatternAtom {
class Clause : public Tree { class Clause : public Tree {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
Clause(int uid) : Tree(uid) {} Clause(int uid) : Tree(uid) {}
}; };
class Pattern : public Tree { class Pattern : public Tree {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
@ -140,8 +153,8 @@ class Pattern : public Tree {
} }
visitor.PostVisit(*this); visitor.PostVisit(*this);
} }
Identifier* identifier_ = nullptr; Identifier *identifier_ = nullptr;
std::vector<PatternAtom*> atoms_; std::vector<PatternAtom *> atoms_;
protected: protected:
Pattern(int uid) : Tree(uid) {} Pattern(int uid) : Tree(uid) {}
@ -149,6 +162,7 @@ class Pattern : public Tree {
class Query : public Tree { class Query : public Tree {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
@ -157,16 +171,18 @@ class Query : public Tree {
} }
visitor.PostVisit(*this); visitor.PostVisit(*this);
} }
std::vector<Clause*> clauses_; std::vector<Clause *> clauses_;
protected: protected:
Query(int uid) : Tree(uid) {} Query(int uid) : Tree(uid) {}
}; };
class Create : public Clause { class Create : public Clause {
friend class AstTreeStorage;
public: public:
Create(int uid) : Clause(uid) {} Create(int uid) : Clause(uid) {}
std::vector<Pattern*> patterns_; std::vector<Pattern *> patterns_;
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
for (auto &pattern : patterns_) { for (auto &pattern : patterns_) {
@ -178,8 +194,9 @@ class Create : public Clause {
class Match : public Clause { class Match : public Clause {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
std::vector<Pattern*> patterns_; std::vector<Pattern *> patterns_;
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
for (auto &pattern : patterns_) { for (auto &pattern : patterns_) {
@ -194,6 +211,7 @@ class Match : public Clause {
class Return : public Clause { class Return : public Clause {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
void Accept(TreeVisitorBase &visitor) override { void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this); visitor.Visit(*this);
@ -202,7 +220,7 @@ class Return : public Clause {
} }
visitor.PostVisit(*this); visitor.PostVisit(*this);
} }
std::vector<NamedExpression*> named_expressions_; std::vector<NamedExpression *> named_expressions_;
protected: protected:
Return(int uid) : Clause(uid) {} Return(int uid) : Clause(uid) {}
@ -215,14 +233,12 @@ class AstTreeStorage {
friend class AstTreeStorage; friend class AstTreeStorage;
public: public:
AstTreeStorage() { AstTreeStorage() { storage_.emplace_back(new Query(next_uid_++)); }
storage_.emplace_back(new Query(next_uid_++));
}
AstTreeStorage(const AstTreeStorage &) = delete; AstTreeStorage(const AstTreeStorage &) = delete;
AstTreeStorage &operator=(const AstTreeStorage &) = delete; AstTreeStorage &operator=(const AstTreeStorage &) = delete;
template<typename T, typename... Args> template <typename T, typename... Args>
T *Create(Args&&... args) { T *Create(Args &&... args) {
// Never call create for a Query. Call query() instead. // Never call create for a Query. Call query() instead.
static_assert(!std::is_same<T, Query>::value, "Call query() instead"); static_assert(!std::is_same<T, Query>::value, "Call query() instead");
// TODO: use std::forward here // TODO: use std::forward here
@ -231,7 +247,7 @@ class AstTreeStorage {
return p; return p;
} }
Query *query() { return dynamic_cast<Query*>(storage_[0].get()); } Query *query() { return dynamic_cast<Query *>(storage_[0].get()); }
private: private:
int next_uid_ = 0; int next_uid_ = 0;

View File

@ -41,8 +41,8 @@ namespace {
const std::string CypherMainVisitor::kAnonPrefix = "anon"; const std::string CypherMainVisitor::kAnonPrefix = "anon";
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitSingleQuery(
CypherMainVisitor::visitSingleQuery(CypherParser::SingleQueryContext *ctx) { CypherParser::SingleQueryContext *ctx) {
query_ = storage_.query(); query_ = storage_.query();
for (auto *child : ctx->clause()) { for (auto *child : ctx->clause()) {
query_->clauses_.push_back(child->accept(this)); query_->clauses_.push_back(child->accept(this));
@ -68,12 +68,15 @@ antlrcpp::Any CypherMainVisitor::visitClause(CypherParser::ClauseContext *ctx) {
if (ctx->cypherMatch()) { if (ctx->cypherMatch()) {
return (Clause *)ctx->cypherMatch()->accept(this).as<Match *>(); return (Clause *)ctx->cypherMatch()->accept(this).as<Match *>();
} }
if (ctx->create()) {
return (Clause *)ctx->create()->accept(this).as<Create *>();
}
throw std::exception(); throw std::exception();
return visitChildren(ctx); return visitChildren(ctx);
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitCypherMatch(
CypherMainVisitor::visitCypherMatch(CypherParser::CypherMatchContext *ctx) { CypherParser::CypherMatchContext *ctx) {
auto *match = storage_.Create<Match>(); auto *match = storage_.Create<Match>();
if (ctx->OPTIONAL() || ctx->where()) { if (ctx->OPTIONAL() || ctx->where()) {
throw std::exception(); throw std::exception();
@ -82,24 +85,31 @@ CypherMainVisitor::visitCypherMatch(CypherParser::CypherMatchContext *ctx) {
return match; return match;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitCreate(CypherParser::CreateContext *ctx) {
CypherMainVisitor::visitCypherReturn(CypherParser::CypherReturnContext *ctx) { auto *create = storage_.Create<Create>();
create->patterns_ = ctx->pattern()->accept(this).as<std::vector<Pattern *>>();
return create;
;
}
antlrcpp::Any CypherMainVisitor::visitCypherReturn(
CypherParser::CypherReturnContext *ctx) {
if (ctx->DISTINCT()) { if (ctx->DISTINCT()) {
throw std::exception(); throw std::exception();
} }
return visitChildren(ctx); return visitChildren(ctx);
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitReturnBody(
CypherMainVisitor::visitReturnBody(CypherParser::ReturnBodyContext *ctx) { CypherParser::ReturnBodyContext *ctx) {
if (ctx->order() || ctx->skip() || ctx->limit()) { if (ctx->order() || ctx->skip() || ctx->limit()) {
throw std::exception(); throw std::exception();
} }
return ctx->returnItems()->accept(this); return ctx->returnItems()->accept(this);
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitReturnItems(
CypherMainVisitor::visitReturnItems(CypherParser::ReturnItemsContext *ctx) { CypherParser::ReturnItemsContext *ctx) {
auto *return_clause = storage_.Create<Return>(); auto *return_clause = storage_.Create<Return>();
if (ctx->getTokens(kReturnAllTokenId).size()) { if (ctx->getTokens(kReturnAllTokenId).size()) {
throw std::exception(); throw std::exception();
@ -110,8 +120,8 @@ CypherMainVisitor::visitReturnItems(CypherParser::ReturnItemsContext *ctx) {
return return_clause; return return_clause;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitReturnItem(
CypherMainVisitor::visitReturnItem(CypherParser::ReturnItemContext *ctx) { CypherParser::ReturnItemContext *ctx) {
auto *named_expr = storage_.Create<NamedExpression>(); auto *named_expr = storage_.Create<NamedExpression>();
if (ctx->variable()) { if (ctx->variable()) {
named_expr->name_ = named_expr->name_ =
@ -124,8 +134,8 @@ CypherMainVisitor::visitReturnItem(CypherParser::ReturnItemContext *ctx) {
return named_expr; return named_expr;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitNodePattern(
CypherMainVisitor::visitNodePattern(CypherParser::NodePatternContext *ctx) { CypherParser::NodePatternContext *ctx) {
auto *node = storage_.Create<NodeAtom>(); auto *node = storage_.Create<NodeAtom>();
if (ctx->variable()) { if (ctx->variable()) {
std::string variable = ctx->variable()->accept(this); std::string variable = ctx->variable()->accept(this);
@ -139,17 +149,15 @@ CypherMainVisitor::visitNodePattern(CypherParser::NodePatternContext *ctx) {
ctx->nodeLabels()->accept(this).as<std::vector<GraphDb::Label>>(); ctx->nodeLabels()->accept(this).as<std::vector<GraphDb::Label>>();
} }
if (ctx->properties()) { if (ctx->properties()) {
throw std::exception(); node->properties_ = ctx->properties()
// node.properties = ctx->properties() ->accept(this)
// ->accept(this) .as<std::map<GraphDb::Property, Expression *>>();
// .as<std::unordered_map<std::string,
// std::string>>();
} }
return node; return node;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitNodeLabels(
CypherMainVisitor::visitNodeLabels(CypherParser::NodeLabelsContext *ctx) { CypherParser::NodeLabelsContext *ctx) {
std::vector<GraphDb::Label> labels; std::vector<GraphDb::Label> labels;
for (auto *node_label : ctx->nodeLabel()) { for (auto *node_label : ctx->nodeLabel()) {
labels.push_back(ctx_.db_accessor_.label(node_label->accept(this))); labels.push_back(ctx_.db_accessor_.label(node_label->accept(this)));
@ -157,31 +165,35 @@ CypherMainVisitor::visitNodeLabels(CypherParser::NodeLabelsContext *ctx) {
return labels; return labels;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitProperties(
CypherMainVisitor::visitProperties(CypherParser::PropertiesContext *ctx) { CypherParser::PropertiesContext *ctx) {
if (!ctx->mapLiteral()) { if (!ctx->mapLiteral()) {
// If child is not mapLiteral that means child is params. At the moment // If child is not mapLiteral that means child is params. At the moment
// memgraph doesn't support params. // we don't support properties to be a param because we can generate
// better logical plan if we have an information about properties at
// compile time.
throw std::exception(); throw std::exception();
} }
return ctx->mapLiteral()->accept(this); return ctx->mapLiteral()->accept(this);
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitMapLiteral(
CypherMainVisitor::visitMapLiteral(CypherParser::MapLiteralContext *ctx) { CypherParser::MapLiteralContext *ctx) {
throw std::exception(); std::map<GraphDb::Property, Expression *> map;
(void)ctx; for (int i = 0; i < (int)ctx->propertyKeyName().size(); ++i) {
return 0; map[ctx->propertyKeyName()[i]->accept(this)] =
// std::unordered_map<std::string, std::string> map; ctx->expression()[i]->accept(this);
// for (int i = 0; i < (int)ctx->propertyKeyName().size(); ++i) { }
// map[ctx->propertyKeyName()[i]->accept(this).as<std::string>()] = return map;
// ctx->expression()[i]->accept(this).as<std::string>();
// }
// return map;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitPropertyKeyName(
CypherMainVisitor::visitSymbolicName(CypherParser::SymbolicNameContext *ctx) { CypherParser::PropertyKeyNameContext *ctx) {
return ctx_.db_accessor_.property(visitChildren(ctx));
}
antlrcpp::Any CypherMainVisitor::visitSymbolicName(
CypherParser::SymbolicNameContext *ctx) {
if (ctx->EscapedSymbolicName()) { if (ctx->EscapedSymbolicName()) {
// We don't allow at this point for variable to be EscapedSymbolicName // We don't allow at this point for variable to be EscapedSymbolicName
// because we would have t ofigure out how escaping works since same // because we would have t ofigure out how escaping works since same
@ -192,8 +204,8 @@ CypherMainVisitor::visitSymbolicName(CypherParser::SymbolicNameContext *ctx) {
return std::string(ctx->getText()); return std::string(ctx->getText());
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitPattern(
CypherMainVisitor::visitPattern(CypherParser::PatternContext *ctx) { CypherParser::PatternContext *ctx) {
std::vector<Pattern *> patterns; std::vector<Pattern *> patterns;
for (auto *pattern_part : ctx->patternPart()) { for (auto *pattern_part : ctx->patternPart()) {
patterns.push_back(pattern_part->accept(this)); patterns.push_back(pattern_part->accept(this));
@ -201,8 +213,8 @@ CypherMainVisitor::visitPattern(CypherParser::PatternContext *ctx) {
return patterns; return patterns;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitPatternPart(
CypherMainVisitor::visitPatternPart(CypherParser::PatternPartContext *ctx) { CypherParser::PatternPartContext *ctx) {
Pattern *pattern = ctx->anonymousPatternPart()->accept(this); Pattern *pattern = ctx->anonymousPatternPart()->accept(this);
if (ctx->variable()) { if (ctx->variable()) {
std::string variable = ctx->variable()->accept(this); std::string variable = ctx->variable()->accept(this);
@ -298,8 +310,8 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipTypes(
return types; return types;
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitRangeLiteral(
CypherMainVisitor::visitRangeLiteral(CypherParser::RangeLiteralContext *ctx) { CypherParser::RangeLiteralContext *ctx) {
if (ctx->integerLiteral().size() == 0U) { if (ctx->integerLiteral().size() == 0U) {
// -[*]- // -[*]-
return std::pair<int64_t, int64_t>(1LL, LLONG_MAX); return std::pair<int64_t, int64_t>(1LL, LLONG_MAX);
@ -326,8 +338,8 @@ CypherMainVisitor::visitRangeLiteral(CypherParser::RangeLiteralContext *ctx) {
} }
} }
antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitExpression(
CypherMainVisitor::visitExpression(CypherParser::ExpressionContext *ctx) { CypherParser::ExpressionContext *ctx) {
return visitChildren(ctx); return visitChildren(ctx);
} }
@ -504,23 +516,22 @@ CypherMainVisitor::visitExpression(CypherParser::ExpressionContext *ctx) {
// } // }
// return visitChildren(ctx); // return visitChildren(ctx);
//} //}
//
// antlrcpp::Any antlrcpp::Any CypherMainVisitor::visitExpression2(
// CypherMainVisitor::visitExpression2(CypherParser::Expression2Context *ctx) { CypherParser::Expression2Context *ctx) {
// if (ctx->nodeLabels().size()) { if (ctx->nodeLabels().size()) {
// // TODO: Implement this. We don't currently support label checking in // TODO: Implement this. We don't currently support label checking in
// // expresssion. // expresssion.
// throw SemanticException(); throw std::exception();
// } }
// auto operand = ctx->atom()->accept(this).as<std::string>(); Expression *expression = ctx->atom()->accept(this);
// for (int i = 0; i < (int)ctx->propertyLookup().size(); ++i) { for (auto *lookup : ctx->propertyLookup()) {
// auto lhs_id = new_id(); auto property_lookup =
// symbol_table_[lhs_id] = storage_.Create<PropertyLookup>(expression, lookup->accept(this));
// SimpleExpression{Function::PROPERTY_GETTER, {operand}}; expression = property_lookup;
// operand = lhs_id; }
// } return expression;
// return operand; }
//}
antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) { antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
if (ctx->literal()) { if (ctx->literal()) {
@ -555,7 +566,7 @@ antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
} else if (ctx->variable()) { } else if (ctx->variable()) {
std::string variable = ctx->variable()->accept(this); std::string variable = ctx->variable()->accept(this);
users_identifiers.insert(variable); users_identifiers.insert(variable);
return storage_.Create<Identifier>(variable); return (Expression *)storage_.Create<Identifier>(variable);
} }
// TODO: Implement this. We don't support comprehensions, functions, // TODO: Implement this. We don't support comprehensions, functions,
// filtering... at the moment. // filtering... at the moment.

View File

@ -15,10 +15,10 @@ using query::Context;
using antlropencypher::CypherParser; using antlropencypher::CypherParser;
class CypherMainVisitor : public antlropencypher::CypherBaseVisitor { class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
public: public:
CypherMainVisitor(Context &ctx) : ctx_(ctx) {} CypherMainVisitor(Context &ctx) : ctx_(ctx) {}
private: private:
// template <typename TExpression> // template <typename TExpression>
// antlrcpp::Any // antlrcpp::Any
// LeftAssociativeOperatorExpression(std::vector<TExpression *> children, // LeftAssociativeOperatorExpression(std::vector<TExpression *> children,
@ -49,90 +49,109 @@ private:
// children, std::vector<Function>((int)children.size() - 1, op)); // children, std::vector<Function>((int)children.size() - 1, op));
// } // }
antlrcpp::Any /**
visitSingleQuery(CypherParser::SingleQueryContext *ctx) override; * @return Query*
*/
antlrcpp::Any visitSingleQuery(
CypherParser::SingleQueryContext *ctx) override;
/**
* @return Clause*
*/
antlrcpp::Any visitClause(CypherParser::ClauseContext *ctx) override; antlrcpp::Any visitClause(CypherParser::ClauseContext *ctx) override;
antlrcpp::Any /**
visitCypherMatch(CypherParser::CypherMatchContext *ctx) override; * @return Match*
*/
antlrcpp::Any visitCypherMatch(
CypherParser::CypherMatchContext *ctx) override;
antlrcpp::Any /**
visitCypherReturn(CypherParser::CypherReturnContext *ctx) override; * @return Create*
*/
antlrcpp::Any visitCreate(CypherParser::CreateContext *ctx) override;
/**
* @return Return*
*/
antlrcpp::Any visitCypherReturn(
CypherParser::CypherReturnContext *ctx) override;
/**
* @return Return*
*/
antlrcpp::Any visitReturnBody(CypherParser::ReturnBodyContext *ctx) override; antlrcpp::Any visitReturnBody(CypherParser::ReturnBodyContext *ctx) override;
antlrcpp::Any /**
visitReturnItems(CypherParser::ReturnItemsContext *ctx) override; * @return Return*
*/
antlrcpp::Any visitReturnItems(
CypherParser::ReturnItemsContext *ctx) override;
/**
* @return NamedExpression*
*/
antlrcpp::Any visitReturnItem(CypherParser::ReturnItemContext *ctx) override; antlrcpp::Any visitReturnItem(CypherParser::ReturnItemContext *ctx) override;
/** /**
* Creates Node and stores it in symbol_table_. If variable is defined it is * @return NodeAtom*
* stored in ids_map_. */
* antlrcpp::Any visitNodePattern(
* @return string - node id. CypherParser::NodePatternContext *ctx) override;
*/
antlrcpp::Any
visitNodePattern(CypherParser::NodePatternContext *ctx) override;
/** /**
* @return vector<string> labels. * @return vector<GraphDb::Label>
*/ */
antlrcpp::Any visitNodeLabels(CypherParser::NodeLabelsContext *ctx) override; antlrcpp::Any visitNodeLabels(CypherParser::NodeLabelsContext *ctx) override;
/** /**
* @return unordered_map<string, string> properties - property key to * @return unordered_map<GraphDb::Property, Expression*>
* expression id. */
*/
antlrcpp::Any visitProperties(CypherParser::PropertiesContext *ctx) override; antlrcpp::Any visitProperties(CypherParser::PropertiesContext *ctx) override;
/** /**
* @return unordered_map<string, string> map - key to expression id. * @return unordered_map<GraphDb::Property, Expression*>
*/ */
antlrcpp::Any visitMapLiteral(CypherParser::MapLiteralContext *ctx) override; antlrcpp::Any visitMapLiteral(CypherParser::MapLiteralContext *ctx) override;
/** /**
* @return string. * @return GraphDb::Property
*/ */
antlrcpp::Any antlrcpp::Any visitPropertyKeyName(
visitSymbolicName(CypherParser::SymbolicNameContext *ctx) override; CypherParser::PropertyKeyNameContext *ctx) override;
/** /**
* @return vector<PatternPart> pattern. * @return string
*/ */
antlrcpp::Any visitSymbolicName(
CypherParser::SymbolicNameContext *ctx) override;
/**
* @return vector<Pattern*>
*/
antlrcpp::Any visitPattern(CypherParser::PatternContext *ctx) override; antlrcpp::Any visitPattern(CypherParser::PatternContext *ctx) override;
/** /**
* Stores PatternPart in symbol_table_. If variable is defined it is stored * @return Pattern*
*in */
* ids_map_. antlrcpp::Any visitPatternPart(
* CypherParser::PatternPartContext *ctx) override;
* @return string - pattern part id.
*/
antlrcpp::Any
visitPatternPart(CypherParser::PatternPartContext *ctx) override;
/** /**
* Creates PatternPart. * @return Pattern*
* */
* @return PatternPart. antlrcpp::Any visitPatternElement(
*/ CypherParser::PatternElementContext *ctx) override;
antlrcpp::Any
visitPatternElement(CypherParser::PatternElementContext *ctx) override;
/** /**
* @return pair<string, string> - node and relationship ids. * @return vector<pair<EdgeAtom*, NodeAtom*>>
*/ */
antlrcpp::Any visitPatternElementChain( antlrcpp::Any visitPatternElementChain(
CypherParser::PatternElementChainContext *ctx) override; CypherParser::PatternElementChainContext *ctx) override;
/** /**
* Creates Relationship and stores it in symbol_table_. If variable is defined *@return EdgeAtom*
* it is stored in symbol_table_. */
*
* @return string - relationship id.
*/
antlrcpp::Any visitRelationshipPattern( antlrcpp::Any visitRelationshipPattern(
CypherParser::RelationshipPatternContext *ctx) override; CypherParser::RelationshipPatternContext *ctx) override;
@ -142,23 +161,24 @@ private:
*/ */
antlrcpp::Any visitRelationshipDetail( antlrcpp::Any visitRelationshipDetail(
CypherParser::RelationshipDetailContext *ctx) override; CypherParser::RelationshipDetailContext *ctx) override;
/** /**
* @return vector<string>. * @return vector<GraphDb::EdgeType>
*/ */
antlrcpp::Any antlrcpp::Any visitRelationshipTypes(
visitRelationshipTypes(CypherParser::RelationshipTypesContext *ctx) override; CypherParser::RelationshipTypesContext *ctx) override;
/** /**
* @return pair<int64_t, int64_t>. * @return pair<int64_t, int64_t>.
*/ */
antlrcpp::Any antlrcpp::Any visitRangeLiteral(
visitRangeLiteral(CypherParser::RangeLiteralContext *ctx) override; CypherParser::RangeLiteralContext *ctx) override;
/** /**
* Top level expression. * Top level expression, does nothing.
* *
* @return string - expression id. * @return Expression*
*/ */
antlrcpp::Any visitExpression(CypherParser::ExpressionContext *ctx) override; antlrcpp::Any visitExpression(CypherParser::ExpressionContext *ctx) override;
///** ///**
@ -248,18 +268,18 @@ private:
// antlrcpp::Any // antlrcpp::Any
// visitExpression3(CypherParser::Expression3Context *ctx) override; // visitExpression3(CypherParser::Expression3Context *ctx) override;
///** /**
//* Property lookup, test for node labels existence... * Property lookup, test for node labels existence...
//* *
//* @return string - expression id. * @return Expression*
//*/ */
// antlrcpp::Any antlrcpp::Any visitExpression2(
// visitExpression2(CypherParser::Expression2Context *ctx) override; CypherParser::Expression2Context *ctx) override;
/** /**
* Literals, params, list comprehension... * Literals, params, list comprehension...
* *
* @return string - expression id. * @return Expression*
*/ */
antlrcpp::Any visitAtom(CypherParser::AtomContext *ctx) override; antlrcpp::Any visitAtom(CypherParser::AtomContext *ctx) override;
@ -285,14 +305,14 @@ private:
/** /**
* @return int64_t. * @return int64_t.
*/ */
antlrcpp::Any antlrcpp::Any visitIntegerLiteral(
visitIntegerLiteral(CypherParser::IntegerLiteralContext *ctx) override; CypherParser::IntegerLiteralContext *ctx) override;
public: public:
Query *query() { return query_; } Query *query() { return query_; }
const static std::string kAnonPrefix; const static std::string kAnonPrefix;
private: private:
Context &ctx_; Context &ctx_;
// Set of identifiers from queries. // Set of identifiers from queries.
std::unordered_set<std::string> users_identifiers; std::unordered_set<std::string> users_identifiers;

View File

@ -7,10 +7,10 @@
#include "antlr4-runtime.h" #include "antlr4-runtime.h"
#include "dbms/dbms.hpp" #include "dbms/dbms.hpp"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "query/context.hpp" #include "query/context.hpp"
#include "query/frontend/ast/cypher_main_visitor.hpp" #include "query/frontend/ast/cypher_main_visitor.hpp"
#include "query/frontend/opencypher/parser.hpp" #include "query/frontend/opencypher/parser.hpp"
#include "gtest/gtest.h"
namespace { namespace {
@ -19,11 +19,15 @@ using namespace query::frontend;
using testing::UnorderedElementsAre; using testing::UnorderedElementsAre;
class AstGenerator { class AstGenerator {
public: public:
AstGenerator(const std::string &query) AstGenerator(const std::string &query)
: dbms_(), db_accessor_(dbms_.active()), : dbms_(),
context_(Config{}, *db_accessor_), query_string_(query), parser_(query), db_accessor_(dbms_.active()),
visitor_(context_), query_([&]() { context_(Config{}, *db_accessor_),
query_string_(query),
parser_(query),
visitor_(context_),
query_([&]() {
visitor_.visit(parser_.tree()); visitor_.visit(parser_.tree());
return visitor_.query(); return visitor_.query();
}()) {} }()) {}
@ -37,11 +41,11 @@ public:
Query *query_; Query *query_;
}; };
TEST(CompilerStructuresTest, SyntaxException) { TEST(CypherMainVisitorTest, SyntaxException) {
ASSERT_THROW(AstGenerator("CREATE ()-[*1...2]-()"), std::exception); ASSERT_THROW(AstGenerator("CREATE ()-[*1...2]-()"), std::exception);
} }
TEST(CompilerStructuresTest, NodePattern) { TEST(CypherMainVisitorTest, NodePattern) {
AstGenerator ast_generator("MATCH (:label1:label2:label3)"); AstGenerator ast_generator("MATCH (:label1:label2:label3)");
auto *query = ast_generator.query_; auto *query = ast_generator.query_;
ASSERT_EQ(query->clauses_.size(), 1U); ASSERT_EQ(query->clauses_.size(), 1U);
@ -62,7 +66,7 @@ TEST(CompilerStructuresTest, NodePattern) {
// TODO: add test for properties. // TODO: add test for properties.
} }
TEST(CompilerStructuresTest, NodePatternIdentifier) { TEST(CypherMainVisitorTest, NodePatternIdentifier) {
AstGenerator ast_generator("MATCH (var)"); AstGenerator ast_generator("MATCH (var)");
auto *query = ast_generator.query_; auto *query = ast_generator.query_;
auto *match = dynamic_cast<Match *>(query->clauses_[0]); auto *match = dynamic_cast<Match *>(query->clauses_[0]);
@ -73,7 +77,7 @@ TEST(CompilerStructuresTest, NodePatternIdentifier) {
// TODO: add test for properties. // TODO: add test for properties.
} }
TEST(CompilerStructuresTest, RelationshipPatternNoDetails) { TEST(CypherMainVisitorTest, RelationshipPatternNoDetails) {
AstGenerator ast_generator("MATCH ()--()"); AstGenerator ast_generator("MATCH ()--()");
auto *query = ast_generator.query_; auto *query = ast_generator.query_;
auto *match = dynamic_cast<Match *>(query->clauses_[0]); auto *match = dynamic_cast<Match *>(query->clauses_[0]);
@ -92,7 +96,7 @@ TEST(CompilerStructuresTest, RelationshipPatternNoDetails) {
CypherMainVisitor::kAnonPrefix + std::to_string(2)); CypherMainVisitor::kAnonPrefix + std::to_string(2));
} }
TEST(CompilerStructuresTest, RelationshipPatternDetails) { TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
AstGenerator ast_generator("MATCH ()<-[:type1|type2]-()"); AstGenerator ast_generator("MATCH ()<-[:type1|type2]-()");
auto *query = ast_generator.query_; auto *query = ast_generator.query_;
auto *match = dynamic_cast<Match *>(query->clauses_[0]); auto *match = dynamic_cast<Match *>(query->clauses_[0]);
@ -105,7 +109,7 @@ TEST(CompilerStructuresTest, RelationshipPatternDetails) {
// TODO: test properties // TODO: test properties
} }
TEST(CompilerStructuresTest, RelationshipPatternVariable) { TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
AstGenerator ast_generator("MATCH ()-[var]->()"); AstGenerator ast_generator("MATCH ()-[var]->()");
auto *query = ast_generator.query_; auto *query = ast_generator.query_;
auto *match = dynamic_cast<Match *>(query->clauses_[0]); auto *match = dynamic_cast<Match *>(query->clauses_[0]);
@ -116,7 +120,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
} }
// // Relationship with unbounded variable range. // // Relationship with unbounded variable range.
// TEST(CompilerStructuresTest, RelationshipPatternUnbounded) { // TEST(CypherMainVisitorTest, RelationshipPatternUnbounded) {
// ParserTables parser("CREATE ()-[*]-()"); // ParserTables parser("CREATE ()-[*]-()");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
@ -126,7 +130,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // Relationship with lower bounded variable range. // // Relationship with lower bounded variable range.
// TEST(CompilerStructuresTest, RelationshipPatternLowerBounded) { // TEST(CypherMainVisitorTest, RelationshipPatternLowerBounded) {
// ParserTables parser("CREATE ()-[*5..]-()"); // ParserTables parser("CREATE ()-[*5..]-()");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
@ -136,7 +140,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // Relationship with upper bounded variable range. // // Relationship with upper bounded variable range.
// TEST(CompilerStructuresTest, RelationshipPatternUpperBounded) { // TEST(CypherMainVisitorTest, RelationshipPatternUpperBounded) {
// ParserTables parser("CREATE ()-[*..10]-()"); // ParserTables parser("CREATE ()-[*..10]-()");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
@ -145,7 +149,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // Relationship with lower and upper bounded variable range. // // Relationship with lower and upper bounded variable range.
// TEST(CompilerStructuresTest, RelationshipPatternLowerUpperBounded) { // TEST(CypherMainVisitorTest, RelationshipPatternLowerUpperBounded) {
// ParserTables parser("CREATE ()-[*5..10]-()"); // ParserTables parser("CREATE ()-[*5..10]-()");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
@ -154,7 +158,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // Relationship with fixed number of edges. // // Relationship with fixed number of edges.
// TEST(CompilerStructuresTest, RelationshipPatternFixedRange) { // TEST(CypherMainVisitorTest, RelationshipPatternFixedRange) {
// ParserTables parser("CREATE ()-[*10]-()"); // ParserTables parser("CREATE ()-[*10]-()");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
@ -163,15 +167,14 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // Relationship with invalid bound (larger than long long). // // Relationship with invalid bound (larger than long long).
// TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) { // TEST(CypherMainVisitorTest, RelationshipPatternInvalidBound) {
// ASSERT_THROW( // ASSERT_THROW(
// ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"), // ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"),
// SemanticException); // SemanticException);
// } // }
// //
//
// // PatternPart. // // PatternPart.
// TEST(CompilerStructuresTest, PatternPart) { // TEST(CypherMainVisitorTest, PatternPart) {
// ParserTables parser("CREATE ()--()"); // ParserTables parser("CREATE ()--()");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
@ -182,7 +185,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // PatternPart in braces. // // PatternPart in braces.
// TEST(CompilerStructuresTest, PatternPartBraces) { // TEST(CypherMainVisitorTest, PatternPartBraces) {
// ParserTables parser("CREATE ((()--()))"); // ParserTables parser("CREATE ((()--()))");
// ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
// ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
@ -193,7 +196,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // PatternPart with variable. // // PatternPart with variable.
// TEST(CompilerStructuresTest, PatternPartVariable) { // TEST(CypherMainVisitorTest, PatternPartVariable) {
// ParserTables parser("CREATE var=()--()"); // ParserTables parser("CREATE var=()--()");
// ASSERT_EQ(parser.identifiers_map_.size(), 1U); // ASSERT_EQ(parser.identifiers_map_.size(), 1U);
// ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
@ -209,8 +212,49 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
// } // }
// //
// // Multiple nodes with same variable and properties. // // Multiple nodes with same variable and properties.
// TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) { // TEST(CypherMainVisitorTest, MultipleNodesWithVariableAndProperties) {
// ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"), // ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"),
// SemanticException); // SemanticException);
// } // }
TEST(CypherMainVisitorTest, ReturnUnanemdIdentifier) {
AstGenerator ast_generator("RETURN var");
auto *query = ast_generator.query_;
ASSERT_EQ(query->clauses_.size(), 1U);
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
ASSERT_TRUE(return_clause);
ASSERT_EQ(return_clause->named_expressions_.size(), 1U);
auto *named_expr = return_clause->named_expressions_[0];
ASSERT_TRUE(named_expr);
ASSERT_EQ(named_expr->name_, "var");
auto *identifier = dynamic_cast<Identifier *>(named_expr->expression_);
ASSERT_TRUE(identifier);
ASSERT_EQ(identifier->name_, "var");
}
TEST(CypherMainVisitorTest, ReturnNamedIdentifier) {
AstGenerator ast_generator("RETURN var AS var5");
auto *query = ast_generator.query_;
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *named_expr = return_clause->named_expressions_[0];
ASSERT_EQ(named_expr->name_, "var5");
auto *identifier = dynamic_cast<Identifier *>(named_expr->expression_);
ASSERT_EQ(identifier->name_, "var");
}
TEST(CypherMainVisitorTest, Create) {
AstGenerator ast_generator("CREATE (n)");
auto *query = ast_generator.query_;
ASSERT_EQ(query->clauses_.size(), 1U);
auto *create = dynamic_cast<Create *>(query->clauses_[0]);
ASSERT_TRUE(create);
ASSERT_EQ(create->patterns_.size(), 1U);
ASSERT_TRUE(create->patterns_[0]);
ASSERT_EQ(create->patterns_[0]->atoms_.size(), 1U);
auto node = dynamic_cast<NodeAtom *>(create->patterns_[0]->atoms_[0]);
ASSERT_TRUE(node);
ASSERT_TRUE(node->identifier_);
ASSERT_EQ(node->identifier_->name_, "n");
// TODO: add test for properties.
}
} }