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:
parent
ffd399906a
commit
da0c9c03d6
@ -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) {}
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user