it compilesga -A!

This commit is contained in:
Marko Budiselic 2017-03-12 00:04:10 +01:00
parent 026e0e6fbd
commit 1f75572d5e
11 changed files with 376 additions and 409 deletions

View File

@ -61,12 +61,12 @@ State state_executor_run(RecordStream<Socket> &output_stream, BoltDecoder &decod
{{"code", "Memgraph.SyntaxException"}, {"message", "Syntax error"}}); {{"code", "Memgraph.SyntaxException"}, {"message", "Syntax error"}});
output_stream.send(); output_stream.send();
return ERROR; return ERROR;
} catch (const backend::cpp::GeneratorException &e) { // } catch (const backend::cpp::GeneratorException &e) {
output_stream.write_failure( // output_stream.write_failure(
{{"code", "Memgraph.GeneratorException"}, // {{"code", "Memgraph.GeneratorException"},
{"message", "Unsupported query"}}); // {"message", "Unsupported query"}});
output_stream.send(); // output_stream.send();
return ERROR; // return ERROR;
} catch (const QueryEngineException &e) { } catch (const QueryEngineException &e) {
output_stream.write_failure( output_stream.write_failure(
{{"code", "Memgraph.QueryEngineException"}, {{"code", "Memgraph.QueryEngineException"},

View File

@ -1,38 +0,0 @@
#pragma once
#include "antlr4-runtime.h"
#include "query/frontend/ast/cypher_main_visitor.hpp"
#include <experimental/filesystem>
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);
}
};
}
}

View File

@ -3,9 +3,10 @@
namespace query { namespace query {
void HighLevelAstConversion::Apply(Context &ctx, std::shared_ptr<Query> HighLevelAstConversion::Apply(Context &ctx,
antlr4::tree::ParseTree *tree) { antlr4::tree::ParseTree *tree) {
query::frontend::CypherMainVisitor visitor(ctx); query::frontend::CypherMainVisitor visitor(ctx);
visitor.visit(tree); visitor.visit(tree);
return visitor.query();
} }
} }

View File

@ -10,6 +10,7 @@ class TypedcheckedTree {};
class LogicalPlan {}; class LogicalPlan {};
class Context; class Context;
class Query;
class LogicalPlanGenerator { class LogicalPlanGenerator {
public: public:
@ -48,6 +49,6 @@ private:
class HighLevelAstConversion { class HighLevelAstConversion {
public: public:
void Apply(Context &ctx, antlr4::tree::ParseTree *tree); std::shared_ptr<Query> Apply(Context &ctx, antlr4::tree::ParseTree *tree);
}; };
} }

View File

@ -7,7 +7,6 @@ namespace fs = std::experimental::filesystem;
#include "data_structures/concurrent/concurrent_map.hpp" #include "data_structures/concurrent/concurrent_map.hpp"
#include "database/graph_db.hpp" #include "database/graph_db.hpp"
#include "logging/loggable.hpp" #include "logging/loggable.hpp"
#include "query/backend/cpp/generator.hpp"
#include "query/exception/query_engine.hpp" #include "query/exception/query_engine.hpp"
#include "query/frontend/opencypher/parser.hpp" #include "query/frontend/opencypher/parser.hpp"
#include "query/plan_compiler.hpp" #include "query/plan_compiler.hpp"
@ -137,8 +136,8 @@ private:
std::to_string(stripped.hash) + ".cpp"); std::to_string(stripped.hash) + ".cpp");
frontend::opencypher::Parser parser(stripped.query); frontend::opencypher::Parser parser(stripped.query);
backend::cpp::Generator(parser.tree(), stripped.query, stripped.hash, // backend::cpp::Generator(parser.tree(), stripped.query, stripped.hash,
generated_path); // generated_path);
return LoadCpp(generated_path, stripped.hash); return LoadCpp(generated_path, stripped.hash);
} }

View File

