From 30864af98b1f47268eba3d7ee337daf9125e1de3 Mon Sep 17 00:00:00 2001 From: antoniofilipovic Date: Thu, 4 Aug 2022 14:04:51 +0200 Subject: [PATCH] add subgraph accessor and visitor logic for graph --- src/query/db_accessor.hpp | 64 ++++--- src/query/plan/operator.cpp | 8 +- src/query/procedure/mg_procedure_impl.cpp | 209 +++++++++++++++++----- src/query/procedure/mg_procedure_impl.hpp | 44 ++++- 4 files changed, 245 insertions(+), 80 deletions(-) diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp index 896d6a1b5..21b96402a 100644 --- a/src/query/db_accessor.hpp +++ b/src/query/db_accessor.hpp @@ -189,38 +189,38 @@ inline VertexAccessor EdgeAccessor::From() const { return VertexAccessor(impl_.F inline bool EdgeAccessor::IsCycle() const { return To() == From(); } -class DbAccessor final { - storage::Storage::Accessor *accessor_; +class VerticesIterable final { + storage::VerticesIterable iterable_; - class VerticesIterable final { - storage::VerticesIterable iterable_; + public: + class Iterator final { + storage::VerticesIterable::Iterator it_; public: - class Iterator final { - storage::VerticesIterable::Iterator it_; + explicit Iterator(storage::VerticesIterable::Iterator it) : it_(it) {} - public: - explicit Iterator(storage::VerticesIterable::Iterator it) : it_(it) {} + VertexAccessor operator*() const { return VertexAccessor(*it_); } - VertexAccessor operator*() const { return VertexAccessor(*it_); } + Iterator &operator++() { + ++it_; + return *this; + } - Iterator &operator++() { - ++it_; - return *this; - } + bool operator==(const Iterator &other) const { return it_ == other.it_; } - bool operator==(const Iterator &other) const { return it_ == other.it_; } - - bool operator!=(const Iterator &other) const { return !(other == *this); } - }; - - explicit VerticesIterable(storage::VerticesIterable iterable) : iterable_(std::move(iterable)) {} - - Iterator begin() { return Iterator(iterable_.begin()); } - - Iterator end() { return Iterator(iterable_.end()); } + bool operator!=(const Iterator &other) const { return !(other == *this); } }; + explicit VerticesIterable(storage::VerticesIterable iterable) : iterable_(std::move(iterable)) {} + + Iterator begin() { return Iterator(iterable_.begin()); } + + Iterator end() { return Iterator(iterable_.end()); } +}; + +class DbAccessor final { + storage::Storage::Accessor *accessor_; + public: explicit DbAccessor(storage::Storage::Accessor *accessor) : accessor_(accessor) {} @@ -362,6 +362,24 @@ class DbAccessor final { storage::ConstraintsInfo ListAllConstraints() const { return accessor_->ListAllConstraints(); } }; +class SubgraphDbAccessor final { + DbAccessor *db_accessor_; + + public: + explicit SubgraphDbAccessor(query::DbAccessor *db_accessor) : db_accessor_(db_accessor) {} + + const std::string &PropertyToName(storage::PropertyId prop) const { return db_accessor_->PropertyToName(prop); } + + const std::string &LabelToName(storage::LabelId label) const { return db_accessor_->LabelToName(label); } + + const std::string &EdgeTypeToName(storage::EdgeTypeId type) const { return db_accessor_->EdgeTypeToName(type); } +}; + +class SubgraphVertexAccessor final { + public: + query::VertexAccessor impl_; +}; + } // namespace memgraph::query namespace std { diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index 0a2ba7f1d..83abe8a6a 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -3739,12 +3739,12 @@ void CallCustomProcedure(const std::string_view fully_qualified_procedure_name, for (auto *expression : args) { args_list.emplace_back(expression->Accept(*evaluator)); } - + query::Graph *subgraph = nullptr; if (!args_list.empty() && args_list.front().type() == TypedValue::Type::Graph) { - TypedValue subgraph = TypedValue(args_list.front(), args_list.front().ValueGraph().GetMemoryResource()); + TypedValue subgraph_typed = TypedValue(args_list.front(), args_list.front().ValueGraph().GetMemoryResource()); - args_list.erase(args_list.begin()); // ova linija obrise vertexe - graph.subgraph = &subgraph.ValueGraph(); + args_list.erase(args_list.begin()); + subgraph = &subgraph_typed.ValueGraph(); } // if we have graph at first element, it is okay to have 1+ element here diff --git a/src/query/procedure/mg_procedure_impl.cpp b/src/query/procedure/mg_procedure_impl.cpp index 9da7306b0..1042459f7 100644 --- a/src/query/procedure/mg_procedure_impl.cpp +++ b/src/query/procedure/mg_procedure_impl.cpp @@ -1502,9 +1502,17 @@ mgp_error mgp_properties_iterator_next(mgp_properties_iterator *it, mgp_property return nullptr; } memgraph::utils::OnScopeExit clean_up([it] { it->current = std::nullopt; }); - it->current.emplace(memgraph::utils::pmr::string(it->graph->impl->PropertyToName(it->current_it->first), - it->GetMemoryResource()), - mgp_value(it->current_it->second, it->GetMemoryResource())); + auto propToName = std::visit(memgraph::utils::Overloaded{ + [it](memgraph::query::DbAccessor *impl) { + return memgraph::utils::pmr::string( + impl->PropertyToName(it->current_it->first), it->GetMemoryResource()); + }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::utils::pmr::string { + throw std::logic_error{"cannot process this"}; + }, + }, + it->graph->impl); + it->current.emplace(propToName, mgp_value(it->current_it->second, it->GetMemoryResource())); it->property.name = it->current->first.c_str(); it->property.value = &it->current->second; clean_up.Disable(); @@ -1586,7 +1594,15 @@ mgp_error mgp_vertex_set_property(struct mgp_vertex *v, const char *property_nam if (!MgpVertexIsMutable(*v)) { throw ImmutableObjectException{"Cannot set a property on an immutable vertex!"}; } - const auto prop_key = v->graph->impl->NameToProperty(property_name); + + const auto prop_key = std::visit( + memgraph::utils::Overloaded{ + [property_name](memgraph::query::DbAccessor *impl) { return impl->NameToProperty(property_name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::PropertyId { + throw std::logic_error{"cannot process this"}; + }, + }, + v->graph->impl); const auto result = v->impl.SetProperty(prop_key, ToPropertyValue(*property_value)); if (result.HasError()) { switch (result.GetError()) { @@ -1626,7 +1642,14 @@ mgp_error mgp_vertex_add_label(struct mgp_vertex *v, mgp_label label) { if (!MgpVertexIsMutable(*v)) { throw ImmutableObjectException{"Cannot add a label to an immutable vertex!"}; } - const auto label_id = v->graph->impl->NameToLabel(label.name); + const auto label_id = + std::visit(memgraph::utils::Overloaded{ + [label](memgraph::query::DbAccessor *impl) { return impl->NameToLabel(label.name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::LabelId { + throw std::logic_error{"cannot process this"}; + }, + }, + v->graph->impl); const auto result = v->impl.AddLabel(label_id); if (result.HasError()) { @@ -1658,7 +1681,14 @@ mgp_error mgp_vertex_remove_label(struct mgp_vertex *v, mgp_label label) { if (!MgpVertexIsMutable(*v)) { throw ImmutableObjectException{"Cannot remove a label from an immutable vertex!"}; } - const auto label_id = v->graph->impl->NameToLabel(label.name); + const auto label_id = + std::visit(memgraph::utils::Overloaded{ + [label](memgraph::query::DbAccessor *impl) { return impl->NameToLabel(label.name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::LabelId { + throw std::logic_error{"cannot process this"}; + }, + }, + v->graph->impl); const auto result = v->impl.RemoveLabel(label_id); if (result.HasError()) { @@ -1740,10 +1770,17 @@ mgp_error mgp_vertex_label_at(mgp_vertex *v, size_t i, mgp_label *result) { throw std::out_of_range("Label cannot be retrieved, because index exceeds the number of labels!"); } const auto &label = (*maybe_labels)[i]; - static_assert(std::is_lvalue_reference_vgraph->impl->LabelToName(label))>, + static_assert(std::is_lvalue_reference_v< + decltype(std::get(v->graph->impl)->LabelToName(label))>, "Expected LabelToName to return a pointer or reference, so we " "don't have to take a copy and manage memory."); - const auto &name = v->graph->impl->LabelToName(label); + + const auto &name = + std::visit(memgraph::utils::Overloaded{ + [label](memgraph::query::DbAccessor *impl) { return impl->LabelToName(label); }, + [label](memgraph::query::SubgraphDbAccessor *impl) { return impl->LabelToName(label); }, + }, + v->graph->impl); return name.c_str(); }, &result->name); @@ -1753,7 +1790,13 @@ mgp_error mgp_vertex_has_label_named(mgp_vertex *v, const char *name, int *resul return WrapExceptions( [v, name] { memgraph::storage::LabelId label; - label = v->graph->impl->NameToLabel(name); + label = std::visit(memgraph::utils::Overloaded{ + [name](memgraph::query::DbAccessor *impl) { return impl->NameToLabel(name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::LabelId { + throw std::logic_error{"cannot process this"}; + }, + }, + v->graph->impl); auto maybe_has_label = v->impl.HasLabel(v->graph->view, label); if (maybe_has_label.HasError()) { @@ -1783,7 +1826,15 @@ mgp_error mgp_vertex_has_label(mgp_vertex *v, mgp_label label, int *result) { mgp_error mgp_vertex_get_property(mgp_vertex *v, const char *name, mgp_memory *memory, mgp_value **result) { return WrapExceptions( [v, name, memory]() -> mgp_value * { - const auto &key = v->graph->impl->NameToProperty(name); + const auto &key = + std::visit(memgraph::utils::Overloaded{ + [name](memgraph::query::DbAccessor *impl) { return impl->NameToProperty(name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::PropertyId { + throw std::logic_error{"cannot process this"}; + }, + }, + v->graph->impl); + auto maybe_prop = v->impl.GetProperty(v->graph->view, key); if (maybe_prop.HasError()) { switch (maybe_prop.GetError()) { @@ -1869,33 +1920,33 @@ mgp_error mgp_vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory, mgp_edges [v, memory] { auto it = NewMgpObject(memory, *v); MG_ASSERT(it != nullptr); - if (v->graph->subgraph) { - spdlog::info("works here"); - auto edges = v->graph->subgraph->OutEdges(v->impl); + // if (v->graph->subgraph) { + // spdlog::info("works here"); + // auto edges = v->graph->subgraph->OutEdges(v->impl); - auto maybe_edges = v->impl.OutEdgesFiltered(v->graph->view); + // auto maybe_edges = v->impl.OutEdgesFiltered(v->graph->view); - std::vector filtered_edges; + // std::vector filtered_edges; - for (auto it = maybe_edges->begin(); it != maybe_edges->end(); ++it) { - for (auto it2 = edges.begin(); it2 != edges.end(); ++it2) { - if (it->FromVertex() == it2->impl_.FromVertex() && it->ToVertex() == it2->impl_.ToVertex()) { - filtered_edges.push_back(*it); - break; - } - } - } - auto filtered_edges_final = - iter::imap(memgraph::query::VertexAccessor::MakeEdgeAccessor, std::move(filtered_edges)); + // for (auto it = maybe_edges->begin(); it != maybe_edges->end(); ++it) { + // for (auto it2 = edges.begin(); it2 != edges.end(); ++it2) { + // if (it->FromVertex() == it2->impl_.FromVertex() && it->ToVertex() == it2->impl_.ToVertex()) { + // filtered_edges.push_back(*it); + // break; + // } + // } + // } + // auto filtered_edges_final = + // iter::imap(memgraph::query::VertexAccessor::MakeEdgeAccessor, std::move(filtered_edges)); - it->out.emplace(std::move(filtered_edges_final)); - it->out_it.emplace(it->out->begin()); - if (*it->out_it != it->out->end()) { - it->current_e.emplace(**it->out_it, v->graph, it->GetMemoryResource()); - } + // it->out.emplace(std::move(filtered_edges_final)); + // it->out_it.emplace(it->out->begin()); + // if (*it->out_it != it->out->end()) { + // it->current_e.emplace(**it->out_it, v->graph, it->GetMemoryResource()); + // } - return it.release(); - } + // return it.release(); + // } auto maybe_edges = v->impl.OutEdges(v->graph->view); @@ -2000,10 +2051,15 @@ mgp_error mgp_edge_equal(mgp_edge *e1, mgp_edge *e2, int *result) { mgp_error mgp_edge_get_type(mgp_edge *e, mgp_edge_type *result) { return WrapExceptions( [e] { - const auto &name = e->from.graph->impl->EdgeTypeToName(e->impl.EdgeType()); - static_assert(std::is_lvalue_reference_vfrom.graph->impl->EdgeTypeToName(e->impl.EdgeType()))>, - "Expected EdgeTypeToName to return a pointer or reference, so we " - "don't have to take a copy and manage memory."); + const auto &name = std::visit( + memgraph::utils::Overloaded{ + [e](memgraph::query::DbAccessor *impl) { return impl->EdgeTypeToName(e->impl.EdgeType()); }, + [e](memgraph::query::SubgraphDbAccessor *impl) { return impl->EdgeTypeToName(e->impl.EdgeType()); }, + }, + e->from.graph->impl); + // static_assert(std::is_lvalue_reference_vfrom.graph->impl->EdgeTypeToName(e->impl.EdgeType()))>, + // "Expected EdgeTypeToName to return a pointer or reference, so we " + // "don't have to take a copy and manage memory."); return name.c_str(); }, &result->name); @@ -2022,7 +2078,14 @@ mgp_error mgp_edge_get_to(mgp_edge *e, mgp_vertex **result) { mgp_error mgp_edge_get_property(mgp_edge *e, const char *name, mgp_memory *memory, mgp_value **result) { return WrapExceptions( [e, name, memory] { - const auto &key = e->from.graph->impl->NameToProperty(name); + const auto &key = + std::visit(memgraph::utils::Overloaded{ + [name](memgraph::query::DbAccessor *impl) { return impl->NameToProperty(name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::PropertyId { + throw std::logic_error{"cannot process this"}; + }, + }, + e->from.graph->impl); auto view = e->from.graph->view; auto maybe_prop = e->impl.GetProperty(view, key); if (maybe_prop.HasError()) { @@ -2048,7 +2111,14 @@ mgp_error mgp_edge_set_property(struct mgp_edge *e, const char *property_name, m if (!MgpEdgeIsMutable(*e)) { throw ImmutableObjectException{"Cannot set a property on an immutable edge!"}; } - const auto prop_key = e->from.graph->impl->NameToProperty(property_name); + const auto prop_key = std::visit( + memgraph::utils::Overloaded{ + [property_name](memgraph::query::DbAccessor *impl) { return impl->NameToProperty(property_name); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::storage::PropertyId { + throw std::logic_error{"cannot process this"}; + }, + }, + e->from.graph->impl); const auto result = e->impl.SetProperty(prop_key, ToPropertyValue(*property_value)); if (result.HasError()) { @@ -2115,7 +2185,16 @@ mgp_error mgp_edge_iter_properties(mgp_edge *e, mgp_memory *memory, mgp_properti mgp_error mgp_graph_get_vertex_by_id(mgp_graph *graph, mgp_vertex_id id, mgp_memory *memory, mgp_vertex **result) { return WrapExceptions( [graph, id, memory]() -> mgp_vertex * { - auto maybe_vertex = graph->impl->FindVertex(memgraph::storage::Gid::FromInt(id.as_int), graph->view); + auto maybe_vertex = std::visit( + memgraph::utils::Overloaded{ + [graph, id](memgraph::query::DbAccessor *impl) { + return impl->FindVertex(memgraph::storage::Gid::FromInt(id.as_int), graph->view); + }, + [](memgraph::query::SubgraphDbAccessor *impl) -> std::optional { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); if (maybe_vertex) { return NewRawMgpObject(memory, *maybe_vertex, graph); } @@ -2135,7 +2214,13 @@ mgp_error mgp_graph_create_vertex(struct mgp_graph *graph, mgp_memory *memory, m if (!MgpGraphIsMutable(*graph)) { throw ImmutableObjectException{"Cannot create a vertex in an immutable graph!"}; } - auto vertex = graph->impl->InsertVertex(); + auto vertex = std::visit(memgraph::utils::Overloaded{ + [](memgraph::query::DbAccessor *impl) { return impl->InsertVertex(); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::query::VertexAccessor { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); auto &ctx = graph->ctx; ctx->execution_stats[memgraph::query::ExecutionStats::Key::CREATED_NODES] += 1; @@ -2153,7 +2238,16 @@ mgp_error mgp_graph_delete_vertex(struct mgp_graph *graph, mgp_vertex *vertex) { if (!MgpGraphIsMutable(*graph)) { throw ImmutableObjectException{"Cannot remove a vertex from an immutable graph!"}; } - const auto result = graph->impl->RemoveVertex(&vertex->impl); + + const auto result = + std::visit(memgraph::utils::Overloaded{ + [vertex](memgraph::query::DbAccessor *impl) { return impl->RemoveVertex(&vertex->impl); }, + [](memgraph::query::SubgraphDbAccessor *impl) + -> memgraph::storage::Result> { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); if (result.HasError()) { switch (result.GetError()) { @@ -2188,7 +2282,16 @@ mgp_error mgp_graph_detach_delete_vertex(struct mgp_graph *graph, mgp_vertex *ve if (!MgpGraphIsMutable(*graph)) { throw ImmutableObjectException{"Cannot remove a vertex from an immutable graph!"}; } - const auto result = graph->impl->DetachRemoveVertex(&vertex->impl); + const auto result = std::visit( + memgraph::utils::Overloaded{ + [vertex](memgraph::query::DbAccessor *impl) { return impl->DetachRemoveVertex(&vertex->impl); }, + [](memgraph::query::SubgraphDbAccessor *impl) + -> memgraph::storage::Result>>> { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); if (result.HasError()) { switch (result.GetError()) { @@ -2235,8 +2338,16 @@ mgp_error mgp_graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex * if (!MgpGraphIsMutable(*graph)) { throw ImmutableObjectException{"Cannot create an edge in an immutable graph!"}; } - - auto edge = graph->impl->InsertEdge(&from->impl, &to->impl, from->graph->impl->NameToEdgeType(type.name)); + auto edge = std::visit(memgraph::utils::Overloaded{ + [from, to, type](memgraph::query::DbAccessor *impl) { + return impl->InsertEdge(&from->impl, &to->impl, impl->NameToEdgeType(type.name)); + }, + [](memgraph::query::SubgraphDbAccessor *impl) + -> memgraph::storage::Result { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); if (edge.HasError()) { switch (edge.GetError()) { case memgraph::storage::Error::DELETED_OBJECT: @@ -2267,8 +2378,16 @@ mgp_error mgp_graph_delete_edge(struct mgp_graph *graph, mgp_edge *edge) { if (!MgpGraphIsMutable(*graph)) { throw ImmutableObjectException{"Cannot remove an edge from an immutable graph!"}; } - const auto result = graph->impl->RemoveEdge(&edge->impl); + const auto result = + std::visit(memgraph::utils::Overloaded{ + [edge](memgraph::query::DbAccessor *impl) { return impl->RemoveEdge(&edge->impl); }, + [](memgraph::query::SubgraphDbAccessor *impl) + -> memgraph::storage::Result> { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); if (result.HasError()) { switch (result.GetError()) { case memgraph::storage::Error::NONEXISTENT_OBJECT: diff --git a/src/query/procedure/mg_procedure_impl.hpp b/src/query/procedure/mg_procedure_impl.hpp index 07c126ed0..a25705ded 100644 --- a/src/query/procedure/mg_procedure_impl.hpp +++ b/src/query/procedure/mg_procedure_impl.hpp @@ -32,6 +32,7 @@ #include "utils/pmr/string.hpp" #include "utils/pmr/vector.hpp" #include "utils/temporal.hpp" +#include "utils/variant_helpers.hpp" /// Wraps memory resource used in custom procedures. /// /// This should have been `using mgp_memory = memgraph::utils::MemoryResource`, but that's @@ -571,22 +572,30 @@ struct mgp_func_result { }; struct mgp_graph { - memgraph::query::DbAccessor *impl; + std::variant impl; memgraph::storage::View view; // TODO: Merge `mgp_graph` and `mgp_memory` into a single `mgp_context`. The // `ctx` field is out of place here. memgraph::query::ExecutionContext *ctx; - memgraph::query::Graph *subgraph; // memgraph:::query::Graph *subraph; static mgp_graph WritableGraph(memgraph::query::DbAccessor &acc, memgraph::storage::View view, memgraph::query::ExecutionContext &ctx) { - return mgp_graph{&acc, view, &ctx, nullptr}; + return mgp_graph{&acc, view, &ctx}; } static mgp_graph NonWritableGraph(memgraph::query::DbAccessor &acc, memgraph::storage::View view) { - return mgp_graph{&acc, view, nullptr, nullptr}; + return mgp_graph{&acc, view, nullptr}; + } + + static mgp_graph WritableGraph(memgraph::query::SubgraphDbAccessor &acc, memgraph::storage::View view, + memgraph::query::ExecutionContext &ctx) { + return mgp_graph{&acc, view, &ctx}; + } + + static mgp_graph NonWritableGraph(memgraph::query::SubgraphDbAccessor &acc, memgraph::storage::View view) { + return mgp_graph{&acc, view, nullptr}; } }; @@ -618,8 +627,18 @@ struct mgp_properties_iterator { mgp_properties_iterator(mgp_graph *graph, decltype(pvs) pvs, memgraph::utils::MemoryResource *memory) : memory(memory), graph(graph), pvs(std::move(pvs)), current_it(this->pvs.begin()) { if (current_it != this->pvs.end()) { - current.emplace(memgraph::utils::pmr::string(graph->impl->PropertyToName(current_it->first), memory), - mgp_value(current_it->second, memory)); + auto visitor = + std::visit(memgraph::utils::Overloaded{ + [this, memory](const memgraph::query::DbAccessor *impl) { + return memgraph::utils::pmr::string(impl->PropertyToName(current_it->first), memory); + }, + [](const memgraph::query::SubgraphDbAccessor *impl) -> memgraph::utils::pmr::string { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl); + + current.emplace(visitor, mgp_value(current_it->second, memory)); property.name = current->first.c_str(); property.value = ¤t->second; } @@ -677,7 +696,16 @@ struct mgp_vertices_iterator { /// @throw anything VerticesIterable may throw mgp_vertices_iterator(mgp_graph *graph, memgraph::utils::MemoryResource *memory) - : memory(memory), graph(graph), vertices(graph->impl->Vertices(graph->view)), current_it(vertices.begin()) { + : memory(memory), + graph(graph), + vertices(std::visit(memgraph::utils::Overloaded{ + [graph](memgraph::query::DbAccessor *impl) { return impl->Vertices(graph->view); }, + [](memgraph::query::SubgraphDbAccessor *impl) -> memgraph::query::VerticesIterable { + throw std::logic_error{"cannot process this"}; + }, + }, + graph->impl)), + current_it(vertices.begin()) { if (current_it != vertices.end()) { current_v.emplace(*current_it, graph, memory); } @@ -687,7 +715,7 @@ struct mgp_vertices_iterator { memgraph::utils::MemoryResource *memory; mgp_graph *graph; - decltype(graph->impl->Vertices(graph->view)) vertices; + memgraph::query::VerticesIterable vertices; decltype(vertices.begin()) current_it; std::optional current_v; };