Add deep clone to Ast
Summary: Prepare your aspergillums for blessing this magnificent diff. Reviewers: buda, teon.banek, florijan Reviewed By: teon.banek Subscribers: lion, pullbot Differential Revision: https://phabricator.memgraph.io/D458
This commit is contained in:
parent
c6b2336f04
commit
f7d540829a
@ -354,6 +354,7 @@ set(memgraph_src_files
|
||||
${src_dir}/query/stripped.cpp
|
||||
${src_dir}/query/common.cpp
|
||||
${src_dir}/query/console.cpp
|
||||
${src_dir}/query/frontend/ast/ast.cpp
|
||||
${src_dir}/query/frontend/ast/cypher_main_visitor.cpp
|
||||
${src_dir}/query/typed_value.cpp
|
||||
${src_dir}/query/interpret/awesome_memgraph_functions.cpp
|
||||
|
28
src/query/frontend/ast/ast.cpp
Normal file
28
src/query/frontend/ast/ast.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
|
||||
namespace query {
|
||||
|
||||
AstTreeStorage::AstTreeStorage() {
|
||||
storage_.emplace_back(new Query(next_uid_++));
|
||||
}
|
||||
|
||||
Query *AstTreeStorage::query() const {
|
||||
return dynamic_cast<Query *>(storage_[0].get());
|
||||
}
|
||||
|
||||
ReturnBody CloneReturnBody(AstTreeStorage &storage, const ReturnBody &body) {
|
||||
ReturnBody new_body;
|
||||
new_body.distinct = body.distinct;
|
||||
new_body.all_identifiers = body.all_identifiers;
|
||||
for (auto *named_expr : body.named_expressions) {
|
||||
new_body.named_expressions.push_back(named_expr->Clone(storage));
|
||||
}
|
||||
for (auto order : body.order_by) {
|
||||
new_body.order_by.emplace_back(order.first, order.second->Clone(storage));
|
||||
}
|
||||
new_body.skip = body.skip ? body.skip->Clone(storage) : nullptr;
|
||||
new_body.limit = body.limit ? body.limit->Clone(storage) : nullptr;
|
||||
return new_body;
|
||||
}
|
||||
|
||||
} // namespace query
|
@ -12,7 +12,47 @@
|
||||
|
||||
namespace query {
|
||||
|
||||
class AstTreeStorage;
|
||||
#define CLONE_BINARY_EXPRESSION \
|
||||
auto Clone(AstTreeStorage &storage) const->std::remove_const< \
|
||||
std::remove_pointer<decltype(this)>::type>::type * override { \
|
||||
return storage.Create< \
|
||||
std::remove_cv<std::remove_reference<decltype(*this)>::type>::type>( \
|
||||
expression1_->Clone(storage), expression2_->Clone(storage)); \
|
||||
}
|
||||
#define CLONE_UNARY_EXPRESSION \
|
||||
auto Clone(AstTreeStorage &storage) const->std::remove_const< \
|
||||
std::remove_pointer<decltype(this)>::type>::type * override { \
|
||||
return storage.Create< \
|
||||
std::remove_cv<std::remove_reference<decltype(*this)>::type>::type>( \
|
||||
expression_->Clone(storage)); \
|
||||
}
|
||||
|
||||
class Tree;
|
||||
|
||||
// It would be better to call this AstTree, but we already have a class Tree,
|
||||
// which could be renamed to Node or AstTreeNode, but we also have a class
|
||||
// called NodeAtom...
|
||||
class AstTreeStorage {
|
||||
public:
|
||||
AstTreeStorage();
|
||||
AstTreeStorage(const AstTreeStorage &) = delete;
|
||||
AstTreeStorage &operator=(const AstTreeStorage &) = delete;
|
||||
|
||||
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");
|
||||
T *p = new T(next_uid_++, std::forward<Args>(args)...);
|
||||
storage_.emplace_back(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
Query *query() const;
|
||||
|
||||
private:
|
||||
int next_uid_ = 0;
|
||||
std::vector<std::unique_ptr<Tree>> storage_;
|
||||
};
|
||||
|
||||
class Tree : public ::utils::Visitable<HierarchicalTreeVisitor>,
|
||||
::utils::Visitable<TreeVisitor<TypedValue>> {
|
||||
@ -24,6 +64,8 @@ class Tree : public ::utils::Visitable<HierarchicalTreeVisitor>,
|
||||
|
||||
int uid() const { return uid_; }
|
||||
|
||||
virtual Tree *Clone(AstTreeStorage &storage) const = 0;
|
||||
|
||||
protected:
|
||||
Tree(int uid) : uid_(uid) {}
|
||||
|
||||
@ -34,6 +76,9 @@ class Tree : public ::utils::Visitable<HierarchicalTreeVisitor>,
|
||||
class Expression : public Tree {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
Expression *Clone(AstTreeStorage &storage) const override = 0;
|
||||
|
||||
protected:
|
||||
Expression(int uid) : Tree(uid) {}
|
||||
};
|
||||
@ -45,6 +90,8 @@ class BinaryOperator : public Expression {
|
||||
Expression *expression1_ = nullptr;
|
||||
Expression *expression2_ = nullptr;
|
||||
|
||||
BinaryOperator *Clone(AstTreeStorage &storage) const override = 0;
|
||||
|
||||
protected:
|
||||
BinaryOperator(int uid) : Expression(uid) {}
|
||||
BinaryOperator(int uid, Expression *expression1, Expression *expression2)
|
||||
@ -57,6 +104,8 @@ class UnaryOperator : public Expression {
|
||||
public:
|
||||
Expression *expression_ = nullptr;
|
||||
|
||||
UnaryOperator *Clone(AstTreeStorage &storage) const override = 0;
|
||||
|
||||
protected:
|
||||
UnaryOperator(int uid) : Expression(uid) {}
|
||||
UnaryOperator(int uid, Expression *expression)
|
||||
@ -74,6 +123,7 @@ class OrOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -90,6 +140,7 @@ class XorOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -106,6 +157,7 @@ class AndOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -126,6 +178,7 @@ class FilterAndOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -142,6 +195,7 @@ class AdditionOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -158,6 +212,7 @@ class SubtractionOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -174,6 +229,7 @@ class MultiplicationOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -190,6 +246,7 @@ class DivisionOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -206,6 +263,7 @@ class ModOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -222,6 +280,7 @@ class NotEqualOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -238,6 +297,7 @@ class EqualOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -254,6 +314,7 @@ class LessOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -270,6 +331,7 @@ class GreaterOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -286,6 +348,7 @@ class LessEqualOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -302,6 +365,7 @@ class GreaterEqualOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -318,6 +382,7 @@ class InListOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -334,6 +399,7 @@ class ListIndexingOperator : public BinaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_BINARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using BinaryOperator::BinaryOperator;
|
||||
@ -357,6 +423,13 @@ class ListSlicingOperator : public Expression {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
ListSlicingOperator *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<ListSlicingOperator>(
|
||||
list_->Clone(storage),
|
||||
lower_bound_ ? lower_bound_->Clone(storage) : nullptr,
|
||||
upper_bound_ ? upper_bound_->Clone(storage) : nullptr);
|
||||
}
|
||||
|
||||
Expression *list_;
|
||||
Expression *lower_bound_;
|
||||
Expression *upper_bound_;
|
||||
@ -381,6 +454,7 @@ class NotOperator : public UnaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_UNARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using UnaryOperator::UnaryOperator;
|
||||
@ -397,6 +471,7 @@ class UnaryPlusOperator : public UnaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_UNARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using UnaryOperator::UnaryOperator;
|
||||
@ -413,6 +488,7 @@ class UnaryMinusOperator : public UnaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_UNARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using UnaryOperator::UnaryOperator;
|
||||
@ -429,6 +505,7 @@ class IsNullOperator : public UnaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
CLONE_UNARY_EXPRESSION;
|
||||
|
||||
protected:
|
||||
using UnaryOperator::UnaryOperator;
|
||||
@ -437,6 +514,9 @@ class IsNullOperator : public UnaryOperator {
|
||||
class BaseLiteral : public Expression {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
BaseLiteral *Clone(AstTreeStorage &storage) const override = 0;
|
||||
|
||||
protected:
|
||||
BaseLiteral(int uid) : Expression(uid) {}
|
||||
};
|
||||
@ -447,6 +527,11 @@ class PrimitiveLiteral : public BaseLiteral {
|
||||
public:
|
||||
DEFVISITABLE(TreeVisitor<TypedValue>);
|
||||
DEFVISITABLE(HierarchicalTreeVisitor);
|
||||
|
||||
PrimitiveLiteral *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<PrimitiveLiteral>(value_);
|
||||
}
|
||||
|
||||
TypedValue value_;
|
||||
|
||||
protected:
|
||||
@ -459,7 +544,6 @@ class ListLiteral : public BaseLiteral {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
const std::vector<Expression *> elements_;
|
||||
DEFVISITABLE(TreeVisitor<TypedValue>);
|
||||
bool Accept(HierarchicalTreeVisitor &visitor) override {
|
||||
if (visitor.PreVisit(*this)) {
|
||||
@ -469,6 +553,16 @@ class ListLiteral : public BaseLiteral {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
ListLiteral *Clone(AstTreeStorage &storage) const override {
|
||||
auto *list = storage.Create<ListLiteral>();
|
||||
for (auto *element : elements_) {
|
||||
list->elements_.push_back(element->Clone(storage));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
std::vector<Expression *> elements_;
|
||||
|
||||
protected:
|
||||
ListLiteral(int uid) : BaseLiteral(uid) {}
|
||||
ListLiteral(int uid, const std::vector<Expression *> &elements)
|
||||
@ -481,6 +575,11 @@ class Identifier : public Expression {
|
||||
public:
|
||||
DEFVISITABLE(TreeVisitor<TypedValue>);
|
||||
DEFVISITABLE(HierarchicalTreeVisitor);
|
||||
|
||||
Identifier *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<Identifier>(name_, user_declared_);
|
||||
}
|
||||
|
||||
std::string name_;
|
||||
bool user_declared_ = true;
|
||||
|
||||
@ -502,6 +601,11 @@ class PropertyLookup : public Expression {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
PropertyLookup *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<PropertyLookup>(expression_->Clone(storage),
|
||||
property_);
|
||||
}
|
||||
|
||||
Expression *expression_ = nullptr;
|
||||
GraphDbTypes::Property property_ = nullptr;
|
||||
// TODO potential problem: property lookups are allowed on both map literals
|
||||
@ -530,6 +634,10 @@ class LabelsTest : public Expression {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
LabelsTest *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<LabelsTest>(expression_->Clone(storage), labels_);
|
||||
}
|
||||
|
||||
Expression *expression_ = nullptr;
|
||||
std::vector<GraphDbTypes::Label> labels_;
|
||||
|
||||
@ -551,6 +659,11 @@ class EdgeTypeTest : public Expression {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
EdgeTypeTest *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<EdgeTypeTest>(expression_->Clone(storage),
|
||||
edge_types_);
|
||||
}
|
||||
|
||||
Expression *expression_ = nullptr;
|
||||
std::vector<GraphDbTypes::EdgeType> edge_types_;
|
||||
|
||||
@ -577,6 +690,15 @@ class Function : public Expression {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
// TODO: Think if there are any problems if function_ is mutable.
|
||||
Function *Clone(AstTreeStorage &storage) const override {
|
||||
std::vector<Expression *> arguments;
|
||||
for (auto *argument : arguments_) {
|
||||
arguments.push_back(argument->Clone(storage));
|
||||
}
|
||||
return storage.Create<Function>(function_, arguments);
|
||||
}
|
||||
|
||||
std::function<TypedValue(const std::vector<TypedValue> &, GraphDbAccessor &)>
|
||||
function_;
|
||||
std::vector<Expression *> arguments_;
|
||||
@ -610,6 +732,12 @@ class Aggregation : public UnaryOperator {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Aggregation *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<Aggregation>(
|
||||
expression_ ? expression_->Clone(storage) : nullptr, op_);
|
||||
}
|
||||
|
||||
Op op_;
|
||||
|
||||
protected:
|
||||
@ -633,6 +761,10 @@ class NamedExpression : public Tree {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
NamedExpression *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<NamedExpression>(name_, expression_->Clone(storage));
|
||||
}
|
||||
|
||||
std::string name_;
|
||||
Expression *expression_ = nullptr;
|
||||
|
||||
@ -649,6 +781,8 @@ class PatternAtom : public Tree {
|
||||
public:
|
||||
Identifier *identifier_ = nullptr;
|
||||
|
||||
PatternAtom *Clone(AstTreeStorage &storage) const override = 0;
|
||||
|
||||
protected:
|
||||
PatternAtom(int uid) : Tree(uid) {}
|
||||
PatternAtom(int uid, Identifier *identifier)
|
||||
@ -667,6 +801,15 @@ class NodeAtom : public PatternAtom {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
NodeAtom *Clone(AstTreeStorage &storage) const override {
|
||||
auto *node_atom = storage.Create<NodeAtom>(identifier_->Clone(storage));
|
||||
node_atom->labels_ = labels_;
|
||||
for (auto property : properties_) {
|
||||
node_atom->properties_[property.first] = property.second->Clone(storage);
|
||||
}
|
||||
return node_atom;
|
||||
}
|
||||
|
||||
std::vector<GraphDbTypes::Label> labels_;
|
||||
// TODO: change to unordered_map
|
||||
std::map<GraphDbTypes::Property, Expression *> properties_;
|
||||
@ -689,6 +832,16 @@ class EdgeAtom : public PatternAtom {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
EdgeAtom *Clone(AstTreeStorage &storage) const override {
|
||||
auto *edge_atom = storage.Create<EdgeAtom>(identifier_->Clone(storage));
|
||||
edge_atom->direction_ = direction_;
|
||||
edge_atom->edge_types_ = edge_types_;
|
||||
for (auto property : properties_) {
|
||||
edge_atom->properties_[property.first] = property.second->Clone(storage);
|
||||
}
|
||||
return edge_atom;
|
||||
}
|
||||
|
||||
Direction direction_ = Direction::BOTH;
|
||||
std::vector<GraphDbTypes::EdgeType> edge_types_;
|
||||
// TODO: change to unordered_map
|
||||
@ -705,6 +858,8 @@ class Clause : public Tree {
|
||||
|
||||
public:
|
||||
Clause(int uid) : Tree(uid) {}
|
||||
|
||||
Clause *Clone(AstTreeStorage &storage) const override = 0;
|
||||
};
|
||||
|
||||
class Pattern : public Tree {
|
||||
@ -720,6 +875,16 @@ class Pattern : public Tree {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Pattern *Clone(AstTreeStorage &storage) const override {
|
||||
auto *pattern = storage.Create<Pattern>();
|
||||
pattern->identifier_ = identifier_->Clone(storage);
|
||||
for (auto *atom : atoms_) {
|
||||
pattern->atoms_.push_back(atom->Clone(storage));
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
Identifier *identifier_ = nullptr;
|
||||
std::vector<PatternAtom *> atoms_;
|
||||
|
||||
@ -740,6 +905,16 @@ class Query : public Tree {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
// Creates deep copy of whole ast.
|
||||
Query *Clone(AstTreeStorage &storage) const override {
|
||||
auto *query = storage.query();
|
||||
for (auto *clause : clauses_) {
|
||||
query->clauses_.push_back(clause->Clone(storage));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
std::vector<Clause *> clauses_;
|
||||
|
||||
protected:
|
||||
@ -751,7 +926,6 @@ class Create : public Clause {
|
||||
|
||||
public:
|
||||
Create(int uid) : Clause(uid) {}
|
||||
std::vector<Pattern *> patterns_;
|
||||
DEFVISITABLE(TreeVisitor<TypedValue>);
|
||||
bool Accept(HierarchicalTreeVisitor &visitor) override {
|
||||
if (visitor.PreVisit(*this)) {
|
||||
@ -761,6 +935,16 @@ class Create : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Create *Clone(AstTreeStorage &storage) const override {
|
||||
auto *create = storage.Create<Create>();
|
||||
for (auto *pattern : patterns_) {
|
||||
create->patterns_.push_back(pattern->Clone(storage));
|
||||
}
|
||||
return create;
|
||||
}
|
||||
|
||||
std::vector<Pattern *> patterns_;
|
||||
};
|
||||
|
||||
class Where : public Tree {
|
||||
@ -774,6 +958,11 @@ class Where : public Tree {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Where *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<Where>(expression_->Clone(storage));
|
||||
}
|
||||
|
||||
Expression *expression_ = nullptr;
|
||||
|
||||
protected:
|
||||
@ -801,6 +990,16 @@ class Match : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Match *Clone(AstTreeStorage &storage) const override {
|
||||
auto *match = storage.Create<Match>(optional_);
|
||||
for (auto *pattern : patterns_) {
|
||||
match->patterns_.push_back(pattern->Clone(storage));
|
||||
}
|
||||
match->where_ = where_ ? where_->Clone(storage) : nullptr;
|
||||
return match;
|
||||
}
|
||||
|
||||
std::vector<Pattern *> patterns_;
|
||||
Where *where_ = nullptr;
|
||||
bool optional_ = false;
|
||||
@ -831,6 +1030,11 @@ struct ReturnBody {
|
||||
Expression *limit = nullptr;
|
||||
};
|
||||
|
||||
// Deep copy ReturnBody.
|
||||
// TODO: Think about turning ReturnBody to class and making this
|
||||
// function class member.
|
||||
ReturnBody CloneReturnBody(AstTreeStorage &storage, const ReturnBody &body);
|
||||
|
||||
class Return : public Clause {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
@ -859,6 +1063,12 @@ class Return : public Clause {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Return *Clone(AstTreeStorage &storage) const override {
|
||||
auto *ret = storage.Create<Return>();
|
||||
ret->body_ = CloneReturnBody(storage, body_);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ReturnBody body_;
|
||||
|
||||
protected:
|
||||
@ -894,6 +1104,13 @@ class With : public Clause {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
With *Clone(AstTreeStorage &storage) const override {
|
||||
auto *with = storage.Create<With>();
|
||||
with->body_ = CloneReturnBody(storage, body_);
|
||||
with->where_ = where_ ? where_->Clone(storage) : nullptr;
|
||||
return with;
|
||||
}
|
||||
|
||||
ReturnBody body_;
|
||||
Where *where_ = nullptr;
|
||||
|
||||
@ -914,6 +1131,16 @@ class Delete : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Delete *Clone(AstTreeStorage &storage) const override {
|
||||
auto *del = storage.Create<Delete>();
|
||||
for (auto *expression : expressions_) {
|
||||
del->expressions_.push_back(expression->Clone(storage));
|
||||
}
|
||||
del->detach_ = detach_;
|
||||
return del;
|
||||
}
|
||||
|
||||
std::vector<Expression *> expressions_;
|
||||
bool detach_ = false;
|
||||
|
||||
@ -932,6 +1159,12 @@ class SetProperty : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
SetProperty *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<SetProperty>(property_lookup_->Clone(storage),
|
||||
expression_->Clone(storage));
|
||||
}
|
||||
|
||||
PropertyLookup *property_lookup_ = nullptr;
|
||||
Expression *expression_ = nullptr;
|
||||
|
||||
@ -954,6 +1187,12 @@ class SetProperties : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
SetProperties *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<SetProperties>(identifier_->Clone(storage),
|
||||
expression_->Clone(storage), update_);
|
||||
}
|
||||
|
||||
Identifier *identifier_ = nullptr;
|
||||
Expression *expression_ = nullptr;
|
||||
bool update_ = false;
|
||||
@ -979,6 +1218,11 @@ class SetLabels : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
SetLabels *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<SetLabels>(identifier_->Clone(storage), labels_);
|
||||
}
|
||||
|
||||
Identifier *identifier_ = nullptr;
|
||||
std::vector<GraphDbTypes::Label> labels_;
|
||||
|
||||
@ -1000,6 +1244,11 @@ class RemoveProperty : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
RemoveProperty *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<RemoveProperty>(property_lookup_->Clone(storage));
|
||||
}
|
||||
|
||||
PropertyLookup *property_lookup_ = nullptr;
|
||||
|
||||
protected:
|
||||
@ -1019,6 +1268,11 @@ class RemoveLabels : public Clause {
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
RemoveLabels *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<RemoveLabels>(identifier_->Clone(storage), labels_);
|
||||
}
|
||||
|
||||
Identifier *identifier_ = nullptr;
|
||||
std::vector<GraphDbTypes::Label> labels_;
|
||||
|
||||
@ -1057,6 +1311,18 @@ class Merge : public Clause {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Merge *Clone(AstTreeStorage &storage) const override {
|
||||
auto *merge = storage.Create<Merge>();
|
||||
merge->pattern_ = pattern_->Clone(storage);
|
||||
for (auto *on_match : on_match_) {
|
||||
merge->on_match_.push_back(on_match->Clone(storage));
|
||||
}
|
||||
for (auto *on_create : on_create_) {
|
||||
merge->on_create_.push_back(on_create->Clone(storage));
|
||||
}
|
||||
return merge;
|
||||
}
|
||||
|
||||
Pattern *pattern_ = nullptr;
|
||||
std::vector<Clause *> on_match_;
|
||||
std::vector<Clause *> on_create_;
|
||||
@ -1077,6 +1343,10 @@ class Unwind : public Clause {
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
Unwind *Clone(AstTreeStorage &storage) const override {
|
||||
return storage.Create<Unwind>(named_expression_->Clone(storage));
|
||||
}
|
||||
|
||||
NamedExpression *const named_expression_ = nullptr;
|
||||
|
||||
protected:
|
||||
@ -1087,28 +1357,6 @@ class Unwind : public Clause {
|
||||
}
|
||||
};
|
||||
|
||||
// It would be better to call this AstTree, but we already have a class Tree,
|
||||
// which could be renamed to Node or AstTreeNode, but we also have a class
|
||||
// called NodeAtom...
|
||||
class AstTreeStorage {
|
||||
public:
|
||||
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) {
|
||||
// Never call create for a Query. Call query() instead.
|
||||
static_assert(!std::is_same<T, Query>::value, "Call query() instead");
|
||||
T *p = new T(next_uid_++, std::forward<Args>(args)...);
|
||||
storage_.emplace_back(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
Query *query() { return dynamic_cast<Query *>(storage_[0].get()); }
|
||||
|
||||
private:
|
||||
int next_uid_ = 0;
|
||||
std::vector<std::unique_ptr<Tree>> storage_;
|
||||
};
|
||||
#undef CLONE_BINARY_EXPRESSION
|
||||
#undef CLONE_UNARY_EXPRESSION
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ using testing::Pair;
|
||||
using testing::ElementsAre;
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
// This generator uses ast constructed by parsing the query.
|
||||
class AstGenerator {
|
||||
public:
|
||||
AstGenerator(const std::string &query)
|
||||
@ -46,16 +47,60 @@ class AstGenerator {
|
||||
Query *query_;
|
||||
};
|
||||
|
||||
TEST(CypherMainVisitorTest, SyntaxException) {
|
||||
ASSERT_THROW(AstGenerator("CREATE ()-[*1...2]-()"), SyntaxException);
|
||||
// This clones ast, but uses original one. This done just to ensure that cloning
|
||||
// doesn't change original.
|
||||
class OriginalAfterCloningAstGenerator : public AstGenerator {
|
||||
public:
|
||||
OriginalAfterCloningAstGenerator(const std::string &query)
|
||||
: AstGenerator(query) {
|
||||
AstTreeStorage storage;
|
||||
visitor_.query()->Clone(storage);
|
||||
}
|
||||
};
|
||||
|
||||
// This generator clones parsed ast and uses that one.
|
||||
// Original ast is cleared after cloning to ensure that cloned ast doesn't reuse
|
||||
// any data from original ast.
|
||||
class ClonedAstGenerator {
|
||||
public:
|
||||
ClonedAstGenerator(const std::string &query)
|
||||
: dbms_(),
|
||||
db_accessor_(dbms_.active()),
|
||||
context_(Config{}, *db_accessor_),
|
||||
query_string_(query),
|
||||
query_([&]() {
|
||||
::frontend::opencypher::Parser parser(query);
|
||||
CypherMainVisitor visitor(context_);
|
||||
visitor.visit(parser.tree());
|
||||
return visitor.query()->Clone(storage);
|
||||
}()) {}
|
||||
|
||||
Dbms dbms_;
|
||||
std::unique_ptr<GraphDbAccessor> db_accessor_;
|
||||
Context context_;
|
||||
std::string query_string_;
|
||||
AstTreeStorage storage;
|
||||
Query *query_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CypherMainVisitorTest : public ::testing::Test {};
|
||||
|
||||
typedef ::testing::Types<AstGenerator, OriginalAfterCloningAstGenerator,
|
||||
ClonedAstGenerator>
|
||||
AstGeneratorTypes;
|
||||
TYPED_TEST_CASE(CypherMainVisitorTest, AstGeneratorTypes);
|
||||
|
||||
TYPED_TEST(CypherMainVisitorTest, SyntaxException) {
|
||||
ASSERT_THROW(TypeParam("CREATE ()-[*1...2]-()"), SyntaxException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, SyntaxExceptionOnTrailingText) {
|
||||
ASSERT_THROW(AstGenerator("RETURN 2 + 2 mirko"), SyntaxException);
|
||||
TYPED_TEST(CypherMainVisitorTest, SyntaxExceptionOnTrailingText) {
|
||||
ASSERT_THROW(TypeParam("RETURN 2 + 2 mirko"), SyntaxException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, PropertyLookup) {
|
||||
AstGenerator ast_generator("RETURN n.x");
|
||||
TYPED_TEST(CypherMainVisitorTest, PropertyLookup) {
|
||||
TypeParam ast_generator("RETURN n.x");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -69,8 +114,8 @@ TEST(CypherMainVisitorTest, PropertyLookup) {
|
||||
ast_generator.db_accessor_->property("x"));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, LabelsTest) {
|
||||
AstGenerator ast_generator("RETURN n:x:y");
|
||||
TYPED_TEST(CypherMainVisitorTest, LabelsTest) {
|
||||
TypeParam ast_generator("RETURN n:x:y");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -85,8 +130,8 @@ TEST(CypherMainVisitorTest, LabelsTest) {
|
||||
ast_generator.db_accessor_->label("y")));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, EscapedLabel) {
|
||||
AstGenerator ast_generator("RETURN n:`l-$\"'ab``e````l`");
|
||||
TYPED_TEST(CypherMainVisitorTest, EscapedLabel) {
|
||||
TypeParam ast_generator("RETURN n:`l-$\"'ab``e````l`");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -98,8 +143,8 @@ TEST(CypherMainVisitorTest, EscapedLabel) {
|
||||
ElementsAre(ast_generator.db_accessor_->label("l-$\"'ab`e``l")));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnNoDistinctNoBagSemantics) {
|
||||
AstGenerator ast_generator("RETURN x");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnNoDistinctNoBagSemantics) {
|
||||
TypeParam ast_generator("RETURN x");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -111,16 +156,16 @@ TEST(CypherMainVisitorTest, ReturnNoDistinctNoBagSemantics) {
|
||||
ASSERT_FALSE(return_clause->body_.distinct);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnDistinct) {
|
||||
AstGenerator ast_generator("RETURN DISTINCT x");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnDistinct) {
|
||||
TypeParam ast_generator("RETURN DISTINCT x");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(return_clause->body_.distinct);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnLimit) {
|
||||
AstGenerator ast_generator("RETURN x LIMIT 5");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnLimit) {
|
||||
TypeParam ast_generator("RETURN x LIMIT 5");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -130,8 +175,8 @@ TEST(CypherMainVisitorTest, ReturnLimit) {
|
||||
ASSERT_EQ(literal->value_.Value<int64_t>(), 5);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnSkip) {
|
||||
AstGenerator ast_generator("RETURN x SKIP 5");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnSkip) {
|
||||
TypeParam ast_generator("RETURN x SKIP 5");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -141,8 +186,8 @@ TEST(CypherMainVisitorTest, ReturnSkip) {
|
||||
ASSERT_EQ(literal->value_.Value<int64_t>(), 5);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnOrderBy) {
|
||||
AstGenerator ast_generator("RETURN x, y, z ORDER BY z ASC, x, y DESC");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnOrderBy) {
|
||||
TypeParam ast_generator("RETURN x, y, z ORDER BY z ASC, x, y DESC");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -157,8 +202,8 @@ TEST(CypherMainVisitorTest, ReturnOrderBy) {
|
||||
Pair(Ordering::DESC, "y")));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnNamedIdentifier) {
|
||||
AstGenerator ast_generator("RETURN var AS var5");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnNamedIdentifier) {
|
||||
TypeParam ast_generator("RETURN var AS var5");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
ASSERT_FALSE(return_clause->body_.all_identifiers);
|
||||
@ -168,16 +213,16 @@ TEST(CypherMainVisitorTest, ReturnNamedIdentifier) {
|
||||
ASSERT_EQ(identifier->name_, "var");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnAsterisk) {
|
||||
AstGenerator ast_generator("RETURN *");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnAsterisk) {
|
||||
TypeParam ast_generator("RETURN *");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(return_clause->body_.all_identifiers);
|
||||
ASSERT_EQ(return_clause->body_.named_expressions.size(), 0U);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, IntegerLiteral) {
|
||||
AstGenerator ast_generator("RETURN 42");
|
||||
TYPED_TEST(CypherMainVisitorTest, IntegerLiteral) {
|
||||
TypeParam ast_generator("RETURN 42");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -186,13 +231,13 @@ TEST(CypherMainVisitorTest, IntegerLiteral) {
|
||||
ASSERT_EQ(literal->value_.Value<int64_t>(), 42);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, IntegerLiteralTooLarge) {
|
||||
ASSERT_THROW(AstGenerator("RETURN 10000000000000000000000000"),
|
||||
TYPED_TEST(CypherMainVisitorTest, IntegerLiteralTooLarge) {
|
||||
ASSERT_THROW(TypeParam("RETURN 10000000000000000000000000"),
|
||||
SemanticException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, BooleanLiteralTrue) {
|
||||
AstGenerator ast_generator("RETURN TrUe");
|
||||
TYPED_TEST(CypherMainVisitorTest, BooleanLiteralTrue) {
|
||||
TypeParam ast_generator("RETURN TrUe");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -201,8 +246,8 @@ TEST(CypherMainVisitorTest, BooleanLiteralTrue) {
|
||||
ASSERT_EQ(literal->value_.Value<bool>(), true);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, BooleanLiteralFalse) {
|
||||
AstGenerator ast_generator("RETURN faLSE");
|
||||
TYPED_TEST(CypherMainVisitorTest, BooleanLiteralFalse) {
|
||||
TypeParam ast_generator("RETURN faLSE");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -211,8 +256,8 @@ TEST(CypherMainVisitorTest, BooleanLiteralFalse) {
|
||||
ASSERT_EQ(literal->value_.Value<bool>(), false);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, NullLiteral) {
|
||||
AstGenerator ast_generator("RETURN nULl");
|
||||
TYPED_TEST(CypherMainVisitorTest, NullLiteral) {
|
||||
TypeParam ast_generator("RETURN nULl");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -221,8 +266,8 @@ TEST(CypherMainVisitorTest, NullLiteral) {
|
||||
ASSERT_EQ(literal->value_.type(), TypedValue::Type::Null);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ParenthesizedExpression) {
|
||||
AstGenerator ast_generator("RETURN (2)");
|
||||
TYPED_TEST(CypherMainVisitorTest, ParenthesizedExpression) {
|
||||
TypeParam ast_generator("RETURN (2)");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -231,8 +276,8 @@ TEST(CypherMainVisitorTest, ParenthesizedExpression) {
|
||||
ASSERT_EQ(literal->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, OrOperator) {
|
||||
AstGenerator ast_generator("RETURN true Or false oR n");
|
||||
TYPED_TEST(CypherMainVisitorTest, OrOperator) {
|
||||
TypeParam ast_generator("RETURN true Or false oR n");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -252,8 +297,8 @@ TEST(CypherMainVisitorTest, OrOperator) {
|
||||
ASSERT_EQ(operand3->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, XorOperator) {
|
||||
AstGenerator ast_generator("RETURN true xOr false");
|
||||
TYPED_TEST(CypherMainVisitorTest, XorOperator) {
|
||||
TypeParam ast_generator("RETURN true xOr false");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *xor_operator = dynamic_cast<XorOperator *>(
|
||||
@ -266,8 +311,8 @@ TEST(CypherMainVisitorTest, XorOperator) {
|
||||
ASSERT_EQ(operand2->value_.Value<bool>(), false);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, AndOperator) {
|
||||
AstGenerator ast_generator("RETURN true and false");
|
||||
TYPED_TEST(CypherMainVisitorTest, AndOperator) {
|
||||
TypeParam ast_generator("RETURN true and false");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *and_operator = dynamic_cast<AndOperator *>(
|
||||
@ -280,8 +325,8 @@ TEST(CypherMainVisitorTest, AndOperator) {
|
||||
ASSERT_EQ(operand2->value_.Value<bool>(), false);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, AdditionSubtractionOperators) {
|
||||
AstGenerator ast_generator("RETURN 1 - 2 + 3");
|
||||
TYPED_TEST(CypherMainVisitorTest, AdditionSubtractionOperators) {
|
||||
TypeParam ast_generator("RETURN 1 - 2 + 3");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *addition_operator = dynamic_cast<AdditionOperator *>(
|
||||
@ -304,8 +349,8 @@ TEST(CypherMainVisitorTest, AdditionSubtractionOperators) {
|
||||
ASSERT_EQ(operand3->value_.Value<int64_t>(), 3);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, MulitplicationOperator) {
|
||||
AstGenerator ast_generator("RETURN 2 * 3");
|
||||
TYPED_TEST(CypherMainVisitorTest, MulitplicationOperator) {
|
||||
TypeParam ast_generator("RETURN 2 * 3");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *mult_operator = dynamic_cast<MultiplicationOperator *>(
|
||||
@ -320,8 +365,8 @@ TEST(CypherMainVisitorTest, MulitplicationOperator) {
|
||||
ASSERT_EQ(operand2->value_.Value<int64_t>(), 3);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, DivisionOperator) {
|
||||
AstGenerator ast_generator("RETURN 2 / 3");
|
||||
TYPED_TEST(CypherMainVisitorTest, DivisionOperator) {
|
||||
TypeParam ast_generator("RETURN 2 / 3");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *div_operator = dynamic_cast<DivisionOperator *>(
|
||||
@ -334,8 +379,8 @@ TEST(CypherMainVisitorTest, DivisionOperator) {
|
||||
ASSERT_EQ(operand2->value_.Value<int64_t>(), 3);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ModOperator) {
|
||||
AstGenerator ast_generator("RETURN 2 % 3");
|
||||
TYPED_TEST(CypherMainVisitorTest, ModOperator) {
|
||||
TypeParam ast_generator("RETURN 2 % 3");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *mod_operator = dynamic_cast<ModOperator *>(
|
||||
@ -363,8 +408,8 @@ TEST(CypherMainVisitorTest, ModOperator) {
|
||||
ASSERT_EQ(operand2->value_.Value<int64_t>(), VALUE2); \
|
||||
} while (0)
|
||||
|
||||
TEST(CypherMainVisitorTest, ComparisonOperators) {
|
||||
AstGenerator ast_generator("RETURN 2 = 3 != 4 <> 5 < 6 > 7 <= 8 >= 9");
|
||||
TYPED_TEST(CypherMainVisitorTest, ComparisonOperators) {
|
||||
TypeParam ast_generator("RETURN 2 = 3 != 4 <> 5 < 6 > 7 <= 8 >= 9");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
Expression *_operator =
|
||||
@ -385,8 +430,8 @@ TEST(CypherMainVisitorTest, ComparisonOperators) {
|
||||
|
||||
#undef CHECK_COMPARISON
|
||||
|
||||
TEST(CypherMainVisitorTest, ListIndexingOperator) {
|
||||
AstGenerator ast_generator("RETURN [1,2,3] [ 2 ]");
|
||||
TYPED_TEST(CypherMainVisitorTest, ListIndexingOperator) {
|
||||
TypeParam ast_generator("RETURN [1,2,3] [ 2 ]");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *list_index_op = dynamic_cast<ListIndexingOperator *>(
|
||||
@ -398,12 +443,12 @@ TEST(CypherMainVisitorTest, ListIndexingOperator) {
|
||||
ASSERT_EQ(index->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ListSlicingOperatorNoBounds) {
|
||||
ASSERT_THROW(AstGenerator("RETURN [1,2,3] [ .. ]"), SemanticException);
|
||||
TYPED_TEST(CypherMainVisitorTest, ListSlicingOperatorNoBounds) {
|
||||
ASSERT_THROW(TypeParam("RETURN [1,2,3] [ .. ]"), SemanticException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ListSlicingOperator) {
|
||||
AstGenerator ast_generator("RETURN [1,2,3] [ .. 2 ]");
|
||||
TYPED_TEST(CypherMainVisitorTest, ListSlicingOperator) {
|
||||
TypeParam ast_generator("RETURN [1,2,3] [ .. 2 ]");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *list_slicing_op = dynamic_cast<ListSlicingOperator *>(
|
||||
@ -417,8 +462,8 @@ TEST(CypherMainVisitorTest, ListSlicingOperator) {
|
||||
EXPECT_EQ(upper_bound->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, InListOperator) {
|
||||
AstGenerator ast_generator("RETURN 5 IN [1,2]");
|
||||
TYPED_TEST(CypherMainVisitorTest, InListOperator) {
|
||||
TypeParam ast_generator("RETURN 5 IN [1,2]");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *in_list_operator = dynamic_cast<InListOperator *>(
|
||||
@ -432,8 +477,8 @@ TEST(CypherMainVisitorTest, InListOperator) {
|
||||
ASSERT_TRUE(list);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, InWithListIndexing) {
|
||||
AstGenerator ast_generator("RETURN 1 IN [[1,2]][0]");
|
||||
TYPED_TEST(CypherMainVisitorTest, InWithListIndexing) {
|
||||
TypeParam ast_generator("RETURN 1 IN [[1,2]][0]");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *in_list_operator = dynamic_cast<InListOperator *>(
|
||||
@ -443,16 +488,18 @@ TEST(CypherMainVisitorTest, InWithListIndexing) {
|
||||
dynamic_cast<PrimitiveLiteral *>(in_list_operator->expression1_);
|
||||
ASSERT_TRUE(literal);
|
||||
EXPECT_EQ(literal->value_.Value<int64_t>(), 1);
|
||||
auto *list_indexing = dynamic_cast<ListIndexingOperator *>(in_list_operator->expression2_);
|
||||
auto *list_indexing =
|
||||
dynamic_cast<ListIndexingOperator *>(in_list_operator->expression2_);
|
||||
ASSERT_TRUE(list_indexing);
|
||||
auto *list = dynamic_cast<ListLiteral *>(list_indexing->expression1_);
|
||||
EXPECT_TRUE(list);
|
||||
auto *list_index = dynamic_cast<PrimitiveLiteral *>(list_indexing->expression2_);
|
||||
auto *list_index =
|
||||
dynamic_cast<PrimitiveLiteral *>(list_indexing->expression2_);
|
||||
EXPECT_TRUE(list_index);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, IsNull) {
|
||||
AstGenerator ast_generator("RETURN 2 iS NulL");
|
||||
TYPED_TEST(CypherMainVisitorTest, IsNull) {
|
||||
TypeParam ast_generator("RETURN 2 iS NulL");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *is_type_operator = dynamic_cast<IsNullOperator *>(
|
||||
@ -463,8 +510,8 @@ TEST(CypherMainVisitorTest, IsNull) {
|
||||
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, IsNotNull) {
|
||||
AstGenerator ast_generator("RETURN 2 iS nOT NulL");
|
||||
TYPED_TEST(CypherMainVisitorTest, IsNotNull) {
|
||||
TypeParam ast_generator("RETURN 2 iS nOT NulL");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *not_operator = dynamic_cast<NotOperator *>(
|
||||
@ -477,8 +524,8 @@ TEST(CypherMainVisitorTest, IsNotNull) {
|
||||
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, NotOperator) {
|
||||
AstGenerator ast_generator("RETURN not true");
|
||||
TYPED_TEST(CypherMainVisitorTest, NotOperator) {
|
||||
TypeParam ast_generator("RETURN not true");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *not_operator = dynamic_cast<NotOperator *>(
|
||||
@ -488,8 +535,8 @@ TEST(CypherMainVisitorTest, NotOperator) {
|
||||
ASSERT_EQ(operand->value_.Value<bool>(), true);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, UnaryMinusPlusOperators) {
|
||||
AstGenerator ast_generator("RETURN -+5");
|
||||
TYPED_TEST(CypherMainVisitorTest, UnaryMinusPlusOperators) {
|
||||
TypeParam ast_generator("RETURN -+5");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *unary_minus_operator = dynamic_cast<UnaryMinusOperator *>(
|
||||
@ -504,8 +551,8 @@ TEST(CypherMainVisitorTest, UnaryMinusPlusOperators) {
|
||||
ASSERT_EQ(operand->value_.Value<int64_t>(), 5);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Aggregation) {
|
||||
AstGenerator ast_generator(
|
||||
TYPED_TEST(CypherMainVisitorTest, Aggregation) {
|
||||
TypeParam ast_generator(
|
||||
"RETURN COUNT(a), MIN(b), MAX(c), SUM(d), AVG(e), COLLECT(f), COUNT(*)");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -530,15 +577,15 @@ TEST(CypherMainVisitorTest, Aggregation) {
|
||||
ASSERT_FALSE(aggregation->expression_);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, UndefinedFunction) {
|
||||
ASSERT_THROW(AstGenerator("RETURN "
|
||||
"IHopeWeWillNeverHaveAwesomeMemgraphProcedureWithS"
|
||||
"uchALongAndAwesomeNameSinceThisTestWouldFail(1)"),
|
||||
TYPED_TEST(CypherMainVisitorTest, UndefinedFunction) {
|
||||
ASSERT_THROW(TypeParam("RETURN "
|
||||
"IHopeWeWillNeverHaveAwesomeMemgraphProcedureWithS"
|
||||
"uchALongAndAwesomeNameSinceThisTestWouldFail(1)"),
|
||||
SemanticException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Function) {
|
||||
AstGenerator ast_generator("RETURN abs(n, 2)");
|
||||
TYPED_TEST(CypherMainVisitorTest, Function) {
|
||||
TypeParam ast_generator("RETURN abs(n, 2)");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
ASSERT_EQ(return_clause->body_.named_expressions.size(), 1);
|
||||
@ -548,8 +595,8 @@ TEST(CypherMainVisitorTest, Function) {
|
||||
ASSERT_TRUE(function->function_);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, StringLiteralDoubleQuotes) {
|
||||
AstGenerator ast_generator("RETURN \"mi'rko\"");
|
||||
TYPED_TEST(CypherMainVisitorTest, StringLiteralDoubleQuotes) {
|
||||
TypeParam ast_generator("RETURN \"mi'rko\"");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -558,8 +605,8 @@ TEST(CypherMainVisitorTest, StringLiteralDoubleQuotes) {
|
||||
ASSERT_EQ(literal->value_.Value<std::string>(), "mi'rko");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, StringLiteralSingleQuotes) {
|
||||
AstGenerator ast_generator("RETURN 'mi\"rko'");
|
||||
TYPED_TEST(CypherMainVisitorTest, StringLiteralSingleQuotes) {
|
||||
TypeParam ast_generator("RETURN 'mi\"rko'");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -568,9 +615,8 @@ TEST(CypherMainVisitorTest, StringLiteralSingleQuotes) {
|
||||
ASSERT_EQ(literal->value_.Value<std::string>(), "mi\"rko");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, StringLiteralEscapedChars) {
|
||||
AstGenerator ast_generator(
|
||||
"RETURN '\\\\\\'\\\"\\b\\B\\f\\F\\n\\N\\r\\R\\t\\T'");
|
||||
TYPED_TEST(CypherMainVisitorTest, StringLiteralEscapedChars) {
|
||||
TypeParam ast_generator("RETURN '\\\\\\'\\\"\\b\\B\\f\\F\\n\\N\\r\\R\\t\\T'");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -579,8 +625,8 @@ TEST(CypherMainVisitorTest, StringLiteralEscapedChars) {
|
||||
ASSERT_EQ(literal->value_.Value<std::string>(), "\\'\"\b\b\f\f\n\n\r\r\t\t");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, StringLiteralEscapedUtf16) {
|
||||
AstGenerator ast_generator("RETURN '\\u221daaa\\U221daaa'");
|
||||
TYPED_TEST(CypherMainVisitorTest, StringLiteralEscapedUtf16) {
|
||||
TypeParam ast_generator("RETURN '\\u221daaa\\U221daaa'");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -589,8 +635,8 @@ TEST(CypherMainVisitorTest, StringLiteralEscapedUtf16) {
|
||||
ASSERT_EQ(literal->value_.Value<std::string>(), u8"\u221daaa\u221daaa");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, StringLiteralEscapedUtf32) {
|
||||
AstGenerator ast_generator("RETURN '\\u0001F600aaaa\\U0001F600aaaaaaaa'");
|
||||
TYPED_TEST(CypherMainVisitorTest, StringLiteralEscapedUtf32) {
|
||||
TypeParam ast_generator("RETURN '\\u0001F600aaaa\\U0001F600aaaaaaaa'");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -600,8 +646,8 @@ TEST(CypherMainVisitorTest, StringLiteralEscapedUtf32) {
|
||||
u8"\U0001F600aaaa\U0001F600aaaaaaaa");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, DoubleLiteral) {
|
||||
AstGenerator ast_generator("RETURN 3.5");
|
||||
TYPED_TEST(CypherMainVisitorTest, DoubleLiteral) {
|
||||
TypeParam ast_generator("RETURN 3.5");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -610,8 +656,8 @@ TEST(CypherMainVisitorTest, DoubleLiteral) {
|
||||
ASSERT_EQ(literal->value_.Value<double>(), 3.5);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, DoubleLiteralExponent) {
|
||||
AstGenerator ast_generator("RETURN 5e-1");
|
||||
TYPED_TEST(CypherMainVisitorTest, DoubleLiteralExponent) {
|
||||
TypeParam ast_generator("RETURN 5e-1");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *literal = dynamic_cast<PrimitiveLiteral *>(
|
||||
@ -620,8 +666,8 @@ TEST(CypherMainVisitorTest, DoubleLiteralExponent) {
|
||||
ASSERT_EQ(literal->value_.Value<double>(), 0.5);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ListLiteral) {
|
||||
AstGenerator ast_generator("RETURN [3, [], 'johhny']");
|
||||
TYPED_TEST(CypherMainVisitorTest, ListLiteral) {
|
||||
TypeParam ast_generator("RETURN [3, [], 'johhny']");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *list_literal = dynamic_cast<ListLiteral *>(
|
||||
@ -639,8 +685,8 @@ TEST(CypherMainVisitorTest, ListLiteral) {
|
||||
EXPECT_EQ(elem_2->value_.type(), TypedValue::Type::String);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, NodePattern) {
|
||||
AstGenerator ast_generator(
|
||||
TYPED_TEST(CypherMainVisitorTest, NodePattern) {
|
||||
TypeParam ast_generator(
|
||||
"MATCH (:label1:label2:label3 {a : 5, b : 10}) RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
@ -674,12 +720,12 @@ TEST(CypherMainVisitorTest, NodePattern) {
|
||||
Pair(ast_generator.db_accessor_->property("b"), 10)));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, PropertyMapSameKeyAppearsTwice) {
|
||||
EXPECT_THROW(AstGenerator("MATCH ({a : 1, a : 2})"), SemanticException);
|
||||
TYPED_TEST(CypherMainVisitorTest, PropertyMapSameKeyAppearsTwice) {
|
||||
EXPECT_THROW(TypeParam("MATCH ({a : 1, a : 2})"), SemanticException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, NodePatternIdentifier) {
|
||||
AstGenerator ast_generator("MATCH (var) RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, NodePatternIdentifier) {
|
||||
TypeParam ast_generator("MATCH (var) RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(match);
|
||||
@ -694,8 +740,8 @@ TEST(CypherMainVisitorTest, NodePatternIdentifier) {
|
||||
EXPECT_THAT(node->properties_, UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, RelationshipPatternNoDetails) {
|
||||
AstGenerator ast_generator("MATCH ()--() RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternNoDetails) {
|
||||
TypeParam ast_generator("MATCH ()--() RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(match);
|
||||
@ -718,8 +764,8 @@ TEST(CypherMainVisitorTest, RelationshipPatternNoDetails) {
|
||||
}
|
||||
|
||||
// PatternPart in braces.
|
||||
TEST(CypherMainVisitorTest, PatternPartBraces) {
|
||||
AstGenerator ast_generator("MATCH ((()--())) RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, PatternPartBraces) {
|
||||
TypeParam ast_generator("MATCH ((()--())) RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(match);
|
||||
@ -740,8 +786,8 @@ TEST(CypherMainVisitorTest, PatternPartBraces) {
|
||||
EXPECT_FALSE(edge->identifier_->user_declared_);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
|
||||
AstGenerator ast_generator(
|
||||
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
|
||||
TypeParam ast_generator(
|
||||
"MATCH ()<-[:type1|type2 {a : 5, b : 10}]-() RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
@ -768,8 +814,8 @@ TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
|
||||
Pair(ast_generator.db_accessor_->property("b"), 10)));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
AstGenerator ast_generator("MATCH ()-[var]->() RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
TypeParam ast_generator("MATCH ()-[var]->() RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(match);
|
||||
@ -784,7 +830,7 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
}
|
||||
|
||||
// // Relationship with unbounded variable range.
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternUnbounded) {
|
||||
// TYPED_TEST(CypherMainVisitorTest, RelationshipPatternUnbounded) {
|
||||
// ParserTables parser("CREATE ()-[*]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -794,7 +840,7 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with lower bounded variable range.
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternLowerBounded) {
|
||||
// TYPED_TEST(CypherMainVisitorTest, RelationshipPatternLowerBounded) {
|
||||
// ParserTables parser("CREATE ()-[*5..]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -804,7 +850,7 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with upper bounded variable range.
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternUpperBounded) {
|
||||
// TYPED_TEST(CypherMainVisitorTest, RelationshipPatternUpperBounded) {
|
||||
// ParserTables parser("CREATE ()-[*..10]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -813,7 +859,7 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with lower and upper bounded variable range.
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternLowerUpperBounded) {
|
||||
// TYPED_TEST(CypherMainVisitorTest, RelationshipPatternLowerUpperBounded) {
|
||||
// ParserTables parser("CREATE ()-[*5..10]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -822,7 +868,7 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
// }
|
||||
//
|
||||
// // Relationship with fixed number of edges.
|
||||
// TEST(CypherMainVisitorTest, RelationshipPatternFixedRange) {
|
||||
// TYPED_TEST(CypherMainVisitorTest, RelationshipPatternFixedRange) {
|
||||
// ParserTables parser("CREATE ()-[*10]-()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 0U);
|
||||
// ASSERT_EQ(parser.relationships_.size(), 1U);
|
||||
@ -832,7 +878,7 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
//
|
||||
//
|
||||
// // PatternPart with variable.
|
||||
// TEST(CypherMainVisitorTest, PatternPartVariable) {
|
||||
// TYPED_TEST(CypherMainVisitorTest, PatternPartVariable) {
|
||||
// ParserTables parser("CREATE var=()--()");
|
||||
// ASSERT_EQ(parser.identifiers_map_.size(), 1U);
|
||||
// ASSERT_EQ(parser.pattern_parts_.size(), 1U);
|
||||
@ -847,8 +893,8 @@ TEST(CypherMainVisitorTest, RelationshipPatternVariable) {
|
||||
// parser.pattern_parts_.end());
|
||||
// }
|
||||
|
||||
TEST(CypherMainVisitorTest, ReturnUnanemdIdentifier) {
|
||||
AstGenerator ast_generator("RETURN var");
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnUnanemdIdentifier) {
|
||||
TypeParam ast_generator("RETURN var");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
@ -863,8 +909,8 @@ TEST(CypherMainVisitorTest, ReturnUnanemdIdentifier) {
|
||||
ASSERT_TRUE(identifier->user_declared_);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Create) {
|
||||
AstGenerator ast_generator("CREATE (n)");
|
||||
TYPED_TEST(CypherMainVisitorTest, Create) {
|
||||
TypeParam ast_generator("CREATE (n)");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *create = dynamic_cast<Create *>(query->clauses_[0]);
|
||||
@ -878,8 +924,8 @@ TEST(CypherMainVisitorTest, Create) {
|
||||
ASSERT_EQ(node->identifier_->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Delete) {
|
||||
AstGenerator ast_generator("DELETE n, m");
|
||||
TYPED_TEST(CypherMainVisitorTest, Delete) {
|
||||
TypeParam ast_generator("DELETE n, m");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *del = dynamic_cast<Delete *>(query->clauses_[0]);
|
||||
@ -894,8 +940,8 @@ TEST(CypherMainVisitorTest, Delete) {
|
||||
ASSERT_EQ(identifier2->name_, "m");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, DeleteDetach) {
|
||||
AstGenerator ast_generator("DETACH DELETE n");
|
||||
TYPED_TEST(CypherMainVisitorTest, DeleteDetach) {
|
||||
TypeParam ast_generator("DETACH DELETE n");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *del = dynamic_cast<Delete *>(query->clauses_[0]);
|
||||
@ -907,8 +953,8 @@ TEST(CypherMainVisitorTest, DeleteDetach) {
|
||||
ASSERT_EQ(identifier1->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, OptionalMatchWhere) {
|
||||
AstGenerator ast_generator("OPTIONAL MATCH (n) WHERE m RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, OptionalMatchWhere) {
|
||||
TypeParam ast_generator("OPTIONAL MATCH (n) WHERE m RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
||||
@ -920,8 +966,8 @@ TEST(CypherMainVisitorTest, OptionalMatchWhere) {
|
||||
ASSERT_EQ(identifier->name_, "m");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Set) {
|
||||
AstGenerator ast_generator("SET a.x = b, c = d, e += f, g : h : i ");
|
||||
TYPED_TEST(CypherMainVisitorTest, Set) {
|
||||
TypeParam ast_generator("SET a.x = b, c = d, e += f, g : h : i ");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 4U);
|
||||
|
||||
@ -974,8 +1020,8 @@ TEST(CypherMainVisitorTest, Set) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Remove) {
|
||||
AstGenerator ast_generator("REMOVE a.x, g : h : i");
|
||||
TYPED_TEST(CypherMainVisitorTest, Remove) {
|
||||
TypeParam ast_generator("REMOVE a.x, g : h : i");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
|
||||
@ -1001,8 +1047,8 @@ TEST(CypherMainVisitorTest, Remove) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, With) {
|
||||
AstGenerator ast_generator("WITH n AS m RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, With) {
|
||||
TypeParam ast_generator("WITH n AS m RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *with = dynamic_cast<With *>(query->clauses_[0]);
|
||||
@ -1019,12 +1065,12 @@ TEST(CypherMainVisitorTest, With) {
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, WithNonAliasedExpression) {
|
||||
ASSERT_THROW(AstGenerator("WITH n.x RETURN 1"), SemanticException);
|
||||
TYPED_TEST(CypherMainVisitorTest, WithNonAliasedExpression) {
|
||||
ASSERT_THROW(TypeParam("WITH n.x RETURN 1"), SemanticException);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, WithNonAliasedVariable) {
|
||||
AstGenerator ast_generator("WITH n RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, WithNonAliasedVariable) {
|
||||
TypeParam ast_generator("WITH n RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *with = dynamic_cast<With *>(query->clauses_[0]);
|
||||
@ -1036,8 +1082,8 @@ TEST(CypherMainVisitorTest, WithNonAliasedVariable) {
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, WithDistinct) {
|
||||
AstGenerator ast_generator("WITH DISTINCT n AS m RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, WithDistinct) {
|
||||
TypeParam ast_generator("WITH DISTINCT n AS m RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *with = dynamic_cast<With *>(query->clauses_[0]);
|
||||
@ -1050,8 +1096,8 @@ TEST(CypherMainVisitorTest, WithDistinct) {
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, WithBag) {
|
||||
AstGenerator ast_generator("WITH n as m ORDER BY m SKIP 1 LIMIT 2 RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, WithBag) {
|
||||
TypeParam ast_generator("WITH n as m ORDER BY m SKIP 1 LIMIT 2 RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *with = dynamic_cast<With *>(query->clauses_[0]);
|
||||
@ -1064,8 +1110,8 @@ TEST(CypherMainVisitorTest, WithBag) {
|
||||
ASSERT_TRUE(with->body_.skip);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, WithWhere) {
|
||||
AstGenerator ast_generator("WITH n AS m WHERE k RETURN 1");
|
||||
TYPED_TEST(CypherMainVisitorTest, WithWhere) {
|
||||
TypeParam ast_generator("WITH n AS m WHERE k RETURN 1");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *with = dynamic_cast<With *>(query->clauses_[0]);
|
||||
@ -1081,53 +1127,52 @@ TEST(CypherMainVisitorTest, WithWhere) {
|
||||
ASSERT_EQ(identifier2->name_, "n");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, ClausesOrdering) {
|
||||
TYPED_TEST(CypherMainVisitorTest, ClausesOrdering) {
|
||||
// Obviously some of the ridiculous combinations don't fail here, but they
|
||||
// will fail in semantic analysis or they make perfect sense as a part of
|
||||
// bigger query.
|
||||
AstGenerator("RETURN 1");
|
||||
ASSERT_THROW(AstGenerator("RETURN 1 RETURN 1"), SemanticException);
|
||||
ASSERT_THROW(AstGenerator("RETURN 1 MATCH (n) RETURN n"), SemanticException);
|
||||
ASSERT_THROW(AstGenerator("RETURN 1 DELETE n"), SemanticException);
|
||||
ASSERT_THROW(AstGenerator("RETURN 1 MERGE (n)"), SemanticException);
|
||||
ASSERT_THROW(AstGenerator("RETURN 1 WITH n AS m RETURN 1"),
|
||||
SemanticException);
|
||||
ASSERT_THROW(AstGenerator("RETURN 1 AS n UNWIND n AS x RETURN x"),
|
||||
TypeParam("RETURN 1");
|
||||
ASSERT_THROW(TypeParam("RETURN 1 RETURN 1"), SemanticException);
|
||||
ASSERT_THROW(TypeParam("RETURN 1 MATCH (n) RETURN n"), SemanticException);
|
||||
ASSERT_THROW(TypeParam("RETURN 1 DELETE n"), SemanticException);
|
||||
ASSERT_THROW(TypeParam("RETURN 1 MERGE (n)"), SemanticException);
|
||||
ASSERT_THROW(TypeParam("RETURN 1 WITH n AS m RETURN 1"), SemanticException);
|
||||
ASSERT_THROW(TypeParam("RETURN 1 AS n UNWIND n AS x RETURN x"),
|
||||
SemanticException);
|
||||
|
||||
ASSERT_THROW(AstGenerator("OPTIONAL MATCH (n) MATCH (m) RETURN n, m"),
|
||||
ASSERT_THROW(TypeParam("OPTIONAL MATCH (n) MATCH (m) RETURN n, m"),
|
||||
SemanticException);
|
||||
AstGenerator("OPTIONAL MATCH (n) WITH n MATCH (m) RETURN n, m");
|
||||
AstGenerator("OPTIONAL MATCH (n) OPTIONAL MATCH (m) RETURN n, m");
|
||||
AstGenerator("MATCH (n) OPTIONAL MATCH (m) RETURN n, m");
|
||||
TypeParam("OPTIONAL MATCH (n) WITH n MATCH (m) RETURN n, m");
|
||||
TypeParam("OPTIONAL MATCH (n) OPTIONAL MATCH (m) RETURN n, m");
|
||||
TypeParam("MATCH (n) OPTIONAL MATCH (m) RETURN n, m");
|
||||
|
||||
AstGenerator("CREATE (n)");
|
||||
ASSERT_THROW(AstGenerator("SET n:x MATCH (n) RETURN n"), SemanticException);
|
||||
AstGenerator("REMOVE n.x SET n.x = 1");
|
||||
AstGenerator("REMOVE n:L RETURN n");
|
||||
AstGenerator("SET n.x = 1 WITH n AS m RETURN m");
|
||||
TypeParam("CREATE (n)");
|
||||
ASSERT_THROW(TypeParam("SET n:x MATCH (n) RETURN n"), SemanticException);
|
||||
TypeParam("REMOVE n.x SET n.x = 1");
|
||||
TypeParam("REMOVE n:L RETURN n");
|
||||
TypeParam("SET n.x = 1 WITH n AS m RETURN m");
|
||||
|
||||
ASSERT_THROW(AstGenerator("MATCH (n)"), SemanticException);
|
||||
AstGenerator("MATCH (n) MATCH (n) RETURN n");
|
||||
AstGenerator("MATCH (n) SET n = m");
|
||||
AstGenerator("MATCH (n) RETURN n");
|
||||
AstGenerator("MATCH (n) WITH n AS m RETURN m");
|
||||
ASSERT_THROW(TypeParam("MATCH (n)"), SemanticException);
|
||||
TypeParam("MATCH (n) MATCH (n) RETURN n");
|
||||
TypeParam("MATCH (n) SET n = m");
|
||||
TypeParam("MATCH (n) RETURN n");
|
||||
TypeParam("MATCH (n) WITH n AS m RETURN m");
|
||||
|
||||
ASSERT_THROW(AstGenerator("WITH 1 AS n"), SemanticException);
|
||||
AstGenerator("WITH 1 AS n WITH n AS m RETURN m");
|
||||
AstGenerator("WITH 1 AS n RETURN n");
|
||||
AstGenerator("WITH 1 AS n SET n += m");
|
||||
AstGenerator("WITH 1 AS n MATCH (n) RETURN n");
|
||||
ASSERT_THROW(TypeParam("WITH 1 AS n"), SemanticException);
|
||||
TypeParam("WITH 1 AS n WITH n AS m RETURN m");
|
||||
TypeParam("WITH 1 AS n RETURN n");
|
||||
TypeParam("WITH 1 AS n SET n += m");
|
||||
TypeParam("WITH 1 AS n MATCH (n) RETURN n");
|
||||
|
||||
ASSERT_THROW(AstGenerator("UNWIND [1,2,3] AS x"), SemanticException);
|
||||
ASSERT_THROW(AstGenerator("CREATE (n) UNWIND [1,2,3] AS x RETURN x"),
|
||||
ASSERT_THROW(TypeParam("UNWIND [1,2,3] AS x"), SemanticException);
|
||||
ASSERT_THROW(TypeParam("CREATE (n) UNWIND [1,2,3] AS x RETURN x"),
|
||||
SemanticException);
|
||||
AstGenerator("UNWIND [1,2,3] AS x CREATE (n) RETURN x");
|
||||
AstGenerator("CREATE (n) WITH n UNWIND [1,2,3] AS x RETURN x");
|
||||
TypeParam("UNWIND [1,2,3] AS x CREATE (n) RETURN x");
|
||||
TypeParam("CREATE (n) WITH n UNWIND [1,2,3] AS x RETURN x");
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Merge) {
|
||||
AstGenerator ast_generator(
|
||||
TYPED_TEST(CypherMainVisitorTest, Merge) {
|
||||
TypeParam ast_generator(
|
||||
"MERGE (a) -[:r]- (b) ON MATCH SET a.x = b.x "
|
||||
"ON CREATE SET b :label ON MATCH SET b = a");
|
||||
auto *query = ast_generator.query_;
|
||||
@ -1142,8 +1187,8 @@ TEST(CypherMainVisitorTest, Merge) {
|
||||
EXPECT_TRUE(dynamic_cast<SetLabels *>(merge->on_create_[0]));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, Unwind) {
|
||||
AstGenerator ast_generator("UNWIND [1,2,3] AS elem RETURN elem");
|
||||
TYPED_TEST(CypherMainVisitorTest, Unwind) {
|
||||
TypeParam ast_generator("UNWIND [1,2,3] AS elem RETURN elem");
|
||||
auto *query = ast_generator.query_;
|
||||
ASSERT_EQ(query->clauses_.size(), 2U);
|
||||
auto *unwind = dynamic_cast<Unwind *>(query->clauses_[0]);
|
||||
@ -1157,7 +1202,7 @@ TEST(CypherMainVisitorTest, Unwind) {
|
||||
ASSERT_TRUE(dynamic_cast<ListLiteral *>(expr));
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, UnwindWithoutAsError) {
|
||||
EXPECT_THROW(AstGenerator("UNWIND [1,2,3] RETURN 42"), SyntaxException);
|
||||
TYPED_TEST(CypherMainVisitorTest, UnwindWithoutAsError) {
|
||||
EXPECT_THROW(TypeParam("UNWIND [1,2,3] RETURN 42"), SyntaxException);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user