Generate ParameterLookup instead of PrimitiveLiteral

Summary:
This is done when the generated AST will be cached.
Remove LiteralsPlugger.

Reviewers: florijan, mislav.bradac

Reviewed By: mislav.bradac

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D788
This commit is contained in:
Teon Banek 2017-09-13 16:48:46 +02:00
parent bfbec8d550
commit d116e0deb1
10 changed files with 222 additions and 383 deletions

View File

@ -13,6 +13,7 @@ class Context {
GraphDbAccessor &db_accessor_;
SymbolTable symbol_table_;
Parameters parameters_;
bool is_query_cached_ = false;
};
} // namespace query

View File

@ -1621,80 +1621,6 @@ class CreateIndex : public Clause {
: Clause(uid), label_(label), property_(property) {}
};
/// CachedAst is used for storing high level asts.
///
/// After query is stripped, parsed and converted to high level ast it can be
/// stored in this class and new trees can be created by plugging different
/// literals.
class CachedAst {
public:
CachedAst(AstTreeStorage storage) : storage_(std::move(storage)) {}
/// Create new storage by plugging literals and named expessions on theirs
/// positions.
AstTreeStorage Plug(const Parameters &literals,
const std::unordered_map<int, std::string> &named_exprs) {
AstTreeStorage new_ast;
storage_.query()->Clone(new_ast);
LiteralsPlugger plugger(literals, named_exprs);
new_ast.query()->Accept(plugger);
return new_ast;
}
private:
class LiteralsPlugger : public HierarchicalTreeVisitor {
public:
using HierarchicalTreeVisitor::PreVisit;
using typename HierarchicalTreeVisitor::ReturnType;
using HierarchicalTreeVisitor::Visit;
using HierarchicalTreeVisitor::PostVisit;
LiteralsPlugger(const Parameters &literals,
const std::unordered_map<int, std::string> &named_exprs)
: literals_(literals), named_exprs_(named_exprs) {}
bool Visit(PrimitiveLiteral &literal) override {
if (!literal.value_.IsNull()) {
permanent_assert(literal.token_position_ != -1,
"Use AstPlugLiteralsVisitor only on ast created by "
"parsing queries");
literal.value_ = literals_.AtTokenPosition(literal.token_position_);
}
return true;
}
bool PreVisit(NamedExpression &named_expr) override {
// We care only about aliased named expressions in return.
if (!in_return_ || named_expr.token_position_ == -1) return true;
permanent_assert(
named_exprs_.count(named_expr.token_position_),
"There is no named expression string for needed position");
named_expr.name_ = named_exprs_.at(named_expr.token_position_);
return true;
}
bool Visit(Identifier &) override { return true; }
bool Visit(ParameterLookup &) override { return true; }
bool Visit(CreateIndex &) override { return true; }
bool PreVisit(Return &) override {
in_return_ = true;
return true;
}
bool PostVisit(Return &) override {
in_return_ = false;
return true;
}
private:
const Parameters &literals_;
const std::unordered_map<int, std::string> &named_exprs_;
bool in_return_ = false;
};
AstTreeStorage storage_;
};
#undef CLONE_BINARY_EXPRESSION
#undef CLONE_UNARY_EXPRESSION
}

View File

