diff --git a/src/communication/bolt/v1/states/executor.hpp b/src/communication/bolt/v1/states/executor.hpp index 09a4f227c..07058fc37 100644 --- a/src/communication/bolt/v1/states/executor.hpp +++ b/src/communication/bolt/v1/states/executor.hpp @@ -61,12 +61,12 @@ State state_executor_run(RecordStream &output_stream, BoltDecoder &decod {{"code", "Memgraph.SyntaxException"}, {"message", "Syntax error"}}); output_stream.send(); return ERROR; - } catch (const backend::cpp::GeneratorException &e) { - output_stream.write_failure( - {{"code", "Memgraph.GeneratorException"}, - {"message", "Unsupported query"}}); - output_stream.send(); - return ERROR; + // } catch (const backend::cpp::GeneratorException &e) { + // output_stream.write_failure( + // {{"code", "Memgraph.GeneratorException"}, + // {"message", "Unsupported query"}}); + // output_stream.send(); + // return ERROR; } catch (const QueryEngineException &e) { output_stream.write_failure( {{"code", "Memgraph.QueryEngineException"}, diff --git a/src/query/backend/cpp/generator.hpp b/src/query/backend/cpp/generator.hpp deleted file mode 100644 index df3f08236..000000000 --- a/src/query/backend/cpp/generator.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "antlr4-runtime.h" -#include "query/frontend/ast/cypher_main_visitor.hpp" -#include - -namespace fs = std::experimental::filesystem; - -namespace backend { - -namespace cpp { - -using namespace antlr4; - -class GeneratorException : public BasicException { -public: - using BasicException::BasicException; - GeneratorException() : BasicException("") {} -}; - -/** - * Traverse Antlr tree::ParseTree generated from Cypher grammar and generate - * C++. - */ -class Generator { -public: - /** - * Generates cpp code inside file on the path. - */ - Generator(tree::ParseTree *tree, const std::string &query, - const uint64_t stripped_hash, const fs::path &path) { - throw GeneratorException("unsupported query"); - CypherMainVisitor visitor; - visitor.visit(tree); - } -}; -} -} diff --git a/src/query/context.cpp b/src/query/context.cpp index 177a37cb7..10accd9b9 100644 --- a/src/query/context.cpp +++ b/src/query/context.cpp @@ -3,9 +3,10 @@ namespace query { -void HighLevelAstConversion::Apply(Context &ctx, +std::shared_ptr HighLevelAstConversion::Apply(Context &ctx, antlr4::tree::ParseTree *tree) { query::frontend::CypherMainVisitor visitor(ctx); visitor.visit(tree); + return visitor.query(); } } diff --git a/src/query/context.hpp b/src/query/context.hpp index 4c73f17ad..e065c27fd 100644 --- a/src/query/context.hpp +++ b/src/query/context.hpp @@ -10,6 +10,7 @@ class TypedcheckedTree {}; class LogicalPlan {}; class Context; +class Query; class LogicalPlanGenerator { public: @@ -48,6 +49,6 @@ private: class HighLevelAstConversion { public: - void Apply(Context &ctx, antlr4::tree::ParseTree *tree); + std::shared_ptr Apply(Context &ctx, antlr4::tree::ParseTree *tree); }; } diff --git a/src/query/engine.hpp b/src/query/engine.hpp index d7ae8445c..7626d0fe6 100644 --- a/src/query/engine.hpp +++ b/src/query/engine.hpp @@ -7,7 +7,6 @@ namespace fs = std::experimental::filesystem; #include "data_structures/concurrent/concurrent_map.hpp" #include "database/graph_db.hpp" #include "logging/loggable.hpp" -#include "query/backend/cpp/generator.hpp" #include "query/exception/query_engine.hpp" #include "query/frontend/opencypher/parser.hpp" #include "query/plan_compiler.hpp" @@ -137,8 +136,8 @@ private: std::to_string(stripped.hash) + ".cpp"); frontend::opencypher::Parser parser(stripped.query); - backend::cpp::Generator(parser.tree(), stripped.query, stripped.hash, - generated_path); + // backend::cpp::Generator(parser.tree(), stripped.query, stripped.hash, + // generated_path); return LoadCpp(generated_path, stripped.hash); } diff --git a/src/query/entry.hpp b/src/query/entry.hpp index c55b0e1bf..29b23451f 100644 --- a/src/query/entry.hpp +++ b/src/query/entry.hpp @@ -1,5 +1,8 @@ #pragma once +#include "query/frontend/interpret/interpret.hpp" +#include "query/frontend/logical/planner.hpp" +#include "query/context.hpp" #include "database/graph_db_accessor.hpp" #include "query/context.hpp" #include "query/frontend/opencypher/parser.hpp" @@ -21,35 +24,32 @@ class Engine { auto low_level_tree = parser.tree(); // AST -> high level tree + HighLevelAstConversion low2high_tree; auto high_level_tree = low2high_tree.Apply(ctx, low_level_tree); // symbol table fill SymbolTable symbol_table; - TypeCheckVisitor typecheck_visitor; - high_level_tree.Accept(typecheck_visitor); + TypeCheckVisitor typecheck_visitor(symbol_table); + high_level_tree->Accept(typecheck_visitor); // high level tree -> logical plan - auto logical_plan = query::Apply(high_level_tree); + auto logical_plan = Apply(*high_level_tree); // generate frame based on symbol table max_position Frame frame(symbol_table.max_position()); // interpret - auto cursor = logical_plan.MakeCursor(frame); - logical_plan.WriteHeader(stream); - auto symbols = logical_plan.OutputSymbols(symbol_table); - while (cursor.pull(frame, context)) { + auto cursor = logical_plan->MakeCursor(db_accessor); + logical_plan->WriteHeader(stream); + auto symbols = logical_plan->OutputSymbols(symbol_table); + while (cursor->pull(frame, symbol_table)) { std::vector values(symbols.size()); for (auto symbol : symbols) { - values.emplace_back(frame[symbol]); + values.emplace_back(frame[symbol.position_]); } stream.Result(values); } - stream.Summary({"type" : "r"}); + stream.Summary({{std::string("type"), TypedValue("r")}}); } - - private: - Context ctx; - HighLevelAstConversion low2high_tree; }; } diff --git a/src/query/frontend/ast/cypher_main_visitor.hpp b/src/query/frontend/ast/cypher_main_visitor.hpp index b5dd3acbb..ae0569ca8 100644 --- a/src/query/frontend/ast/cypher_main_visitor.hpp +++ b/src/query/frontend/ast/cypher_main_visitor.hpp @@ -281,6 +281,9 @@ private: antlrcpp::Any visitIntegerLiteral(CypherParser::IntegerLiteralContext *ctx) override; +public: + std::shared_ptr query() { return query_; } + private: Context &ctx_; int next_ident_id_; diff --git a/src/query/frontend/logical/operator.hpp b/src/query/frontend/logical/operator.hpp index b0e8f99c0..228cfc2bf 100644 --- a/src/query/frontend/logical/operator.hpp +++ b/src/query/frontend/logical/operator.hpp @@ -82,7 +82,7 @@ class ScanAll : public LogicalOperator { for (auto label : node_part->labels_) { if (!vertex.has_label(label)) return false; } - frame[symbol_table[node_part->identifier_].position_] = vertex; + frame[symbol_table[*node_part->identifier_].position_] = vertex; return true; } }; diff --git a/src/query/frontend/logical/planner.hpp b/src/query/frontend/logical/planner.hpp index 6e049dda2..dded0b299 100644 --- a/src/query/frontend/logical/planner.hpp +++ b/src/query/frontend/logical/planner.hpp @@ -18,10 +18,10 @@ std::shared_ptr GenMatch( throw std::runtime_error("Not implemented"); } auto& pattern = match.patterns_[0]; - if (pattern->node_parts_.size() != 1) { + if (pattern->parts_.size() != 1) { throw std::runtime_error("Not implemented"); } - auto& node_part = pattern->node_parts_[0]; + auto node_part = std::dynamic_pointer_cast(pattern->parts_[0]); return std::make_shared(node_part); } diff --git a/tests/manual/compiler_prototype.cpp b/tests/manual/compiler_prototype.cpp index 665acc041..0763cacc1 100644 --- a/tests/manual/compiler_prototype.cpp +++ b/tests/manual/compiler_prototype.cpp @@ -5,6 +5,7 @@ #include "logging/streams/stdout.cpp" #include "query/entry.hpp" #include "query/backend/cpp/typed_value.hpp" +#include "query/frontend/logical/operator.hpp" using std::cout; using std::cin; @@ -20,8 +21,8 @@ int main(int argc, char* argv[]) { // init db context Dbms dbms; - ConsoleResultStream stream; - query::Engine query_engine; + query::ConsoleResultStream stream; + query::Engine query_engine; // initialize the database auto dba = dbms.active(); diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index 0c8bcb7b5..955ad7bc4 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -13,348 +13,348 @@ using namespace ::testing; -namespace { - -using query::Context; -using namespace query::frontend; - -class ParserTables { - template - auto FilterAnies(std::unordered_map map) { - std::unordered_map filtered; - for (auto x : map) { - if (x.second.is()) { - filtered[x.first] = x.second.as(); - } - } - return filtered; - } - -public: - ParserTables(const std::string &query) { - frontend::opencypher::Parser parser(query); - auto *tree = parser.tree(); - CypherMainVisitor visitor; - visitor.visit(tree); - identifiers_map_ = visitor.ids_map().back(); - symbol_table_ = visitor.symbol_table(); - pattern_parts_ = FilterAnies(symbol_table_); - nodes_ = FilterAnies(symbol_table_); - relationships_ = FilterAnies(symbol_table_); - } - - std::unordered_map identifiers_map_; - std::unordered_map symbol_table_; - std::unordered_map pattern_parts_; - std::unordered_map nodes_; - std::unordered_map relationships_; -}; - -// TODO: Once expression evaluation is implemented, we should also test if -// property values are equal. -void CompareNodes(std::pair node_entry, - std::vector labels, - std::vector property_keys) { - auto node = node_entry.second; - ASSERT_EQ(node_entry.first, node.output_id); - ASSERT_THAT(node.labels, - UnorderedElementsAreArray(labels.begin(), labels.end())); - std::vector node_property_keys; - for (auto x : node.properties) { - node_property_keys.push_back(x.first); - } - ASSERT_THAT( - node_property_keys, - UnorderedElementsAreArray(property_keys.begin(), property_keys.end())); -} - -// If has_range is false, lower and upper bound values are ignored. -// TODO: Once expression evaluation is implemented, we should also test if -// property values are equal. -void CompareRelationships( - std::pair relationship_entry, - Relationship::Direction direction, std::vector types, - std::vector property_keys, bool has_range, - int64_t lower_bound = 1LL, int64_t upper_bound = LLONG_MAX) { - auto relationship = relationship_entry.second; - ASSERT_EQ(relationship_entry.first, relationship.output_id); - ASSERT_EQ(relationship.direction, direction); - ASSERT_THAT(relationship.types, - UnorderedElementsAreArray(types.begin(), types.end())); - std::vector relationship_property_keys; - for (auto x : relationship.properties) { - relationship_property_keys.push_back(x.first); - } - ASSERT_THAT( - relationship_property_keys, - UnorderedElementsAreArray(property_keys.begin(), property_keys.end())); - ASSERT_EQ(relationship.has_range, has_range); - if (!has_range) - return; - ASSERT_EQ(relationship.lower_bound, lower_bound); - ASSERT_EQ(relationship.upper_bound, upper_bound); -} - -// SyntaxException on incorrect syntax. -TEST(CompilerStructuresTest, SyntaxException) { - ASSERT_THROW(ParserTables("CREATE ()-[*1...2]-()"), - frontend::opencypher::SyntaxException); -} - -// Empty node. -TEST(CompilerStructuresTest, NodePatternEmpty) { - ParserTables parser("CREATE ()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.nodes_.size(), 1U); - CompareNodes(*parser.nodes_.begin(), {}, {}); -} - -// Node with variable. -TEST(CompilerStructuresTest, NodePatternVariable) { - ParserTables parser("CREATE (var)"); - ASSERT_EQ(parser.identifiers_map_.size(), 1U); - ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); - ASSERT_EQ(parser.nodes_.size(), 1U); - auto output_identifier = parser.identifiers_map_["var"]; - ASSERT_NE(parser.nodes_.find(output_identifier), parser.nodes_.end()); - CompareNodes(*parser.nodes_.begin(), {}, {}); -} - -// Node with labels. -TEST(CompilerStructuresTest, NodePatternLabels) { - ParserTables parser("CREATE (:label1:label2:label3)"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.nodes_.size(), 1U); - CompareNodes(*parser.nodes_.begin(), {"label1", "label2", "label3"}, {}); -} - -// Node with properties. -TEST(CompilerStructuresTest, NodePatternProperties) { - ParserTables parser("CREATE ({age: 5, name: \"John\", surname: \"Smith\"})"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.nodes_.size(), 1U); - CompareNodes(*parser.nodes_.begin(), {}, {"age", "name", "surname"}); -} - -// Relationship without relationship details. -TEST(CompilerStructuresTest, RelationshipPatternNoDetails) { - ParserTables parser("CREATE ()--()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, false); -} - -// Relationship with empty relationship details. -TEST(CompilerStructuresTest, RelationshipPatternEmptyDetails) { - ParserTables parser("CREATE ()-[]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, false); -} - -// Relationship with left direction. -TEST(CompilerStructuresTest, RelationshipPatternLeftDirection) { - ParserTables parser("CREATE ()<--()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::LEFT, {}, {}, false); -} - -// Relationship with right direction. -TEST(CompilerStructuresTest, RelationshipPatternRightDirection) { - ParserTables parser("CREATE ()-[]->()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::RIGHT, {}, {}, false); -} - -// Relationship with both directions. -TEST(CompilerStructuresTest, RelationshipPatternBothDirection) { - ParserTables parser("CREATE ()<-[]->()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, false); -} - -// Relationship with unbounded variable range. -TEST(CompilerStructuresTest, RelationshipPatternUnbounded) { - ParserTables parser("CREATE ()-[*]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, true, 1, - LLONG_MAX); -} - -// Relationship with lower bounded variable range. -TEST(CompilerStructuresTest, RelationshipPatternLowerBounded) { - ParserTables parser("CREATE ()-[*5..]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, true, 5, - LLONG_MAX); -} - -// Relationship with upper bounded variable range. -TEST(CompilerStructuresTest, RelationshipPatternUpperBounded) { - ParserTables parser("CREATE ()-[*..10]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, true, 1, 10); -} - -// Relationship with lower and upper bounded variable range. -TEST(CompilerStructuresTest, RelationshipPatternLowerUpperBounded) { - ParserTables parser("CREATE ()-[*5..10]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, true, 5, 10); -} - -// Relationship with fixed number of edges. -TEST(CompilerStructuresTest, RelationshipPatternFixedRange) { - ParserTables parser("CREATE ()-[*10]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, true, 10, 10); -} - -// Relationship with invalid bound (larger than long long). -TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) { - ASSERT_THROW( - ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"), - SemanticException); -} - -// Relationship with variable -TEST(CompilerStructuresTest, RelationshipPatternVariable) { - ParserTables parser("CREATE ()-[var]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 1U); - ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); - ASSERT_EQ(parser.relationships_.size(), 1U); - auto output_identifier = parser.identifiers_map_["var"]; - ASSERT_NE(parser.relationships_.find(output_identifier), - parser.relationships_.end()); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, {}, false); -} - -// Relationship with labels. -TEST(CompilerStructuresTest, RelationshipPatternLabels) { - ParserTables parser("CREATE ()-[:label1|label2|:label3]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, - {"label1", "label2", "label3"}, {}, false); -} - -// Relationship with properties. -TEST(CompilerStructuresTest, RelationshipPatternProperties) { - ParserTables parser( - "CREATE ()-[{age: 5, name: \"John\", surname: \"Smith\"}]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.relationships_.size(), 1U); - CompareRelationships(*parser.relationships_.begin(), - Relationship::Direction::BOTH, {}, - {"age", "name", "surname"}, false); -} - -// PatternPart. -TEST(CompilerStructuresTest, PatternPart) { - ParserTables parser("CREATE ()--()"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.pattern_parts_.size(), 1U); - ASSERT_EQ(parser.relationships_.size(), 1U); - ASSERT_EQ(parser.nodes_.size(), 2U); - ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); - ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); -} - -// PatternPart in braces. -TEST(CompilerStructuresTest, PatternPartBraces) { - ParserTables parser("CREATE ((()--()))"); - ASSERT_EQ(parser.identifiers_map_.size(), 0U); - ASSERT_EQ(parser.pattern_parts_.size(), 1U); - ASSERT_EQ(parser.relationships_.size(), 1U); - ASSERT_EQ(parser.nodes_.size(), 2U); - ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); - ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); -} - -// PatternPart with variable. -TEST(CompilerStructuresTest, PatternPartVariable) { - ParserTables parser("CREATE var=()--()"); - ASSERT_EQ(parser.identifiers_map_.size(), 1U); - ASSERT_EQ(parser.pattern_parts_.size(), 1U); - ASSERT_EQ(parser.relationships_.size(), 1U); - ASSERT_EQ(parser.nodes_.size(), 2U); - ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); - ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); - ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); - auto output_identifier = parser.identifiers_map_["var"]; - ASSERT_NE(parser.pattern_parts_.find(output_identifier), - parser.pattern_parts_.end()); -} - -// Multiple nodes with same variable and properties. -TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) { - ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"), - SemanticException); -} - -// Multiple nodes with same variable name. -TEST(CompilerStructuresTest, MultipleNodesWithVariable) { - ParserTables parser("CREATE (a {b: 5, c: 5})-[]-(a)"); - ASSERT_EQ(parser.identifiers_map_.size(), 1U); - ASSERT_EQ(parser.pattern_parts_.size(), 1U); - ASSERT_EQ(parser.relationships_.size(), 1U); - ASSERT_EQ(parser.nodes_.size(), 1U); - auto pattern_part = parser.pattern_parts_.begin()->second; - ASSERT_EQ(pattern_part.nodes.size(), 2U); - ASSERT_EQ(pattern_part.relationships.size(), 1U); - ASSERT_EQ(pattern_part.nodes[0], pattern_part.nodes[1]); -} - -// Multiple relationships with same variable name and properties. -TEST(CompilerStructuresTest, MultipleRelationshipsWithVariableAndProperties) { - ASSERT_THROW(ParserTables parser("CREATE ()-[e {a: 5}]-()-[e {c: 5}]-()"), - SemanticException); -} - -// Multiple relationships with same variable name. -TEST(CompilerStructuresTest, MultipleRelationshipsWithVariable) { - ParserTables parser("CREATE ()-[a {a: 5}]-()-[a]-()"); - ASSERT_EQ(parser.identifiers_map_.size(), 1U); - ASSERT_EQ(parser.pattern_parts_.size(), 1U); - ASSERT_EQ(parser.relationships_.size(), 1U); - ASSERT_EQ(parser.nodes_.size(), 3U); - auto pattern_part = parser.pattern_parts_.begin()->second; - ASSERT_EQ(pattern_part.nodes.size(), 3U); - ASSERT_EQ(pattern_part.relationships.size(), 2U); - ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[1]); - ASSERT_NE(pattern_part.nodes[1], pattern_part.nodes[2]); - ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[2]); - ASSERT_EQ(pattern_part.relationships[0], pattern_part.relationships[1]); -} - -// Different structures (nodes, realtionships, patterns) with same variable -// name. -TEST(CompilerStructuresTest, DifferentTypesWithVariable) { - ASSERT_THROW(ParserTables parser("CREATE a=(a)"), SemanticException); - ASSERT_THROW(ParserTables parser("CREATE (a)-[a]-()"), SemanticException); - ASSERT_THROW(ParserTables parser("CREATE a=()-[a]-()"), SemanticException); -} -} +// namespace { +// +// using query::Context; +// using namespace query::frontend; +// +// class ParserTables { +// template +// auto FilterAnies(std::unordered_map map) { +// std::unordered_map filtered; +// for (auto x : map) { +// if (x.second.is()) { +// filtered[x.first] = x.second.as(); +// } +// } +// return filtered; +// } +// +// public: +// ParserTables(const std::string &query) { +// frontend::opencypher::Parser parser(query); +// auto *tree = parser.tree(); +// CypherMainVisitor visitor; +// visitor.visit(tree); +// identifiers_map_ = visitor.ids_map().back(); +// symbol_table_ = visitor.symbol_table(); +// pattern_parts_ = FilterAnies(symbol_table_); +// nodes_ = FilterAnies(symbol_table_); +// relationships_ = FilterAnies(symbol_table_); +// } +// +// std::unordered_map identifiers_map_; +// std::unordered_map symbol_table_; +// std::unordered_map pattern_parts_; +// std::unordered_map nodes_; +// std::unordered_map relationships_; +// }; +// +// // TODO: Once expression evaluation is implemented, we should also test if +// // property values are equal. +// void CompareNodes(std::pair node_entry, +// std::vector labels, +// std::vector property_keys) { +// auto node = node_entry.second; +// ASSERT_EQ(node_entry.first, node.output_id); +// ASSERT_THAT(node.labels, +// UnorderedElementsAreArray(labels.begin(), labels.end())); +// std::vector node_property_keys; +// for (auto x : node.properties) { +// node_property_keys.push_back(x.first); +// } +// ASSERT_THAT( +// node_property_keys, +// UnorderedElementsAreArray(property_keys.begin(), property_keys.end())); +// } +// +// // If has_range is false, lower and upper bound values are ignored. +// // TODO: Once expression evaluation is implemented, we should also test if +// // property values are equal. +// void CompareRelationships( +// std::pair relationship_entry, +// Relationship::Direction direction, std::vector types, +// std::vector property_keys, bool has_range, +// int64_t lower_bound = 1LL, int64_t upper_bound = LLONG_MAX) { +// auto relationship = relationship_entry.second; +// ASSERT_EQ(relationship_entry.first, relationship.output_id); +// ASSERT_EQ(relationship.direction, direction); +// ASSERT_THAT(relationship.types, +// UnorderedElementsAreArray(types.begin(), types.end())); +// std::vector relationship_property_keys; +// for (auto x : relationship.properties) { +// relationship_property_keys.push_back(x.first); +// } +// ASSERT_THAT( +// relationship_property_keys, +// UnorderedElementsAreArray(property_keys.begin(), property_keys.end())); +// ASSERT_EQ(relationship.has_range, has_range); +// if (!has_range) +// return; +// ASSERT_EQ(relationship.lower_bound, lower_bound); +// ASSERT_EQ(relationship.upper_bound, upper_bound); +// } +// +// // SyntaxException on incorrect syntax. +// TEST(CompilerStructuresTest, SyntaxException) { +// ASSERT_THROW(ParserTables("CREATE ()-[*1...2]-()"), +// frontend::opencypher::SyntaxException); +// } +// +// // Empty node. +// TEST(CompilerStructuresTest, NodePatternEmpty) { +// ParserTables parser("CREATE ()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.nodes_.size(), 1U); +// CompareNodes(*parser.nodes_.begin(), {}, {}); +// } +// +// // Node with variable. +// TEST(CompilerStructuresTest, NodePatternVariable) { +// ParserTables parser("CREATE (var)"); +// ASSERT_EQ(parser.identifiers_map_.size(), 1U); +// ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); +// ASSERT_EQ(parser.nodes_.size(), 1U); +// auto output_identifier = parser.identifiers_map_["var"]; +// ASSERT_NE(parser.nodes_.find(output_identifier), parser.nodes_.end()); +// CompareNodes(*parser.nodes_.begin(), {}, {}); +// } +// +// // Node with labels. +// TEST(CompilerStructuresTest, NodePatternLabels) { +// ParserTables parser("CREATE (:label1:label2:label3)"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.nodes_.size(), 1U); +// CompareNodes(*parser.nodes_.begin(), {"label1", "label2", "label3"}, {}); +// } +// +// // Node with properties. +// TEST(CompilerStructuresTest, NodePatternProperties) { +// ParserTables parser("CREATE ({age: 5, name: \"John\", surname: \"Smith\"})"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.nodes_.size(), 1U); +// CompareNodes(*parser.nodes_.begin(), {}, {"age", "name", "surname"}); +// } +// +// // Relationship without relationship details. +// TEST(CompilerStructuresTest, RelationshipPatternNoDetails) { +// ParserTables parser("CREATE ()--()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, false); +// } +// +// // Relationship with empty relationship details. +// TEST(CompilerStructuresTest, RelationshipPatternEmptyDetails) { +// ParserTables parser("CREATE ()-[]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, false); +// } +// +// // Relationship with left direction. +// TEST(CompilerStructuresTest, RelationshipPatternLeftDirection) { +// ParserTables parser("CREATE ()<--()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::LEFT, {}, {}, false); +// } +// +// // Relationship with right direction. +// TEST(CompilerStructuresTest, RelationshipPatternRightDirection) { +// ParserTables parser("CREATE ()-[]->()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::RIGHT, {}, {}, false); +// } +// +// // Relationship with both directions. +// TEST(CompilerStructuresTest, RelationshipPatternBothDirection) { +// ParserTables parser("CREATE ()<-[]->()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, false); +// } +// +// // Relationship with unbounded variable range. +// TEST(CompilerStructuresTest, RelationshipPatternUnbounded) { +// ParserTables parser("CREATE ()-[*]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, true, 1, +// LLONG_MAX); +// } +// +// // Relationship with lower bounded variable range. +// TEST(CompilerStructuresTest, RelationshipPatternLowerBounded) { +// ParserTables parser("CREATE ()-[*5..]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, true, 5, +// LLONG_MAX); +// } +// +// // Relationship with upper bounded variable range. +// TEST(CompilerStructuresTest, RelationshipPatternUpperBounded) { +// ParserTables parser("CREATE ()-[*..10]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, true, 1, 10); +// } +// +// // Relationship with lower and upper bounded variable range. +// TEST(CompilerStructuresTest, RelationshipPatternLowerUpperBounded) { +// ParserTables parser("CREATE ()-[*5..10]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, true, 5, 10); +// } +// +// // Relationship with fixed number of edges. +// TEST(CompilerStructuresTest, RelationshipPatternFixedRange) { +// ParserTables parser("CREATE ()-[*10]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, true, 10, 10); +// } +// +// // Relationship with invalid bound (larger than long long). +// TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) { +// ASSERT_THROW( +// ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"), +// SemanticException); +// } +// +// // Relationship with variable +// TEST(CompilerStructuresTest, RelationshipPatternVariable) { +// ParserTables parser("CREATE ()-[var]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 1U); +// ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// auto output_identifier = parser.identifiers_map_["var"]; +// ASSERT_NE(parser.relationships_.find(output_identifier), +// parser.relationships_.end()); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, {}, false); +// } +// +// // Relationship with labels. +// TEST(CompilerStructuresTest, RelationshipPatternLabels) { +// ParserTables parser("CREATE ()-[:label1|label2|:label3]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, +// {"label1", "label2", "label3"}, {}, false); +// } +// +// // Relationship with properties. +// TEST(CompilerStructuresTest, RelationshipPatternProperties) { +// ParserTables parser( +// "CREATE ()-[{age: 5, name: \"John\", surname: \"Smith\"}]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// CompareRelationships(*parser.relationships_.begin(), +// Relationship::Direction::BOTH, {}, +// {"age", "name", "surname"}, false); +// } +// +// // PatternPart. +// TEST(CompilerStructuresTest, PatternPart) { +// ParserTables parser("CREATE ()--()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.pattern_parts_.size(), 1U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// ASSERT_EQ(parser.nodes_.size(), 2U); +// ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); +// ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); +// } +// +// // PatternPart in braces. +// TEST(CompilerStructuresTest, PatternPartBraces) { +// ParserTables parser("CREATE ((()--()))"); +// ASSERT_EQ(parser.identifiers_map_.size(), 0U); +// ASSERT_EQ(parser.pattern_parts_.size(), 1U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// ASSERT_EQ(parser.nodes_.size(), 2U); +// ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); +// ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); +// } +// +// // PatternPart with variable. +// TEST(CompilerStructuresTest, PatternPartVariable) { +// ParserTables parser("CREATE var=()--()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 1U); +// ASSERT_EQ(parser.pattern_parts_.size(), 1U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// ASSERT_EQ(parser.nodes_.size(), 2U); +// ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); +// ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); +// ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); +// auto output_identifier = parser.identifiers_map_["var"]; +// ASSERT_NE(parser.pattern_parts_.find(output_identifier), +// parser.pattern_parts_.end()); +// } +// +// // Multiple nodes with same variable and properties. +// TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) { +// ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"), +// SemanticException); +// } +// +// // Multiple nodes with same variable name. +// TEST(CompilerStructuresTest, MultipleNodesWithVariable) { +// ParserTables parser("CREATE (a {b: 5, c: 5})-[]-(a)"); +// ASSERT_EQ(parser.identifiers_map_.size(), 1U); +// ASSERT_EQ(parser.pattern_parts_.size(), 1U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// ASSERT_EQ(parser.nodes_.size(), 1U); +// auto pattern_part = parser.pattern_parts_.begin()->second; +// ASSERT_EQ(pattern_part.nodes.size(), 2U); +// ASSERT_EQ(pattern_part.relationships.size(), 1U); +// ASSERT_EQ(pattern_part.nodes[0], pattern_part.nodes[1]); +// } +// +// // Multiple relationships with same variable name and properties. +// TEST(CompilerStructuresTest, MultipleRelationshipsWithVariableAndProperties) { +// ASSERT_THROW(ParserTables parser("CREATE ()-[e {a: 5}]-()-[e {c: 5}]-()"), +// SemanticException); +// } +// +// // Multiple relationships with same variable name. +// TEST(CompilerStructuresTest, MultipleRelationshipsWithVariable) { +// ParserTables parser("CREATE ()-[a {a: 5}]-()-[a]-()"); +// ASSERT_EQ(parser.identifiers_map_.size(), 1U); +// ASSERT_EQ(parser.pattern_parts_.size(), 1U); +// ASSERT_EQ(parser.relationships_.size(), 1U); +// ASSERT_EQ(parser.nodes_.size(), 3U); +// auto pattern_part = parser.pattern_parts_.begin()->second; +// ASSERT_EQ(pattern_part.nodes.size(), 3U); +// ASSERT_EQ(pattern_part.relationships.size(), 2U); +// ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[1]); +// ASSERT_NE(pattern_part.nodes[1], pattern_part.nodes[2]); +// ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[2]); +// ASSERT_EQ(pattern_part.relationships[0], pattern_part.relationships[1]); +// } +// +// // Different structures (nodes, realtionships, patterns) with same variable +// // name. +// TEST(CompilerStructuresTest, DifferentTypesWithVariable) { +// ASSERT_THROW(ParserTables parser("CREATE a=(a)"), SemanticException); +// ASSERT_THROW(ParserTables parser("CREATE (a)-[a]-()"), SemanticException); +// ASSERT_THROW(ParserTables parser("CREATE a=()-[a]-()"), SemanticException); +// } +// } int main(int argc, char **argv) { InitGoogleTest(&argc, argv);