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:
parent
5e6aaf231d
commit
848d022c60
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -13,6 +14,7 @@ class AstTreeStorage;
|
||||
|
||||
class Tree : public ::utils::Visitable<TreeVisitorBase> {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
int uid() const { return uid_; }
|
||||
|
||||
@ -30,6 +32,7 @@ class Expression : public Tree {
|
||||
|
||||
class Identifier : public Expression {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
DEFVISITABLE(TreeVisitorBase);
|
||||
std::string name_;
|
||||
@ -40,6 +43,7 @@ class Identifier : public Expression {
|
||||
|
||||
class PropertyLookup : public Expression {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
@ -57,13 +61,13 @@ class PropertyLookup : public Expression {
|
||||
// between the two depending on Expression result
|
||||
|
||||
protected:
|
||||
PropertyLookup(int uid, Expression* expression,
|
||||
GraphDb::Property property)
|
||||
PropertyLookup(int uid, Expression *expression, GraphDb::Property property)
|
||||
: Expression(uid), expression_(expression), property_(property) {}
|
||||
};
|
||||
|
||||
class NamedExpression : public Tree {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
@ -72,18 +76,20 @@ class NamedExpression : public Tree {
|
||||
}
|
||||
|
||||
std::string name_;
|
||||
Expression* expression_ = nullptr;
|
||||
Expression *expression_ = nullptr;
|
||||
|
||||
protected:
|
||||
NamedExpression(int uid) : Tree(uid) {}
|
||||
NamedExpression(int uid, std::string name, Expression *expression) :
|
||||
Tree(uid), name_(name), expression_(expression) {}
|
||||
NamedExpression(int uid, std::string name, Expression *expression)
|
||||
: Tree(uid), name_(name), expression_(expression) {}
|
||||
};
|
||||
|
||||
class PatternAtom : public Tree {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
Identifier* identifier_ = nullptr;
|
||||
Identifier *identifier_ = nullptr;
|
||||
|
||||
protected:
|
||||
PatternAtom(int uid) : Tree(uid) {}
|
||||
PatternAtom(int uid, Identifier *identifier)
|
||||
@ -92,6 +98,7 @@ class PatternAtom : public Tree {
|
||||
|
||||
class NodeAtom : public PatternAtom {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
@ -100,7 +107,8 @@ class NodeAtom : public PatternAtom {
|
||||
}
|
||||
|
||||
std::vector<GraphDb::Label> labels_;
|
||||
std::map<GraphDb::Property, Expression*> properties_;
|
||||
// TODO: change to unordered_map
|
||||
std::map<GraphDb::Property, Expression *> properties_;
|
||||
|
||||
protected:
|
||||
using PatternAtom::PatternAtom;
|
||||
@ -108,6 +116,7 @@ class NodeAtom : public PatternAtom {
|
||||
|
||||
class EdgeAtom : public PatternAtom {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
enum class Direction { LEFT, RIGHT, BOTH };
|
||||
|
||||
@ -119,6 +128,8 @@ class EdgeAtom : public PatternAtom {
|
||||
|
||||
Direction direction_ = Direction::BOTH;
|
||||
std::vector<GraphDb::EdgeType> types_;
|
||||
// TODO: change to unordered_map
|
||||
std::map<GraphDb::Property, Expression *> properties_;
|
||||
|
||||
protected:
|
||||
using PatternAtom::PatternAtom;
|
||||
@ -126,12 +137,14 @@ class EdgeAtom : public PatternAtom {
|
||||
|
||||
class Clause : public Tree {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
Clause(int uid) : Tree(uid) {}
|
||||
};
|
||||
|
||||
class Pattern : public Tree {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
@ -140,8 +153,8 @@ class Pattern : public Tree {
|
||||
}
|
||||
visitor.PostVisit(*this);
|
||||
}
|
||||
Identifier* identifier_ = nullptr;
|
||||
std::vector<PatternAtom*> atoms_;
|
||||
Identifier *identifier_ = nullptr;
|
||||
std::vector<PatternAtom *> atoms_;
|
||||
|
||||
protected:
|
||||
Pattern(int uid) : Tree(uid) {}
|
||||
@ -149,6 +162,7 @@ class Pattern : public Tree {
|
||||
|
||||
class Query : public Tree {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
@ -157,16 +171,18 @@ class Query : public Tree {
|
||||
}
|
||||
visitor.PostVisit(*this);
|
||||
}
|
||||
std::vector<Clause*> clauses_;
|
||||
std::vector<Clause *> clauses_;
|
||||
|
||||
protected:
|
||||
Query(int uid) : Tree(uid) {}
|
||||
};
|
||||
|
||||
class Create : public Clause {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
Create(int uid) : Clause(uid) {}
|
||||
std::vector<Pattern*> patterns_;
|
||||
std::vector<Pattern *> patterns_;
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
for (auto &pattern : patterns_) {
|
||||
@ -178,8 +194,9 @@ class Create : public Clause {
|
||||
|
||||
class Match : public Clause {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
std::vector<Pattern*> patterns_;
|
||||
std::vector<Pattern *> patterns_;
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
for (auto &pattern : patterns_) {
|
||||
@ -194,6 +211,7 @@ class Match : public Clause {
|
||||
|
||||
class Return : public Clause {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
@ -202,7 +220,7 @@ class Return : public Clause {
|
||||
}
|
||||
visitor.PostVisit(*this);
|
||||
}
|
||||
std::vector<NamedExpression*> named_expressions_;
|
||||
std::vector<NamedExpression *> named_expressions_;
|
||||
|
||||
protected:
|
||||
Return(int uid) : Clause(uid) {}
|
||||
@ -215,14 +233,12 @@ class AstTreeStorage {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
AstTreeStorage() {
|
||||
storage_.emplace_back(new Query(next_uid_++));
|
||||
}
|
||||
AstTreeStorage() { storage_.emplace_back(new Query(next_uid_++)); }
|
||||
AstTreeStorage(const AstTreeStorage &) = delete;
|
||||
AstTreeStorage &operator=(const AstTreeStorage &) = delete;
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T *Create(Args&&... args) {
|
||||
template <typename T, typename... Args>
|
||||
T *Create(Args &&... args) {
|
||||
// Never call create for a Query. Call query() instead.
|
||||
static_assert(!std::is_same<T, Query>::value, "Call query() instead");
|
||||
// TODO: use std::forward here
|
||||
@ -231,7 +247,7 @@ class AstTreeStorage {
|
||||
return p;
|
||||
}
|
||||
|
||||
Query *query() { return dynamic_cast<Query*>(storage_[0].get()); }
|
||||
Query *query() { return dynamic_cast<Query *>(storage_[0].get()); }
|
||||
|
||||
private:
|
||||
int next_uid_ = 0;
|
||||
|
@ -41,8 +41,8 @@ namespace {
|
||||
|
||||
const std::string CypherMainVisitor::kAnonPrefix = "anon";
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitSingleQuery(CypherParser::SingleQueryContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitSingleQuery(
|
||||
CypherParser::SingleQueryContext *ctx) {
|
||||
query_ = storage_.query();
|
||||
for (auto *child : ctx->clause()) {
|
||||
query_->clauses_.push_back(child->accept(this));
|
||||
@ -68,12 +68,15 @@ antlrcpp::Any CypherMainVisitor::visitClause(CypherParser::ClauseContext *ctx) {
|
||||
if (ctx->cypherMatch()) {
|
||||
return (Clause *)ctx->cypherMatch()->accept(this).as<Match *>();
|
||||
}
|
||||
if (ctx->create()) {
|
||||
return (Clause *)ctx->create()->accept(this).as<Create *>();
|
||||
}
|
||||
throw std::exception();
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitCypherMatch(CypherParser::CypherMatchContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitCypherMatch(
|
||||
CypherParser::CypherMatchContext *ctx) {
|
||||
auto *match = storage_.Create<Match>();
|
||||
if (ctx->OPTIONAL() || ctx->where()) {
|
||||
throw std::exception();
|
||||
@ -82,24 +85,31 @@ CypherMainVisitor::visitCypherMatch(CypherParser::CypherMatchContext *ctx) {
|
||||
return match;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitCypherReturn(CypherParser::CypherReturnContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitCreate(CypherParser::CreateContext *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()) {
|
||||
throw std::exception();
|
||||
}
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitReturnBody(CypherParser::ReturnBodyContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitReturnBody(
|
||||
CypherParser::ReturnBodyContext *ctx) {
|
||||
if (ctx->order() || ctx->skip() || ctx->limit()) {
|
||||
throw std::exception();
|
||||
}
|
||||
return ctx->returnItems()->accept(this);
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitReturnItems(CypherParser::ReturnItemsContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitReturnItems(
|
||||
CypherParser::ReturnItemsContext *ctx) {
|
||||
auto *return_clause = storage_.Create<Return>();
|
||||
if (ctx->getTokens(kReturnAllTokenId).size()) {
|
||||
throw std::exception();
|
||||
@ -110,8 +120,8 @@ CypherMainVisitor::visitReturnItems(CypherParser::ReturnItemsContext *ctx) {
|
||||
return return_clause;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitReturnItem(CypherParser::ReturnItemContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitReturnItem(
|
||||
CypherParser::ReturnItemContext *ctx) {
|
||||
auto *named_expr = storage_.Create<NamedExpression>();
|
||||
if (ctx->variable()) {
|
||||
named_expr->name_ =
|
||||
@ -124,8 +134,8 @@ CypherMainVisitor::visitReturnItem(CypherParser::ReturnItemContext *ctx) {
|
||||
return named_expr;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitNodePattern(CypherParser::NodePatternContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitNodePattern(
|
||||
CypherParser::NodePatternContext *ctx) {
|
||||
auto *node = storage_.Create<NodeAtom>();
|
||||
if (ctx->variable()) {
|
||||
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>>();
|
||||
}
|
||||
if (ctx->properties()) {
|
||||
throw std::exception();
|
||||
// node.properties = ctx->properties()
|
||||
// ->accept(this)
|
||||
// .as<std::unordered_map<std::string,
|
||||
// std::string>>();
|
||||
node->properties_ = ctx->properties()
|
||||
->accept(this)
|
||||
.as<std::map<GraphDb::Property, Expression *>>();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitNodeLabels(CypherParser::NodeLabelsContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitNodeLabels(
|
||||
CypherParser::NodeLabelsContext *ctx) {
|
||||
std::vector<GraphDb::Label> labels;
|
||||
for (auto *node_label : ctx->nodeLabel()) {
|
||||
labels.push_back(ctx_.db_accessor_.label(node_label->accept(this)));
|
||||
@ -157,31 +165,35 @@ CypherMainVisitor::visitNodeLabels(CypherParser::NodeLabelsContext *ctx) {
|
||||
return labels;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitProperties(CypherParser::PropertiesContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitProperties(
|
||||
CypherParser::PropertiesContext *ctx) {
|
||||
if (!ctx->mapLiteral()) {
|
||||
// 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();
|
||||
}
|
||||
return ctx->mapLiteral()->accept(this);
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitMapLiteral(CypherParser::MapLiteralContext *ctx) {
|
||||
throw std::exception();
|
||||
(void)ctx;
|
||||
return 0;
|
||||
// std::unordered_map<std::string, std::string> map;
|
||||
// for (int i = 0; i < (int)ctx->propertyKeyName().size(); ++i) {
|
||||
// map[ctx->propertyKeyName()[i]->accept(this).as<std::string>()] =
|
||||
// ctx->expression()[i]->accept(this).as<std::string>();
|
||||
// }
|
||||
// return map;
|
||||
antlrcpp::Any CypherMainVisitor::visitMapLiteral(
|
||||
CypherParser::MapLiteralContext *ctx) {
|
||||
std::map<GraphDb::Property, Expression *> map;
|
||||
for (int i = 0; i < (int)ctx->propertyKeyName().size(); ++i) {
|
||||
map[ctx->propertyKeyName()[i]->accept(this)] =
|
||||
ctx->expression()[i]->accept(this);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitSymbolicName(CypherParser::SymbolicNameContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitPropertyKeyName(
|
||||
CypherParser::PropertyKeyNameContext *ctx) {
|
||||
return ctx_.db_accessor_.property(visitChildren(ctx));
|
||||
}
|
||||
|
||||
antlrcpp::Any CypherMainVisitor::visitSymbolicName(
|
||||
CypherParser::SymbolicNameContext *ctx) {
|
||||
if (ctx->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
|
||||
@ -192,8 +204,8 @@ CypherMainVisitor::visitSymbolicName(CypherParser::SymbolicNameContext *ctx) {
|
||||
return std::string(ctx->getText());
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitPattern(CypherParser::PatternContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitPattern(
|
||||
CypherParser::PatternContext *ctx) {
|
||||
std::vector<Pattern *> patterns;
|
||||
for (auto *pattern_part : ctx->patternPart()) {
|
||||
patterns.push_back(pattern_part->accept(this));
|
||||
@ -201,8 +213,8 @@ CypherMainVisitor::visitPattern(CypherParser::PatternContext *ctx) {
|
||||
return patterns;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitPatternPart(CypherParser::PatternPartContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitPatternPart(
|
||||
CypherParser::PatternPartContext *ctx) {
|
||||
Pattern *pattern = ctx->anonymousPatternPart()->accept(this);
|
||||
if (ctx->variable()) {
|
||||
std::string variable = ctx->variable()->accept(this);
|
||||
@ -298,8 +310,8 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipTypes(
|
||||
return types;
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitRangeLiteral(CypherParser::RangeLiteralContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitRangeLiteral(
|
||||
CypherParser::RangeLiteralContext *ctx) {
|
||||
if (ctx->integerLiteral().size() == 0U) {
|
||||
// -[*]-
|
||||
return std::pair<int64_t, int64_t>(1LL, LLONG_MAX);
|
||||
@ -326,8 +338,8 @@ CypherMainVisitor::visitRangeLiteral(CypherParser::RangeLiteralContext *ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
antlrcpp::Any
|
||||
CypherMainVisitor::visitExpression(CypherParser::ExpressionContext *ctx) {
|
||||
antlrcpp::Any CypherMainVisitor::visitExpression(
|
||||
CypherParser::ExpressionContext *ctx) {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
@ -504,23 +516,22 @@ CypherMainVisitor::visitExpression(CypherParser::ExpressionContext *ctx) {
|
||||
// }
|
||||
// return visitChildren(ctx);
|
||||
//}
|
||||
//
|
||||
// antlrcpp::Any
|
||||
// CypherMainVisitor::visitExpression2(CypherParser::Expression2Context *ctx) {
|
||||
// if (ctx->nodeLabels().size()) {
|
||||
// // TODO: Implement this. We don't currently support label checking in
|
||||
// // expresssion.
|
||||
// throw SemanticException();
|
||||
// }
|
||||
// auto operand = ctx->atom()->accept(this).as<std::string>();
|
||||
// for (int i = 0; i < (int)ctx->propertyLookup().size(); ++i) {
|
||||
// auto lhs_id = new_id();
|
||||
// symbol_table_[lhs_id] =
|
||||
// SimpleExpression{Function::PROPERTY_GETTER, {operand}};
|
||||
// operand = lhs_id;
|
||||
// }
|
||||
// return operand;
|
||||
//}
|
||||
|
||||
antlrcpp::Any CypherMainVisitor::visitExpression2(
|
||||
CypherParser::Expression2Context *ctx) {
|
||||
if (ctx->nodeLabels().size()) {
|
||||
// TODO: Implement this. We don't currently support label checking in
|
||||
// expresssion.
|
||||
throw std::exception();
|
||||
}
|
||||
Expression *expression = ctx->atom()->accept(this);
|
||||
for (auto *lookup : ctx->propertyLookup()) {
|
||||
auto property_lookup =
|
||||
storage_.Create<PropertyLookup>(expression, lookup->accept(this));
|
||||
expression = property_lookup;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
|
||||
if (ctx->literal()) {
|
||||
@ -555,7 +566,7 @@ antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
|
||||
} else if (ctx->variable()) {
|
||||
std::string variable = ctx->variable()->accept(this);
|
||||
users_identifiers.insert(variable);
|
||||
return storage_.Create<Identifier>(variable);
|
||||
return (Expression *)storage_.Create<Identifier>(variable);
|
||||
}
|
||||
// TODO: Implement this. We don't support comprehensions, functions,
|
||||
// filtering... at the moment.
|
||||
|
@ -15,10 +15,10 @@ using query::Context;
|
||||
using antlropencypher::CypherParser;
|
||||
|
||||
class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
|
||||
public:
|
||||
public:
|
||||
CypherMainVisitor(Context &ctx) : ctx_(ctx) {}
|
||||
|
||||
private:
|
||||
private:
|
||||
// template <typename TExpression>
|
||||
// antlrcpp::Any
|
||||
// LeftAssociativeOperatorExpression(std::vector<TExpression *> children,
|
||||
@ -49,90 +49,109 @@ private:
|
||||
// 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
|
||||
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
|
||||
visitReturnItems(CypherParser::ReturnItemsContext *ctx) override;
|
||||
/**
|
||||
* @return Return*
|
||||
*/
|
||||
antlrcpp::Any visitReturnItems(
|
||||
CypherParser::ReturnItemsContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return NamedExpression*
|
||||
*/
|
||||
antlrcpp::Any visitReturnItem(CypherParser::ReturnItemContext *ctx) override;
|
||||
|
||||
/**
|
||||
* Creates Node and stores it in symbol_table_. If variable is defined it is
|
||||
* stored in ids_map_.
|
||||
*
|
||||
* @return string - node id.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitNodePattern(CypherParser::NodePatternContext *ctx) override;
|
||||
* @return NodeAtom*
|
||||
*/
|
||||
antlrcpp::Any visitNodePattern(
|
||||
CypherParser::NodePatternContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return vector<string> labels.
|
||||
*/
|
||||
* @return vector<GraphDb::Label>
|
||||
*/
|
||||
antlrcpp::Any visitNodeLabels(CypherParser::NodeLabelsContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return unordered_map<string, string> properties - property key to
|
||||
* expression id.
|
||||
*/
|
||||
* @return unordered_map<GraphDb::Property, Expression*>
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @return string.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitSymbolicName(CypherParser::SymbolicNameContext *ctx) override;
|
||||
* @return GraphDb::Property
|
||||
*/
|
||||
antlrcpp::Any visitPropertyKeyName(
|
||||
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;
|
||||
|
||||
/**
|
||||
* Stores PatternPart in symbol_table_. If variable is defined it is stored
|
||||
*in
|
||||
* ids_map_.
|
||||
*
|
||||
* @return string - pattern part id.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitPatternPart(CypherParser::PatternPartContext *ctx) override;
|
||||
* @return Pattern*
|
||||
*/
|
||||
antlrcpp::Any visitPatternPart(
|
||||
CypherParser::PatternPartContext *ctx) override;
|
||||
|
||||
/**
|
||||
* Creates PatternPart.
|
||||
*
|
||||
* @return PatternPart.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitPatternElement(CypherParser::PatternElementContext *ctx) override;
|
||||
* @return Pattern*
|
||||
*/
|
||||
antlrcpp::Any visitPatternElement(
|
||||
CypherParser::PatternElementContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return pair<string, string> - node and relationship ids.
|
||||
*/
|
||||
* @return vector<pair<EdgeAtom*, NodeAtom*>>
|
||||
*/
|
||||
antlrcpp::Any visitPatternElementChain(
|
||||
CypherParser::PatternElementChainContext *ctx) override;
|
||||
|
||||
/**
|
||||
* Creates Relationship and stores it in symbol_table_. If variable is defined
|
||||
* it is stored in symbol_table_.
|
||||
*
|
||||
* @return string - relationship id.
|
||||
*/
|
||||
*@return EdgeAtom*
|
||||
*/
|
||||
antlrcpp::Any visitRelationshipPattern(
|
||||
CypherParser::RelationshipPatternContext *ctx) override;
|
||||
|
||||
@ -142,23 +161,24 @@ private:
|
||||
*/
|
||||
antlrcpp::Any visitRelationshipDetail(
|
||||
CypherParser::RelationshipDetailContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return vector<string>.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitRelationshipTypes(CypherParser::RelationshipTypesContext *ctx) override;
|
||||
* @return vector<GraphDb::EdgeType>
|
||||
*/
|
||||
antlrcpp::Any visitRelationshipTypes(
|
||||
CypherParser::RelationshipTypesContext *ctx) override;
|
||||
|
||||
/**
|
||||
* @return pair<int64_t, int64_t>.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitRangeLiteral(CypherParser::RangeLiteralContext *ctx) override;
|
||||
antlrcpp::Any visitRangeLiteral(
|
||||
CypherParser::RangeLiteralContext *ctx) override;
|
||||
|
||||
/**
|
||||
* Top level expression.
|
||||
*
|
||||
* @return string - expression id.
|
||||
*/
|
||||
* Top level expression, does nothing.
|
||||
*
|
||||
* @return Expression*
|
||||
*/
|
||||
antlrcpp::Any visitExpression(CypherParser::ExpressionContext *ctx) override;
|
||||
|
||||
///**
|
||||
@ -248,18 +268,18 @@ private:
|
||||
// antlrcpp::Any
|
||||
// visitExpression3(CypherParser::Expression3Context *ctx) override;
|
||||
|
||||
///**
|
||||
//* Property lookup, test for node labels existence...
|
||||
//*
|
||||
//* @return string - expression id.
|
||||
//*/
|
||||
// antlrcpp::Any
|
||||
// visitExpression2(CypherParser::Expression2Context *ctx) override;
|
||||
/**
|
||||
* Property lookup, test for node labels existence...
|
||||
*
|
||||
* @return Expression*
|
||||
*/
|
||||
antlrcpp::Any visitExpression2(
|
||||
CypherParser::Expression2Context *ctx) override;
|
||||
|
||||
/**
|
||||
* Literals, params, list comprehension...
|
||||
*
|
||||
* @return string - expression id.
|
||||
* @return Expression*
|
||||
*/
|
||||
antlrcpp::Any visitAtom(CypherParser::AtomContext *ctx) override;
|
||||
|
||||
@ -285,14 +305,14 @@ private:
|
||||
/**
|
||||
* @return int64_t.
|
||||
*/
|
||||
antlrcpp::Any
|
||||
visitIntegerLiteral(CypherParser::IntegerLiteralContext *ctx) override;
|
||||
antlrcpp::Any visitIntegerLiteral(
|
||||
CypherParser::IntegerLiteralContext *ctx) override;
|
||||
|
||||
public:
|
||||
public:
|
||||
Query *query() { return query_; }
|
||||
const static std::string kAnonPrefix;
|
||||
|
||||
private:
|
||||
private:
|
||||
Context &ctx_;
|
||||
// Set of identifiers from queries.
|
||||
std::unordered_set<std::string> users_identifiers;
|
||||
|
@ -7,10 +7,10 @@
|
||||
#include "antlr4-runtime.h"
|
||||
#include "dbms/dbms.hpp"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "query/context.hpp"
|
||||
#include "query/frontend/ast/cypher_main_visitor.hpp"
|
||||
#include "query/frontend/opencypher/parser.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -19,11 +19,15 @@ using namespace query::frontend;
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
class AstGenerator {
|
||||
public:
|
||||
public:
|
||||
AstGenerator(const std::string &query)
|
||||
: dbms_(), db_accessor_(dbms_.active()),
|
||||
context_(Config{}, *db_accessor_), query_string_(query), parser_(query),
|
||||
visitor_(context_), query_([&]() {
|
||||
: dbms_(),
|
||||
db_accessor_(dbms_.active()),
|
||||
context_(Config{}, *db_accessor_),
|
||||
query_string_(query),
|
||||
parser_(query),
|
||||
visitor_(context_),
|
||||
query_([&]() {
|
||||
visitor_.visit(parser_.tree());
|
||||
return visitor_.query();
|
||||
}()) {}
|
||||
@ -37,11 +41,11 @@ public:
|
||||
Query *query_;
|
||||
};
|
||||
|
||||
TEST(CompilerStructuresTest, SyntaxException) {
|
||||
TEST(CypherMainVisitorTest, SyntaxException) {
|
||||
ASSERT_THROW(AstGenerator("CREATE ()-[*1...2]-()"), std::exception);
|
||||
}
|
||||
|
||||
TEST(CompilerStructuresTest, NodePattern) {
|
||||
TEST(CypherMainVisitorTest, NodePattern) {
|
||||
AstGenerator ast_generator("MATCH (:label1:label2:label3)");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
@ -62,7 +66,7 @@ TEST(CompilerStructuresTest, NodePattern) {
|
||||
// TODO: add test for properties.
|
||||
}
|
||||
|
||||
TEST(CompilerStructuresTest, NodePatternIdentifier) {
|
||||
TEST(CypherMainVisitorTest, NodePatternIdentifier) {
|
||||
AstGenerator ast_generator("MATCH (var)");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
@ -73,7 +77,7 @@ TEST(CompilerStructuresTest, NodePatternIdentifier) {
|
||||
// TODO: add test for properties.
|
||||
}
|
||||
|
||||
TEST(CompilerStructuresTest, RelationshipPatternNoDetails) {
|
||||
TEST(CypherMainVisitorTest, RelationshipPatternNoDetails) {
|
||||
AstGenerator ast_generator("MATCH ()--()");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
@ -92,7 +96,7 @@ TEST(CompilerStructuresTest, RelationshipPatternNoDetails) {
|
||||
CypherMainVisitor::kAnonPrefix + std::to_string(2));
|
||||
}
|
||||
|
||||
TEST(CompilerStructuresTest, RelationshipPatternDetails) {
|
||||
TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
|
||||
AstGenerator ast_generator("MATCH ()<-[:type1|type2]-()");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
@ -105,7 +109,7 @@ TEST(CompilerStructuresTest, RelationshipPatternDetails) {
|
||||
// TODO: test properties
|
||||
}
|
||||
|
||||
TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
AstGenerator ast_generator("MATCH ()-[var]->()");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
@ -116,7 +120,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
}
|
||||
|
||||
// // Relationship with unbounded variable range.
|
||||
// TEST(CompilerStructuresTest, RelationshipPatternUnbounded) {
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternUnbounded) {
|
||||
// ParserTables parser("CREATE ()-[*]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -126,7 +130,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with lower bounded variable range.
|
||||
// TEST(CompilerStructuresTest, RelationshipPatternLowerBounded) {
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternLowerBounded) {
|
||||
// ParserTables parser("CREATE ()-[*5..]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -136,7 +140,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with upper bounded variable range.
|
||||
// TEST(CompilerStructuresTest, RelationshipPatternUpperBounded) {
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternUpperBounded) {
|
||||
// ParserTables parser("CREATE ()-[*..10]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -145,7 +149,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with lower and upper bounded variable range.
|
||||
// TEST(CompilerStructuresTest, RelationshipPatternLowerUpperBounded) {
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternLowerUpperBounded) {
|
||||
// ParserTables parser("CREATE ()-[*5..10]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -154,7 +158,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with fixed number of edges.
|
||||
// TEST(CompilerStructuresTest, RelationshipPatternFixedRange) {
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternFixedRange) {
|
||||
// ParserTables parser("CREATE ()-[*10]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -163,15 +167,14 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with invalid bound (larger than long long).
|
||||
// TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) {
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternInvalidBound) {
|
||||
// ASSERT_THROW(
|
||||
// ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"),
|
||||
// SemanticException);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // PatternPart.
|
||||
// TEST(CompilerStructuresTest, PatternPart) {
|
||||
// TEST(CypherMainVisitorTest, PatternPart) {
|
||||
// ParserTables parser("CREATE ()--()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.pattern_parts_.size(), 1U);
|
||||
@ -182,7 +185,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // PatternPart in braces.
|
||||
// TEST(CompilerStructuresTest, PatternPartBraces) {
|
||||
// TEST(CypherMainVisitorTest, PatternPartBraces) {
|
||||
// ParserTables parser("CREATE ((()--()))");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.pattern_parts_.size(), 1U);
|
||||
@ -193,7 +196,7 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // PatternPart with variable.
|
||||
// TEST(CompilerStructuresTest, PatternPartVariable) {
|
||||
// TEST(CypherMainVisitorTest, PatternPartVariable) {
|
||||
// ParserTables parser("CREATE var=()--()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 1U);
|
||||
// ASSERT_EQ(parser.pattern_parts_.size(), 1U);
|
||||
@ -209,8 +212,49 @@ TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Multiple nodes with same variable and properties.
|
||||
// TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) {
|
||||
// TEST(CypherMainVisitorTest, MultipleNodesWithVariableAndProperties) {
|
||||
// ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"),
|
||||
// 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.
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user