2017-03-12 04:19:57 +08:00
|
|
|
#include <algorithm>
|
2017-02-24 00:15:31 +08:00
|
|
|
#include <climits>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
2017-03-12 04:19:57 +08:00
|
|
|
#include <vector>
|
|
|
|
|
2017-02-24 00:15:31 +08:00
|
|
|
#include "antlr4-runtime.h"
|
2017-03-17 17:43:18 +08:00
|
|
|
#include "dbms/dbms.hpp"
|
2017-02-24 00:15:31 +08:00
|
|
|
#include "gmock/gmock.h"
|
2017-03-12 04:19:57 +08:00
|
|
|
#include "query/context.hpp"
|
|
|
|
#include "query/frontend/ast/cypher_main_visitor.hpp"
|
2017-02-24 00:15:31 +08:00
|
|
|
#include "query/frontend/opencypher/parser.hpp"
|
2017-03-12 04:19:57 +08:00
|
|
|
#include "gtest/gtest.h"
|
2017-02-24 00:15:31 +08:00
|
|
|
|
2017-03-17 17:43:18 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
using namespace query;
|
|
|
|
using namespace query::frontend;
|
|
|
|
using testing::UnorderedElementsAre;
|
|
|
|
|
|
|
|
class AstGenerator {
|
|
|
|
public:
|
|
|
|
AstGenerator(const std::string &query)
|
|
|
|
: dbms_(), db_accessor_(dbms_.active()),
|
|
|
|
context_(Config{}, *db_accessor_), query_string_(query), parser_(query),
|
|
|
|
visitor_(context_), query_([&]() {
|
|
|
|
visitor_.visit(parser_.tree());
|
|
|
|
return visitor_.query();
|
|
|
|
}()) {}
|
|
|
|
|
|
|
|
Dbms dbms_;
|
|
|
|
std::unique_ptr<GraphDbAccessor> db_accessor_;
|
|
|
|
Context context_;
|
|
|
|
std::string query_string_;
|
|
|
|
::frontend::opencypher::Parser parser_;
|
|
|
|
CypherMainVisitor visitor_;
|
|
|
|
Query *query_;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST(CompilerStructuresTest, SyntaxException) {
|
|
|
|
ASSERT_THROW(AstGenerator("CREATE ()-[*1...2]-()"), std::exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CompilerStructuresTest, NodePattern) {
|
|
|
|
AstGenerator ast_generator("MATCH (:label1:label2:label3)");
|
|
|
|
auto *query = ast_generator.query_;
|
|
|
|
ASSERT_EQ(query->clauses_.size(), 1U);
|
|
|
|
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
|
|
|
ASSERT_TRUE(match);
|
|
|
|
ASSERT_EQ(match->patterns_.size(), 1U);
|
|
|
|
ASSERT_TRUE(match->patterns_[0]);
|
|
|
|
ASSERT_EQ(match->patterns_[0]->atoms_.size(), 1U);
|
|
|
|
auto node = dynamic_cast<NodeAtom *>(match->patterns_[0]->atoms_[0]);
|
|
|
|
ASSERT_TRUE(node);
|
|
|
|
ASSERT_TRUE(node->identifier_);
|
|
|
|
ASSERT_EQ(node->identifier_->name_,
|
|
|
|
CypherMainVisitor::kAnonPrefix + std::to_string(1));
|
|
|
|
ASSERT_THAT(node->labels_, UnorderedElementsAre(
|
|
|
|
ast_generator.db_accessor_->label("label1"),
|
|
|
|
ast_generator.db_accessor_->label("label2"),
|
|
|
|
ast_generator.db_accessor_->label("label3")));
|
|
|
|
// TODO: add test for properties.
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CompilerStructuresTest, NodePatternIdentifier) {
|
|
|
|
AstGenerator ast_generator("MATCH (var)");
|
|
|
|
auto *query = ast_generator.query_;
|
|
|
|
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
|
|
|
auto node = dynamic_cast<NodeAtom *>(match->patterns_[0]->atoms_[0]);
|
|
|
|
ASSERT_TRUE(node->identifier_);
|
|
|
|
ASSERT_EQ(node->identifier_->name_, "var");
|
|
|
|
ASSERT_THAT(node->labels_, UnorderedElementsAre());
|
|
|
|
// TODO: add test for properties.
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CompilerStructuresTest, RelationshipPatternNoDetails) {
|
|
|
|
AstGenerator ast_generator("MATCH ()--()");
|
|
|
|
auto *query = ast_generator.query_;
|
|
|
|
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
|
|
|
ASSERT_EQ(match->patterns_.size(), 1U);
|
|
|
|
ASSERT_TRUE(match->patterns_[0]);
|
|
|
|
ASSERT_EQ(match->patterns_[0]->atoms_.size(), 3U);
|
|
|
|
auto *node1 = dynamic_cast<NodeAtom *>(match->patterns_[0]->atoms_[0]);
|
|
|
|
ASSERT_TRUE(node1);
|
|
|
|
auto *edge = dynamic_cast<EdgeAtom *>(match->patterns_[0]->atoms_[1]);
|
|
|
|
ASSERT_TRUE(edge);
|
|
|
|
auto *node2 = dynamic_cast<NodeAtom *>(match->patterns_[0]->atoms_[2]);
|
|
|
|
ASSERT_TRUE(node2);
|
|
|
|
ASSERT_EQ(edge->direction_, EdgeAtom::Direction::BOTH);
|
|
|
|
ASSERT_TRUE(edge->identifier_);
|
|
|
|
ASSERT_THAT(edge->identifier_->name_,
|
|
|
|
CypherMainVisitor::kAnonPrefix + std::to_string(2));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CompilerStructuresTest, RelationshipPatternDetails) {
|
|
|
|
AstGenerator ast_generator("MATCH ()<-[:type1|type2]-()");
|
|
|
|
auto *query = ast_generator.query_;
|
|
|
|
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
|
|
|
auto *edge = dynamic_cast<EdgeAtom *>(match->patterns_[0]->atoms_[1]);
|
|
|
|
ASSERT_EQ(edge->direction_, EdgeAtom::Direction::LEFT);
|
|
|
|
ASSERT_THAT(
|
|
|
|
edge->types_,
|
|
|
|
UnorderedElementsAre(ast_generator.db_accessor_->edge_type("type1"),
|
|
|
|
ast_generator.db_accessor_->edge_type("type2")));
|
|
|
|
// TODO: test properties
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CompilerStructuresTest, RelationshipPatternVariable) {
|
|
|
|
AstGenerator ast_generator("MATCH ()-[var]->()");
|
|
|
|
auto *query = ast_generator.query_;
|
|
|
|
auto *match = dynamic_cast<Match *>(query->clauses_[0]);
|
|
|
|
auto *edge = dynamic_cast<EdgeAtom *>(match->patterns_[0]->atoms_[1]);
|
|
|
|
ASSERT_EQ(edge->direction_, EdgeAtom::Direction::RIGHT);
|
|
|
|
ASSERT_TRUE(edge->identifier_);
|
|
|
|
ASSERT_THAT(edge->identifier_->name_, "var");
|
|
|
|
}
|
2017-02-24 00:15:31 +08:00
|
|
|
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // Relationship with invalid bound (larger than long long).
|
|
|
|
// TEST(CompilerStructuresTest, RelationshipPatternInvalidBound) {
|
|
|
|
// ASSERT_THROW(
|
|
|
|
// ParserTables parser("CREATE ()-[*100000000000000000000000000]-()"),
|
|
|
|
// SemanticException);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // 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);
|
2017-03-17 17:43:18 +08:00
|
|
|
// ASSERT_NE(parser.identifiers_map_.find("var"),
|
|
|
|
// parser.identifiers_map_.end());
|
2017-03-12 07:04:10 +08:00
|
|
|
// auto output_identifier = parser.identifiers_map_["var"];
|
|
|
|
// ASSERT_NE(parser.pattern_parts_.find(output_identifier),
|
|
|
|
// parser.pattern_parts_.end());
|
|
|
|
// }
|
2017-03-17 17:43:18 +08:00
|
|
|
//
|
2017-03-12 07:04:10 +08:00
|
|
|
// // Multiple nodes with same variable and properties.
|
|
|
|
// TEST(CompilerStructuresTest, MultipleNodesWithVariableAndProperties) {
|
|
|
|
// ASSERT_THROW(ParserTables parser("CREATE (a {b: 5})-[]-(a {c: 5})"),
|
|
|
|
// SemanticException);
|
|
|
|
// }
|
2017-02-24 00:15:31 +08:00
|
|
|
}
|