@ -1,5 +1,8 @@
#pragma once #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 "database/graph_db_accessor.hpp"
#include "query/context.hpp" #include "query/context.hpp"
#include "query/frontend/opencypher/parser.hpp" #include "query/frontend/opencypher/parser.hpp"
@ -21,35 +24,32 @@ class Engine {
auto low_level_tree = parser.tree(); auto low_level_tree = parser.tree();
// AST -> high level tree // AST -> high level tree
HighLevelAstConversion low2high_tree;
auto high_level_tree = low2high_tree.Apply(ctx, low_level_tree); auto high_level_tree = low2high_tree.Apply(ctx, low_level_tree);
// symbol table fill // symbol table fill
SymbolTable symbol_table; SymbolTable symbol_table;
TypeCheckVisitor typecheck_visitor; TypeCheckVisitor typecheck_visitor(symbol_table);
high_level_tree.Accept(typecheck_visitor); high_level_tree->Accept(typecheck_visitor);
// high level tree -> logical plan // 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 // generate frame based on symbol table max_position
Frame frame(symbol_table.max_position()); Frame frame(symbol_table.max_position());
// interpret // interpret
auto cursor = logical_plan.MakeCursor(frame); auto cursor = logical_plan->MakeCursor(db_accessor);
logical_plan.WriteHeader(stream); logical_plan->WriteHeader(stream);
auto symbols = logical_plan.OutputSymbols(symbol_table); auto symbols = logical_plan->OutputSymbols(symbol_table);
while (cursor.pull(frame, context)) { while (cursor->pull(frame, symbol_table)) {
std::vector<TypedValue> values(symbols.size()); std::vector<TypedValue> values(symbols.size());
for (auto symbol : symbols) { for (auto symbol : symbols) {
values.emplace_back(frame[symbol]); values.emplace_back(frame[symbol.position_]);
} }
stream.Result(values); stream.Result(values);
} }
stream.Summary({"type" : "r"}); stream.Summary({{std::string("type"), TypedValue("r")}});
} }
private:
Context ctx;
HighLevelAstConversion low2high_tree;
}; };
} }

View File

@ -281,6 +281,9 @@ private:
antlrcpp::Any antlrcpp::Any
visitIntegerLiteral(CypherParser::IntegerLiteralContext *ctx) override; visitIntegerLiteral(CypherParser::IntegerLiteralContext *ctx) override;
public:
std::shared_ptr<Query> query() { return query_; }
private: private:
Context &ctx_; Context &ctx_;
int next_ident_id_; int next_ident_id_;

View File

@ -82,7 +82,7 @@ class ScanAll : public LogicalOperator {
for (auto label : node_part->labels_) { for (auto label : node_part->labels_) {
if (!vertex.has_label(label)) return false; 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; return true;
} }
}; };

View File

@ -18,10 +18,10 @@ std::shared_ptr<LogicalOperator> GenMatch(
throw std::runtime_error("Not implemented"); throw std::runtime_error("Not implemented");
} }
auto& pattern = match.patterns_[0]; auto& pattern = match.patterns_[0];
if (pattern->node_parts_.size() != 1) { if (pattern->parts_.size() != 1) {
throw std::runtime_error("Not implemented"); throw std::runtime_error("Not implemented");
} }
auto& node_part = pattern->node_parts_[0]; auto node_part = std::dynamic_pointer_cast<NodePart>(pattern->parts_[0]);
return std::make_shared<ScanAll>(node_part); return std::make_shared<ScanAll>(node_part);
} }

View File

