diff --git a/src/query/context.hpp b/src/query/context.hpp index def5e57ae..8afc3b091 100644 --- a/src/query/context.hpp +++ b/src/query/context.hpp @@ -13,6 +13,7 @@ class Context { GraphDbAccessor &db_accessor_; SymbolTable symbol_table_; Parameters parameters_; + bool is_query_cached_ = false; }; } // namespace query diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp index c10c0f7e8..3cbbccf7a 100644 --- a/src/query/frontend/ast/ast.hpp +++ b/src/query/frontend/ast/ast.hpp @@ -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 } diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index 247999a73..ff79ee504 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -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>, diff --git a/src/query/frontend/ast/cypher_main_visitor.hpp b/src/query/frontend/ast/cypher_main_visitor.hpp index c6ca1d50c..7afae403b 100644 --- a/src/query/frontend/ast/cypher_main_visitor.hpp +++ b/src/query/frontend/ast/cypher_main_visitor.hpp @@ -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; diff --git a/src/query/frontend/semantic/symbol_generator.cpp b/src/query/frontend/semantic/symbol_generator.cpp index ad8eb20fd..e73f3b810 100644 --- a/src/query/frontend/semantic/symbol_generator.cpp +++ b/src/query/frontend/semantic/symbol_generator.cpp @@ -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) { diff --git a/src/query/frontend/semantic/symbol_generator.hpp b/src/query/frontend/semantic/symbol_generator.hpp index 0b6791375..996e8d183 100644 --- a/src/query/frontend/semantic/symbol_generator.hpp +++ b/src/query/frontend/semantic/symbol_generator.hpp @@ -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. diff --git a/src/query/frontend/semantic/symbol_table.hpp b/src/query/frontend/semantic/symbol_table.hpp index 84e63242c..27671a810 100644 --- a/src/query/frontend/semantic/symbol_table.hpp +++ b/src/query/frontend/semantic/symbol_table.hpp @@ -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()]; } diff --git a/src/query/interpreter.hpp b/src/query/interpreter.hpp index 73a20d601..efc955097 100644 --- a/src/query/interpreter.hpp +++ b/src/query/interpreter.hpp @@ -35,11 +35,14 @@ class Interpreter { const std::map<std::string, TypedValue> ¶ms) { 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 diff --git a/src/query/plan/rule_based_planner.cpp b/src/query/plan/rule_based_planner.cpp index e410064cf..97e46653a 100644 --- a/src/query/plan/rule_based_planner.cpp +++ b/src/query/plan/rule_based_planner.cpp @@ -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 diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index 9c5d5b7de..f35da20a2 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -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); }