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
#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;

View File

@ -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.

View File

@ -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;

View File

@ -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.
}
}