Query - create implementation started

Summary: CreateOp tests

Reviewers: teon.banek, buda, mislav.bradac

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D132
This commit is contained in:
florijan 2017-03-16 09:28:16 +01:00
parent ffd399906a
commit da0c9c03d6
5 changed files with 133 additions and 18 deletions

View File

@ -84,6 +84,7 @@ class NodeAtom : public PatternAtom {
std::shared_ptr<Identifier> identifier_;
std::vector<GraphDb::Label> labels_;
std::map<GraphDb::Property, std::shared_ptr<Expression>> properties_;
};
class EdgeAtom : public PatternAtom {
@ -133,6 +134,19 @@ class Query : public Tree {
std::vector<std::shared_ptr<Clause>> clauses_;
};
class Create : public Clause {
public:
Create(int uid) : Clause(uid) {}
std::vector<std::shared_ptr<Pattern>> patterns_;
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
for (auto &pattern : patterns_) {
pattern->Accept(visitor);
}
visitor.PostVisit(*this);
}
};
class Match : public Clause {
public:
Match(int uid) : Clause(uid) {}

View File

@ -9,6 +9,7 @@ class Query;
class NamedExpression;
class Identifier;
class PropertyLookup;
class Create;
class Match;
class Return;
class Pattern;
@ -16,7 +17,6 @@ class NodeAtom;
class EdgeAtom;
using TreeVisitorBase =
::utils::Visitor<Query, NamedExpression, Identifier, PropertyLookup, Match,
Return, Pattern, NodeAtom, EdgeAtom>;
::utils::Visitor<Query, NamedExpression, Identifier, PropertyLookup, Create,
Match, Return, Pattern, NodeAtom, EdgeAtom>;
}

View File