@ -772,11 +772,10 @@ antlrcpp::Any CypherMainVisitor::visitExpression2b(
antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
if (ctx->literal()) {
return static_cast<Expression *>(
ctx->literal()->accept(this).as<BaseLiteral *>());
return ctx->literal()->accept(this);
} else if (ctx->parameter()) {
return static_cast<Expression *>(
ctx->parameter()->accept(this).as<PrimitiveLiteral *>());
ctx->parameter()->accept(this).as<ParameterLookup *>());
} else if (ctx->parenthesizedExpression()) {
return static_cast<Expression *>(
ctx->parenthesizedExpression()->accept(this));
@ -813,34 +812,41 @@ antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
antlrcpp::Any CypherMainVisitor::visitParameter(
CypherParser::ParameterContext *ctx) {
return storage_.Create<PrimitiveLiteral>(
ctx->getText(), // Not really important since we do parameter
// substitution by token position not by its name.
// Lookup by name is already done in stage before.
ctx->getStart()->getTokenIndex());
return storage_.Create<ParameterLookup>(ctx->getStart()->getTokenIndex());
}
antlrcpp::Any CypherMainVisitor::visitLiteral(
CypherParser::LiteralContext *ctx) {
int token_position = ctx->getStart()->getTokenIndex();
if (ctx->CYPHERNULL()) {
return static_cast<BaseLiteral *>(
storage_.Create<PrimitiveLiteral>(TypedValue::Null, token_position));
} else if (ctx->StringLiteral()) {
return static_cast<BaseLiteral *>(storage_.Create<PrimitiveLiteral>(
visitStringLiteral(ctx->StringLiteral()->getText()).as<std::string>(),
token_position));
} else if (ctx->booleanLiteral()) {
return static_cast<BaseLiteral *>(storage_.Create<PrimitiveLiteral>(
ctx->booleanLiteral()->accept(this).as<bool>(), token_position));
} else if (ctx->numberLiteral()) {
return static_cast<BaseLiteral *>(storage_.Create<PrimitiveLiteral>(
ctx->numberLiteral()->accept(this).as<TypedValue>(), token_position));
if (ctx->CYPHERNULL() || ctx->StringLiteral() || ctx->booleanLiteral() ||
ctx->numberLiteral()) {
int token_position = ctx->getStart()->getTokenIndex();
if (ctx->CYPHERNULL()) {
return static_cast<Expression *>(
storage_.Create<PrimitiveLiteral>(TypedValue::Null, token_position));
} else if (ctx_.is_query_cached_) {
// Instead of generating PrimitiveLiteral, we generate a ParameterLookup,
// so that the AST can be cached. This allows for varying literals, which
// are then looked up in the parameters table (even though they are not
// user provided). Note, that NULL always generates a PrimitiveLiteral.
return static_cast<Expression *>(
storage_.Create<ParameterLookup>(token_position));
} else if (ctx->StringLiteral()) {
return static_cast<Expression *>(storage_.Create<PrimitiveLiteral>(
visitStringLiteral(ctx->StringLiteral()->getText()).as<std::string>(),
token_position));
} else if (ctx->booleanLiteral()) {
return static_cast<Expression *>(storage_.Create<PrimitiveLiteral>(
ctx->booleanLiteral()->accept(this).as<bool>(), token_position));
} else if (ctx->numberLiteral()) {
return static_cast<Expression *>(storage_.Create<PrimitiveLiteral>(
ctx->numberLiteral()->accept(this).as<TypedValue>(), token_position));
}
debug_fail("Expected to handle all cases above");
} else if (ctx->listLiteral()) {
return static_cast<BaseLiteral *>(storage_.Create<ListLiteral>(
return static_cast<Expression *>(storage_.Create<ListLiteral>(
ctx->listLiteral()->accept(this).as<std::vector<Expression *>>()));
} else {
return static_cast<BaseLiteral *>(storage_.Create<MapLiteral>(
return static_cast<Expression *>(storage_.Create<MapLiteral>(
ctx->mapLiteral()
->accept(this)
.as<std::map<std::pair<std::string, GraphDbTypes::Property>,

View File

@ -426,7 +426,7 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
antlrcpp::Any visitAtom(CypherParser::AtomContext *ctx) override;
/**
* @return PrimitiveLiteral*
* @return ParameterLookup*
*/
antlrcpp::Any visitParameter(CypherParser::ParameterContext *ctx) override;
@ -449,7 +449,7 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
CypherParser::FunctionNameContext *ctx) override;
/**
* @return BaseLiteral*
* @return Expression*
*/
antlrcpp::Any visitLiteral(CypherParser::LiteralContext *ctx) override;

View File

@ -12,8 +12,9 @@
namespace query {
auto SymbolGenerator::CreateSymbol(const std::string &name, bool user_declared,
Symbol::Type type) {
auto symbol = symbol_table_.CreateSymbol(name, user_declared, type);
Symbol::Type type, int token_position) {
auto symbol =
symbol_table_.CreateSymbol(name, user_declared, type, token_position);
scope_.symbols[name] = symbol;
return symbol;
}
@ -76,7 +77,8 @@ void SymbolGenerator::VisitReturnBody(ReturnBody &body, Where *where) {
}
// An improvement would be to infer the type of the expression, so that the
// new symbol would have a more specific type.
symbol_table_[*named_expr] = CreateSymbol(name, true);
symbol_table_[*named_expr] = CreateSymbol(name, true, Symbol::Type::Any,
named_expr->token_position_);
}
scope_.in_order_by = true;
for (const auto &order_pair : body.order_by) {

View File

@ -106,7 +106,8 @@ class SymbolGenerator : public HierarchicalTreeVisitor {
// Returns a freshly generated symbol. Previous mapping of the same name to a
// different symbol is replaced with the new one.
auto CreateSymbol(const std::string &name, bool user_declared,
Symbol::Type type = Symbol::Type::Any);
Symbol::Type type = Symbol::Type::Any,
int token_position = -1);
// Returns the symbol by name. If the mapping already exists, checks if the
// types match. Otherwise, returns a new symbol.

View File

@ -21,11 +21,12 @@ class Symbol {
Symbol() {}
Symbol(const std::string &name, int position, bool user_declared,
Type type = Type::Any)
Type type = Type::Any, int token_position = -1)
: name_(name),
position_(position),
user_declared_(user_declared),
type_(type) {}
type_(type),
token_position_(token_position) {}
bool operator==(const Symbol &other) const {
return position_ == other.position_ && name_ == other.name_ &&
@ -37,20 +38,23 @@ class Symbol {
int position() const { return position_; }
Type type() const { return type_; }
bool user_declared() const { return user_declared_; }
int token_position() const { return token_position_; }
private:
std::string name_;
int position_;
bool user_declared_ = true;
Type type_ = Type::Any;
int token_position_ = -1;
};
class SymbolTable {
public:
Symbol CreateSymbol(const std::string &name, bool user_declared,
Symbol::Type type = Symbol::Type::Any) {
Symbol::Type type = Symbol::Type::Any,
int token_position = -1) {
int position = position_++;
return Symbol(name, position, user_declared, type);
return Symbol(name, position, user_declared, type, token_position);
}
auto &operator[](const Tree &tree) { return table_[tree.uid()]; }

View File

@ -35,11 +35,14 @@ class Interpreter {
const std::map<std::string, TypedValue> &params) {
utils::Timer frontend_timer;
Context ctx(db_accessor);
ctx.is_query_cached_ = FLAGS_ast_cache;
std::map<std::string, TypedValue> summary;
// query -> stripped query
StrippedQuery stripped(query);
// stripped query -> high level tree
AstTreeStorage ast_storage = [&]() {
if (!FLAGS_ast_cache) {
if (!ctx.is_query_cached_) {
// This is totally fine, since we don't really expect anyone to turn off
// the cache.
if (!params.empty()) {
@ -61,12 +64,9 @@ class Interpreter {
return std::move(visitor.storage());
}
// query -> stripped query
StrippedQuery stripped(query);
auto ast_cache_accessor = ast_cache_.access();
auto it = ast_cache_accessor.find(stripped.hash());
if (it == ast_cache_accessor.end()) {
auto ast_it = ast_cache_accessor.find(stripped.hash());
if (ast_it == ast_cache_accessor.end()) {
// stripped query -> AST
auto parser = [&] {
// Be careful about unlocking since parser can throw.
@ -81,10 +81,9 @@ class Interpreter {
visitor.visit(low_level_tree);
// Cache it.
it = ast_cache_accessor
.insert(stripped.hash(),
CachedAst(std::move(visitor.storage())))
.first;
ast_it = ast_cache_accessor
.insert(stripped.hash(), std::move(visitor.storage()))
.first;
}
// Update context with provided parameters.
@ -98,8 +97,9 @@ class Interpreter {
ctx.parameters_.Add(param_pair.first, param_it->second);
}
// Plug literals, parameters and named expressions.
return it->second.Plug(ctx.parameters_, stripped.named_expressions());
AstTreeStorage new_ast;
ast_it->second.query()->Clone(new_ast);
return new_ast;
}();
auto frontend_time = frontend_timer.Elapsed();
@ -146,7 +146,16 @@ class Interpreter {
// clause, so stream out the results.
// generate header
for (const auto &symbol : output_symbols) header.push_back(symbol.name());
for (const auto &symbol : output_symbols) {
// When the symbol is aliased or expanded from '*' (inside RETURN or
// WITH), then there is no token position, so use symbol name.
// Otherwise, find the name from stripped query.
if (symbol.token_position() == -1)
header.push_back(symbol.name());
else
header.push_back(
stripped.named_expressions().at(symbol.token_position()));
}
stream.Header(header);
// stream out results
@ -192,7 +201,7 @@ class Interpreter {
}
private:
ConcurrentMap<HashType, CachedAst> ast_cache_;
ConcurrentMap<HashType, AstTreeStorage> ast_cache_;
// Antlr has singleton instance that is shared between threads. It is
// protected by locks inside of antlr. Unfortunately, they are not protected
// in a very good way. Once we have antlr version without race conditions we

View File

@ -377,8 +377,15 @@ class ReturnBodyContext : public HierarchicalTreeVisitor {
return true;
}
bool Visit(ParameterLookup &) override { return true; }
bool Visit(query::CreateIndex &) override { return true; }
bool Visit(ParameterLookup &) override {
has_aggregation_.emplace_back(false);
return true;
}
bool Visit(query::CreateIndex &) override {
has_aggregation_.emplace_back(false);
return true;
}
// Creates NamedExpression with an Identifier for each user declared symbol.
// This should be used when body.all_identifiers is true, to generate

View File

@ -92,12 +92,15 @@ class CachedAstGenerator : public Base {
CachedAstGenerator(const std::string &query)
: Base(query),
storage_([&]() {
context_.is_query_cached_ = true;
StrippedQuery stripped(query_string_);
context_.parameters_ = stripped.literals();
::frontend::opencypher::Parser parser(stripped.query());
CypherMainVisitor visitor(context_);
visitor.visit(parser.tree());
CachedAst cached(std::move(visitor.storage()));
return cached.Plug(stripped.literals(), stripped.named_expressions());
AstTreeStorage new_ast;
visitor.storage().query()->Clone(new_ast);
return new_ast;
}()),
query_(storage_.query()) {}
@ -203,15 +206,43 @@ TYPED_TEST(CypherMainVisitorTest, ReturnDistinct) {
ASSERT_TRUE(return_clause->body_.distinct);
}
TypedValue LiteralValue(const Context &context, Expression *expression) {
if (context.is_query_cached_) {
auto *param_lookup = dynamic_cast<ParameterLookup *>(expression);
return context.parameters_.AtTokenPosition(param_lookup->token_position_);
} else {
auto *literal = dynamic_cast<PrimitiveLiteral *>(expression);
return literal->value_;
}
}
void CheckLiteral(const Context &context, Expression *expression,
const TypedValue &expected,
const std::experimental::optional<int> &token_position =
std::experimental::nullopt) {
TypedValue value;
if (!expected.IsNull() && context.is_query_cached_) {
auto *param_lookup = dynamic_cast<ParameterLookup *>(expression);
ASSERT_TRUE(param_lookup);
if (token_position)
EXPECT_EQ(param_lookup->token_position_, *token_position);
value = context.parameters_.AtTokenPosition(param_lookup->token_position_);
} else {
auto *literal = dynamic_cast<PrimitiveLiteral *>(expression);
ASSERT_TRUE(literal);
if (token_position) ASSERT_EQ(literal->token_position_, *token_position);
value = literal->value_;
}
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected));
}
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]);
ASSERT_TRUE(return_clause->body_.limit);
auto *literal = dynamic_cast<PrimitiveLiteral *>(return_clause->body_.limit);
ASSERT_TRUE(literal);
ASSERT_EQ(literal->value_.Value<int64_t>(), 5);
CheckLiteral(ast_generator.context_, return_clause->body_.limit, 5);
}
TYPED_TEST(CypherMainVisitorTest, ReturnSkip) {
@ -220,9 +251,7 @@ TYPED_TEST(CypherMainVisitorTest, ReturnSkip) {
ASSERT_EQ(query->clauses_.size(), 1U);
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
ASSERT_TRUE(return_clause->body_.skip);
auto *literal = dynamic_cast<PrimitiveLiteral *>(return_clause->body_.skip);
ASSERT_TRUE(literal);
ASSERT_EQ(literal->value_.Value<int64_t>(), 5);
CheckLiteral(ast_generator.context_, return_clause->body_.skip, 5);
}
TYPED_TEST(CypherMainVisitorTest, ReturnOrderBy) {
@ -264,11 +293,8 @@ 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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<int64_t>(), 42);
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, 42, 2);
}
TYPED_TEST(CypherMainVisitorTest, IntegerLiteralTooLarge) {
@ -280,43 +306,34 @@ 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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<bool>(), true);
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, true, 2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<bool>(), false);
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, false,
2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.type(), TypedValue::Type::Null);
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_,
TypedValue::Null, 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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
ASSERT_EQ(literal->value_.Value<int64_t>(), 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, 2);
}
TYPED_TEST(CypherMainVisitorTest, OrOperator) {
@ -329,12 +346,8 @@ TYPED_TEST(CypherMainVisitorTest, OrOperator) {
ASSERT_TRUE(or_operator2);
auto *or_operator1 = dynamic_cast<OrOperator *>(or_operator2->expression1_);
ASSERT_TRUE(or_operator1);
auto *operand1 = dynamic_cast<PrimitiveLiteral *>(or_operator1->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<bool>(), true);
auto *operand2 = dynamic_cast<PrimitiveLiteral *>(or_operator1->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<bool>(), false);
CheckLiteral(ast_generator.context_, or_operator1->expression1_, true);
CheckLiteral(ast_generator.context_, or_operator1->expression2_, false);
auto *operand3 = dynamic_cast<Identifier *>(or_operator2->expression2_);
ASSERT_TRUE(operand3);
ASSERT_EQ(operand3->name_, "n");
@ -346,12 +359,8 @@ TYPED_TEST(CypherMainVisitorTest, XorOperator) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *xor_operator = dynamic_cast<XorOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand1 = dynamic_cast<PrimitiveLiteral *>(xor_operator->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<bool>(), true);
auto *operand2 = dynamic_cast<PrimitiveLiteral *>(xor_operator->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<bool>(), false);
CheckLiteral(ast_generator.context_, xor_operator->expression1_, true);
CheckLiteral(ast_generator.context_, xor_operator->expression2_, false);
}
TYPED_TEST(CypherMainVisitorTest, AndOperator) {
@ -360,12 +369,8 @@ TYPED_TEST(CypherMainVisitorTest, AndOperator) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *and_operator = dynamic_cast<AndOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand1 = dynamic_cast<PrimitiveLiteral *>(and_operator->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<bool>(), true);
auto *operand2 = dynamic_cast<PrimitiveLiteral *>(and_operator->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<bool>(), false);
CheckLiteral(ast_generator.context_, and_operator->expression1_, true);
CheckLiteral(ast_generator.context_, and_operator->expression2_, false);
}
TYPED_TEST(CypherMainVisitorTest, AdditionSubtractionOperators) {
@ -378,18 +383,9 @@ TYPED_TEST(CypherMainVisitorTest, AdditionSubtractionOperators) {
auto *subtraction_operator =
dynamic_cast<SubtractionOperator *>(addition_operator->expression1_);
ASSERT_TRUE(subtraction_operator);
auto *operand1 =
dynamic_cast<PrimitiveLiteral *>(subtraction_operator->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 1);
auto *operand2 =
dynamic_cast<PrimitiveLiteral *>(subtraction_operator->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<int64_t>(), 2);
auto *operand3 =
dynamic_cast<PrimitiveLiteral *>(addition_operator->expression2_);
ASSERT_TRUE(operand3);
ASSERT_EQ(operand3->value_.Value<int64_t>(), 3);
CheckLiteral(ast_generator.context_, subtraction_operator->expression1_, 1);
CheckLiteral(ast_generator.context_, subtraction_operator->expression2_, 2);
CheckLiteral(ast_generator.context_, addition_operator->expression2_, 3);
}
TYPED_TEST(CypherMainVisitorTest, MulitplicationOperator) {
@ -398,14 +394,8 @@ TYPED_TEST(CypherMainVisitorTest, MulitplicationOperator) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *mult_operator = dynamic_cast<MultiplicationOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand1 =
dynamic_cast<PrimitiveLiteral *>(mult_operator->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
auto *operand2 =
dynamic_cast<PrimitiveLiteral *>(mult_operator->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<int64_t>(), 3);
CheckLiteral(ast_generator.context_, mult_operator->expression1_, 2);
CheckLiteral(ast_generator.context_, mult_operator->expression2_, 3);
}
TYPED_TEST(CypherMainVisitorTest, DivisionOperator) {
@ -414,12 +404,8 @@ TYPED_TEST(CypherMainVisitorTest, DivisionOperator) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *div_operator = dynamic_cast<DivisionOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand1 = dynamic_cast<PrimitiveLiteral *>(div_operator->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
auto *operand2 = dynamic_cast<PrimitiveLiteral *>(div_operator->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<int64_t>(), 3);
CheckLiteral(ast_generator.context_, div_operator->expression1_, 2);
CheckLiteral(ast_generator.context_, div_operator->expression2_, 3);
}
TYPED_TEST(CypherMainVisitorTest, ModOperator) {
@ -428,27 +414,19 @@ TYPED_TEST(CypherMainVisitorTest, ModOperator) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *mod_operator = dynamic_cast<ModOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand1 = dynamic_cast<PrimitiveLiteral *>(mod_operator->expression1_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
auto *operand2 = dynamic_cast<PrimitiveLiteral *>(mod_operator->expression2_);
ASSERT_TRUE(operand2);
ASSERT_EQ(operand2->value_.Value<int64_t>(), 3);
CheckLiteral(ast_generator.context_, mod_operator->expression1_, 2);
CheckLiteral(ast_generator.context_, mod_operator->expression2_, 3);
}
#define CHECK_COMPARISON(TYPE, VALUE1, VALUE2) \
do { \
auto *and_operator = dynamic_cast<AndOperator *>(_operator); \
ASSERT_TRUE(and_operator); \
_operator = and_operator->expression1_; \
auto *cmp_operator = dynamic_cast<TYPE *>(and_operator->expression2_); \
ASSERT_TRUE(cmp_operator); \
auto *operand1 = \
dynamic_cast<PrimitiveLiteral *>(cmp_operator->expression1_); \
ASSERT_EQ(operand1->value_.Value<int64_t>(), VALUE1); \
auto *operand2 = \
dynamic_cast<PrimitiveLiteral *>(cmp_operator->expression2_); \
ASSERT_EQ(operand2->value_.Value<int64_t>(), VALUE2); \
#define CHECK_COMPARISON(TYPE, VALUE1, VALUE2) \
do { \
auto *and_operator = dynamic_cast<AndOperator *>(_operator); \
ASSERT_TRUE(and_operator); \
_operator = and_operator->expression1_; \
auto *cmp_operator = dynamic_cast<TYPE *>(and_operator->expression2_); \
ASSERT_TRUE(cmp_operator); \
CheckLiteral(ast_generator.context_, cmp_operator->expression1_, VALUE1); \
CheckLiteral(ast_generator.context_, cmp_operator->expression2_, VALUE2); \
} while (0)
TYPED_TEST(CypherMainVisitorTest, ComparisonOperators) {
@ -465,10 +443,8 @@ TYPED_TEST(CypherMainVisitorTest, ComparisonOperators) {
CHECK_COMPARISON(NotEqualOperator, 3, 4);
auto *cmp_operator = dynamic_cast<EqualOperator *>(_operator);
ASSERT_TRUE(cmp_operator);
auto *operand1 = dynamic_cast<PrimitiveLiteral *>(cmp_operator->expression1_);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
auto *operand2 = dynamic_cast<PrimitiveLiteral *>(cmp_operator->expression2_);
ASSERT_EQ(operand2->value_.Value<int64_t>(), 3);
CheckLiteral(ast_generator.context_, cmp_operator->expression1_, 2);
CheckLiteral(ast_generator.context_, cmp_operator->expression2_, 3);
}
#undef CHECK_COMPARISON
@ -482,8 +458,7 @@ TYPED_TEST(CypherMainVisitorTest, ListIndexing) {
ASSERT_TRUE(list_index_op);
auto *list = dynamic_cast<ListLiteral *>(list_index_op->expression1_);
EXPECT_TRUE(list);
auto *index = dynamic_cast<PrimitiveLiteral *>(list_index_op->expression2_);
ASSERT_EQ(index->value_.Value<int64_t>(), 2);
CheckLiteral(ast_generator.context_, list_index_op->expression2_, 2);
}
TYPED_TEST(CypherMainVisitorTest, ListSlicingOperatorNoBounds) {
@ -500,9 +475,7 @@ TYPED_TEST(CypherMainVisitorTest, ListSlicingOperator) {
auto *list = dynamic_cast<ListLiteral *>(list_slicing_op->list_);
EXPECT_TRUE(list);
EXPECT_FALSE(list_slicing_op->lower_bound_);
auto *upper_bound =
dynamic_cast<PrimitiveLiteral *>(list_slicing_op->upper_bound_);
EXPECT_EQ(upper_bound->value_.Value<int64_t>(), 2);
CheckLiteral(ast_generator.context_, list_slicing_op->upper_bound_, 2);
}
TYPED_TEST(CypherMainVisitorTest, InListOperator) {
@ -512,10 +485,7 @@ TYPED_TEST(CypherMainVisitorTest, InListOperator) {
auto *in_list_operator = dynamic_cast<InListOperator *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(in_list_operator);
auto *literal =
dynamic_cast<PrimitiveLiteral *>(in_list_operator->expression1_);
ASSERT_TRUE(literal);
ASSERT_EQ(literal->value_.Value<int64_t>(), 5);
CheckLiteral(ast_generator.context_, in_list_operator->expression1_, 5);
auto *list = dynamic_cast<ListLiteral *>(in_list_operator->expression2_);
ASSERT_TRUE(list);
}
@ -527,18 +497,13 @@ TYPED_TEST(CypherMainVisitorTest, InWithListIndexing) {
auto *in_list_operator = dynamic_cast<InListOperator *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(in_list_operator);
auto *literal =
dynamic_cast<PrimitiveLiteral *>(in_list_operator->expression1_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<int64_t>(), 1);
CheckLiteral(ast_generator.context_, in_list_operator->expression1_, 1);
auto *list_indexing =
dynamic_cast<ListMapIndexingOperator *>(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_);
EXPECT_TRUE(list_index);
CheckLiteral(ast_generator.context_, list_indexing->expression2_, 0);
}
TYPED_TEST(CypherMainVisitorTest, CaseGenericForm) {
@ -551,24 +516,16 @@ TYPED_TEST(CypherMainVisitorTest, CaseGenericForm) {
ASSERT_TRUE(if_operator);
auto *condition = dynamic_cast<LessOperator *>(if_operator->condition_);
ASSERT_TRUE(condition);
auto *then_expression =
dynamic_cast<PrimitiveLiteral *>(if_operator->then_expression_);
ASSERT_TRUE(then_expression);
ASSERT_EQ(then_expression->value_.Value<int64_t>(), 1);
CheckLiteral(ast_generator.context_, if_operator->then_expression_, 1);
auto *if_operator2 =
dynamic_cast<IfOperator *>(if_operator->else_expression_);
ASSERT_TRUE(if_operator2);
auto *condition2 = dynamic_cast<GreaterOperator *>(if_operator2->condition_);
ASSERT_TRUE(condition2);
auto *then_expression2 =
dynamic_cast<PrimitiveLiteral *>(if_operator2->then_expression_);
ASSERT_TRUE(then_expression2);
ASSERT_EQ(then_expression2->value_.Value<int64_t>(), 2);
auto *else_expression2 =
dynamic_cast<PrimitiveLiteral *>(if_operator2->else_expression_);
ASSERT_TRUE(else_expression2);
ASSERT_TRUE(else_expression2->value_.IsNull());
CheckLiteral(ast_generator.context_, if_operator2->then_expression_, 2);
CheckLiteral(ast_generator.context_, if_operator2->else_expression_,
TypedValue::Null);
}
TYPED_TEST(CypherMainVisitorTest, CaseGenericFormElse) {
@ -579,13 +536,8 @@ TYPED_TEST(CypherMainVisitorTest, CaseGenericFormElse) {
return_clause->body_.named_expressions[0]->expression_);
auto *condition = dynamic_cast<LessOperator *>(if_operator->condition_);
ASSERT_TRUE(condition);
auto *then_expression =
dynamic_cast<PrimitiveLiteral *>(if_operator->then_expression_);
ASSERT_EQ(then_expression->value_.Value<int64_t>(), 1);
auto *else_expression =
dynamic_cast<PrimitiveLiteral *>(if_operator->else_expression_);
ASSERT_TRUE(else_expression);
ASSERT_EQ(else_expression->value_.Value<int64_t>(), 2);
CheckLiteral(ast_generator.context_, if_operator->then_expression_, 1);
CheckLiteral(ast_generator.context_, if_operator->else_expression_, 2);
}
TYPED_TEST(CypherMainVisitorTest, CaseSimpleForm) {
@ -596,19 +548,11 @@ TYPED_TEST(CypherMainVisitorTest, CaseSimpleForm) {
return_clause->body_.named_expressions[0]->expression_);
auto *condition = dynamic_cast<EqualOperator *>(if_operator->condition_);
ASSERT_TRUE(condition);
auto *expr1 = dynamic_cast<PrimitiveLiteral *>(condition->expression1_);
ASSERT_TRUE(expr1);
ASSERT_EQ(expr1->value_.Value<int64_t>(), 5);
auto *expr2 = dynamic_cast<PrimitiveLiteral *>(condition->expression2_);
ASSERT_TRUE(expr2);
ASSERT_EQ(expr2->value_.Value<int64_t>(), 10);
auto *then_expression =
dynamic_cast<PrimitiveLiteral *>(if_operator->then_expression_);
ASSERT_EQ(then_expression->value_.Value<int64_t>(), 1);
auto *else_expression =
dynamic_cast<PrimitiveLiteral *>(if_operator->else_expression_);
ASSERT_TRUE(else_expression);
ASSERT_TRUE(else_expression->value_.IsNull());
CheckLiteral(ast_generator.context_, condition->expression1_, 5);
CheckLiteral(ast_generator.context_, condition->expression2_, 10);
CheckLiteral(ast_generator.context_, if_operator->then_expression_, 1);
CheckLiteral(ast_generator.context_, if_operator->else_expression_,
TypedValue::Null);
}
TYPED_TEST(CypherMainVisitorTest, IsNull) {
@ -617,10 +561,7 @@ TYPED_TEST(CypherMainVisitorTest, IsNull) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *is_type_operator = dynamic_cast<IsNullOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand1 =
dynamic_cast<PrimitiveLiteral *>(is_type_operator->expression_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
CheckLiteral(ast_generator.context_, is_type_operator->expression_, 2);
}
TYPED_TEST(CypherMainVisitorTest, IsNotNull) {
@ -631,10 +572,7 @@ TYPED_TEST(CypherMainVisitorTest, IsNotNull) {
return_clause->body_.named_expressions[0]->expression_);
auto *is_type_operator =
dynamic_cast<IsNullOperator *>(not_operator->expression_);
auto *operand1 =
dynamic_cast<PrimitiveLiteral *>(is_type_operator->expression_);
ASSERT_TRUE(operand1);
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
CheckLiteral(ast_generator.context_, is_type_operator->expression_, 2);
}
TYPED_TEST(CypherMainVisitorTest, NotOperator) {
@ -643,9 +581,7 @@ TYPED_TEST(CypherMainVisitorTest, NotOperator) {
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
auto *not_operator = dynamic_cast<NotOperator *>(
return_clause->body_.named_expressions[0]->expression_);
auto *operand = dynamic_cast<PrimitiveLiteral *>(not_operator->expression_);
ASSERT_TRUE(operand);
ASSERT_EQ(operand->value_.Value<bool>(), true);
CheckLiteral(ast_generator.context_, not_operator->expression_, true);
}
TYPED_TEST(CypherMainVisitorTest, UnaryMinusPlusOperators) {
@ -658,10 +594,7 @@ TYPED_TEST(CypherMainVisitorTest, UnaryMinusPlusOperators) {
auto *unary_plus_operator =
dynamic_cast<UnaryPlusOperator *>(unary_minus_operator->expression_);
ASSERT_TRUE(unary_plus_operator);
auto *operand =
dynamic_cast<PrimitiveLiteral *>(unary_plus_operator->expression_);
ASSERT_TRUE(operand);
ASSERT_EQ(operand->value_.Value<int64_t>(), 5);
CheckLiteral(ast_generator.context_, unary_plus_operator->expression_, 5);
}
TYPED_TEST(CypherMainVisitorTest, Aggregation) {
@ -713,44 +646,36 @@ 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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<std::string>(), "mi'rko");
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, "mi'rko",
2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<std::string>(), "mi\"rko");
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_,
"mi\"rko", 2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<std::string>(), "\\'\"\b\b\f\f\n\n\r\r\t\t");
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_,
"\\'\"\b\b\f\f\n\n\r\r\t\t", 2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<std::string>(), u8"\u221daaa\u221daaa");
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_,
u8"\u221daaa\u221daaa", 2);
}
TYPED_TEST(CypherMainVisitorTest, StringLiteralEscapedUtf16Error) {
@ -761,34 +686,25 @@ 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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<std::string>(),
u8"\U0001F600aaaa\U0001F600aaaaaaaa");
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_,
u8"\U0001F600aaaa\U0001F600aaaaaaaa", 2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<double>(), 3.5);
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, 3.5, 2);
}
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 *>(
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(literal);
EXPECT_EQ(literal->value_.Value<double>(), 0.5);
EXPECT_EQ(literal->token_position_, 2);
CheckLiteral(ast_generator.context_,
return_clause->body_.named_expressions[0]->expression_, 0.5, 2);
}
TYPED_TEST(CypherMainVisitorTest, ListLiteral) {
@ -799,15 +715,11 @@ TYPED_TEST(CypherMainVisitorTest, ListLiteral) {
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(list_literal);
ASSERT_EQ(3, list_literal->elements_.size());
auto *elem_0 = dynamic_cast<PrimitiveLiteral *>(list_literal->elements_[0]);
ASSERT_TRUE(elem_0);
EXPECT_EQ(elem_0->value_.type(), TypedValue::Type::Int);
CheckLiteral(ast_generator.context_, list_literal->elements_[0], 3);
auto *elem_1 = dynamic_cast<ListLiteral *>(list_literal->elements_[1]);
ASSERT_TRUE(elem_1);
EXPECT_EQ(0, elem_1->elements_.size());
auto *elem_2 = dynamic_cast<PrimitiveLiteral *>(list_literal->elements_[2]);
ASSERT_TRUE(elem_2);
EXPECT_EQ(elem_2->value_.type(), TypedValue::Type::String);
CheckLiteral(ast_generator.context_, list_literal->elements_[2], "johhny");
}
TYPED_TEST(CypherMainVisitorTest, MapLiteral) {
@ -818,14 +730,10 @@ TYPED_TEST(CypherMainVisitorTest, MapLiteral) {
return_clause->body_.named_expressions[0]->expression_);
ASSERT_TRUE(map_literal);
ASSERT_EQ(3, map_literal->elements_.size());
auto *elem_0 = dynamic_cast<PrimitiveLiteral *>(
map_literal->elements_[ast_generator.PropPair("a")]);
ASSERT_TRUE(elem_0);
EXPECT_EQ(elem_0->value_.type(), TypedValue::Type::Int);
auto *elem_1 = dynamic_cast<PrimitiveLiteral *>(
map_literal->elements_[ast_generator.PropPair("b")]);
ASSERT_TRUE(elem_1);
EXPECT_EQ(elem_1->value_.type(), TypedValue::Type::String);
CheckLiteral(ast_generator.context_,
map_literal->elements_[ast_generator.PropPair("a")], 1);
CheckLiteral(ast_generator.context_,
map_literal->elements_[ast_generator.PropPair("b")], "bla");
auto *elem_2 = dynamic_cast<ListLiteral *>(
map_literal->elements_[ast_generator.PropPair("c")]);
ASSERT_TRUE(elem_2);
@ -859,10 +767,9 @@ TYPED_TEST(CypherMainVisitorTest, NodePattern) {
ast_generator.db_accessor_->Label("label3")));
std::map<std::pair<std::string, GraphDbTypes::Property>, int64_t> properties;
for (auto x : node->properties_) {
auto *literal = dynamic_cast<PrimitiveLiteral *>(x.second);
ASSERT_TRUE(literal);
ASSERT_TRUE(literal->value_.type() == TypedValue::Type::Int);
properties[x.first] = literal->value_.Value<int64_t>();
TypedValue value = LiteralValue(ast_generator.context_, x.second);
ASSERT_TRUE(value.type() == TypedValue::Type::Int);
properties[x.first] = value.Value<int64_t>();
}
EXPECT_THAT(properties,
UnorderedElementsAre(Pair(ast_generator.PropPair("a"), 5),
@ -952,10 +859,9 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
ast_generator.db_accessor_->EdgeType("type2")));
std::map<std::pair<std::string, GraphDbTypes::Property>, int64_t> properties;
for (auto x : edge->properties_) {
auto *literal = dynamic_cast<PrimitiveLiteral *>(x.second);
ASSERT_TRUE(literal);
ASSERT_TRUE(literal->value_.type() == TypedValue::Type::Int);
properties[x.first] = literal->value_.Value<int64_t>();
TypedValue value = LiteralValue(ast_generator.context_, x.second);
ASSERT_TRUE(value.type() == TypedValue::Type::Int);
properties[x.first] = value.Value<int64_t>();
}
EXPECT_THAT(properties,
UnorderedElementsAre(Pair(ast_generator.PropPair("a"), 5),
@ -1007,9 +913,7 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternLowerBounded) {
AssertMatchSingleEdgeAtom(match, edge);
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::OUT);
EXPECT_TRUE(edge->has_range_);
auto *lower_bound = dynamic_cast<PrimitiveLiteral *>(edge->lower_bound_);
ASSERT_TRUE(lower_bound);
EXPECT_TRUE(lower_bound->value_.Value<int64_t>() == 42);
CheckLiteral(ast_generator.context_, edge->lower_bound_, 42);
EXPECT_EQ(edge->upper_bound_, nullptr);
}
@ -1022,9 +926,7 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternUpperBounded) {
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::OUT);
EXPECT_TRUE(edge->has_range_);
EXPECT_EQ(edge->lower_bound_, nullptr);
auto upper_bound = dynamic_cast<PrimitiveLiteral *>(edge->upper_bound_);
ASSERT_TRUE(upper_bound);
EXPECT_EQ(upper_bound->value_.Value<int64_t>(), 42);
CheckLiteral(ast_generator.context_, edge->upper_bound_, 42);
}
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternLowerUpperBounded) {
@ -1035,12 +937,8 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternLowerUpperBounded) {
AssertMatchSingleEdgeAtom(match, edge);
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::OUT);
EXPECT_TRUE(edge->has_range_);
auto lower_bound = dynamic_cast<PrimitiveLiteral *>(edge->lower_bound_);
ASSERT_TRUE(lower_bound);
EXPECT_EQ(lower_bound->value_.Value<int64_t>(), 24);
auto upper_bound = dynamic_cast<PrimitiveLiteral *>(edge->upper_bound_);
ASSERT_TRUE(upper_bound);
EXPECT_EQ(upper_bound->value_.Value<int64_t>(), 42);
CheckLiteral(ast_generator.context_, edge->lower_bound_, 24);
CheckLiteral(ast_generator.context_, edge->upper_bound_, 42);
}
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternFixedRange) {
@ -1051,12 +949,8 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternFixedRange) {
AssertMatchSingleEdgeAtom(match, edge);
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::OUT);
EXPECT_TRUE(edge->has_range_);
auto lower_bound = dynamic_cast<PrimitiveLiteral *>(edge->lower_bound_);
ASSERT_TRUE(lower_bound);
EXPECT_EQ(lower_bound->value_.Value<int64_t>(), 42);
auto upper_bound = dynamic_cast<PrimitiveLiteral *>(edge->upper_bound_);
ASSERT_TRUE(upper_bound);
EXPECT_EQ(upper_bound->value_.Value<int64_t>(), 42);
CheckLiteral(ast_generator.context_, edge->lower_bound_, 42);
CheckLiteral(ast_generator.context_, edge->upper_bound_, 42);
}
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternFloatingUpperBound) {
@ -1068,12 +962,8 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternFloatingUpperBound) {
AssertMatchSingleEdgeAtom(match, edge);
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::OUT);
EXPECT_TRUE(edge->has_range_);
auto lower_bound = dynamic_cast<PrimitiveLiteral *>(edge->lower_bound_);
ASSERT_TRUE(lower_bound);
EXPECT_EQ(lower_bound->value_.Value<int64_t>(), 1);
auto upper_bound = dynamic_cast<PrimitiveLiteral *>(edge->upper_bound_);
ASSERT_TRUE(upper_bound);
EXPECT_EQ(upper_bound->value_.Value<double>(), 0.2);
CheckLiteral(ast_generator.context_, edge->lower_bound_, 1);
CheckLiteral(ast_generator.context_, edge->upper_bound_, 0.2);
}
TYPED_TEST(CypherMainVisitorTest, RelationshipPatternUnboundedWithProperty) {
@ -1086,9 +976,8 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternUnboundedWithProperty) {
EXPECT_TRUE(edge->has_range_);
EXPECT_EQ(edge->lower_bound_, nullptr);
EXPECT_EQ(edge->upper_bound_, nullptr);
auto prop_literal = dynamic_cast<PrimitiveLiteral *>(
edge->properties_[ast_generator.PropPair("prop")]);
EXPECT_EQ(prop_literal->value_.Value<int64_t>(), 42);
CheckLiteral(ast_generator.context_,
edge->properties_[ast_generator.PropPair("prop")], 42);
}
TYPED_TEST(CypherMainVisitorTest,
@ -1102,9 +991,8 @@ TYPED_TEST(CypherMainVisitorTest,
EXPECT_TRUE(edge->has_range_);
EXPECT_EQ(edge->lower_bound_, nullptr);
EXPECT_EQ(edge->upper_bound_, nullptr);
auto prop_literal = dynamic_cast<PrimitiveLiteral *>(
edge->properties_[ast_generator.PropPair("prop")]);
EXPECT_EQ(prop_literal->value_.Value<int64_t>(), 42);
CheckLiteral(ast_generator.context_,
edge->properties_[ast_generator.PropPair("prop")], 42);
ASSERT_EQ(edge->edge_types_.size(), 1U);
auto edge_type = ast_generator.db_accessor_->EdgeType("edge_type");
EXPECT_EQ(edge->edge_types_[0], edge_type);
@ -1119,12 +1007,9 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternUpperBoundedWithProperty) {
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::OUT);
EXPECT_TRUE(edge->has_range_);
EXPECT_EQ(edge->lower_bound_, nullptr);
auto upper_bound = dynamic_cast<PrimitiveLiteral *>(edge->upper_bound_);
ASSERT_TRUE(upper_bound);
EXPECT_EQ(upper_bound->value_.Value<int64_t>(), 2);
auto prop_literal = dynamic_cast<PrimitiveLiteral *>(
edge->properties_[ast_generator.PropPair("prop")]);
EXPECT_EQ(prop_literal->value_.Value<int64_t>(), 42);
CheckLiteral(ast_generator.context_, edge->upper_bound_, 2);
CheckLiteral(ast_generator.context_,
edge->properties_[ast_generator.PropPair("prop")], 42);
}
// // PatternPart with variable.
@ -1510,9 +1395,7 @@ TYPED_TEST(CypherMainVisitorTest, MatchBfsReturn) {
EXPECT_EQ(bfs->identifier_->name_, "r");
EXPECT_EQ(bfs->traversed_edge_identifier_->name_, "e");
EXPECT_EQ(bfs->next_node_identifier_->name_, "n");
auto *max_depth = dynamic_cast<PrimitiveLiteral *>(bfs->max_depth_);
ASSERT_TRUE(max_depth);
EXPECT_EQ(max_depth->value_.Value<int64_t>(), 10U);
CheckLiteral(ast_generator.context_, bfs->max_depth_, 10);
auto *eq = dynamic_cast<EqualOperator *>(bfs->filter_expression_);
ASSERT_TRUE(eq);
}