diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index 5f107cbde..92e775b71 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -291,13 +291,32 @@ antlrcpp::Any CypherMainVisitor::visitPropertyKeyName( antlrcpp::Any CypherMainVisitor::visitSymbolicName( CypherParser::SymbolicNameContext *ctx) { if (ctx->EscapedSymbolicName()) { - // We don't allow at this point for variable to be EscapedSymbolicName - // because we would have t ofigure out how escaping works since same - // variable can be referenced in two ways: escaped and unescaped. - // TODO: implement other clauses. - throw utils::NotYetImplemented(); + auto quoted_name = ctx->getText(); + debug_assert(quoted_name.size() >= 2U && quoted_name[0] == '`' && + quoted_name.back() == '`', + "Can't happen. Grammar ensures this"); + // Remove enclosing backticks. + std::string escaped_name = + quoted_name.substr(1, static_cast(quoted_name.size()) - 2); + // Unescape remaining backticks. + std::string name; + bool escaped = false; + for (auto c : escaped_name) { + if (escaped) { + if (c == '`') { + name.push_back('`'); + escaped = false; + } else { + debug_assert(false, "Can't happen. Grammar ensures that."); + } + } else if (c == '`') { + escaped = true; + } else { + name.push_back(c); + } + } + return name; } - // TODO: We should probably escape string. return std::string(ctx->getText()); } diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index 947ee96e4..0cdd34169 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -85,6 +85,19 @@ TEST(CypherMainVisitorTest, LabelsTest) { ast_generator.db_accessor_->label("y"))); } +TEST(CypherMainVisitorTest, EscapedLabel) { + AstGenerator ast_generator("RETURN n:`l-$\"'ab``e````l`"); + auto *query = ast_generator.query_; + ASSERT_EQ(query->clauses_.size(), 1U); + auto *return_clause = dynamic_cast(query->clauses_[0]); + auto *labels_test = dynamic_cast( + return_clause->body_.named_expressions[0]->expression_); + auto identifier = dynamic_cast(labels_test->expression_); + ASSERT_EQ(identifier->name_, "n"); + ASSERT_THAT(labels_test->labels_, + ElementsAre(ast_generator.db_accessor_->label("l-$\"'ab`e``l"))); +} + TEST(CypherMainVisitorTest, ReturnNoDistinctNoBagSemantics) { AstGenerator ast_generator("RETURN x"); auto *query = ast_generator.query_;