@ -5,6 +5,7 @@
#include "logging/streams/stdout.cpp" #include "logging/streams/stdout.cpp"
#include "query/entry.hpp" #include "query/entry.hpp"
#include "query/backend/cpp/typed_value.hpp" #include "query/backend/cpp/typed_value.hpp"
#include "query/frontend/logical/operator.hpp"
using std::cout; using std::cout;
using std::cin; using std::cin;
@ -20,8 +21,8 @@ int main(int argc, char* argv[]) {
// init db context // init db context
Dbms dbms; Dbms dbms;
ConsoleResultStream stream; query::ConsoleResultStream stream;
query::Engine<ConsoleResultStream> query_engine; query::Engine<query::ConsoleResultStream> query_engine;
// initialize the database // initialize the database
auto dba = dbms.active(); auto dba = dbms.active();

View File

@ -13,348 +13,348 @@
using namespace ::testing; using namespace ::testing;
namespace { // namespace {
//
using query::Context; // using query::Context;
using namespace query::frontend; // using namespace query::frontend;
//
class ParserTables { // class ParserTables {
template <typename T> // template <typename T>
auto FilterAnies(std::unordered_map<std::string, antlrcpp::Any> map) { // auto FilterAnies(std::unordered_map<std::string, antlrcpp::Any> map) {
std::unordered_map<std::string, T> filtered; // std::unordered_map<std::string, T> filtered;
for (auto x : map) { // for (auto x : map) {
if (x.second.is<T>()) { // if (x.second.is<T>()) {
filtered[x.first] = x.second.as<T>(); // filtered[x.first] = x.second.as<T>();
} // }
} // }
return filtered; // return filtered;
} // }
//
public: // public:
ParserTables(const std::string &query) { // ParserTables(const std::string &query) {
frontend::opencypher::Parser parser(query); // frontend::opencypher::Parser parser(query);
auto *tree = parser.tree(); // auto *tree = parser.tree();
CypherMainVisitor visitor; // CypherMainVisitor visitor;
visitor.visit(tree); // visitor.visit(tree);
identifiers_map_ = visitor.ids_map().back(); // identifiers_map_ = visitor.ids_map().back();
symbol_table_ = visitor.symbol_table(); // symbol_table_ = visitor.symbol_table();
pattern_parts_ = FilterAnies<PatternPart>(symbol_table_); // pattern_parts_ = FilterAnies<PatternPart>(symbol_table_);
nodes_ = FilterAnies<Node>(symbol_table_); // nodes_ = FilterAnies<Node>(symbol_table_);
relationships_ = FilterAnies<Relationship>(symbol_table_); // relationships_ = FilterAnies<Relationship>(symbol_table_);
} // }
//
std::unordered_map<std::string, std::string> identifiers_map_; // std::unordered_map<std::string, std::string> identifiers_map_;
std::unordered_map<std::string, antlrcpp::Any> symbol_table_; // std::unordered_map<std::string, antlrcpp::Any> symbol_table_;
std::unordered_map<std::string, PatternPart> pattern_parts_; // std::unordered_map<std::string, PatternPart> pattern_parts_;
std::unordered_map<std::string, Node> nodes_; // std::unordered_map<std::string, Node> nodes_;
std::unordered_map<std::string, Relationship> relationships_; // std::unordered_map<std::string, Relationship> relationships_;
}; // };
//
// TODO: Once expression evaluation is implemented, we should also test if // // TODO: Once expression evaluation is implemented, we should also test if
// property values are equal. // // property values are equal.
void CompareNodes(std::pair<std::string, Node> node_entry, // void CompareNodes(std::pair<std::string, Node> node_entry,
std::vector<std::string> labels, // std::vector<std::string> labels,
std::vector<std::string> property_keys) { // std::vector<std::string> property_keys) {
auto node = node_entry.second; // auto node = node_entry.second;
ASSERT_EQ(node_entry.first, node.output_id); // ASSERT_EQ(node_entry.first, node.output_id);
ASSERT_THAT(node.labels, // ASSERT_THAT(node.labels,
UnorderedElementsAreArray(labels.begin(), labels.end())); // UnorderedElementsAreArray(labels.begin(), labels.end()));
std::vector<std::string> node_property_keys; // std::vector<std::string> node_property_keys;
for (auto x : node.properties) { // for (auto x : node.properties) {
node_property_keys.push_back(x.first); // node_property_keys.push_back(x.first);
} // }
ASSERT_THAT( // ASSERT_THAT(
node_property_keys, // node_property_keys,
UnorderedElementsAreArray(property_keys.begin(), property_keys.end())); // UnorderedElementsAreArray(property_keys.begin(), property_keys.end()));
} // }
//
// If has_range is false, lower and upper bound values are ignored. // // If has_range is false, lower and upper bound values are ignored.
// TODO: Once expression evaluation is implemented, we should also test if // // TODO: Once expression evaluation is implemented, we should also test if
// property values are equal. // // property values are equal.
void CompareRelationships( // void CompareRelationships(
std::pair<std::string, Relationship> relationship_entry, // std::pair<std::string, Relationship> relationship_entry,
Relationship::Direction direction, std::vector<std::string> types, // Relationship::Direction direction, std::vector<std::string> types,
std::vector<std::string> property_keys, bool has_range, // std::vector<std::string> property_keys, bool has_range,
int64_t lower_bound = 1LL, int64_t upper_bound = LLONG_MAX) { // int64_t lower_bound = 1LL, int64_t upper_bound = LLONG_MAX) {
auto relationship = relationship_entry.second; // auto relationship = relationship_entry.second;
ASSERT_EQ(relationship_entry.first, relationship.output_id); // ASSERT_EQ(relationship_entry.first, relationship.output_id);
ASSERT_EQ(relationship.direction, direction); // ASSERT_EQ(relationship.direction, direction);
ASSERT_THAT(relationship.types, // ASSERT_THAT(relationship.types,
UnorderedElementsAreArray(types.begin(), types.end())); // UnorderedElementsAreArray(types.begin(), types.end()));
std::vector<std::string> relationship_property_keys; // std::vector<std::string> relationship_property_keys;
for (auto x : relationship.properties) { // for (auto x : relationship.properties) {
relationship_property_keys.push_back(x.first); // relationship_property_keys.push_back(x.first);
} // }
ASSERT_THAT( // ASSERT_THAT(
relationship_property_keys, // relationship_property_keys,
UnorderedElementsAreArray(property_keys.begin(), property_keys.end())); // UnorderedElementsAreArray(property_keys.begin(), property_keys.end()));
ASSERT_EQ(relationship.has_range, has_range); // ASSERT_EQ(relationship.has_range, has_range);
if (!has_range) // if (!has_range)
return; // return;
ASSERT_EQ(relationship.lower_bound, lower_bound); // ASSERT_EQ(relationship.lower_bound, lower_bound);
ASSERT_EQ(relationship.upper_bound, upper_bound); // ASSERT_EQ(relationship.upper_bound, upper_bound);
} // }
//
// SyntaxException on incorrect syntax. // // SyntaxException on incorrect syntax.
TEST(CompilerStructuresTest, SyntaxException) { // TEST(CompilerStructuresTest, SyntaxException) {
ASSERT_THROW(ParserTables("CREATE ()-[*1...2]-()"), // ASSERT_THROW(ParserTables("CREATE ()-[*1...2]-()"),
frontend::opencypher::SyntaxException); // frontend::opencypher::SyntaxException);
} // }
//
// Empty node. // // Empty node.
TEST(CompilerStructuresTest, NodePatternEmpty) { // TEST(CompilerStructuresTest, NodePatternEmpty) {
ParserTables parser("CREATE ()"); // ParserTables parser("CREATE ()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.nodes_.size(), 1U); // ASSERT_EQ(parser.nodes_.size(), 1U);
CompareNodes(*parser.nodes_.begin(), {}, {}); // CompareNodes(*parser.nodes_.begin(), {}, {});
} // }
//
// Node with variable. // // Node with variable.
TEST(CompilerStructuresTest, NodePatternVariable) { // TEST(CompilerStructuresTest, NodePatternVariable) {
ParserTables parser("CREATE (var)"); // ParserTables parser("CREATE (var)");
ASSERT_EQ(parser.identifiers_map_.size(), 1U); // ASSERT_EQ(parser.identifiers_map_.size(), 1U);
ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); // ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end());
ASSERT_EQ(parser.nodes_.size(), 1U); // ASSERT_EQ(parser.nodes_.size(), 1U);
auto output_identifier = parser.identifiers_map_["var"]; // auto output_identifier = parser.identifiers_map_["var"];
ASSERT_NE(parser.nodes_.find(output_identifier), parser.nodes_.end()); // ASSERT_NE(parser.nodes_.find(output_identifier), parser.nodes_.end());
CompareNodes(*parser.nodes_.begin(), {}, {}); // CompareNodes(*parser.nodes_.begin(), {}, {});
} // }
//
// Node with labels. // // Node with labels.
TEST(CompilerStructuresTest, NodePatternLabels) { // TEST(CompilerStructuresTest, NodePatternLabels) {
ParserTables parser("CREATE (:label1:label2:label3)"); // ParserTables parser("CREATE (:label1:label2:label3)");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.nodes_.size(), 1U); // ASSERT_EQ(parser.nodes_.size(), 1U);
CompareNodes(*parser.nodes_.begin(), {"label1", "label2", "label3"}, {}); // CompareNodes(*parser.nodes_.begin(), {"label1", "label2", "label3"}, {});
} // }
//
// Node with properties. // // Node with properties.
TEST(CompilerStructuresTest, NodePatternProperties) { // TEST(CompilerStructuresTest, NodePatternProperties) {
ParserTables parser("CREATE ({age: 5, name: \"John\", surname: \"Smith\"})"); // ParserTables parser("CREATE ({age: 5, name: \"John\", surname: \"Smith\"})");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.nodes_.size(), 1U); // ASSERT_EQ(parser.nodes_.size(), 1U);
CompareNodes(*parser.nodes_.begin(), {}, {"age", "name", "surname"}); // CompareNodes(*parser.nodes_.begin(), {}, {"age", "name", "surname"});
} // }
//
// Relationship without relationship details. // // Relationship without relationship details.
TEST(CompilerStructuresTest, RelationshipPatternNoDetails) { // TEST(CompilerStructuresTest, RelationshipPatternNoDetails) {
ParserTables parser("CREATE ()--()"); // ParserTables parser("CREATE ()--()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, false); // Relationship::Direction::BOTH, {}, {}, false);
} // }
//
// Relationship with empty relationship details. // // Relationship with empty relationship details.
TEST(CompilerStructuresTest, RelationshipPatternEmptyDetails) { // TEST(CompilerStructuresTest, RelationshipPatternEmptyDetails) {
ParserTables parser("CREATE ()-[]-()"); // ParserTables parser("CREATE ()-[]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, false); // Relationship::Direction::BOTH, {}, {}, false);
} // }
//
// Relationship with left direction. // // Relationship with left direction.
TEST(CompilerStructuresTest, RelationshipPatternLeftDirection) { // TEST(CompilerStructuresTest, RelationshipPatternLeftDirection) {
ParserTables parser("CREATE ()<--()"); // ParserTables parser("CREATE ()<--()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::LEFT, {}, {}, false); // Relationship::Direction::LEFT, {}, {}, false);
} // }
//
// Relationship with right direction. // // Relationship with right direction.
TEST(CompilerStructuresTest, RelationshipPatternRightDirection) { // TEST(CompilerStructuresTest, RelationshipPatternRightDirection) {
ParserTables parser("CREATE ()-[]->()"); // ParserTables parser("CREATE ()-[]->()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::RIGHT, {}, {}, false); // Relationship::Direction::RIGHT, {}, {}, false);
} // }
//
// Relationship with both directions. // // Relationship with both directions.
TEST(CompilerStructuresTest, RelationshipPatternBothDirection) { // TEST(CompilerStructuresTest, RelationshipPatternBothDirection) {
ParserTables parser("CREATE ()<-[]->()"); // ParserTables parser("CREATE ()<-[]->()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, false); // Relationship::Direction::BOTH, {}, {}, false);
} // }
//
// Relationship with unbounded variable range. // // Relationship with unbounded variable range.
TEST(CompilerStructuresTest, RelationshipPatternUnbounded) { // TEST(CompilerStructuresTest, RelationshipPatternUnbounded) {
ParserTables parser("CREATE ()-[*]-()"); // ParserTables parser("CREATE ()-[*]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, true, 1, // Relationship::Direction::BOTH, {}, {}, true, 1,
LLONG_MAX); // LLONG_MAX);
} // }
//
// Relationship with lower bounded variable range. // // Relationship with lower bounded variable range.
TEST(CompilerStructuresTest, RelationshipPatternLowerBounded) { // TEST(CompilerStructuresTest, RelationshipPatternLowerBounded) {
ParserTables parser("CREATE ()-[*5..]-()"); // ParserTables parser("CREATE ()-[*5..]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, true, 5, // Relationship::Direction::BOTH, {}, {}, true, 5,
LLONG_MAX); // LLONG_MAX);
} // }
//
// Relationship with upper bounded variable range. // // Relationship with upper bounded variable range.
TEST(CompilerStructuresTest, RelationshipPatternUpperBounded) { // TEST(CompilerStructuresTest, RelationshipPatternUpperBounded) {
ParserTables parser("CREATE ()-[*..10]-()"); // ParserTables parser("CREATE ()-[*..10]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, true, 1, 10); // Relationship::Direction::BOTH, {}, {}, true, 1, 10);
} // }
//
// Relationship with lower and upper bounded variable range. // // Relationship with lower and upper bounded variable range.
TEST(CompilerStructuresTest, RelationshipPatternLowerUpperBounded) { // TEST(CompilerStructuresTest, RelationshipPatternLowerUpperBounded) {
ParserTables parser("CREATE ()-[*5..10]-()"); // ParserTables parser("CREATE ()-[*5..10]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, true, 5, 10); // Relationship::Direction::BOTH, {}, {}, true, 5, 10);
} // }
//
// Relationship with fixed number of edges. // // Relationship with fixed number of edges.
TEST(CompilerStructuresTest, RelationshipPatternFixedRange) { // TEST(CompilerStructuresTest, RelationshipPatternFixedRange) {
ParserTables parser("CREATE ()-[*10]-()"); // ParserTables parser("CREATE ()-[*10]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, true, 10, 10); // Relationship::Direction::BOTH, {}, {}, true, 10, 10);
} // }
//
// Relationship with invalid bound (larger than long long). // // Relationship with invalid bound (larger than long long).
TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) { // TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) {
ASSERT_THROW( // ASSERT_THROW(
ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"), // ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"),
SemanticException); // SemanticException);
} // }
//
// Relationship with variable // // Relationship with variable
TEST(CompilerStructuresTest, RelationshipPatternVariable) { // TEST(CompilerStructuresTest, RelationshipPatternVariable) {
ParserTables parser("CREATE ()-[var]-()"); // ParserTables parser("CREATE ()-[var]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 1U); // ASSERT_EQ(parser.identifiers_map_.size(), 1U);
ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); // ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end());
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
auto output_identifier = parser.identifiers_map_["var"]; // auto output_identifier = parser.identifiers_map_["var"];
ASSERT_NE(parser.relationships_.find(output_identifier), // ASSERT_NE(parser.relationships_.find(output_identifier),
parser.relationships_.end()); // parser.relationships_.end());
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, {}, false); // Relationship::Direction::BOTH, {}, {}, false);
} // }
//
// Relationship with labels. // // Relationship with labels.
TEST(CompilerStructuresTest, RelationshipPatternLabels) { // TEST(CompilerStructuresTest, RelationshipPatternLabels) {
ParserTables parser("CREATE ()-[:label1|label2|:label3]-()"); // ParserTables parser("CREATE ()-[:label1|label2|:label3]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, // Relationship::Direction::BOTH,
{"label1", "label2", "label3"}, {}, false); // {"label1", "label2", "label3"}, {}, false);
} // }
//
// Relationship with properties. // // Relationship with properties.
TEST(CompilerStructuresTest, RelationshipPatternProperties) { // TEST(CompilerStructuresTest, RelationshipPatternProperties) {
ParserTables parser( // ParserTables parser(
"CREATE ()-[{age: 5, name: \"John\", surname: \"Smith\"}]-()"); // "CREATE ()-[{age: 5, name: \"John\", surname: \"Smith\"}]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
CompareRelationships(*parser.relationships_.begin(), // CompareRelationships(*parser.relationships_.begin(),
Relationship::Direction::BOTH, {}, // Relationship::Direction::BOTH, {},
{"age", "name", "surname"}, false); // {"age", "name", "surname"}, false);
} // }
//
// PatternPart. // // PatternPart.
TEST(CompilerStructuresTest, PatternPart) { // TEST(CompilerStructuresTest, PatternPart) {
ParserTables parser("CREATE ()--()"); // ParserTables parser("CREATE ()--()");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
ASSERT_EQ(parser.nodes_.size(), 2U); // ASSERT_EQ(parser.nodes_.size(), 2U);
ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); // ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U);
ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U);
} // }
//
// PatternPart in braces. // // PatternPart in braces.
TEST(CompilerStructuresTest, PatternPartBraces) { // TEST(CompilerStructuresTest, PatternPartBraces) {
ParserTables parser("CREATE ((()--()))"); // ParserTables parser("CREATE ((()--()))");
ASSERT_EQ(parser.identifiers_map_.size(), 0U); // ASSERT_EQ(parser.identifiers_map_.size(), 0U);
ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
ASSERT_EQ(parser.nodes_.size(), 2U); // ASSERT_EQ(parser.nodes_.size(), 2U);
ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); // ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U);
ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U);
} // }
//
// PatternPart with variable. // // PatternPart with variable.
TEST(CompilerStructuresTest, PatternPartVariable) { // TEST(CompilerStructuresTest, PatternPartVariable) {
ParserTables parser("CREATE var=()--()"); // ParserTables parser("CREATE var=()--()");
ASSERT_EQ(parser.identifiers_map_.size(), 1U); // ASSERT_EQ(parser.identifiers_map_.size(), 1U);
ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
ASSERT_EQ(parser.nodes_.size(), 2U); // ASSERT_EQ(parser.nodes_.size(), 2U);
ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U); // ASSERT_EQ(parser.pattern_parts_.begin()->second.nodes.size(), 2U);
ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.begin()->second.relationships.size(), 1U);
ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end()); // ASSERT_NE(parser.identifiers_map_.find("var"), parser.identifiers_map_.end());
auto output_identifier = parser.identifiers_map_["var"]; // auto output_identifier = parser.identifiers_map_["var"];
ASSERT_NE(parser.pattern_parts_.find(output_identifier), // ASSERT_NE(parser.pattern_parts_.find(output_identifier),
parser.pattern_parts_.end()); // parser.pattern_parts_.end());
} // }
//
// Multiple nodes with same variable and properties. // // Multiple nodes with same variable and properties.
TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) { // TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) {
ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"), // ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"),
SemanticException); // SemanticException);
} // }
//
// Multiple nodes with same variable name. // // Multiple nodes with same variable name.
TEST(CompilerStructuresTest, MultipleNodesWithVariable) { // TEST(CompilerStructuresTest, MultipleNodesWithVariable) {
ParserTables parser("CREATE (a {b: 5, c: 5})-[]-(a)"); // ParserTables parser("CREATE (a {b: 5, c: 5})-[]-(a)");
ASSERT_EQ(parser.identifiers_map_.size(), 1U); // ASSERT_EQ(parser.identifiers_map_.size(), 1U);
ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
ASSERT_EQ(parser.nodes_.size(), 1U); // ASSERT_EQ(parser.nodes_.size(), 1U);
auto pattern_part = parser.pattern_parts_.begin()->second; // auto pattern_part = parser.pattern_parts_.begin()->second;
ASSERT_EQ(pattern_part.nodes.size(), 2U); // ASSERT_EQ(pattern_part.nodes.size(), 2U);
ASSERT_EQ(pattern_part.relationships.size(), 1U); // ASSERT_EQ(pattern_part.relationships.size(), 1U);
ASSERT_EQ(pattern_part.nodes[0], pattern_part.nodes[1]); // ASSERT_EQ(pattern_part.nodes[0], pattern_part.nodes[1]);
} // }
//
// Multiple relationships with same variable name and properties. // // Multiple relationships with same variable name and properties.
TEST(CompilerStructuresTest, MultipleRelationshipsWithVariableAndProperties) { // TEST(CompilerStructuresTest, MultipleRelationshipsWithVariableAndProperties) {
ASSERT_THROW(ParserTables parser("CREATE ()-[e {a: 5}]-()-[e {c: 5}]-()"), // ASSERT_THROW(ParserTables parser("CREATE ()-[e {a: 5}]-()-[e {c: 5}]-()"),
SemanticException); // SemanticException);
} // }
//
// Multiple relationships with same variable name. // // Multiple relationships with same variable name.
TEST(CompilerStructuresTest, MultipleRelationshipsWithVariable) { // TEST(CompilerStructuresTest, MultipleRelationshipsWithVariable) {
ParserTables parser("CREATE ()-[a {a: 5}]-()-[a]-()"); // ParserTables parser("CREATE ()-[a {a: 5}]-()-[a]-()");
ASSERT_EQ(parser.identifiers_map_.size(), 1U); // ASSERT_EQ(parser.identifiers_map_.size(), 1U);
ASSERT_EQ(parser.pattern_parts_.size(), 1U); // ASSERT_EQ(parser.pattern_parts_.size(), 1U);
ASSERT_EQ(parser.relationships_.size(), 1U); // ASSERT_EQ(parser.relationships_.size(), 1U);
ASSERT_EQ(parser.nodes_.size(), 3U); // ASSERT_EQ(parser.nodes_.size(), 3U);
auto pattern_part = parser.pattern_parts_.begin()->second; // auto pattern_part = parser.pattern_parts_.begin()->second;
ASSERT_EQ(pattern_part.nodes.size(), 3U); // ASSERT_EQ(pattern_part.nodes.size(), 3U);
ASSERT_EQ(pattern_part.relationships.size(), 2U); // ASSERT_EQ(pattern_part.relationships.size(), 2U);
ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[1]); // 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[1], pattern_part.nodes[2]);
ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[2]); // ASSERT_NE(pattern_part.nodes[0], pattern_part.nodes[2]);
ASSERT_EQ(pattern_part.relationships[0], pattern_part.relationships[1]); // ASSERT_EQ(pattern_part.relationships[0], pattern_part.relationships[1]);
} // }
//
// Different structures (nodes, realtionships, patterns) with same variable // // Different structures (nodes, realtionships, patterns) with same variable
// name. // // name.
TEST(CompilerStructuresTest, DifferentTypesWithVariable) { // 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); // 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) { int main(int argc, char **argv) {
InitGoogleTest(&argc, argv); InitGoogleTest(&argc, argv);