@ -27,9 +27,51 @@ class LogicalOperator {
std::vector<std::shared_ptr<LogicalOperator>> children_;
};
class CreateOp : public LogicalOperator {
public:
CreateOp(std::shared_ptr<NodeAtom> node_atom) : node_atom_(node_atom) {}
private:
class CreateOpCursor : public Cursor {
public:
CreateOpCursor(CreateOp& self, GraphDbAccessor& db) : self_(self), db_(db) {}
bool Pull(Frame &frame, SymbolTable &symbol_table) override {
if (!did_create_) {
auto new_node = db_.insert_vertex();
for (auto label : self_.node_atom_->labels_)
new_node.add_label(label);
ExpressionEvaluator evaluator(frame, symbol_table);
for (auto &kv : self_.node_atom_->properties_){
kv.second->Accept(evaluator);
new_node.PropsSet(kv.first, evaluator.PopBack());
}
did_create_ = true;
return true;
} else
return false;
}
private:
CreateOp &self_;
GraphDbAccessor &db_;
bool did_create_{false};
};
public:
std::unique_ptr<Cursor> MakeCursor(GraphDbAccessor& db) override {
return std::make_unique<CreateOpCursor>(*this, db);
}
private:
std::shared_ptr<NodeAtom> node_atom_;
};
class ScanAll : public LogicalOperator {
public:
ScanAll(std::shared_ptr<NodeAtom> node_atom) : node_atom(node_atom) {}
ScanAll(std::shared_ptr<NodeAtom> node_atom) : node_atom_(node_atom) {}
private:
class ScanAllCursor : public Cursor {
@ -41,7 +83,7 @@ class ScanAll : public LogicalOperator {
bool Pull(Frame& frame, SymbolTable& symbol_table) override {
if (vertices_it_ == vertices_.end()) return false;
frame[symbol_table[*self_.node_atom->identifier_]] = *vertices_it_++;
frame[symbol_table[*self_.node_atom_->identifier_]] = *vertices_it_++;
return true;
}
@ -57,7 +99,7 @@ class ScanAll : public LogicalOperator {
}
private:
std::shared_ptr<NodeAtom> node_atom;
std::shared_ptr<NodeAtom> node_atom_;
};
class NodeFilter : public LogicalOperator {

View File

@ -8,6 +8,23 @@
namespace query {
std::shared_ptr<LogicalOperator> GenCreate(
Create& match, std::shared_ptr<LogicalOperator> current_op)
{
if (current_op) {
throw std::runtime_error("Not implemented");
}
if (match.patterns_.size() != 1) {
throw std::runtime_error("Not implemented");
}
auto& pattern = match.patterns_[0];
if (pattern->atoms_.size() != 1) {
throw std::runtime_error("Not implemented");
}
auto node_atom = std::dynamic_pointer_cast<NodeAtom>(pattern->atoms_[0]);
return std::make_shared<CreateOp>(node_atom);
}
std::shared_ptr<LogicalOperator> GenMatch(
Match& match, std::shared_ptr<LogicalOperator> current_op)
{
@ -21,8 +38,8 @@ std::shared_ptr<LogicalOperator> GenMatch(
if (pattern->atoms_.size() != 1) {
throw std::runtime_error("Not implemented");
}
auto node_part = std::dynamic_pointer_cast<NodeAtom>(pattern->atoms_[0]);
return std::make_shared<ScanAll>(node_part);
auto node_atom = std::dynamic_pointer_cast<NodeAtom>(pattern->atoms_[0]);
return std::make_shared<ScanAll>(node_atom);
}
std::shared_ptr<LogicalOperator> GenReturn(
@ -39,9 +56,12 @@ std::shared_ptr<LogicalOperator> MakeLogicalPlan(Query& query)
std::shared_ptr<LogicalOperator> current_op;
for (auto& clause : query.clauses_) {
auto* clause_ptr = clause.get();
auto* create = dynamic_cast<Create*>(clause_ptr);
auto* match = dynamic_cast<Match*>(clause_ptr);
auto* ret = dynamic_cast<Return*>(clause_ptr);
if (match) {
if (create) {
current_op = GenCreate(*create, current_op);
} else if (match) {
current_op = GenMatch(*match, current_op);
} else if (ret) {
return GenReturn(*ret, current_op);
@ -51,5 +71,4 @@ std::shared_ptr<LogicalOperator> MakeLogicalPlan(Query& query)
}
return current_op;
}
}

View File

@ -55,6 +55,14 @@ auto CollectProduce(std::shared_ptr<Produce> produce, SymbolTable &symbol_table,
return stream;
}
void ExecuteCreate(std::shared_ptr<CreateOp> create, GraphDbAccessor &db) {
SymbolTable symbol_table;
Frame frame(symbol_table.max_position());
auto cursor = create->MakeCursor(db);
while (cursor->Pull(frame, symbol_table))
;
}
/*
* Following are helper functions that create high level AST
* and logical operator objects.
@ -137,7 +145,8 @@ TEST(Interpreter, NodeFilterLabelsAndProperties) {
auto v4 = dba->insert_vertex();
auto v5 = dba->insert_vertex();
dba->insert_vertex();
// test all combination of (label | no_label) * (no_prop | wrong_prop | right_prop)
// test all combination of (label | no_label) * (no_prop | wrong_prop |
// right_prop)
// only v1 will have the right labels
v1.add_label(label);
v2.add_label(label);
@ -184,17 +193,17 @@ TEST(Interpreter, NodeFilterMultipleLabels) {
GraphDb::Label label2 = dba->label("label2");
GraphDb::Label label3 = dba->label("label3");
// the test will look for nodes that have label1 and label2
dba->insert_vertex(); // NOT accepted
dba->insert_vertex().add_label(label1); // NOT accepted
dba->insert_vertex().add_label(label2); // NOT accepted
dba->insert_vertex().add_label(label3); // NOT accepted
auto v1 = dba->insert_vertex(); // YES accepted
dba->insert_vertex(); // NOT accepted
dba->insert_vertex().add_label(label1); // NOT accepted
dba->insert_vertex().add_label(label2); // NOT accepted
dba->insert_vertex().add_label(label3); // NOT accepted
auto v1 = dba->insert_vertex(); // YES accepted
v1.add_label(label1);
v1.add_label(label2);
auto v2 = dba->insert_vertex(); // NOT accepted
auto v2 = dba->insert_vertex(); // NOT accepted
v2.add_label(label1);
v2.add_label(label3);
auto v3 = dba->insert_vertex(); // YES accepted
auto v3 = dba->insert_vertex(); // YES accepted
v3.add_label(label1);
v3.add_label(label2);
v3.add_label(label3);
@ -226,3 +235,34 @@ TEST(Interpreter, NodeFilterMultipleLabels) {
ResultStreamFaker result = CollectProduce(produce, symbol_table, *dba);
EXPECT_EQ(result.GetResults().size(), 2);
}
TEST(Interpreter, CreateNodeWithAttributes) {
Dbms dbms;
auto dba = dbms.active();
Config config;
Context ctx(config, *dba);
GraphDb::Label label = dba->label("Person");
GraphDb::Property property = dba->label("age");
auto node = MakeNode(ctx, MakeIdentifier(ctx, "n"));
node->labels_.emplace_back(label);
// TODO make a property here with an int literal expression
// node->properties_[property] = TypedValue(42);
auto create = std::make_shared<CreateOp>(node);
ExecuteCreate(create, *dba);
// count the number of vertices
int vertex_count = 0;
for (VertexAccessor vertex : dba->vertices()) {
vertex_count++;
EXPECT_EQ(vertex.labels().size(), 1);
EXPECT_EQ(*vertex.labels().begin(), label);
EXPECT_EQ(vertex.Properties().size(), 1);
auto prop_eq = vertex.PropsAt(property) == TypedValue(42);
ASSERT_EQ(prop_eq.type(), TypedValue::Type::Bool);
EXPECT_TRUE(prop_eq.Value<bool>());
}
EXPECT_EQ(vertex_count, 1);
}