From 3ae5cd46732ede0ffa98038bf8c620fc25bde339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Pintari=C4=87?= <99442742+mpintaric55334@users.noreply.github.com> Date: Tue, 17 Oct 2023 09:42:20 +0200 Subject: [PATCH 01/10] Fix failing tests (#392) --- python/tests/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/tests/requirements.txt b/python/tests/requirements.txt index 9c3c9df7e..42f6a1190 100644 --- a/python/tests/requirements.txt +++ b/python/tests/requirements.txt @@ -1,9 +1,9 @@ -pytest==6.2.5 +pytest==7.0 PyYAML==5.4.1 black==22.3.0 flake8==3.9.2 pymgclient==1.3.1 -pytest-pylint==0.18.0 +pytest-pylint==0.21.0 pytest-timeout==1.4.2 pytest-cov==2.12.1 pytest-benchmark==3.4.1 From 8715d92b8202821f98ecfe1943a8dbb12530ee96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Pintari=C4=87?= <99442742+mpintaric55334@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:34:56 +0200 Subject: [PATCH 02/10] Add memory dispatcher guard (#393) --- .../algorithm/collections.cpp | 34 +++++++++---------- cpp/collections_module/collections_module.cpp | 2 +- .../community_detection_online_module.cpp | 12 +++---- cpp/create_module/algorithm/create.cpp | 20 +++++------ cpp/create_module/create_module.cpp | 2 +- .../distance_calculator.cpp | 6 ++-- cpp/do_module/do_module.cpp | 6 ++-- .../algorithms/ancestors.hpp | 2 +- .../algorithms/chain_nodes.hpp | 2 +- .../algorithms/connect_nodes.hpp | 2 +- .../algorithms/descendants.hpp | 2 +- .../algorithms/topological_sort.hpp | 2 +- cpp/graph_util_module/graph_util_module.cpp | 2 +- .../katz_centrality_online_module.cpp | 2 +- cpp/label_module/algorithm/label.cpp | 2 +- cpp/label_module/label_module.cpp | 2 +- cpp/map_module/algorithm/map.cpp | 18 +++++----- cpp/map_module/map_module.cpp | 2 +- cpp/neighbors_module/algorithm/neighbors.cpp | 4 +-- cpp/neighbors_module/neighbors_module.cpp | 2 +- cpp/node_module/algorithm/node.cpp | 6 ++-- cpp/node_module/node_module.cpp | 2 +- .../node_similarity_module.cpp | 14 ++++---- cpp/nodes_module/algorithm/nodes.cpp | 8 ++--- cpp/nodes_module/nodes_module.cpp | 2 +- .../pagerank_online_module.cpp | 2 +- cpp/path_module/algorithm/path.cpp | 8 ++--- cpp/path_module/path_module.cpp | 2 +- cpp/periodic_module/periodic_iterate.cpp | 4 +-- cpp/refactor_module/algorithm/refactor.cpp | 4 +-- cpp/schema_module/algorithm/schema.cpp | 4 +-- cpp/schema_module/schema_module.cpp | 2 +- cpp/text_module/algorithm/text.cpp | 2 +- cpp/text_module/text_module.cpp | 2 +- cpp/util_module/algorithm/util.cpp | 2 +- cpp/util_module/util_module.cpp | 2 +- 36 files changed, 96 insertions(+), 96 deletions(-) diff --git a/cpp/collections_module/algorithm/collections.cpp b/cpp/collections_module/algorithm/collections.cpp index be69acba5..f9088c859 100644 --- a/cpp/collections_module/algorithm/collections.cpp +++ b/cpp/collections_module/algorithm/collections.cpp @@ -42,7 +42,7 @@ void Collections::SetResult(mgp::Result &result, const mgp::Value &value) { } void Collections::SumLongs(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -67,7 +67,7 @@ void Collections::SumLongs(mgp_list *args, mgp_func_context *ctx, mgp_func_resul } void Collections::Avg(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -94,7 +94,7 @@ void Collections::Avg(mgp_list *args, mgp_func_context *ctx, mgp_func_result *re } void Collections::ContainsAll(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -115,7 +115,7 @@ void Collections::ContainsAll(mgp_list *args, mgp_func_context *ctx, mgp_func_re } void Collections::Intersection(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -147,7 +147,7 @@ void Collections::Intersection(mgp_list *args, mgp_func_context *ctx, mgp_func_r } void Collections::RemoveAll(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -181,7 +181,7 @@ void Collections::RemoveAll(mgp_list *args, mgp_func_context *ctx, mgp_func_resu } void Collections::Sum(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -204,7 +204,7 @@ void Collections::Sum(mgp_list *args, mgp_func_context *ctx, mgp_func_result *re } void Collections::Union(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -249,7 +249,7 @@ void Collections::Union(mgp_list *args, mgp_func_context *ctx, mgp_func_result * } void Collections::Sort(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -271,7 +271,7 @@ void Collections::Sort(mgp_list *args, mgp_func_context *ctx, mgp_func_result *r } void Collections::ContainsSorted(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -304,7 +304,7 @@ void Collections::ContainsSorted(mgp_list *args, mgp_func_context *ctx, mgp_func } void Collections::Max(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -331,7 +331,7 @@ void Collections::Max(mgp_list *args, mgp_func_context *ctx, mgp_func_result *re } void Collections::Split(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); @@ -370,7 +370,7 @@ void Collections::Split(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *r } void Collections::Pairs(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -401,7 +401,7 @@ void Collections::Pairs(mgp_list *args, mgp_func_context *ctx, mgp_func_result * } void Collections::Contains(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -429,7 +429,7 @@ void Collections::Contains(mgp_list *args, mgp_func_context *ctx, mgp_func_resul } void Collections::UnionAll(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -448,7 +448,7 @@ void Collections::UnionAll(mgp_list *args, mgp_func_context *ctx, mgp_func_resul } void Collections::Min(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -486,7 +486,7 @@ void Collections::Min(mgp_list *args, mgp_func_context *ctx, mgp_func_result *re } void Collections::ToSet(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -506,7 +506,7 @@ void Collections::ToSet(mgp_list *args, mgp_func_context *ctx, mgp_func_result * } void Collections::Partition(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/collections_module/collections_module.cpp b/cpp/collections_module/collections_module.cpp index 9d161f6b3..1b41c5017 100644 --- a/cpp/collections_module/collections_module.cpp +++ b/cpp/collections_module/collections_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; mgp::AddFunction(Collections::SumLongs, Collections::kProcedureSumLongs, {mgp::Parameter(Collections::kSumLongsArg1, {mgp::Type::List, mgp::Type::Any})}, module, memory); diff --git a/cpp/community_detection_module/community_detection_online_module.cpp b/cpp/community_detection_module/community_detection_online_module.cpp index 4e46507e4..782e231f2 100644 --- a/cpp/community_detection_module/community_detection_online_module.cpp +++ b/cpp/community_detection_module/community_detection_online_module.cpp @@ -53,7 +53,7 @@ std::string saved_weight_property = kDefaultWeightProperty.data(); void Set(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto graph = mgp::Graph(memgraph_graph); const auto arguments = mgp::List(args); @@ -90,7 +90,7 @@ void Set(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memo void Get(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); @@ -119,7 +119,7 @@ void Get(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memo void Update(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto graph = mgp::Graph(memgraph_graph); const auto arguments = mgp::List(args); @@ -189,7 +189,7 @@ void Update(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_m void Reset(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); @@ -203,7 +203,7 @@ void Reset(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_me auto record = record_factory.NewRecord(); record.Insert(kFieldMessage.data(), "The algorithm has been successfully reset!"); } catch (const std::exception &e) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); auto record = record_factory.NewRecord(); @@ -216,7 +216,7 @@ void Reset(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_me extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto node_list = std::make_pair(mgp::Type::List, mgp::Type::Node); const auto relationship_list = std::make_pair(mgp::Type::List, mgp::Type::Relationship); diff --git a/cpp/create_module/algorithm/create.cpp b/cpp/create_module/algorithm/create.cpp index 7e5d9b1cf..7b1369ea0 100644 --- a/cpp/create_module/algorithm/create.cpp +++ b/cpp/create_module/algorithm/create.cpp @@ -34,7 +34,7 @@ void ModifyAndOutput(mgp::Relationship &relationship, const mgp::List &keys, con } // namespace void Create::RemoveRelProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); @@ -80,7 +80,7 @@ void Create::RemoveRelProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_ } void Create::SetRelProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); @@ -131,7 +131,7 @@ void Create::SetRelProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_res } void Create::Relationship(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); @@ -181,7 +181,7 @@ void Create::ProcessElement(const mgp::Value &element, const mgp::Graph graph, c } void Create::SetRelProperty(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); @@ -256,7 +256,7 @@ void Create::ProcessElement(const mgp::Value &element, const mgp::Graph graph, c } void Create::RemoveLabels(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); @@ -278,7 +278,7 @@ void Create::RemoveLabels(mgp_list *args, mgp_graph *memgraph_graph, mgp_result } void Create::RemoveProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -324,7 +324,7 @@ void Create::ProcessElement(const mgp::Value &element, const mgp::Graph graph, c } void Create::SetProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); @@ -351,7 +351,7 @@ void Create::SetProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result } void Create::Node(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); @@ -379,7 +379,7 @@ void Create::Node(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, } void Create::Nodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -407,7 +407,7 @@ void Create::Nodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result } void Create::SetProperty(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/create_module/create_module.cpp b/cpp/create_module/create_module.cpp index 06130f17e..07cd58777 100644 --- a/cpp/create_module/create_module.cpp +++ b/cpp/create_module/create_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure(Create::SetRelProperty, Create::kProcedureSetRelProp, mgp::ProcedureType::Write, {mgp::Parameter(Create::kArgumentsRelationship, mgp::Type::Any), diff --git a/cpp/distance_calculator/distance_calculator.cpp b/cpp/distance_calculator/distance_calculator.cpp index 13c7ed2cd..fdcc6da5d 100644 --- a/cpp/distance_calculator/distance_calculator.cpp +++ b/cpp/distance_calculator/distance_calculator.cpp @@ -49,7 +49,7 @@ double distance_calc(const mgp::Node &node1, const mgp::Node &node2, bool use_km } void Single(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); try { @@ -69,7 +69,7 @@ void Single(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_m } void Multiple(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); try { @@ -102,7 +102,7 @@ void Multiple(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure( Single, kProcedureSingle, mgp::ProcedureType::Read, diff --git a/cpp/do_module/do_module.cpp b/cpp/do_module/do_module.cpp index 9d144808a..f70483ba0 100644 --- a/cpp/do_module/do_module.cpp +++ b/cpp/do_module/do_module.cpp @@ -309,7 +309,7 @@ bool IsGlobalOperation(std::string_view query) { } void When(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto condition = arguments[0].ValueBool(); @@ -335,7 +335,7 @@ void When(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_mem } void Case(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto conditionals = arguments[0].ValueList(); @@ -391,7 +391,7 @@ void Case(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_mem extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; mgp::AddProcedure(Case, kProcedureCase, mgp::ProcedureType::Read, {mgp::Parameter(kArgumentConditionals, {mgp::Type::List, mgp::Type::Any}), diff --git a/cpp/graph_util_module/algorithms/ancestors.hpp b/cpp/graph_util_module/algorithms/ancestors.hpp index f4cb54d80..a79b4d78b 100644 --- a/cpp/graph_util_module/algorithms/ancestors.hpp +++ b/cpp/graph_util_module/algorithms/ancestors.hpp @@ -5,7 +5,7 @@ const char *kResultAncestors = "ancestors"; void Ancestors(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/graph_util_module/algorithms/chain_nodes.hpp b/cpp/graph_util_module/algorithms/chain_nodes.hpp index f323a05d0..f0c440080 100644 --- a/cpp/graph_util_module/algorithms/chain_nodes.hpp +++ b/cpp/graph_util_module/algorithms/chain_nodes.hpp @@ -4,7 +4,7 @@ const char *kResultChainNodes = "connections"; void ChainNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto graph = mgp::Graph(memgraph_graph); auto factory = mgp::RecordFactory(result); diff --git a/cpp/graph_util_module/algorithms/connect_nodes.hpp b/cpp/graph_util_module/algorithms/connect_nodes.hpp index c0b4d3d04..1b345f57f 100644 --- a/cpp/graph_util_module/algorithms/connect_nodes.hpp +++ b/cpp/graph_util_module/algorithms/connect_nodes.hpp @@ -3,7 +3,7 @@ const char *kResultConnections = "connections"; void ConnectNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/graph_util_module/algorithms/descendants.hpp b/cpp/graph_util_module/algorithms/descendants.hpp index 20ee26894..1e2bf96ea 100644 --- a/cpp/graph_util_module/algorithms/descendants.hpp +++ b/cpp/graph_util_module/algorithms/descendants.hpp @@ -5,7 +5,7 @@ const char *kResultDescendants = "descendants"; void Descendants(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/graph_util_module/algorithms/topological_sort.hpp b/cpp/graph_util_module/algorithms/topological_sort.hpp index a9bc8f1d6..9a73c40f8 100644 --- a/cpp/graph_util_module/algorithms/topological_sort.hpp +++ b/cpp/graph_util_module/algorithms/topological_sort.hpp @@ -5,7 +5,7 @@ const char *kResultSortedNodes = "sorted_nodes"; void TopologicalSort(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); const auto graph = mgp::Graph(memgraph_graph); mgp::List topological_ordering = mgp::List(); diff --git a/cpp/graph_util_module/graph_util_module.cpp b/cpp/graph_util_module/graph_util_module.cpp index 4ccc27385..c0ac56956 100644 --- a/cpp/graph_util_module/graph_util_module.cpp +++ b/cpp/graph_util_module/graph_util_module.cpp @@ -23,7 +23,7 @@ const char *kArgumentNodes = "nodes"; extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; // Register ancestors procedure const auto ancestors_return = std::make_pair(mgp::Type::List, mgp::Type::Node); diff --git a/cpp/katz_centrality_module/katz_centrality_online_module.cpp b/cpp/katz_centrality_module/katz_centrality_online_module.cpp index 5db2511b0..b6c50d9c4 100644 --- a/cpp/katz_centrality_module/katz_centrality_online_module.cpp +++ b/cpp/katz_centrality_module/katz_centrality_online_module.cpp @@ -67,7 +67,7 @@ void SetKatzCentrality(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *re void UpdateKatzCentrality(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); const auto graph = mgp::Graph(memgraph_graph); diff --git a/cpp/label_module/algorithm/label.cpp b/cpp/label_module/algorithm/label.cpp index 73e4b3828..4415691c6 100644 --- a/cpp/label_module/algorithm/label.cpp +++ b/cpp/label_module/algorithm/label.cpp @@ -1,7 +1,7 @@ #include "label.hpp" void Label::Exists(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { diff --git a/cpp/label_module/label_module.cpp b/cpp/label_module/label_module.cpp index dcb141924..c0886dafb 100644 --- a/cpp/label_module/label_module.cpp +++ b/cpp/label_module/label_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; mgp::AddFunction(Label::Exists, Label::kFunctionExists, {mgp::Parameter(Label::kArgumentsNode, mgp::Type::Any), diff --git a/cpp/map_module/algorithm/map.cpp b/cpp/map_module/algorithm/map.cpp index c0cec2d1c..328978bdd 100644 --- a/cpp/map_module/algorithm/map.cpp +++ b/cpp/map_module/algorithm/map.cpp @@ -9,7 +9,7 @@ const auto number_of_elements_in_pair = 2; /*NOTE: FromNodes isn't 1:1 for graphQL, because first, we need to extend C and CPP API to iterate vertices using ctx object, since the `FromNodes` procedure (function if we want to change API) needs to iterate over all graph nodes*/ void Map::FromNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); @@ -55,7 +55,7 @@ void Map::FromNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resul } void Map::FromValues(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -87,7 +87,7 @@ void Map::FromValues(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res } void Map::SetKey(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); @@ -124,7 +124,7 @@ void Map::RemoveRecursion(mgp::Map &result, bool recursive, std::string_view key } void Map::RemoveKey(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -145,7 +145,7 @@ void Map::RemoveKey(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, } void Map::FromPairs(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -173,7 +173,7 @@ void Map::FromPairs(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, } void Map::Merge(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -209,7 +209,7 @@ void Map::FlattenRecursion(mgp::Map &result, const mgp::Map &input, const std::s } void Map::Flatten(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto result = mgp::Result(res); try { @@ -226,7 +226,7 @@ void Map::Flatten(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, m } void Map::FromLists(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; auto arguments = mgp::List(args); auto result_object = mgp::Result(res); try { @@ -272,7 +272,7 @@ void Map::RemoveRecursionSet(mgp::Map &result, bool recursive, std::unordered_se } void Map::RemoveKeys(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; auto arguments = mgp::List(args); auto result = mgp::Result(res); try { diff --git a/cpp/map_module/map_module.cpp b/cpp/map_module/map_module.cpp index c75f00438..9245c485b 100644 --- a/cpp/map_module/map_module.cpp +++ b/cpp/map_module/map_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; mgp::AddFunction(Map::Flatten, std::string(Map::kProcedureFlatten).c_str(), {mgp::Parameter(std::string(Map::kArgumentMapFlatten).c_str(), {mgp::Type::Map, mgp::Type::Any}), diff --git a/cpp/neighbors_module/algorithm/neighbors.cpp b/cpp/neighbors_module/algorithm/neighbors.cpp index 5a7e9f3e3..15ca47505 100644 --- a/cpp/neighbors_module/algorithm/neighbors.cpp +++ b/cpp/neighbors_module/algorithm/neighbors.cpp @@ -38,7 +38,7 @@ void DetermineDirection(mgp::List &rel_types, std::unordered_set types, mgp::Rel } void Node::RelationshipExists(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -165,7 +165,7 @@ void Node::RelationshipExists(mgp_list *args, mgp_graph *memgraph_graph, mgp_res } void Node::RelationshipTypes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/node_module/node_module.cpp b/cpp/node_module/node_module.cpp index f55dcb4a8..35fa39b4a 100644 --- a/cpp/node_module/node_module.cpp +++ b/cpp/node_module/node_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure(Node::RelationshipsExist, std::string(Node::kProcedureRelationshipsExist).c_str(), mgp::ProcedureType::Read, {mgp::Parameter(std::string(Node::kArgumentNodesRelationshipsExist).c_str(), mgp::Type::Node), diff --git a/cpp/node_similarity_module/node_similarity_module.cpp b/cpp/node_similarity_module/node_similarity_module.cpp index b635c5d76..dd2182c46 100644 --- a/cpp/node_similarity_module/node_similarity_module.cpp +++ b/cpp/node_similarity_module/node_similarity_module.cpp @@ -38,7 +38,7 @@ void insert_results(const std::vector> Calculates Jaccard similarity between given pairs of nodes. */ void JaccardPairwise(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); const auto &arguments = mgp::List(args); try { @@ -52,7 +52,7 @@ void JaccardPairwise(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resu Calculates overlap similarity between given pairs of nodes. */ void OverlapPairwise(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto &arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -67,7 +67,7 @@ Calculates Jaccard similarity between all pairs of nodes. Jacc. similarity of two nodes can be calculated as len(intersection(neighbours(node1), neighbours(node2))) / len(union(neighbours(node1), neighbours(node2))) */ void Jaccard(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); try { insert_results(node_similarity_algs::CalculateSimilarityCartesian(mgp::Graph(memgraph_graph), node_similarity_util::Similarity::jaccard), record_factory); @@ -81,7 +81,7 @@ Calculates overlap similarity between all pairs of nodes. Overlap similarity of two nodes can be calculated as len(intersection(neighbours(node1), neighbours(node2))) / min(len(neighbours(node1), len(node2))) */ void Overlap(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); try { insert_results(node_similarity_algs::CalculateSimilarityCartesian(mgp::Graph(memgraph_graph), node_similarity_util::Similarity::overlap), record_factory); @@ -95,7 +95,7 @@ void Overlap(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_ Calculates cosine similarity between all pairs of nodes. */ void Cosine(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); const auto &arguments = mgp::List(args); try { @@ -109,7 +109,7 @@ void Cosine(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_m Calculates overlap similarity between given pairs of nodes. */ void CosinePairwise(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); const auto &arguments = mgp::List(args); try { @@ -121,7 +121,7 @@ void CosinePairwise(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resul extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; // method objects std::vector returns = { mgp::Return(node1_name, mgp::Type::Node), diff --git a/cpp/nodes_module/algorithm/nodes.cpp b/cpp/nodes_module/algorithm/nodes.cpp index a77a85856..ddac2b326 100644 --- a/cpp/nodes_module/algorithm/nodes.cpp +++ b/cpp/nodes_module/algorithm/nodes.cpp @@ -27,7 +27,7 @@ bool Nodes::RelationshipExist(const mgp::Node &node, std::string &rel_type) { } void Nodes::RelationshipsExist(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -167,7 +167,7 @@ void DetachDeleteNode(const mgp::Value &node, mgp::Graph &graph) { } // namespace void Nodes::RelationshipTypes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -182,7 +182,7 @@ void Nodes::RelationshipTypes(mgp_list *args, mgp_graph *memgraph_graph, mgp_res } void Nodes::Delete(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -206,7 +206,7 @@ void Nodes::Delete(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result void Nodes::Link(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/nodes_module/nodes_module.cpp b/cpp/nodes_module/nodes_module.cpp index 73f1296eb..aa381e0fc 100644 --- a/cpp/nodes_module/nodes_module.cpp +++ b/cpp/nodes_module/nodes_module.cpp @@ -5,7 +5,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure(Nodes::Link, std::string(Nodes::kProcedureLink).c_str(), mgp::ProcedureType::Write, {mgp::Parameter(std::string(Nodes::kArgumentNodesLink).c_str(), {mgp::Type::List, mgp::Type::Node}), diff --git a/cpp/pagerank_module/pagerank_online_module.cpp b/cpp/pagerank_module/pagerank_online_module.cpp index fbb4533ab..a904bf3ad 100644 --- a/cpp/pagerank_module/pagerank_online_module.cpp +++ b/cpp/pagerank_module/pagerank_online_module.cpp @@ -69,7 +69,7 @@ void OnlinePageRankSet(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *re void OnlinePageRankUpdate(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto graph = mgp::Graph(memgraph_graph); const auto arguments = mgp::List(args); diff --git a/cpp/path_module/algorithm/path.cpp b/cpp/path_module/algorithm/path.cpp index 9d7b5983d..c5a1371c8 100644 --- a/cpp/path_module/algorithm/path.cpp +++ b/cpp/path_module/algorithm/path.cpp @@ -5,7 +5,7 @@ #include "mgp.hpp" void Path::Create(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -250,7 +250,7 @@ void Path::StartFunction(const mgp::Node &node, const mgp::RecordFactory &record } void Path::Expand(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -416,7 +416,7 @@ void SetConfig(mgp::Map &config) { } void Path::SubgraphNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); @@ -454,7 +454,7 @@ void Path::SubgraphNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result * } void Path::SubgraphAll(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); diff --git a/cpp/path_module/path_module.cpp b/cpp/path_module/path_module.cpp index ca131a199..237743df7 100644 --- a/cpp/path_module/path_module.cpp +++ b/cpp/path_module/path_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure( Path::Expand, std::string(Path::kProcedureExpand).c_str(), mgp::ProcedureType::Read, {mgp::Parameter(std::string(Path::kArgumentStartExpand).c_str(), mgp::Type::Any), diff --git a/cpp/periodic_module/periodic_iterate.cpp b/cpp/periodic_module/periodic_iterate.cpp index e25952ca5..69de092d8 100644 --- a/cpp/periodic_module/periodic_iterate.cpp +++ b/cpp/periodic_module/periodic_iterate.cpp @@ -226,7 +226,7 @@ mg::Client::Params GetClientParams() { } void PeriodicIterate(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); auto num_of_executed_batches = 0; @@ -296,7 +296,7 @@ void PeriodicIterate(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *resu extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; mgp::AddProcedure( PeriodicIterate, kProcedurePeriodic, mgp::ProcedureType::Read, {mgp::Parameter(kArgumentInputQuery, mgp::Type::String), diff --git a/cpp/refactor_module/algorithm/refactor.cpp b/cpp/refactor_module/algorithm/refactor.cpp index 6c1d03ef3..4995fe226 100644 --- a/cpp/refactor_module/algorithm/refactor.cpp +++ b/cpp/refactor_module/algorithm/refactor.cpp @@ -384,7 +384,7 @@ void Refactor::InvertRel(mgp::Graph &graph, mgp::Relationship &rel) { } void Refactor::Invert(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -429,7 +429,7 @@ void Refactor::Collapse(mgp::Graph &graph, const mgp::Node &node, const std::str } void Refactor::CollapseNode(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/schema_module/algorithm/schema.cpp b/cpp/schema_module/algorithm/schema.cpp index 82ad24ca6..107e08932 100644 --- a/cpp/schema_module/algorithm/schema.cpp +++ b/cpp/schema_module/algorithm/schema.cpp @@ -56,7 +56,7 @@ void Schema::ProcessPropertiesRel(mgp::Record &record, const std::string_view &t } void Schema::NodeTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); try { const mgp::Graph graph = mgp::Graph(memgraph_graph); @@ -90,7 +90,7 @@ void Schema::NodeTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_r } void Schema::RelTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto record_factory = mgp::RecordFactory(result); try { const mgp::Graph graph = mgp::Graph(memgraph_graph); diff --git a/cpp/schema_module/schema_module.cpp b/cpp/schema_module/schema_module.cpp index 827abb707..28de5b99c 100644 --- a/cpp/schema_module/schema_module.cpp +++ b/cpp/schema_module/schema_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure(Schema::NodeTypeProperties, std::string(Schema::kProcedureNodeType).c_str(), mgp::ProcedureType::Read, {}, diff --git a/cpp/text_module/algorithm/text.cpp b/cpp/text_module/algorithm/text.cpp index 7bbeb2e7a..81ccbbda9 100644 --- a/cpp/text_module/algorithm/text.cpp +++ b/cpp/text_module/algorithm/text.cpp @@ -1,7 +1,7 @@ #include "text.hpp" void Text::Join(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); diff --git a/cpp/text_module/text_module.cpp b/cpp/text_module/text_module.cpp index 242bc1b23..86713b616 100644 --- a/cpp/text_module/text_module.cpp +++ b/cpp/text_module/text_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure(Text::Join, Text::kProcedureJoin, mgp::ProcedureType::Read, {mgp::Parameter(Text::kJoinArg1, {mgp::Type::List, mgp::Type::String}), diff --git a/cpp/util_module/algorithm/util.cpp b/cpp/util_module/algorithm/util.cpp index d766a7b1e..50b480de6 100644 --- a/cpp/util_module/algorithm/util.cpp +++ b/cpp/util_module/algorithm/util.cpp @@ -2,7 +2,7 @@ #include "md5.hpp" void Util::Md5(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { diff --git a/cpp/util_module/util_module.cpp b/cpp/util_module/util_module.cpp index dcaf13e57..b7a028849 100644 --- a/cpp/util_module/util_module.cpp +++ b/cpp/util_module/util_module.cpp @@ -4,7 +4,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::memory = memory; + mgp::MemoryDispatcherGuard guard{memory};; AddProcedure(Util::Md5, std::string(Util::kProcedureMd5).c_str(), mgp::ProcedureType::Write, {mgp::Parameter(std::string(Util::kArgumentValuesMd5).c_str(), {mgp::Type::List, mgp::Type::Any})}, {mgp::Return(std::string(Util::kArgumentResultMd5).c_str(), mgp::Type::String)}, module, memory); From 032095566d9df81734772bd39fc7b2d1d082ad46 Mon Sep 17 00:00:00 2001 From: imilinovic <44698587+imilinovic@users.noreply.github.com> Date: Wed, 18 Oct 2023 09:25:28 +0200 Subject: [PATCH 03/10] Ignore libmgclient inside setup (#386) --- setup | 84 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/setup b/setup index 59d79e1b9..bd30b7241 100644 --- a/setup +++ b/setup @@ -24,14 +24,15 @@ MG_CONF_DEFAULT_PATH = f"/etc/memgraph/memgraph.conf" MG_CONF_QUERY_MODULES_FLAG = "--query-modules-directory" MAGE_GPU_BUILD = "MAGE_CUGRAPH_ENABLE=ON" -logging.basicConfig(format='%(asctime)-15s [%(levelname)s]: %(message)s') -logger = logging.getLogger('setup') +logging.basicConfig(format="%(asctime)-15s [%(levelname)s]: %(message)s") +logger = logging.getLogger("setup") logger.setLevel(logging.DEBUG) HELP_MESSAGE = """\ For usage info run: python3 setup -h """ + class Lang(Enum): PYTHON = "Python" CPP = "Cpp" @@ -51,6 +52,7 @@ class Lang(Enum): def __str__(self): return str(self.value) + class BuildType(Enum): DEBUG = "Debug" RELEASE = "Release" @@ -58,6 +60,7 @@ class BuildType(Enum): def __str__(self): return str(self.value) + class Parameter(Enum): GPU = "gpu" CPP_BUILD_FLAGS = "cpp_build_flags" @@ -65,6 +68,7 @@ class Parameter(Enum): PATH = "path" TYPE = "type" + def get_arguments(): parser = argparse.ArgumentParser( description="MAGE setup script", @@ -80,7 +84,7 @@ def get_arguments(): build_args_parser.add_argument( "--lang", help="Programming languages to build", - nargs='*', + nargs="*", type=Lang.from_str, choices=Lang, default=list(Lang), @@ -155,7 +159,8 @@ def copytree(src, dst, ignore_patterns=[]) -> None: _copytree() -def run_command(command:List[str])->bool: + +def run_command(command: List[str]) -> bool: logger.debug(f"[Terminal] Running command `{command}`.") try: subprocess.check_output(command) @@ -164,7 +169,8 @@ def run_command(command:List[str])->bool: return False return True -def build_and_copy_cpp_modules(args:Dict[str,Any])->bool: + +def build_and_copy_cpp_modules(args: Dict[str, Any]) -> bool: """ This function builds and copies C++ modules. Returns true if successful, false otherwise. """ @@ -183,9 +189,8 @@ def build_and_copy_cpp_modules(args:Dict[str,Any])->bool: cmake_args += [f"-D{flag}" for flag in args[Parameter.CPP_BUILD_FLAGS.value]] else: cmake_args += [f"-DCMAKE_BUILD_TYPE={BuildType.RELEASE}"] - + cmake_command = ["cmake"] + cmake_args - cmake_status = run_command(cmake_command) if not cmake_status: @@ -194,7 +199,7 @@ def build_and_copy_cpp_modules(args:Dict[str,Any])->bool: core_count = mp.cpu_count() make_command = ["make", f"-j{core_count}"] - + make_status = run_command(make_command) if not make_status: logger.error("[Terminal] (1/8) Building C++ modules failed.") @@ -209,21 +214,33 @@ def build_and_copy_cpp_modules(args:Dict[str,Any])->bool: # NOTE: This is dependent on the cpp/cmake/cugraph ExternalProject_Add (on # the INSTALL_DIR). - logger.info(f"[Terminal] (3/8) Copying built C++ modules to {MAGE_BUILD_DIRECTORY}.") + logger.info( + f"[Terminal] (3/8) Copying built C++ modules to {MAGE_BUILD_DIRECTORY}." + ) all_so = set(glob.glob("**/*.so", recursive=True)) + all_so -= { + "mgclient/src/mgclient-proj-build/src/libmgclient.so", + "mgclient/lib/libmgclient.so", + } + for file in all_so: shutil.copy2(file, MAGE_BUILD_DIRECTORY) - logger.info(f"[Terminal] (4/8) Successfully copied C++ modules to {MAGE_BUILD_DIRECTORY}.") + logger.info( + f"[Terminal] (4/8) Successfully copied C++ modules to {MAGE_BUILD_DIRECTORY}." + ) return True -def copy_python_modules()->bool: + +def copy_python_modules() -> bool: """ Function copies Python modules to MAGE_BUILD_DIRECTORY. Returns true if successful, otherwise false. """ - logger.info(f"[Terminal] (5/8) Copying Python modules to {MAGE_BUILD_DIRECTORY} started.") + logger.info( + f"[Terminal] (5/8) Copying Python modules to {MAGE_BUILD_DIRECTORY} started." + ) os.chdir(PY_DIRECTORY) ignore_list = [ @@ -239,11 +256,14 @@ def copy_python_modules()->bool: copytree(PY_DIRECTORY, MAGE_BUILD_DIRECTORY, ignore_list) os.environ["PYTHONPATH"] = PY_DIRECTORY - logger.info(f"[Terminal] (6/8) Successfully copied Python modules to {MAGE_BUILD_DIRECTORY}.") + logger.info( + f"[Terminal] (6/8) Successfully copied Python modules to {MAGE_BUILD_DIRECTORY}." + ) return True -def build_and_copy_rust_modules(args:Dict[str,Any])->bool: + +def build_and_copy_rust_modules(args: Dict[str, Any]) -> bool: """ Function builds and copies Rust modules. """ @@ -264,10 +284,13 @@ def build_and_copy_rust_modules(args:Dict[str,Any])->bool: rs_build_mode = BuildType.RELEASE rs_build_mode = rs_build_mode.lower() rs_build_flags = ["--release"] - if args[Parameter.TYPE.value] is not None and args[Parameter.TYPE.value] == BuildType.DEBUG: + if ( + args[Parameter.TYPE.value] is not None + and args[Parameter.TYPE.value] == BuildType.DEBUG + ): rs_build_flags = [] - # Build Rust query modules + # Build Rust query modules subprocess.run( ["cargo", "build"] + rs_build_flags, check=True, @@ -285,10 +308,13 @@ def build_and_copy_rust_modules(args:Dict[str,Any])->bool: dst_file = os.path.join(MAGE_BUILD_DIRECTORY, module) shutil.copy2(src_file, dst_file) - logger.info(f"[Terminal] (8/8) Successfully built and copied Rust modules to {MAGE_BUILD_DIRECTORY}.") + logger.info( + f"[Terminal] (8/8) Successfully built and copied Rust modules to {MAGE_BUILD_DIRECTORY}." + ) return True -def build(args:Dict[str, Any])->bool: + +def build(args: Dict[str, Any]) -> bool: shutil.rmtree(MAGE_BUILD_DIRECTORY, ignore_errors=True) os.makedirs(MAGE_BUILD_DIRECTORY, exist_ok=True) copytree(LICENCE_DIRECTORY, MAGE_BUILD_DIRECTORY) @@ -302,20 +328,22 @@ def build(args:Dict[str, Any])->bool: python_status = copy_python_modules() if not python_status: return False - + if Lang.RUST in args[Parameter.LANG.value]: rust_status = build_and_copy_rust_modules(args) if not rust_status: return False - + return True -def run_build_action(args:Dict[str,Any])->bool: +def run_build_action(args: Dict[str, Any]) -> bool: logger.info("[Terminal] Starting building and copying source code...") status = build(args) if not status: - logging.error( "[Terminal] An error occurred while building. Check the output message for more information.") + logging.error( + "[Terminal] An error occurred while building. Check the output message for more information." + ) return False logger.info("[Terminal] Building done successfully.") @@ -323,7 +351,9 @@ def run_build_action(args:Dict[str,Any])->bool: if args[Parameter.PATH.value] is None: return True - logger.info(f"[Terminal] Copying build files from folder {MAGE_BUILD_DIRECTORY} to {args[Parameter.PATH.value]} folder.") + logger.info( + f"[Terminal] Copying build files from folder {MAGE_BUILD_DIRECTORY} to {args[Parameter.PATH.value]} folder." + ) copytree(MAGE_BUILD_DIRECTORY, args[Parameter.PATH.value]) logger.info("[Terminal] Copying done!") @@ -344,10 +374,14 @@ def run_modules_storage_setup_action( modules_storage_path=MAGE_BUILD_DIRECTORY, mg_conf_path=MG_CONF_DEFAULT_PATH ): if not os.path.isfile(mg_conf_path): - logger.info(f"[Terminal] Configuration path does not exist: {mg_conf_path}. Check that Memgraph is installed.") + logger.info( + f"[Terminal] Configuration path does not exist: {mg_conf_path}. Check that Memgraph is installed." + ) return - logger.info(f"[Terminal] --query-modules-dir flag in {modules_storage_path} will be set to {mg_conf_path}") + logger.info( + f"[Terminal] --query-modules-dir flag in {modules_storage_path} will be set to {mg_conf_path}" + ) change_file_lines( mg_conf_path, From d812a0450bd0b4710310b75a31dbc7798d2192ae Mon Sep 17 00:00:00 2001 From: imilinovic <44698587+imilinovic@users.noreply.github.com> Date: Sat, 21 Oct 2023 11:28:03 +0200 Subject: [PATCH 04/10] Use unofficial 2.12 build (#397) --- .github/workflows/test.yml | 21 +++++++++++---------- .gitmodules | 2 +- e2e/collections_test/test_to_set1/test.yml | 10 ++++++---- e2e/collections_test/test_to_set2/test.yml | 3 +-- e2e/collections_test/test_to_set3/input.cyp | 0 e2e/collections_test/test_to_set3/test.yml | 6 ------ 6 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 e2e/collections_test/test_to_set3/input.cyp delete mode 100644 e2e/collections_test/test_to_set3/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ebb098106..5ac9a4306 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ env: MEMGRAPH_PORT: 7687 NEO4J_PORT: 7688 NEO4J_CONTAINER: "neo4j_test" - OFFICIAL: "true" + OFFICIAL: "false" on: [pull_request, workflow_dispatch] @@ -16,10 +16,11 @@ jobs: runs-on: ubuntu-latest continue-on-error: True env: - MEMGRAPH_VERSION: 2.11.0 + MEMGRAPH_VERSION: 2.12.0 strategy: matrix: - architecture: ["amd64", "arm64"] + #architecture: ["amd64", "arm64"] + architecture: ["amd64"] target: ["prod", "dev"] steps: - name: Checkout repository and submodules @@ -44,7 +45,7 @@ jobs: else sudo apt update && sudo apt install -y ca-certificates wget git wget -q https://s3.eu-west-1.amazonaws.com/deps.memgraph.io/memgraph-unofficial/memgraph_${MEMGRAPH_VERSION}-1_amd64.deb -O memgraph-amd64.deb - wget -q https://s3.eu-west-1.amazonaws.com/deps.memgraph.io/memgraph-unofficial/memgraph_${MEMGRAPH_VERSION}-1_arm64.deb -O memgraph-arm64.deb + # wget -q https://s3.eu-west-1.amazonaws.com/deps.memgraph.io/memgraph-unofficial/memgraph_${MEMGRAPH_VERSION}-1_arm64.deb -O memgraph-arm64.deb fi - name: Disk status before cleaning @@ -63,7 +64,7 @@ jobs: run: | df -h docker buildx du - + - name: Rust library tests if: matrix.target == 'dev' run: | @@ -73,7 +74,7 @@ jobs: - name: Build and run Memgraph MAGE:${{ matrix.target }} run: | - + DOCKER_BUILDKIT=1 docker buildx build \ --tag memgraph-mage:${{ matrix.target }} \ --target ${{ matrix.target }} \ @@ -127,18 +128,18 @@ jobs: run: | docker exec -i -u root ${{ env.MAGE_CONTAINER }} bash -c "cd /mage/python/ && python3 -m pytest ." - + - name: Run End-to-end tests - if: matrix.architecture != 'arm64' + #if: matrix.architecture != 'arm64' env: PYTHONPATH: "$PWD/e2e" run: | cd e2e docker exec -i -u root ${{ env.MAGE_CONTAINER }} bash -c "cd /mage/e2e/ && python3 -m pytest . -k 'not cugraph'" - + - name: Run End-to-end correctness tests - if: matrix.architecture != 'arm64' + #if: matrix.architecture != 'arm64' env: PYTHONPATH: "$PWD/e2e" run: | diff --git a/.gitmodules b/.gitmodules index 7554c5052..d925000a8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "cpp/memgraph"] path = cpp/memgraph url = https://github.com/memgraph/memgraph.git - branch = release/2.11 + branch = T675-MAGE-temp-build diff --git a/e2e/collections_test/test_to_set1/test.yml b/e2e/collections_test/test_to_set1/test.yml index 9dfd39a3c..7670d2fc5 100644 --- a/e2e/collections_test/test_to_set1/test.yml +++ b/e2e/collections_test/test_to_set1/test.yml @@ -1,6 +1,8 @@ query: > - RETURN collections.to_set([1,1,2,1,3,4,1]) AS result; + WITH collections.to_set([1,1,2,1,3,4,1]) AS result UNWIND result AS element RETURN element ORDER BY element ASC; - -output: - - result: [4, 3, 2, 1] +output: + - element: 1 + - element: 2 + - element: 3 + - element: 4 diff --git a/e2e/collections_test/test_to_set2/test.yml b/e2e/collections_test/test_to_set2/test.yml index 329b32ac2..a89265c19 100644 --- a/e2e/collections_test/test_to_set2/test.yml +++ b/e2e/collections_test/test_to_set2/test.yml @@ -1,6 +1,5 @@ query: > RETURN collections.to_set([]) AS result; - -output: +output: - result: [] diff --git a/e2e/collections_test/test_to_set3/input.cyp b/e2e/collections_test/test_to_set3/input.cyp deleted file mode 100644 index e69de29bb..000000000 diff --git a/e2e/collections_test/test_to_set3/test.yml b/e2e/collections_test/test_to_set3/test.yml deleted file mode 100644 index 47604ba0e..000000000 --- a/e2e/collections_test/test_to_set3/test.yml +++ /dev/null @@ -1,6 +0,0 @@ -query: > - RETURN collections.to_set(["aa","aa","matija","matija",[1,2,3],[1,2,3],1,2]) AS result; - - -output: - - result: [1, [1,2,3], 2, "matija", "aa"] From 6648d32a24bcb354bcae955bd08aed375abfccad Mon Sep 17 00:00:00 2001 From: imilinovic <44698587+imilinovic@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:41:13 +0200 Subject: [PATCH 05/10] Update submodules (#399) --- cpp/memgraph | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/memgraph b/cpp/memgraph index b719f0744..2bfa148db 160000 --- a/cpp/memgraph +++ b/cpp/memgraph @@ -1 +1 @@ -Subproject commit b719f0744f38d63f23521593cf392461311ca790 +Subproject commit 2bfa148db2daa410175087b2518d8154ce132ce9 From e56adcc3d376e3aa60054a70cfc5b64a0d59c180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Pintari=C4=87?= <99442742+mpintaric55334@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:32:08 +0200 Subject: [PATCH 06/10] Add correctness testing for path output (#355) --- e2e_correctness/conftest.py | 2 - .../path_test/test_path_expand1/config.yml | 2 + .../path_test/test_path_expand1/input.cyp | 7 ++ .../path_test/test_path_expand1/test.yml | 8 ++ e2e_correctness/query_neo_mem.py | 86 ++++++++++++++++++- e2e_correctness/test_modules.py | 81 +++++++++++++++-- test_e2e_correctness.py | 41 ++++++--- 7 files changed, 204 insertions(+), 23 deletions(-) create mode 100644 e2e_correctness/path_test/test_path_expand1/config.yml create mode 100644 e2e_correctness/path_test/test_path_expand1/input.cyp create mode 100644 e2e_correctness/path_test/test_path_expand1/test.yml diff --git a/e2e_correctness/conftest.py b/e2e_correctness/conftest.py index 11f3aae60..79533a42f 100644 --- a/e2e_correctness/conftest.py +++ b/e2e_correctness/conftest.py @@ -1,5 +1,3 @@ - - def pytest_addoption(parser): parser.addoption("--memgraph-port", type=int, action="store") parser.addoption("--neo4j-port", type=int, action="store") diff --git a/e2e_correctness/path_test/test_path_expand1/config.yml b/e2e_correctness/path_test/test_path_expand1/config.yml new file mode 100644 index 000000000..173fc413a --- /dev/null +++ b/e2e_correctness/path_test/test_path_expand1/config.yml @@ -0,0 +1,2 @@ +path_option: > + True diff --git a/e2e_correctness/path_test/test_path_expand1/input.cyp b/e2e_correctness/path_test/test_path_expand1/input.cyp new file mode 100644 index 000000000..8d7b1ed1c --- /dev/null +++ b/e2e_correctness/path_test/test_path_expand1/input.cyp @@ -0,0 +1,7 @@ +CREATE (d:Dog {name: "Rex", id: 0})-[h:HUNTS {id: 0}]->(c:Cat {name: "Tom", id: 1})-[catc:CATCHES {id:1}]->(m:Mouse {name: "Squiggles", id: 2}); +MATCH (d:Dog) CREATE (d)-[bff:BEST_FRIENDS {id:2}]->(c:Cat {name: "Rinko", id: 3}); +MATCH (c:Cat {name: "Tom"}) CREATE (h:Human {name: "Matija", id: 4})-[o:OWNS {id:3}]->(c); +MATCH (d:Dog {name: "Rex"}),(h:Human {name:"Matija"}) CREATE (h)-[o:PLAYS_WITH {id:4}]->(d); +MATCH (d:Dog {name: "Rex"}) CREATE (d)-[l:LIVES {id:5}]->(z:Zadar {id: 5}); +MATCH (m:Mouse {name: "Squiggles"}), (z:Zadar) CREATE (m)-[r:RUNS_THROUGH {id:6}]->(z); +MATCH (z:Zadar) CREATE (h:Human {name: "Dena", id: 6})-[g:GOES_TO {id:7}]->(z); diff --git a/e2e_correctness/path_test/test_path_expand1/test.yml b/e2e_correctness/path_test/test_path_expand1/test.yml new file mode 100644 index 000000000..c0260c510 --- /dev/null +++ b/e2e_correctness/path_test/test_path_expand1/test.yml @@ -0,0 +1,8 @@ +memgraph_query: > + MATCH (d:Dog), (h:Human) + CALL path.expand([d,id(h)],[],[],1,10) YIELD result RETURN result; + + +neo4j_query: > + MATCH (d:Dog), (h:Human) + CALL apoc.path.expand([d,h],"","",1,10) YIELD path RETURN path; diff --git a/e2e_correctness/query_neo_mem.py b/e2e_correctness/query_neo_mem.py index 0650600ad..7bab351a9 100644 --- a/e2e_correctness/query_neo_mem.py +++ b/e2e_correctness/query_neo_mem.py @@ -74,7 +74,11 @@ def __eq__(self, other): class Edge: def __init__( - self, from_vertex: int, to_vertex: int, label: str, properties: Dict[str, Any] + self, + from_vertex: int, + to_vertex: int, + label: str, + properties: Dict[str, Any], ): self._from_vertex = from_vertex self._to_vertex = to_vertex @@ -297,3 +301,83 @@ def neo4j_get_graph(neo4j_driver: neo4j.BoltDriver) -> Graph: json_data = get_neo4j_data_json(neo4j_driver) logger.debug("Building the graph from Neo4j JSON data") return create_graph_neo4j_json(json_data) + + +# additions for path testing +def sort_dict(dict): + keys = list(dict.keys()) + keys.sort() + sorted_dict = {i: dict[i] for i in keys} + return sorted_dict + + +def execute_query_neo4j(driver: neo4j.BoltDriver, query: str) -> list: + with driver.session() as session: + query = neo4j.Query(query) + results = session.run(query).value() + return results + + +def path_to_string_neo4j(path): #type should be neo4j.graph.path but it doesnt recognize it in the definition + path_string_list = ["PATH: "] + + n = len(path.nodes) + + for i in range(0, n): + node = path.nodes[i] + node_labels = list(node.labels) + node_labels.sort() + sorted_dict = sort_dict(node._properties) + if "id" in sorted_dict: + sorted_dict.pop("id") + node_props = str(sorted_dict) + path_string_list.append(f"(id:{str(node.get('id'))} labels: {str(node_labels)} {node_props})-") + + if i == n - 1: + path_string = "".join(path_string_list) + return path_string[:-1] + + relationship = path.relationships[i] + sorted_dict_rel = sort_dict(relationship._properties) + if "id" in sorted_dict_rel: + sorted_dict_rel.pop("id") + rel_props = str(sorted_dict_rel) + path_string_list.append(f"[id:{str(relationship.get('id'))} type: {relationship.type} {str(rel_props)}]-") + +def parse_neo4j(results: list) -> List[str]: + paths = [path_to_string_neo4j(res) for res in results] + paths.sort() + return paths + + +def path_to_string_mem(path: gqlalchemy.Path) -> str: + path_string_list = ["PATH: "] + + n = len(path._nodes) + + for i in range(0, n): + node = path._nodes[i] + node_labels = list(node._labels) + node_labels.sort() + sorted_dict = sort_dict(node._properties) + if "id" in sorted_dict: + sorted_dict.pop("id") + node_props = str(sorted_dict) + path_string_list.append(f"(id:{str(node._properties.get('id'))} labels: {str(node_labels)} {str(node_props)})-") + + if i == n - 1: + path_string = "".join(path_string_list) + return path_string[:-1] + + relationship = path._relationships[i] + sorted_dict_rel = sort_dict(relationship._properties) + if "id" in sorted_dict_rel: + sorted_dict_rel.pop("id") + rel_props = str(sorted_dict_rel) + path_string_list.append(f"[id:{str(relationship._properties.get('id'))} type: {relationship._type} {str(rel_props)}]-") + + +def parse_mem(results:list) -> List[str]: + paths = [path_to_string_mem(result["result"]) for result in results] + paths.sort() + return paths diff --git a/e2e_correctness/test_modules.py b/e2e_correctness/test_modules.py index 9357ed24b..9bf223c73 100644 --- a/e2e_correctness/test_modules.py +++ b/e2e_correctness/test_modules.py @@ -6,6 +6,7 @@ import neo4j import pytest import yaml +import os from gqlalchemy import Memgraph @@ -25,6 +26,11 @@ neo4j_get_graph, run_memgraph_query, run_neo4j_query, + execute_query_neo4j, + path_to_string_neo4j, + parse_neo4j, + path_to_string_mem, + parse_mem, ) logging.basicConfig(format="%(asctime)-15s [%(levelname)s]: %(message)s") @@ -49,6 +55,8 @@ class TestConstants: TEST_FILE = "test.yml" MEMGRAPH_QUERY = "memgraph_query" NEO4J_QUERY = "neo4j_query" + CONFIG_FILE = "config.yml" + class ConfigConstants: @@ -79,7 +87,9 @@ def get_all_tests(): if not test_or_group_dir.is_dir(): continue - if test_or_group_dir.name.endswith(TestConstants.TEST_GROUP_DIR_SUFFIX): + if test_or_group_dir.name.endswith( + TestConstants.TEST_GROUP_DIR_SUFFIX + ): for test_dir in test_or_group_dir.iterdir(): if not test_dir.is_dir(): continue @@ -143,11 +153,15 @@ def _graphs_equal(memgraph_graph: Graph, neo4j_graph: Graph) -> bool: return True -def _run_test(test_dir: str, memgraph_db: Memgraph, neo4j_driver: neo4j.BoltDriver): +def _run_test( + test_dir: str, memgraph_db: Memgraph, neo4j_driver: neo4j.BoltDriver +) -> None: """ Run input queries on Memgraph and Neo4j and compare graphs after running test query """ - input_cyphers = test_dir.joinpath(TestConstants.INPUT_FILE).open("r").readlines() + input_cyphers = ( + test_dir.joinpath(TestConstants.INPUT_FILE).open("r").readlines() + ) mg_execute_cyphers(input_cyphers, memgraph_db) logger.info(f"Imported data into Memgraph from {input_cyphers}") neo4j_execute_cyphers(input_cyphers, neo4j_driver) @@ -162,7 +176,9 @@ def _run_test(test_dir: str, memgraph_db: Memgraph, neo4j_driver: neo4j.BoltDriv run_memgraph_query(test_dict[TestConstants.MEMGRAPH_QUERY], memgraph_db) logger.info("Done") - logger.info(f"Running query against Neo4j: {test_dict[TestConstants.NEO4J_QUERY]}") + logger.info( + f"Running query against Neo4j: {test_dict[TestConstants.NEO4J_QUERY]}" + ) run_neo4j_query(test_dict[TestConstants.NEO4J_QUERY], neo4j_driver) logger.info("Done") @@ -174,11 +190,57 @@ def _run_test(test_dir: str, memgraph_db: Memgraph, neo4j_driver: neo4j.BoltDriv ), "The graphs are not equal, check the logs for more details" +def _run_path_test( + test_dir: str, memgraph_db: Memgraph, neo4j_driver: neo4j.BoltDriver +) -> None: + """ + Run input queries on Memgraph and Neo4j and compare path results after running test query + """ + input_cyphers = ( + test_dir.joinpath(TestConstants.INPUT_FILE).open("r").readlines() + ) + logger.info(f"Importing data from {input_cyphers}") + mg_execute_cyphers(input_cyphers, memgraph_db) + logger.info("Imported data into Memgraph") + neo4j_execute_cyphers(input_cyphers, neo4j_driver) + logger.info("Imported data into Neo4j") + + test_dict = _load_yaml(test_dir.joinpath(TestConstants.TEST_FILE)) + logger.info(f"Test dict {test_dict}") + logger.info( + f"Running query against Memgraph: {test_dict[TestConstants.MEMGRAPH_QUERY]}" + ) + memgraph_results = memgraph_db.execute_and_fetch( + test_dict[TestConstants.MEMGRAPH_QUERY] + ) + memgraph_paths = parse_mem(memgraph_results) + logger.info("Done") + + logger.info( + f"Running query against Neo4j: {test_dict[TestConstants.NEO4J_QUERY]}" + ) + neo4j_results = execute_query_neo4j( + neo4j_driver, test_dict[TestConstants.NEO4J_QUERY] + ) + neo4j_paths = parse_neo4j(neo4j_results) + logger.info("Done") + + assert memgraph_paths == neo4j_paths + +def check_path_option(test_dir): + config_path = test_dir.joinpath(TestConstants.CONFIG_FILE) + if(os.path.exists(config_path)): + config_dict = _load_yaml(config_path) + if "path_option" in config_dict: + option = config_dict["path_option"].strip() + return ( option == "True") + return False @pytest.fixture(scope="session") def memgraph_port(pytestconfig): return pytestconfig.getoption("--memgraph-port") + @pytest.fixture(scope="session", autouse=True) def memgraph_db(memgraph_port): memgraph_db = create_memgraph_db(memgraph_port) @@ -191,6 +253,7 @@ def memgraph_db(memgraph_port): def neo4j_port(pytestconfig): return pytestconfig.getoption("--neo4j-port") + @pytest.fixture(scope="session", autouse=True) def neo4j_driver(neo4j_port): neo4j_driver = create_neo4j_driver(neo4j_port) @@ -201,7 +264,9 @@ def neo4j_driver(neo4j_port): @pytest.mark.parametrize("test_dir", tests) def test_end2end( - test_dir: Path, memgraph_db: Memgraph, neo4j_driver: neo4j.BoltDriver + test_dir: Path, + memgraph_db: Memgraph, + neo4j_driver: neo4j.BoltDriver, ): logger.debug("Dropping the Memgraph and Neo4j databases.") @@ -209,7 +274,11 @@ def test_end2end( clean_neo4j_db(neo4j_driver) if test_dir.name.startswith(TestConstants.TEST_SUBDIR_PREFIX): - _run_test(test_dir, memgraph_db, neo4j_driver) + + if check_path_option(test_dir): + _run_path_test(test_dir, memgraph_db, neo4j_driver) + else: + _run_test(test_dir, memgraph_db, neo4j_driver) else: logger.info(f"Skipping directory: {test_dir.name}") diff --git a/test_e2e_correctness.py b/test_e2e_correctness.py index 10ba141a7..ff1c52c81 100644 --- a/test_e2e_correctness.py +++ b/test_e2e_correctness.py @@ -12,18 +12,26 @@ class ConfigConstants: NEO4J_PORT = 7688 MEMGRAPH_PORT = 7687 + def parse_arguments(): - parser = argparse.ArgumentParser( - description="Test MAGE E2E correctness." - ) + parser = argparse.ArgumentParser(description="Test MAGE E2E correctness.") parser.add_argument( - "-k", help="Filter what tests you want to run", type=str, required=False + "-k", + help="Filter what tests you want to run", + type=str, + required=False, ) parser.add_argument( - "--memgraph-port", help="Set the port that Memgraph is listening on", type=int, required=False + "--memgraph-port", + help="Set the port that Memgraph is listening on", + type=int, + required=False, ) parser.add_argument( - "--neo4j-port", help="Set the port that Neo4j is listening on", type=int, required=False + "--neo4j-port", + help="Set the port that Neo4j is listening on", + type=int, + required=False, ) args = parser.parse_args() return args @@ -34,18 +42,21 @@ def parse_arguments(): ################################################# -def main(test_filter: str = None, - memgraph_port:str = str(ConfigConstants.MEMGRAPH_PORT), - neo4j_port: str = str(ConfigConstants.NEO4J_PORT)): +def main( + test_filter: str = None, + memgraph_port: str = str(ConfigConstants.MEMGRAPH_PORT), + neo4j_port: str = str(ConfigConstants.NEO4J_PORT), +): os.environ["PYTHONPATH"] = E2E_CORRECTNESS_DIRECTORY os.chdir(E2E_CORRECTNESS_DIRECTORY) command = ["python3", "-m", "pytest", ".", "-vv"] if test_filter: command.extend(["-k", test_filter]) - command.extend(["--memgraph-port", memgraph_port]) command.extend(["--neo4j-port", neo4j_port]) + + subprocess.run(command) @@ -59,7 +70,9 @@ def main(test_filter: str = None, memgraph_port = str(memgraph_port) if neo4j_port: neo4j_port = str(neo4j_port) - - main(test_filter=test_filter, - memgraph_port=memgraph_port, - neo4j_port=neo4j_port) + + main( + test_filter=test_filter, + memgraph_port=memgraph_port, + neo4j_port=neo4j_port, + ) From 84c20f5ec4255994dc8f47103f81d57c45a8baed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Pintari=C4=87?= <99442742+mpintaric55334@users.noreply.github.com> Date: Tue, 24 Oct 2023 16:13:24 +0200 Subject: [PATCH 07/10] Bugfix for map merge (#377) --- cpp/map_module/algorithm/map.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/map_module/algorithm/map.cpp b/cpp/map_module/algorithm/map.cpp index 328978bdd..f232b10ca 100644 --- a/cpp/map_module/algorithm/map.cpp +++ b/cpp/map_module/algorithm/map.cpp @@ -181,9 +181,8 @@ void Map::Merge(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp const auto map2 = arguments[1].ValueMap(); mgp::Map merged_map = mgp::Map(std::move(map2)); - for (const auto element : map1) { - if (merged_map.At(element.key).IsNull()) { + if (!merged_map.KeyExists(element.key)) { merged_map.Insert(element.key, element.value); } } From aef3650cda4bdb686589577e3a3bbf9a4c61e363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Pintari=C4=87?= <99442742+mpintaric55334@users.noreply.github.com> Date: Tue, 24 Oct 2023 16:14:09 +0200 Subject: [PATCH 08/10] Implement node in/out degree (#369) --- cpp/node_module/algorithm/node.cpp | 52 ++++++++++++++++++++++++ cpp/node_module/algorithm/node.hpp | 14 +++++++ cpp/node_module/node_module.cpp | 14 ++++++- e2e/node_test/test_degree_in1/input.cyp | 1 + e2e/node_test/test_degree_in1/test.yml | 5 +++ e2e/node_test/test_degree_in2/input.cyp | 1 + e2e/node_test/test_degree_in2/test.yml | 5 +++ e2e/node_test/test_degree_in3/input.cyp | 1 + e2e/node_test/test_degree_in3/test.yml | 5 +++ e2e/node_test/test_degree_out1/input.cyp | 1 + e2e/node_test/test_degree_out1/test.yml | 5 +++ e2e/node_test/test_degree_out2/input.cyp | 1 + e2e/node_test/test_degree_out2/test.yml | 5 +++ e2e/node_test/test_degree_out3/input.cyp | 1 + e2e/node_test/test_degree_out3/test.yml | 5 +++ 15 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 e2e/node_test/test_degree_in1/input.cyp create mode 100644 e2e/node_test/test_degree_in1/test.yml create mode 100644 e2e/node_test/test_degree_in2/input.cyp create mode 100644 e2e/node_test/test_degree_in2/test.yml create mode 100644 e2e/node_test/test_degree_in3/input.cyp create mode 100644 e2e/node_test/test_degree_in3/test.yml create mode 100644 e2e/node_test/test_degree_out1/input.cyp create mode 100644 e2e/node_test/test_degree_out1/test.yml create mode 100644 e2e/node_test/test_degree_out2/input.cyp create mode 100644 e2e/node_test/test_degree_out2/test.yml create mode 100644 e2e/node_test/test_degree_out3/input.cyp create mode 100644 e2e/node_test/test_degree_out3/test.yml diff --git a/cpp/node_module/algorithm/node.cpp b/cpp/node_module/algorithm/node.cpp index 3187d2c9d..67ad3332f 100644 --- a/cpp/node_module/algorithm/node.cpp +++ b/cpp/node_module/algorithm/node.cpp @@ -177,3 +177,55 @@ void Node::RelationshipTypes(mgp_list *args, mgp_graph *memgraph_graph, mgp_resu return; } } + +void Node::DegreeIn(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard{memory}; + const auto arguments = mgp::List(args); + auto result = mgp::Result(res); + try { + const auto node = arguments[0].ValueNode(); + const auto type = arguments[1].ValueString(); + if (type.size() == 0) { + result.SetValue((int64_t)node.InDegree()); + return; + } + int64_t degree = 0; + for (const auto rel : node.InRelationships()) { + if (rel.Type() == type) { + degree += 1; + } + } + result.SetValue(degree); + + + } catch (const std::exception &e) { + result.SetErrorMessage(e.what()); + return; + } +} + +void Node::DegreeOut(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard{memory}; + const auto arguments = mgp::List(args); + auto result = mgp::Result(res); + try { + const auto node = arguments[0].ValueNode(); + const auto type = arguments[1].ValueString(); + if (type.size() == 0) { + result.SetValue((int64_t)node.OutDegree()); + return; + } + int64_t degree = 0; + for (const auto rel : node.OutRelationships()) { + if (rel.Type() == type) { + degree += 1; + } + } + result.SetValue(degree); + + + } catch (const std::exception &e) { + result.SetErrorMessage(e.what()); + return; + } +} diff --git a/cpp/node_module/algorithm/node.hpp b/cpp/node_module/algorithm/node.hpp index 1f9baaa8a..c03b4b00e 100644 --- a/cpp/node_module/algorithm/node.hpp +++ b/cpp/node_module/algorithm/node.hpp @@ -25,6 +25,16 @@ constexpr std::string_view kRelationshipTypesArg1 = "node"; constexpr std::string_view kRelationshipTypesArg2 = "types"; constexpr std::string_view kResultRelationshipTypes = "relationship_types"; +/* degree_in constants */ +constexpr std::string_view kFunctionDegreeIn = "degree_in"; +constexpr std::string_view kDegreeInArg1 = "node"; +constexpr std::string_view kDegreeInArg2 = "type"; + +/* degree_out constants */ +constexpr std::string_view kFunctionDegreeOut = "degree_out"; +constexpr std::string_view kDegreeOutArg1 = "node"; +constexpr std::string_view kDegreeOutArg2 = "type"; + void RelationshipsExist(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); bool RelationshipExist(const mgp::Node &node, std::string &rel_type); @@ -35,4 +45,8 @@ void RelationshipExists(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *r void RelationshipTypes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); +void DegreeIn(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory); + +void DegreeOut(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory); + } // namespace Node diff --git a/cpp/node_module/node_module.cpp b/cpp/node_module/node_module.cpp index 35fa39b4a..3ca023707 100644 --- a/cpp/node_module/node_module.cpp +++ b/cpp/node_module/node_module.cpp @@ -4,7 +4,9 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::MemoryDispatcherGuard guard{memory};; + + mgp::MemoryDispatcherGuard guard{memory}; + AddProcedure(Node::RelationshipsExist, std::string(Node::kProcedureRelationshipsExist).c_str(), mgp::ProcedureType::Read, {mgp::Parameter(std::string(Node::kArgumentNodesRelationshipsExist).c_str(), mgp::Type::Node), @@ -25,6 +27,16 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem mgp::Parameter(Node::kRelationshipTypesArg2, {mgp::Type::List, mgp::Type::String}, mgp::Value(mgp::List{}))}, {mgp::Return(Node::kResultRelationshipTypes, {mgp::Type::List, mgp::Type::String})}, module, memory); + mgp::AddFunction(Node::DegreeIn, Node::kFunctionDegreeIn, + {mgp::Parameter(Node::kDegreeInArg1, mgp::Type::Node), + mgp::Parameter(Node::kDegreeInArg2, mgp::Type::String, "")}, + module, memory); + + mgp::AddFunction(Node::DegreeOut, Node::kFunctionDegreeOut, + {mgp::Parameter(Node::kDegreeOutArg1, mgp::Type::Node), + mgp::Parameter(Node::kDegreeOutArg2, mgp::Type::String, "")}, + module, memory); + } catch (const std::exception &e) { return 1; } diff --git a/e2e/node_test/test_degree_in1/input.cyp b/e2e/node_test/test_degree_in1/input.cyp new file mode 100644 index 000000000..3afd74f02 --- /dev/null +++ b/e2e/node_test/test_degree_in1/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog),(h:Human),(d)-[l:LOVES]->(h),(d)-[o:OWNED_BY]->(h); diff --git a/e2e/node_test/test_degree_in1/test.yml b/e2e/node_test/test_degree_in1/test.yml new file mode 100644 index 000000000..6bfbe5181 --- /dev/null +++ b/e2e/node_test/test_degree_in1/test.yml @@ -0,0 +1,5 @@ +query: > + MATCH (h:Human) RETURN node.degree_in(h, "LOVES") AS result; + +output: + - result: 1 diff --git a/e2e/node_test/test_degree_in2/input.cyp b/e2e/node_test/test_degree_in2/input.cyp new file mode 100644 index 000000000..3afd74f02 --- /dev/null +++ b/e2e/node_test/test_degree_in2/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog),(h:Human),(d)-[l:LOVES]->(h),(d)-[o:OWNED_BY]->(h); diff --git a/e2e/node_test/test_degree_in2/test.yml b/e2e/node_test/test_degree_in2/test.yml new file mode 100644 index 000000000..fb2dfeba3 --- /dev/null +++ b/e2e/node_test/test_degree_in2/test.yml @@ -0,0 +1,5 @@ +query: > + MATCH (h:Human) RETURN node.degree_in(h) AS result; + +output: + - result: 2 diff --git a/e2e/node_test/test_degree_in3/input.cyp b/e2e/node_test/test_degree_in3/input.cyp new file mode 100644 index 000000000..c0ed30ce8 --- /dev/null +++ b/e2e/node_test/test_degree_in3/input.cyp @@ -0,0 +1 @@ +MERGE (d:Dog {name: "Rex"}) WITH d UNWIND range(0, 1000) AS id MERGE (h:Human {name: "Humie" + id}) MERGE (h)-[l:LOVES]->(d); diff --git a/e2e/node_test/test_degree_in3/test.yml b/e2e/node_test/test_degree_in3/test.yml new file mode 100644 index 000000000..17dfea6b9 --- /dev/null +++ b/e2e/node_test/test_degree_in3/test.yml @@ -0,0 +1,5 @@ +query: > + MATCH (d:Dog) RETURN node.degree_in(d) AS result; + +output: + - result: 1001 diff --git a/e2e/node_test/test_degree_out1/input.cyp b/e2e/node_test/test_degree_out1/input.cyp new file mode 100644 index 000000000..3afd74f02 --- /dev/null +++ b/e2e/node_test/test_degree_out1/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog),(h:Human),(d)-[l:LOVES]->(h),(d)-[o:OWNED_BY]->(h); diff --git a/e2e/node_test/test_degree_out1/test.yml b/e2e/node_test/test_degree_out1/test.yml new file mode 100644 index 000000000..a98ecf5f9 --- /dev/null +++ b/e2e/node_test/test_degree_out1/test.yml @@ -0,0 +1,5 @@ +query: > + MATCH (d:Dog) RETURN node.degree_out(d, "LOVES") AS result; + +output: + - result: 1 diff --git a/e2e/node_test/test_degree_out2/input.cyp b/e2e/node_test/test_degree_out2/input.cyp new file mode 100644 index 000000000..3afd74f02 --- /dev/null +++ b/e2e/node_test/test_degree_out2/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog),(h:Human),(d)-[l:LOVES]->(h),(d)-[o:OWNED_BY]->(h); diff --git a/e2e/node_test/test_degree_out2/test.yml b/e2e/node_test/test_degree_out2/test.yml new file mode 100644 index 000000000..1ec1e4c4d --- /dev/null +++ b/e2e/node_test/test_degree_out2/test.yml @@ -0,0 +1,5 @@ +query: > + MATCH (d:Dog) RETURN node.degree_out(d) AS result; + +output: + - result: 2 diff --git a/e2e/node_test/test_degree_out3/input.cyp b/e2e/node_test/test_degree_out3/input.cyp new file mode 100644 index 000000000..65e216d59 --- /dev/null +++ b/e2e/node_test/test_degree_out3/input.cyp @@ -0,0 +1 @@ +MERGE (d:Dog {name: "Rex"}) WITH d UNWIND range(0, 1000) AS id MERGE (h:Human {name: "Humie" + id}) MERGE (d)-[l:LOVES]->(h); diff --git a/e2e/node_test/test_degree_out3/test.yml b/e2e/node_test/test_degree_out3/test.yml new file mode 100644 index 000000000..4d19cdba1 --- /dev/null +++ b/e2e/node_test/test_degree_out3/test.yml @@ -0,0 +1,5 @@ +query: > + MATCH (d:Dog) RETURN node.degree_out(d) AS result; + +output: + - result: 1001 From 9f5a083131a05e363b629986ed70de805a1382ce Mon Sep 17 00:00:00 2001 From: imilinovic <44698587+imilinovic@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:42:11 +0200 Subject: [PATCH 09/10] Add path functions (#394) --- cpp/path_module/algorithm/path.cpp | 752 ++++++++++-------- cpp/path_module/algorithm/path.hpp | 145 +++- cpp/path_module/path_module.cpp | 17 +- e2e/path_test/test_elements_1/input.cyp | 1 + e2e/path_test/test_elements_1/test.yml | 37 + e2e/path_test/test_elements_2/input.cyp | 1 + e2e/path_test/test_elements_2/test.yml | 37 + e2e/path_test/test_expand1/test.yml | 20 +- e2e/path_test/test_expand2/test.yml | 59 +- e2e/path_test/test_expand3/test.yml | 31 +- e2e/path_test/test_expand4/test.yml | 8 +- e2e/path_test/test_subgraph_all_1/test.yml | 8 +- e2e/path_test/test_subgraph_all_2/test.yml | 16 +- e2e/path_test/test_subgraph_all_3/test.yml | 6 +- e2e/path_test/test_subgraph_nodes_1/test.yml | 6 +- e2e/path_test/test_subgraph_nodes_2/test.yml | 30 +- e2e/path_test/test_subgraph_nodes_3/test.yml | 6 +- .../path_test/test_combine_1/config.yml | 2 + .../path_test/test_combine_1/input.cyp | 1 + .../path_test/test_combine_1/test.yml | 10 + .../path_test/test_combine_2/config.yml | 2 + .../path_test/test_combine_2/input.cyp | 1 + .../path_test/test_combine_2/test.yml | 10 + .../path_test/test_slice_1/config.yml | 2 + .../path_test/test_slice_1/input.cyp | 1 + .../path_test/test_slice_1/test.yml | 6 + .../path_test/test_slice_2/config.yml | 2 + .../path_test/test_slice_2/input.cyp | 1 + .../path_test/test_slice_2/test.yml | 6 + .../path_test/test_slice_3/config.yml | 2 + .../path_test/test_slice_3/input.cyp | 1 + .../path_test/test_slice_3/test.yml | 6 + 32 files changed, 806 insertions(+), 427 deletions(-) create mode 100644 e2e/path_test/test_elements_1/input.cyp create mode 100644 e2e/path_test/test_elements_1/test.yml create mode 100644 e2e/path_test/test_elements_2/input.cyp create mode 100644 e2e/path_test/test_elements_2/test.yml create mode 100644 e2e_correctness/path_test/test_combine_1/config.yml create mode 100644 e2e_correctness/path_test/test_combine_1/input.cyp create mode 100644 e2e_correctness/path_test/test_combine_1/test.yml create mode 100644 e2e_correctness/path_test/test_combine_2/config.yml create mode 100644 e2e_correctness/path_test/test_combine_2/input.cyp create mode 100644 e2e_correctness/path_test/test_combine_2/test.yml create mode 100644 e2e_correctness/path_test/test_slice_1/config.yml create mode 100644 e2e_correctness/path_test/test_slice_1/input.cyp create mode 100644 e2e_correctness/path_test/test_slice_1/test.yml create mode 100644 e2e_correctness/path_test/test_slice_2/config.yml create mode 100644 e2e_correctness/path_test/test_slice_2/input.cyp create mode 100644 e2e_correctness/path_test/test_slice_2/test.yml create mode 100644 e2e_correctness/path_test/test_slice_3/config.yml create mode 100644 e2e_correctness/path_test/test_slice_3/input.cyp create mode 100644 e2e_correctness/path_test/test_slice_3/test.yml diff --git a/cpp/path_module/algorithm/path.cpp b/cpp/path_module/algorithm/path.cpp index c5a1371c8..a1af9e87d 100644 --- a/cpp/path_module/algorithm/path.cpp +++ b/cpp/path_module/algorithm/path.cpp @@ -1,11 +1,265 @@ #include "path.hpp" -#include - #include "mgp.hpp" +Path::PathHelper::PathHelper(const mgp::List &labels, const mgp::List &relationships, int64_t min_hops, + int64_t max_hops) { + ParseLabels(labels); + FilterLabelBoolStatus(); + ParseRelationships(relationships); + config_.min_hops = min_hops; + config_.max_hops = max_hops; +} + +Path::PathHelper::PathHelper(const mgp::Map &config) { + auto same_type_or_null = [](const mgp::Type type, const mgp::Type wanted_type) { + return type == wanted_type || type == mgp::Type::Null; + }; + + if (!same_type_or_null(config.At("minHops").Type(), mgp::Type::Int) || + !same_type_or_null(config.At("maxHops").Type(), mgp::Type::Int) || + !same_type_or_null(config.At("relationshipFilter").Type(), mgp::Type::List) || + !same_type_or_null(config.At("labelFilter").Type(), mgp::Type::List) || + !same_type_or_null(config.At("filterStartNode").Type(), mgp::Type::Bool) || + !same_type_or_null(config.At("beginSequenceAtStart").Type(), mgp::Type::Bool) || + !same_type_or_null(config.At("bfs").Type(), mgp::Type::Bool)) { + throw mgp::ValueException( + "The config parameter needs to be a map with keys and values in line with the documentation."); + } + + auto value = config.At("maxHops"); + if (!value.IsNull()) { + config_.max_hops = value.ValueInt(); + } + value = config.At("minHops"); + if (!value.IsNull()) { + config_.min_hops = value.ValueInt(); + } + + value = config.At("relationshipFilter"); + if (!value.IsNull()) { + ParseRelationships(value.ValueList()); + } else { + ParseRelationships(mgp::List()); + } + + value = config.At("labelFilter"); + if (!value.IsNull()) { + ParseLabels(value.ValueList()); + } else { + ParseLabels(mgp::List()); + } + FilterLabelBoolStatus(); + + value = config.At("filterStartNode"); + config_.filter_start_node = value.IsNull() ? true : value.ValueBool(); + + value = config.At("beginSequenceAtStart"); + config_.begin_sequence_at_start = value.IsNull() ? true : value.ValueBool(); + + value = config.At("bfs"); + config_.bfs = value.IsNull() ? false : value.ValueBool(); +} + +Path::RelDirection Path::PathHelper::GetDirection(const std::string &rel_type) const { + auto it = config_.relationship_sets.find(rel_type); + if (it == config_.relationship_sets.end()) { + return RelDirection::kNone; + } + return it->second; +} + +Path::LabelBools Path::PathHelper::GetLabelBools(const mgp::Node &node) const { + LabelBools label_bools; + for (const auto &label : node.Labels()) { + FilterLabel(label, label_bools); + } + return label_bools; +} + +bool Path::PathHelper::AreLabelsValid(const LabelBools &label_bools) const { + return !label_bools.blacklisted && + ((label_bools.end_node && config_.label_bools_status.end_node_activated) || label_bools.terminated || + (!config_.label_bools_status.termination_activated && !config_.label_bools_status.end_node_activated && + Whitelisted(label_bools.whitelisted))); +} + +bool Path::PathHelper::ContinueExpanding(const LabelBools &label_bools, size_t path_size) const { + return (static_cast(path_size) <= config_.max_hops && !label_bools.blacklisted && !label_bools.terminated && + (label_bools.end_node || Whitelisted(label_bools.whitelisted))); +} + +bool Path::PathHelper::PathSizeOk(const int64_t path_size) const { + return (path_size <= config_.max_hops) && (path_size >= config_.min_hops); +} + +bool Path::PathHelper::PathTooBig(const int64_t path_size) const { return path_size > config_.max_hops; } + +bool Path::PathHelper::Whitelisted(const bool whitelisted) const { + return (config_.label_bools_status.whitelist_empty || whitelisted); +} + +void Path::PathHelper::FilterLabelBoolStatus() { + config_.label_bools_status.end_node_activated = !config_.label_sets.end_list.empty(); + config_.label_bools_status.whitelist_empty = config_.label_sets.whitelist.empty(); + config_.label_bools_status.termination_activated = !config_.label_sets.termination_list.empty(); +} + +/*function to set appropriate parameters for filtering*/ +void Path::PathHelper::FilterLabel(std::string_view label, LabelBools &label_bools) const { + if (config_.label_sets.blacklist.contains(label)) { + label_bools.blacklisted = true; + } + + if (config_.label_sets.termination_list.contains(label)) { + label_bools.terminated = true; + } + + if (config_.label_sets.end_list.contains(label)) { + label_bools.end_node = true; + } + + if (config_.label_sets.whitelist.contains(label)) { + label_bools.whitelisted = true; + } +} + +// Function that takes input list of labels, and sorts them into appropriate category +// sets were used so when filtering is done, its done in O(1) +void Path::PathHelper::ParseLabels(const mgp::List &list_of_labels) { + for (const auto &label : list_of_labels) { + std::string_view label_string = label.ValueString(); + const char first_elem = label_string.front(); + switch (first_elem) { + case '-': + label_string.remove_prefix(1); + config_.label_sets.blacklist.insert(label_string); + break; + case '>': + label_string.remove_prefix(1); + config_.label_sets.end_list.insert(label_string); + break; + case '+': + label_string.remove_prefix(1); + config_.label_sets.whitelist.insert(label_string); + break; + case '/': + label_string.remove_prefix(1); + config_.label_sets.termination_list.insert(label_string); + break; + default: + config_.label_sets.whitelist.insert(label_string); + break; + } + } +} + +// Function that takes input list of relationships, and sorts them into appropriate categories +// sets were also used to reduce complexity +void Path::PathHelper::ParseRelationships(const mgp::List &list_of_relationships) { + if (list_of_relationships.Size() == + 0) { // if no relationships were passed as arguments, all relationships are allowed + config_.any_outgoing = true; + config_.any_incoming = true; + return; + } + + for (const auto &rel : list_of_relationships) { + std::string rel_type{std::string(rel.ValueString())}; + bool starts_with = rel_type.starts_with('<'); + bool ends_with = rel_type.ends_with('>'); + + if (rel_type.size() == 1) { + if (starts_with) { + config_.any_incoming = true; + } else if (ends_with) { + config_.any_outgoing = true; + } else { + config_.relationship_sets[rel_type] = RelDirection::kAny; + } + continue; + } + + if (starts_with && ends_with) { // + config_.relationship_sets[rel_type.substr(1, rel_type.size() - 2)] = RelDirection::kBoth; + } else if (starts_with) { // + config_.relationship_sets[rel_type.substr(0, rel_type.size() - 1)] = RelDirection::kOutgoing; + } else { // type + config_.relationship_sets[rel_type] = RelDirection::kAny; + } + } +} + +void Path::Elements(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard(memory); + const auto arguments = mgp::List(args); + auto result = mgp::Result(res); + + try { + const auto path{arguments[0].ValuePath()}; + size_t path_length = path.Length(); + mgp::List split_path(path_length * 2 + 1); + for (int i = 0; i < path_length; ++i) { + split_path.Append(mgp::Value(path.GetNodeAt(i))); + split_path.Append(mgp::Value(path.GetRelationshipAt(i))); + } + split_path.Append(mgp::Value(path.GetNodeAt(path.Length()))); + result.SetValue(std::move(split_path)); + + } catch (const std::exception &e) { + result.SetErrorMessage(e.what()); + } +} + +void Path::Combine(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard(memory); + const auto arguments = mgp::List(args); + auto result = mgp::Result(res); + + try { + auto path1{arguments[0].ValuePath()}; + const auto path2{arguments[1].ValuePath()}; + + for (int i = 0; i < path2.Length(); ++i) { + // Expand will throw an exception if it can't connect + path1.Expand(path2.GetRelationshipAt(i)); + } + + result.SetValue(std::move(path1)); + + } catch (const std::exception &e) { + result.SetErrorMessage(e.what()); + } +} + +void Path::Slice(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard(memory); + const auto arguments = mgp::List(args); + auto result = mgp::Result(res); + + try { + const auto path{arguments[0].ValuePath()}; + const auto offset{arguments[1].ValueInt()}; + const auto length{arguments[2].ValueInt()}; + + mgp::Path new_path{path.GetNodeAt(offset)}; + size_t old_path_length = path.Length(); + size_t max_iteration = std::min((length == -1 ? old_path_length : offset + length), old_path_length); + for (int i = static_cast(offset); i < max_iteration; ++i) { + new_path.Expand(path.GetRelationshipAt(i)); + } + + result.SetValue(std::move(new_path)); + + } catch (const std::exception &e) { + result.SetErrorMessage(e.what()); + } +} + void Path::Create(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -58,391 +312,221 @@ void Path::Create(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, } } -bool Path::PathSizeOk(const int64_t path_size, const int64_t &max_hops, const int64_t &min_hops) { - return (path_size + 1 <= max_hops) && (path_size + 1 >= min_hops); +void Path::PathExpand::ExpandPath(mgp::Path &path, const mgp::Relationship &relationship, int64_t path_size) { + path.Expand(relationship); + path_data_.visited_.insert(relationship.Id().AsInt()); + DFS(path, path_size + 1); + path_data_.visited_.erase(relationship.Id().AsInt()); + path.Pop(); } -bool Path::Whitelisted(const bool &whitelisted, const bool &whitelist_empty) { - return (whitelisted || whitelist_empty); -} -bool Path::ShouldExpand(const LabelBools &labelBools, const LabelBoolsStatus &labelStatus) { - return !labelBools.blacklisted && ((labelBools.end_node && labelStatus.end_node_activated) || labelBools.terminated || - (!labelStatus.termination_activated && !labelStatus.end_node_activated && - Whitelisted(labelBools.whitelisted, labelStatus.whitelist_empty))); -} -void Path::FilterLabelBoolStatus(const LabelSets &labelSets, LabelBoolsStatus &labelStatus) { - if (labelSets.end_list.size() != 0) { // end node is activated, which means only paths ending with it can be saved as - // result, but they can be expanded further - labelStatus.end_node_activated = true; - } - if (labelSets.whitelist.size() == 0) { // whitelist is empty, which means all nodes are whitelisted - labelStatus.whitelist_empty = true; - } - - if (labelSets.termination_list.size() != 0) { - labelStatus.termination_activated = true; // there is a termination node, so only paths ending with it are allowed - } -} +void Path::PathExpand::ExpandFromRelationships(mgp::Path &path, mgp::Relationships relationships, bool outgoing, + int64_t path_size, + std::set> &seen) { + for (const auto relationship : relationships) { + auto type = std::string(relationship.Type()); + auto wanted_direction = path_data_.helper_.GetDirection(type); -bool Path::RelationshipAllowed(const std::string &rel_type, const RelationshipSets &relationshipSets, - bool &any_outgoing, bool &any_incoming, bool outgoing) { - if (outgoing) { // for outgoing rels - if (!any_outgoing && (relationshipSets.outgoing_rel.find(rel_type) == relationshipSets.outgoing_rel.end()) && - (relationshipSets.any_rel.find(rel_type) == - relationshipSets.any_rel.end())) { // check if relationship is allowed or all relationships are allowed - return false; + if ((wanted_direction == RelDirection::kNone && !path_data_.helper_.AnyDirected(outgoing)) || + path_data_.visited_.contains(relationship.Id().AsInt())) { + continue; } - } else { // incoming rels - if (!any_incoming && (relationshipSets.incoming_rel.find(rel_type) == relationshipSets.incoming_rel.end()) && - (relationshipSets.any_rel.find(rel_type) == relationshipSets.any_rel.end())) { // check if rel allowed - return false; + RelDirection curr_direction = outgoing ? RelDirection::kOutgoing : RelDirection::kIncoming; + + if (wanted_direction == RelDirection::kAny || curr_direction == wanted_direction || + path_data_.helper_.AnyDirected(outgoing)) { + ExpandPath(path, relationship, path_size); + } else if (wanted_direction == RelDirection::kBoth) { + if (outgoing && seen.contains({type, relationship.To().Id().AsInt()})) { + ExpandPath(path, relationship, path_size); + } else { + seen.insert({type, relationship.From().Id().AsInt()}); + } } } - return true; } -/*function to set appropriate parameters for filtering*/ -void Path::FilterLabel(const std::string_view label, const LabelSets &labelSets, LabelBools &labelBools) { - if (labelSets.blacklist.find(label) != labelSets.blacklist.end()) { // if label is blacklisted - labelBools.blacklisted = true; - } - if (labelSets.termination_list.find(label) != labelSets.termination_list.end()) { // if label is termination label - labelBools.terminated = true; - } +/*function used for traversal and filtering*/ +void Path::PathExpand::DFS(mgp::Path &path, int64_t path_size) { + const mgp::Node node{path.GetNodeAt(path_size)}; - if (labelSets.end_list.find(label) != labelSets.end_list.end()) { // if label is end label - labelBools.end_node = true; + LabelBools label_bools = path_data_.helper_.GetLabelBools(node); + if (path_data_.helper_.PathSizeOk(path_size) && path_data_.helper_.AreLabelsValid(label_bools)) { + auto record = path_data_.record_factory_.NewRecord(); + record.Insert(std::string(kResultExpand).c_str(), path); } - if (labelSets.whitelist.find(label) != labelSets.whitelist.end()) { // if label is whitelisted - labelBools.whitelisted = true; + if (!path_data_.helper_.ContinueExpanding(label_bools, path_size + 1)) { + return; } -} -/*function that takes input list of labels, and sorts them into appropriate category -sets were used so when filtering is done, its done in O(1)*/ -void Path::ParseLabels(const mgp::List &list_of_labels, LabelSets &labelSets) { - for (const auto label : list_of_labels) { - std::string_view label_string = label.ValueString(); - const char first_elem = label_string.front(); - switch (first_elem) { - case '-': - label_string.remove_prefix(1); - labelSets.blacklist.insert(label_string); - break; - case '>': - label_string.remove_prefix(1); - labelSets.end_list.insert(label_string); - break; - case '+': - label_string.remove_prefix(1); - labelSets.whitelist.insert(label_string); - break; - case '/': - label_string.remove_prefix(1); - labelSets.termination_list.insert(label_string); - break; - default: - labelSets.whitelist.insert(label_string); - break; - } - } + std::set> seen; + this->ExpandFromRelationships(path, node.InRelationships(), false, path_size, seen); + this->ExpandFromRelationships(path, node.OutRelationships(), true, path_size, seen); } -/*function that takes input list of relationships, and sorts them into appropriate categories -sets were also used to reduce complexity*/ -void Path::ParseRelationships(const mgp::List &list_of_relationships, RelationshipSets &relationshipSets, - bool &any_outgoing, bool &any_incoming) { - if (list_of_relationships.Size() == - 0) { // if no relationships were passed as arguments, all relationships are allowed - any_outgoing = true; - any_incoming = true; - return; - } - for (const auto rel : list_of_relationships) { - std::string rel_type = std::string(rel.ValueString()); - const size_t size = rel_type.size(); - const char first_elem = rel_type[0]; - const char last_elem = rel_type[size - 1]; - if (first_elem == '<' && last_elem == '>') { - throw mgp::ValueException("Wrong relationship format => is not allowed!"); - } else if (first_elem == '<' && size == 1) { - any_incoming = true; // all incoming relatiomships are allowed - } else if (first_elem == '<' && size != 1) { - relationshipSets.incoming_rel.insert(rel_type.erase(0, 1)); // only specified incoming relationships are allowed - } else if (last_elem == '>' && size == 1) { - any_outgoing = true; // all outgoing relationships are allowed - - } else if (last_elem == '>' && size != 1) { - rel_type.pop_back(); - relationshipSets.outgoing_rel.insert(rel_type); // only specifed outgoing relationships are allowed - } else { // if not specified, a relationship goes both ways - relationshipSets.any_rel.insert(rel_type); - } - } +void Path::PathExpand::StartAlgorithm(const mgp::Node node) { + mgp::Path path = mgp::Path(node); + DFS(path, 0); } -void Path::DfsByDirection(mgp::Path &path, std::unordered_set &relationships_set, - const mgp::RecordFactory &record_factory, int64_t path_size, const int64_t min_hops, - const int64_t max_hops, const LabelSets &labelSets, const LabelBoolsStatus &labelStatus, - const RelationshipSets &relationshipSets, bool &any_outgoing, bool &any_incoming, - bool outgoing) { - const mgp::Node &node = path.GetNodeAt(path_size); // get latest node in path, and expand on it - - mgp::Relationships rels = outgoing ? node.OutRelationships() : node.InRelationships(); - for (auto rel : rels) { - // go through every relationship of the node and expand to the other node of the relationship - if (relationships_set.find(rel) != - relationships_set.end()) { // relationships_set contains all relationships already visited in this path, and - // the usage of this if loop is to evade cycles - continue; - } - mgp::Path cpy = mgp::Path(path); - const std::string rel_type = std::string(rel.Type()); - bool rel_allowed = outgoing ? RelationshipAllowed(rel_type, relationshipSets, any_outgoing, any_incoming, true) - : RelationshipAllowed(rel_type, relationshipSets, any_outgoing, any_incoming, false); - if (!rel_allowed) { // if relationship not allowed, go to next one - continue; - } - cpy.Expand(rel); // expand the path with this relationships - std::unordered_set relationships_set_cpy = relationships_set; - relationships_set_cpy.insert(rel); // insert the relationship into visited relationships - - /*this part is for label filtering*/ - LabelBools labelBools; - mgp::Labels labels = outgoing ? rel.To().Labels() : rel.From().Labels(); - for (auto label : labels) { // set booleans to their value for the label of the finish node - FilterLabel(label, labelSets, labelBools); - } - - if (PathSizeOk(path_size, max_hops, min_hops) && ShouldExpand(labelBools, labelStatus)) { - auto record = record_factory.NewRecord(); - record.Insert(std::string(std::string(kResultExpand).c_str()).c_str(), cpy); - } - if (path_size + 1 < max_hops && !labelBools.blacklisted && !labelBools.terminated && - (labelBools.end_node || Whitelisted(labelBools.whitelisted, labelStatus.whitelist_empty))) { - PathDFS(cpy, relationships_set_cpy, record_factory, path_size + 1, min_hops, max_hops, labelSets, labelStatus, - relationshipSets, any_outgoing, any_incoming); - } +void Path::PathExpand::Parse(const mgp::Value &value) { + if (value.IsNode()) { + path_data_.start_nodes_.insert((value.ValueNode())); + } else if (value.IsInt()) { + path_data_.start_nodes_.insert((path_data_.graph_.GetNodeById(mgp::Id::FromInt(value.ValueInt())))); + } else { + throw mgp::ValueException("Invalid start type. Expected Node, Int, List[Node, Int]"); } } -/*function used for traversal and filtering*/ -void Path::PathDFS(mgp::Path path, std::unordered_set &relationships_set, - const mgp::RecordFactory &record_factory, int64_t path_size, const int64_t min_hops, - const int64_t max_hops, const LabelSets &labelSets, const LabelBoolsStatus &labelStatus, - const RelationshipSets &relationshipSets, bool &any_outgoing, bool &any_incoming) { - DfsByDirection(path, relationships_set, record_factory, path_size, min_hops, max_hops, labelSets, labelStatus, - relationshipSets, any_outgoing, any_incoming, true); - DfsByDirection(path, relationships_set, record_factory, path_size, min_hops, max_hops, labelSets, labelStatus, - relationshipSets, any_outgoing, any_incoming, false); -} - -void Path::StartFunction(const mgp::Node &node, const mgp::RecordFactory &record_factory, int64_t path_size, - const int64_t min_hops, const int64_t max_hops, const LabelSets &labelSets, - const LabelBoolsStatus &labelStatus, const RelationshipSets &relationshipSets, - bool &any_outgoing, bool &any_incoming) { - mgp::Path path = mgp::Path(node); - std::unordered_set relationships_set; - PathDFS(path, relationships_set, record_factory, 0, min_hops, max_hops, labelSets, labelStatus, relationshipSets, - any_outgoing, any_incoming); +void Path::PathExpand::RunAlgorithm() { + for (const auto &node : path_data_.start_nodes_) { + StartAlgorithm(node); + } } void Path::Expand(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { - mgp::Graph graph = mgp::Graph(memgraph_graph); + auto graph = mgp::Graph(memgraph_graph); const mgp::Value start_value = arguments[0]; - mgp::List relationships = arguments[1].ValueList(); - const mgp::List labels = arguments[2].ValueList(); - int64_t min_hops = arguments[3].ValueInt(); - int64_t max_hops = arguments[4].ValueInt(); - - /*filter label part*/ - LabelSets labelSets; - LabelBoolsStatus labelStatus; - ParseLabels(labels, labelSets); - FilterLabelBoolStatus(labelSets, labelStatus); - /*end filter label part*/ - - /*filter relationships part*/ - RelationshipSets relationshipSets; - bool any_outgoing = false; - bool any_incoming = false; - ParseRelationships(relationships, relationshipSets, any_outgoing, any_incoming); - /*end filter relationships part*/ - - if (start_value.IsNode()) { - StartFunction(start_value.ValueNode(), record_factory, 0, min_hops, max_hops, labelSets, labelStatus, - relationshipSets, any_outgoing, any_incoming); - } else if (start_value.IsInt()) { - StartFunction(graph.GetNodeById(mgp::Id::FromInt(start_value.ValueInt())), record_factory, 0, min_hops, max_hops, - labelSets, labelStatus, relationshipSets, any_outgoing, any_incoming); - } else if (start_value.IsList()) { - for (const auto value : start_value.ValueList()) { - if (value.IsNode()) { - StartFunction(value.ValueNode(), record_factory, 0, min_hops, max_hops, labelSets, labelStatus, - relationshipSets, any_outgoing, any_incoming); - - } else if (value.IsInt()) { - StartFunction(graph.GetNodeById(mgp::Id::FromInt(value.ValueInt())), record_factory, 0, min_hops, max_hops, - labelSets, labelStatus, relationshipSets, any_outgoing, any_incoming); - } else { - throw mgp::ValueException("Invalid start type. Expected Node, Int, List[Node, Int]"); - } - } + mgp::List relationships{arguments[1].ValueList()}; + const mgp::List labels{arguments[2].ValueList()}; + int64_t min_hops{arguments[3].ValueInt()}; + int64_t max_hops{arguments[4].ValueInt()}; + + PathExpand path_expand{PathData(PathHelper{labels, relationships, min_hops, max_hops}, record_factory, graph)}; + + if (!start_value.IsList()) { + path_expand.Parse(start_value); } else { - throw mgp::ValueException("Invalid start type. Expected Node, Int, List[Node, Int]"); + for (const auto &list_item : start_value.ValueList()) { + path_expand.Parse(list_item); + } } + path_expand.RunAlgorithm(); + } catch (const std::exception &e) { record_factory.SetErrorMessage(e.what()); return; } } -void GetStartNodes(const mgp::Value element, const mgp::Graph &graph, std::unordered_set &start_nodes) { - if (!(element.IsNode() || element.IsInt())) { +void Path::PathSubgraph::Parse(const mgp::Value &value) { + if (!(value.IsNode() || value.IsInt())) { throw mgp::ValueException("The first argument needs to be a node, an integer ID, or a list thereof."); } - if (element.IsNode()) { - start_nodes.insert(element.ValueNode()); + if (value.IsNode()) { + path_data_.start_nodes_.insert(value.ValueNode()); return; } - start_nodes.insert(graph.GetNodeById(mgp::Id::FromInt(element.ValueInt()))); + path_data_.start_nodes_.insert(path_data_.graph_.GetNodeById(mgp::Id::FromInt(value.ValueInt()))); } -bool RelFilterAllows(const mgp::Map &config, std::string_view type, bool ingoing) { - mgp::List list_of_types = config.At("relationshipFilter").ValueList(); - if (list_of_types.Size() == 0) { - return true; - } - for (const auto element : list_of_types) { - auto string_rel_type = element.ValueString(); - if (string_rel_type.front() == '<' && ingoing) { - string_rel_type.remove_prefix(1); - } - if (string_rel_type.back() == '>' && !ingoing) { - string_rel_type.remove_suffix(1); - } - if (string_rel_type == type || string_rel_type.size() == 0) { - return true; +void Path::PathSubgraph::ExpandFromRelationships(const std::pair &pair, + const mgp::Relationships relationships, bool outgoing, + std::queue> &queue, + std::set> &seen) { + for (const auto relationship : relationships) { + auto next_node = outgoing ? relationship.To() : relationship.From(); + auto type = std::string(relationship.Type()); + auto wanted_direction = path_data_.helper_.GetDirection(type); + + if (path_data_.helper_.IsNotStartOrSupportsStartRel(pair.second == 0)) { + if ((wanted_direction == RelDirection::kNone && !path_data_.helper_.AnyDirected(outgoing)) || + path_data_.visited_.contains(next_node.Id().AsInt())) { + continue; + } } - } - return false; -} -bool IsLabelListed(const mgp::Node node, std::unordered_set &set) { - for (const auto label : node.Labels()) { - if (set.contains(label)) { - return true; + RelDirection curr_direction = outgoing ? RelDirection::kOutgoing : RelDirection::kIncoming; + + if (wanted_direction == RelDirection::kAny || curr_direction == wanted_direction || + path_data_.helper_.AnyDirected(outgoing)) { + path_data_.visited_.insert(next_node.Id().AsInt()); + queue.push({next_node, pair.second + 1}); + } else if (wanted_direction == RelDirection::kBoth) { + if (outgoing && seen.contains({type, relationship.To().Id().AsInt()})) { + path_data_.visited_.insert(next_node.Id().AsInt()); + queue.push({next_node, pair.second + 1}); + to_be_returned_nodes_.AppendExtend(mgp::Value{next_node}); + } else { + seen.insert({type, relationship.From().Id().AsInt()}); + } } } - return false; } -void Path::VisitNode(const mgp::Node node, std::map &visited_nodes, bool is_start, - const mgp::Map &config, int64_t hop_count, Path::LabelSets &labelFilterSets, - mgp::List &to_be_returned_nodes) { - if (config.At("maxLevel").ValueInt() != -1 && hop_count > config.At("maxLevel").ValueInt()) { - return; - } - if (config.At("filterStartNode").ValueBool() || !is_start) { - if ((IsLabelListed(node, labelFilterSets.blacklist)) || - (!labelFilterSets.whitelist.empty() && !IsLabelListed(node, labelFilterSets.whitelist) && - !IsLabelListed(node, labelFilterSets.end_list) && !IsLabelListed(node, labelFilterSets.termination_list))) { - return; - } - } - try { - if (visited_nodes.at(node) <= hop_count) { - return; +void Path::PathSubgraph::TryInsertNode(const mgp::Node &node, int64_t hop_count, LabelBools &label_bools) { + if (path_data_.helper_.IsNotStartOrSupportsStartNode(hop_count == 0)) { + if (path_data_.helper_.AreLabelsValid(label_bools)) { + to_be_returned_nodes_.AppendExtend(mgp::Value(node)); } - } catch (const std::out_of_range &e) { - // it's okay, the node is not in visited nodes map - if (!is_start || config.At("minLevel").ValueInt() != 1) { - if ((labelFilterSets.end_list.empty() && labelFilterSets.termination_list.empty()) || - IsLabelListed(node, labelFilterSets.end_list) || IsLabelListed(node, labelFilterSets.termination_list)) { - to_be_returned_nodes.AppendExtend(mgp::Value(node)); - } - } - } - visited_nodes.insert({node, hop_count}); - if (IsLabelListed(node, labelFilterSets.termination_list)) { return; } - for (const auto in_rel : node.InRelationships()) { - if (RelFilterAllows(config, in_rel.Type(), true)) { - VisitNode(in_rel.From(), visited_nodes, false, config, hop_count + 1, labelFilterSets, to_be_returned_nodes); - } - } - for (const auto out_rel : node.OutRelationships()) { - if (RelFilterAllows(config, out_rel.Type(), false)) { - VisitNode(out_rel.To(), visited_nodes, false, config, hop_count + 1, labelFilterSets, to_be_returned_nodes); - } + + if (!path_data_.visited_.contains(node.Id().AsInt())) { + to_be_returned_nodes_.AppendExtend(mgp::Value(node)); } } -void SetConfig(mgp::Map &config) { - auto value = config.At("maxLevel"); - if (value.IsNull()) { - config.Insert("maxLevel", mgp::Value(int64_t(-1))); - } - value = config.At("relationshipFilter"); - if (value.IsNull()) { - config.Insert("relationshipFilter", mgp::Value(mgp::List())); - } - value = config.At("labelFilter"); - if (value.IsNull()) { - config.Insert("labelFilter", mgp::Value(mgp::List())); - } - value = config.At("filterStartNode"); - if (value.IsNull()) { - config.Insert("filterStartNode", mgp::Value(false)); - } - value = config.At("minLevel"); - if (value.IsNull()) { - config.Insert("minLevel", mgp::Value(int64_t(0))); +mgp::List Path::PathSubgraph::BFS() { + std::queue> queue; + std::unordered_set visited; + + for (const auto &node : path_data_.start_nodes_) { + queue.push({node, 0}); + visited.insert(node.Id().AsInt()); } - if (!(config.At("minLevel").IsInt() && config.At("maxLevel").IsInt() && config.At("relationshipFilter").IsList() && - config.At("labelFilter").IsList() && config.At("filterStartNode").IsBool()) || - (config.At("minLevel").ValueInt() != 0 && config.At("minLevel").ValueInt() != 1)) { - throw mgp::ValueException( - "The config parameter needs to be a map with keys and values in line with the documentation."); + + while (!queue.empty()) { + auto pair = queue.front(); + queue.pop(); + + if (path_data_.helper_.PathTooBig(pair.second)) { + continue; + } + + LabelBools label_bools = path_data_.helper_.GetLabelBools(pair.first); + TryInsertNode(pair.first, pair.second, label_bools); + if (!path_data_.helper_.ContinueExpanding(label_bools, pair.second + 1)) { + continue; + } + + std::set> seen; + this->ExpandFromRelationships(pair, pair.first.InRelationships(), false, queue, seen); + this->ExpandFromRelationships(pair, pair.first.OutRelationships(), true, queue, seen); } + + return to_be_returned_nodes_; } void Path::SubgraphNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); try { auto config = arguments[1].ValueMap(); - SetConfig(config); + PathSubgraph path_subgraph{PathData(PathHelper{config}, record_factory, graph)}; - std::unordered_set start_nodes; - if (arguments[0].IsList()) { - for (const auto element : arguments[0].ValueList()) { - GetStartNodes(element, graph, start_nodes); - } + auto start_value = arguments[0]; + if (!start_value.IsList()) { + path_subgraph.Parse(start_value); } else { - GetStartNodes(arguments[0], graph, start_nodes); + for (const auto &list_item : start_value.ValueList()) { + path_subgraph.Parse(list_item); + } } - LabelSets labelFilterSets; - ParseLabels(config.At("labelFilter").ValueList(), labelFilterSets); + auto to_be_returned_nodes = path_subgraph.BFS(); - std::map visited_nodes; - mgp::List to_be_returned_nodes; - for (const auto node : start_nodes) { - VisitNode(node, visited_nodes, true, config, 0, labelFilterSets, to_be_returned_nodes); - } - - for (auto node : to_be_returned_nodes) { + for (const auto &node : to_be_returned_nodes) { auto record = record_factory.NewRecord(); record.Insert(std::string(kResultSubgraphNodes).c_str(), node); } @@ -454,36 +538,30 @@ void Path::SubgraphNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result * } void Path::SubgraphAll(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); const auto graph = mgp::Graph(memgraph_graph); const auto record_factory = mgp::RecordFactory(result); try { auto config = arguments[1].ValueMap(); - SetConfig(config); + PathSubgraph path_subgraph{PathData(PathHelper{config}, record_factory, graph)}; - std::unordered_set start_nodes; - if (arguments[0].IsList()) { - for (const auto element : arguments[0].ValueList()) { - GetStartNodes(element, graph, start_nodes); - } + auto start_value = arguments[0]; + if (!start_value.IsList()) { + path_subgraph.Parse(start_value); } else { - GetStartNodes(arguments[0], graph, start_nodes); + for (const auto &list_item : start_value.ValueList()) { + path_subgraph.Parse(list_item); + } } - LabelSets labelFilterSets; - ParseLabels(config.At("labelFilter").ValueList(), labelFilterSets); - - std::map visited_nodes; - mgp::List to_be_returned_nodes; - for (const auto node : start_nodes) { - VisitNode(node, visited_nodes, true, config, 0, labelFilterSets, to_be_returned_nodes); - } + const auto to_be_returned_nodes = path_subgraph.BFS(); std::unordered_set to_be_returned_nodes_searchable; - for (auto node : to_be_returned_nodes) { - to_be_returned_nodes_searchable.insert(node.ValueNode()); - } + + std::transform(to_be_returned_nodes.begin(), to_be_returned_nodes.end(), + std::inserter(to_be_returned_nodes_searchable, to_be_returned_nodes_searchable.begin()), + [](const mgp::Value &node) { return node.ValueNode(); }); mgp::List to_be_returned_rels; for (auto node : to_be_returned_nodes) { diff --git a/cpp/path_module/algorithm/path.hpp b/cpp/path_module/algorithm/path.hpp index 0e3ca7d1d..c724a43e1 100644 --- a/cpp/path_module/algorithm/path.hpp +++ b/cpp/path_module/algorithm/path.hpp @@ -2,11 +2,27 @@ #include +#include #include #include namespace Path { +/* elements constants */ +constexpr const std::string_view kProcedureElements = "elements"; +constexpr const std::string_view kElementsArg1 = "path"; + +/* combine constants */ +constexpr const std::string_view kProcedureCombine = "combine"; +constexpr const std::string_view kCombineArg1 = "first"; +constexpr const std::string_view kCombineArg2 = "second"; + +/* slice constants */ +constexpr const std::string_view kProcedureSlice = "slice"; +constexpr const std::string_view kSliceArg1 = "path"; +constexpr const std::string_view kSliceArg2 = "offset"; +constexpr const std::string_view kSliceArg3 = "length"; + /* create constants */ constexpr const std::string_view kProcedureCreate = "create"; constexpr const std::string_view kCreateArg1 = "start_node"; @@ -44,64 +60,131 @@ struct LabelSets { }; struct LabelBools { + // no node in the path will be blacklisted bool blacklisted = false; + // returned paths end with a termination node but don't continue to be expanded further, + // takes precedence over end nodes bool terminated = false; + // returned paths end with an end node but continue to be expanded further bool end_node = false; + // all nodes in the path will be whitelisted (except end and termination nodes) + // end and termination nodes don't have to respect whitelists and blacklists bool whitelisted = false; }; struct LabelBoolsStatus { + // true if there is an end node -> only paths ending with it can be saved as result, + // but they can be expanded further bool end_node_activated = false; + // true if no whitelist is given -> all nodes are whitelisted bool whitelist_empty = false; + // true if there is a termination node -> only paths ending with it are allowed bool termination_activated = false; }; -struct RelationshipSets { - std::unordered_set outgoing_rel; - std::unordered_set incoming_rel; - std::unordered_set any_rel; +enum class RelDirection { kNone = -1, kAny = 0, kIncoming = 1, kOutgoing = 2, kBoth = 3 }; + +struct Config { + LabelBoolsStatus label_bools_status; + std::unordered_map relationship_sets; + LabelSets label_sets; + int64_t min_hops = 0; + int64_t max_hops = std::numeric_limits::max(); + bool any_incoming = false; + bool any_outgoing = false; + bool filter_start_node = true; + bool begin_sequence_at_start = true; + bool bfs = false; }; -void Create(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); +class PathHelper { + public: + explicit PathHelper(const mgp::List &labels, const mgp::List &relationships, int64_t min_hops, int64_t max_hops); + explicit PathHelper(const mgp::Map &config); -void FilterLabelBoolStatus(const LabelSets &labelSets, LabelBoolsStatus &labelStatus); + RelDirection GetDirection(const std::string &rel_type) const; + LabelBools GetLabelBools(const mgp::Node &node) const; -bool ShouldExpand(const LabelBools &labelBools, const LabelBoolsStatus &labelStatus); + bool AnyDirected(bool outgoing) const { return outgoing ? config_.any_outgoing : config_.any_incoming; } + bool IsNotStartOrSupportsStartNode(bool is_start) const { return (config_.filter_start_node || !is_start); } + bool IsNotStartOrSupportsStartRel(bool is_start) const { return (config_.begin_sequence_at_start || !is_start); } -void Expand(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); + bool AreLabelsValid(const LabelBools &label_bools) const; + bool ContinueExpanding(const LabelBools &label_bools, size_t path_size) const; -void FilterLabel(const std::string_view label, const LabelSets &labelFilters, LabelBools &labelBools); + bool PathSizeOk(int64_t path_size) const; + bool PathTooBig(int64_t path_size) const; + bool Whitelisted(bool whitelisted) const; -void ParseLabels(const mgp::List &list_of_labels, LabelSets &labelSets); + // methods for parsing config + void FilterLabelBoolStatus(); + void FilterLabel(std::string_view label, LabelBools &label_bools) const; + void ParseLabels(const mgp::List &list_of_labels); + void ParseRelationships(const mgp::List &list_of_relationships); -void ParseRelationships(const mgp::List &list_of_relationships, RelationshipSets &relationshipSets, bool &any_outgoing, - bool &any_incoming); -bool PathSizeOk(const int64_t path_size, const int64_t &max_hops, const int64_t &min_hops); + private: + Config config_; +}; -bool RelationshipAllowed(const std::string &rel_type, const RelationshipSets &relationshipSets, bool &any_outgoing, - bool &any_incoming, bool outgoing); +class PathData { + public: + friend class PathExpand; + friend class PathSubgraph; -bool Whitelisted(const bool &whitelisted, const bool &whitelist_empty); + explicit PathData(PathHelper &&helper, const mgp::RecordFactory &record_factory, const mgp::Graph &graph) + : helper_(std::move(helper)), record_factory_(record_factory), graph_(graph) {} -void PathDFS(mgp::Path path, std::unordered_set &relationships_set, - const mgp::RecordFactory &record_factory, int64_t path_size, const int64_t min_hops, - const int64_t max_hops, const LabelSets &labelFilters, const LabelBoolsStatus &labelStatus, - const RelationshipSets &relationshipSets, bool &any_outgoing, bool &any_incoming); + PathHelper helper_; + const mgp::RecordFactory &record_factory_; + const mgp::Graph &graph_; + std::unordered_set visited_; + std::unordered_set start_nodes_; +}; + +class PathExpand { + public: + explicit PathExpand(PathData &&path_data) : path_data_(std::move(path_data)) {} + + void ExpandPath(mgp::Path &path, const mgp::Relationship &relationship, int64_t path_size); + void ExpandFromRelationships(mgp::Path &path, mgp::Relationships relationships, bool outgoing, int64_t path_size, + std::set> &seen); + void StartAlgorithm(mgp::Node node); + void Parse(const mgp::Value &value); + void DFS(mgp::Path &path, int64_t path_size); + void RunAlgorithm(); + + private: + PathData path_data_; +}; -void DfsByDirection(mgp::Path &path, std::unordered_set &relationships_set, - const mgp::RecordFactory &record_factory, int64_t path_size, const int64_t min_hops, - const int64_t max_hops, const LabelSets &labelFilters, const LabelBoolsStatus &labelStatus, - const RelationshipSets &relationshipSets, bool &any_outgoing, bool &any_incoming, bool outgoing); +class PathSubgraph { + public: + explicit PathSubgraph(PathData &&path_data) : path_data_(std::move(path_data)) {} -void StartFunction(const mgp::Node &node, const mgp::RecordFactory &record_factory, int64_t path_size, - const int64_t min_hops, const int64_t max_hops, const LabelSets &labelSets, - const LabelBoolsStatus &labelStatus, const RelationshipSets &relationshipSets, bool &any_outgoing, - bool &any_incoming); + void ExpandFromRelationships(const std::pair &pair, mgp::Relationships relationships, + bool outgoing, std::queue> &queue, + std::set> &seen); + void Parse(const mgp::Value &value); + void TryInsertNode(const mgp::Node &node, int64_t hop_count, LabelBools &label_bools); + mgp::List BFS(); + + private: + PathData path_data_; + mgp::List to_be_returned_nodes_; +}; + +void Elements(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory); + +void Combine(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory); + +void Slice(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory); + +void Create(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); + +void Expand(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); void SubgraphNodes(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); + void SubgraphAll(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); -void VisitNode(const mgp::Node node, std::map &visited_nodes, bool is_start, - const mgp::Map &config, int64_t hop_count, Path::LabelSets &labelFilterSets, - mgp::List &to_be_returned_nodes); } // namespace Path diff --git a/cpp/path_module/path_module.cpp b/cpp/path_module/path_module.cpp index 237743df7..eb0de2e31 100644 --- a/cpp/path_module/path_module.cpp +++ b/cpp/path_module/path_module.cpp @@ -4,7 +4,22 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { try { - mgp::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; + + mgp::AddFunction(Path::Elements, Path::kProcedureElements, {mgp::Parameter(Path::kElementsArg1, mgp::Type::Path)}, + module, memory); + + mgp::AddFunction( + Path::Combine, Path::kProcedureCombine, + {mgp::Parameter(Path::kCombineArg1, mgp::Type::Path), mgp::Parameter(Path::kCombineArg2, mgp::Type::Path)}, + module, memory); + + mgp::AddFunction(Path::Slice, Path::kProcedureSlice, + {mgp::Parameter(Path::kSliceArg1, mgp::Type::Path), + mgp::Parameter(Path::kSliceArg2, mgp::Type::Int, static_cast(0)), + mgp::Parameter(Path::kSliceArg3, mgp::Type::Int, static_cast(-1))}, + module, memory); + AddProcedure( Path::Expand, std::string(Path::kProcedureExpand).c_str(), mgp::ProcedureType::Read, {mgp::Parameter(std::string(Path::kArgumentStartExpand).c_str(), mgp::Type::Any), diff --git a/e2e/path_test/test_elements_1/input.cyp b/e2e/path_test/test_elements_1/input.cyp new file mode 100644 index 000000000..2ebb0e8e5 --- /dev/null +++ b/e2e/path_test/test_elements_1/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {id: 1})-[:CONNECTED {id: 1}]->(:Node {id: 2})-[:CONNECTED {id: 2}]->(:Node {id: 3})-[:CONNECTED {id: 3}]->(:Node {id: 4})-[:CONNECTED {id: 4}]->(:Node {id: 5}); diff --git a/e2e/path_test/test_elements_1/test.yml b/e2e/path_test/test_elements_1/test.yml new file mode 100644 index 000000000..d2a84083c --- /dev/null +++ b/e2e/path_test/test_elements_1/test.yml @@ -0,0 +1,37 @@ +query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) RETURN + path.elements(path) AS result; +output: + - result: + - labels: + - Node + properties: + id: 1 + - label: CONNECTED + properties: + id: 1 + - labels: + - Node + properties: + id: 2 + - label: CONNECTED + properties: + id: 2 + - labels: + - Node + properties: + id: 3 + - label: CONNECTED + properties: + id: 3 + - labels: + - Node + properties: + id: 4 + - label: CONNECTED + properties: + id: 4 + - labels: + - Node + properties: + id: 5 diff --git a/e2e/path_test/test_elements_2/input.cyp b/e2e/path_test/test_elements_2/input.cyp new file mode 100644 index 000000000..01f3f5f8e --- /dev/null +++ b/e2e/path_test/test_elements_2/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {id: 1})<-[:CONNECTED {id: 1}]-(:Node {id: 2})-[:CONNECTED {id: 2}]->(:Node {id: 3})<-[:CONNECTED {id: 3}]-(:Node {id: 4})-[:CONNECTED {id: 4}]->(:Node {id: 5}); diff --git a/e2e/path_test/test_elements_2/test.yml b/e2e/path_test/test_elements_2/test.yml new file mode 100644 index 000000000..1a2b5336b --- /dev/null +++ b/e2e/path_test/test_elements_2/test.yml @@ -0,0 +1,37 @@ +query: > + MATCH path = (:Node {id: 1})<-[:CONNECTED*4]->(:Node {id: 5}) RETURN + path.elements(path) AS result; +output: + - result: + - labels: + - Node + properties: + id: 1 + - label: CONNECTED + properties: + id: 1 + - labels: + - Node + properties: + id: 2 + - label: CONNECTED + properties: + id: 2 + - labels: + - Node + properties: + id: 3 + - label: CONNECTED + properties: + id: 3 + - labels: + - Node + properties: + id: 4 + - label: CONNECTED + properties: + id: 4 + - labels: + - Node + properties: + id: 5 diff --git a/e2e/path_test/test_expand1/test.yml b/e2e/path_test/test_expand1/test.yml index d0868a07b..345a0e85d 100644 --- a/e2e/path_test/test_expand1/test.yml +++ b/e2e/path_test/test_expand1/test.yml @@ -1,7 +1,17 @@ query: > - MATCH (d:Dog) - CALL path.expand(d,["HUNTS>"],[],0,3) YIELD result RETURN result; - - + MATCH (d:Dog) CALL path.expand(d,["HUNTS>"],[],1,3) YIELD result RETURN + result; output: - - result: {'nodes': [{'labels': ['Dog'],'properties': {'name': 'Rex'}},{'labels': ['Cat'],'properties': {'name': 'Tom'}}],'relationships': [{'label': 'HUNTS','properties': {}}]} + - result: + nodes: + - labels: + - Dog + properties: + name: Rex + - labels: + - Cat + properties: + name: Tom + relationships: + - label: HUNTS + properties: {} diff --git a/e2e/path_test/test_expand2/test.yml b/e2e/path_test/test_expand2/test.yml index 09531bcdc..24822e83e 100644 --- a/e2e/path_test/test_expand2/test.yml +++ b/e2e/path_test/test_expand2/test.yml @@ -1,9 +1,54 @@ query: > - MATCH (d:Dog) - CALL path.expand(d,[],["-Human","/Cat"],0,3) YIELD result RETURN result; - - + MATCH (d:Dog) CALL path.expand(d,[],["-Human","/Cat"],0,3) YIELD result RETURN + result; output: - - result: {'nodes': [{'labels': ['Dog'],'properties': {'name': 'Rex'}},{'labels': ['Cat'],'properties': {'name': 'Tom'}}],'relationships': [{'label': 'HUNTS','properties': {}}]} - - result: {'nodes': [{'labels': ['Dog'],'properties': {'name': 'Rex'}},{'labels': ['Cat'],'properties': {'name': 'Rinko'}}],'relationships': [{'label': 'BEST_FRIENDS','properties': {}}]} - - result: {'nodes': [{'labels': ['Dog'], 'properties': {'name': 'Rex'}}, {'labels': ['Zadar'], 'properties': {}}, {'labels': ['Mouse'], 'properties': {'name': 'Squiggles'}}, {'labels': ['Cat'],'properties': {'name': 'Tom'}}],'relationships': [{'label': 'LIVES', 'properties': {}}, {'label': 'RUNS_THROUGH','properties': {}},{'label': 'CATCHES','properties': {}}]} + - result: + nodes: + - labels: + - Dog + properties: + name: Rex + - labels: + - Cat + properties: + name: Tom + relationships: + - label: HUNTS + properties: {} + - result: + nodes: + - labels: + - Dog + properties: + name: Rex + - labels: + - Cat + properties: + name: Rinko + relationships: + - label: BEST_FRIENDS + properties: {} + - result: + nodes: + - labels: + - Dog + properties: + name: Rex + - labels: + - Zadar + properties: {} + - labels: + - Mouse + properties: + name: Squiggles + - labels: + - Cat + properties: + name: Tom + relationships: + - label: LIVES + properties: {} + - label: RUNS_THROUGH + properties: {} + - label: CATCHES + properties: {} diff --git a/e2e/path_test/test_expand3/test.yml b/e2e/path_test/test_expand3/test.yml index 906cbfafb..55e52c68f 100644 --- a/e2e/path_test/test_expand3/test.yml +++ b/e2e/path_test/test_expand3/test.yml @@ -1,7 +1,28 @@ query: > - MATCH (d:Dog) - CALL path.expand(d,[">","Zadar","/Human"],3,3) YIELD result RETURN result; - - + MATCH (d:Dog) CALL path.expand(d,[">","Zadar","/Human"],3,3) YIELD + result RETURN result; output: - - result: {'nodes': [{'labels': ['Dog'],'properties': {'name': 'Rex'}},{'labels': ['Cat'],'properties': {'name': 'Tom'}},{'labels': ['Mouse'],'properties': {'name': 'Squiggles'}},{'labels': ['Zadar'],'properties': {}}],'relationships': [{'label': 'HUNTS','properties': {}},{'label': 'CATCHES','properties': {}},{'label': 'RUNS_THROUGH', 'properties': {}}]} + - result: + nodes: + - labels: + - Dog + properties: + name: Rex + - labels: + - Cat + properties: + name: Tom + - labels: + - Mouse + properties: + name: Squiggles + - labels: + - Zadar + properties: {} + relationships: + - label: HUNTS + properties: {} + - label: CATCHES + properties: {} + - label: RUNS_THROUGH + properties: {} diff --git a/e2e/path_test/test_expand4/test.yml b/e2e/path_test/test_expand4/test.yml index d7ac17a95..70240e149 100644 --- a/e2e/path_test/test_expand4/test.yml +++ b/e2e/path_test/test_expand4/test.yml @@ -1,7 +1,5 @@ query: > - MATCH (d:Dog), (h:Human) - CALL path.expand([d,id(h)],[],[],1,10) YIELD result RETURN count(result) AS count; - - + MATCH (d:Dog), (h:Human) CALL path.expand([d,id(h)],[],[],1,10) YIELD result + RETURN count(result) AS count; output: - - count: 142 + - count: 142 diff --git a/e2e/path_test/test_subgraph_all_1/test.yml b/e2e/path_test/test_subgraph_all_1/test.yml index 3dbf02f48..dd7a5e6b3 100644 --- a/e2e/path_test/test_subgraph_all_1/test.yml +++ b/e2e/path_test/test_subgraph_all_1/test.yml @@ -9,6 +9,10 @@ query: > output: - nodes: + - labels: + - Operations + properties: + name: Jill - labels: - Research properties: @@ -17,10 +21,6 @@ output: - Operations properties: name: Steve - - labels: - - Operations - properties: - name: Jill rels: - label: FOLLOWS properties: {} diff --git a/e2e/path_test/test_subgraph_all_2/test.yml b/e2e/path_test/test_subgraph_all_2/test.yml index 769ce629d..8953f1f72 100644 --- a/e2e/path_test/test_subgraph_all_2/test.yml +++ b/e2e/path_test/test_subgraph_all_2/test.yml @@ -2,8 +2,8 @@ query: > MATCH (p:Strategy {name: "Amber"}) CALL path.subgraph_all(p, { relationshipFilter: [">"], - minLevel: 0, - maxLevel: 2 + minHops: 0, + maxHops: 2 }) YIELD nodes, rels RETURN nodes, rels; @@ -22,6 +22,10 @@ output: - Operations properties: name: Jill + - labels: + - Support + properties: + name: Jackson - labels: - Research properties: @@ -34,10 +38,6 @@ output: - Analytics properties: name: Zack - - labels: - - Support - properties: - name: Jackson - labels: - Support properties: @@ -57,10 +57,10 @@ output: properties: {} - label: KNOWS properties: {} - - label: FOLLOWS - properties: {} - label: KNOWS properties: {} + - label: FOLLOWS + properties: {} - label: KNOWS properties: {} - label: FOLLOWS diff --git a/e2e/path_test/test_subgraph_all_3/test.yml b/e2e/path_test/test_subgraph_all_3/test.yml index 3c2314384..e0b768077 100644 --- a/e2e/path_test/test_subgraph_all_3/test.yml +++ b/e2e/path_test/test_subgraph_all_3/test.yml @@ -17,15 +17,15 @@ output: - labels: - Node properties: - name: E + name: C - labels: - Node properties: - name: D + name: E - labels: - Node properties: - name: C + name: D rels: - label: CONNECTED_TO properties: {} diff --git a/e2e/path_test/test_subgraph_nodes_1/test.yml b/e2e/path_test/test_subgraph_nodes_1/test.yml index ccb8719bf..c12f07633 100644 --- a/e2e/path_test/test_subgraph_nodes_1/test.yml +++ b/e2e/path_test/test_subgraph_nodes_1/test.yml @@ -5,7 +5,7 @@ query: > labelFilter: ["+Strategy", "/Operations", ">Research", "-Support", "Analytics"] }) YIELD nodes - RETURN nodes; + RETURN nodes ORDER BY id(nodes) ASC output: - nodes: @@ -17,9 +17,9 @@ output: labels: - Operations properties: - name: Steve + name: Jill - nodes: labels: - Operations properties: - name: Jill + name: Steve diff --git a/e2e/path_test/test_subgraph_nodes_2/test.yml b/e2e/path_test/test_subgraph_nodes_2/test.yml index 5c19cdd5d..be72d00b1 100644 --- a/e2e/path_test/test_subgraph_nodes_2/test.yml +++ b/e2e/path_test/test_subgraph_nodes_2/test.yml @@ -2,43 +2,43 @@ query: > MATCH (p:Strategy {name: "Amber"}) CALL path.subgraph_nodes(p, { relationshipFilter: [">"], - minLevel: 0, - maxLevel: 2 + minHops: 0, + maxHops: 2 }) YIELD nodes - RETURN nodes; + RETURN nodes ORDER BY id(nodes); output: - nodes: labels: - - Strategy + - Research properties: - name: Amber + name: Matt - nodes: labels: - - Strategy + - Analytics properties: - name: Jacob + name: Patricia - nodes: labels: - - Operations + - Analytics properties: - name: Jill + name: Zack - nodes: labels: - - Research + - Operations properties: - name: Matt + name: Jill - nodes: labels: - - Analytics + - Strategy properties: - name: Patricia + name: Amber - nodes: labels: - - Analytics + - Strategy properties: - name: Zack + name: Jacob - nodes: labels: - Support diff --git a/e2e/path_test/test_subgraph_nodes_3/test.yml b/e2e/path_test/test_subgraph_nodes_3/test.yml index f4714ec9e..cf544bff1 100644 --- a/e2e/path_test/test_subgraph_nodes_3/test.yml +++ b/e2e/path_test/test_subgraph_nodes_3/test.yml @@ -2,7 +2,7 @@ query: > MATCH (a:Node {name: "A"}) CALL path.subgraph_nodes(a, {relationshipFilter: ['CONNECTED_TO>']}) YIELD nodes - RETURN nodes + RETURN nodes ORDER BY id(nodes) ASC; output: - nodes: @@ -19,7 +19,7 @@ output: labels: - Node properties: - name: E + name: C - nodes: labels: - Node @@ -29,4 +29,4 @@ output: labels: - Node properties: - name: C + name: E diff --git a/e2e_correctness/path_test/test_combine_1/config.yml b/e2e_correctness/path_test/test_combine_1/config.yml new file mode 100644 index 000000000..3c7888e88 --- /dev/null +++ b/e2e_correctness/path_test/test_combine_1/config.yml @@ -0,0 +1,2 @@ +path_option: > + True diff --git a/e2e_correctness/path_test/test_combine_1/input.cyp b/e2e_correctness/path_test/test_combine_1/input.cyp new file mode 100644 index 000000000..09d857655 --- /dev/null +++ b/e2e_correctness/path_test/test_combine_1/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {name: 'Node 1', id:1})-[:CONNECTED {id:1}]->(:Node {name: 'Node 2', id:2})-[:CONNECTED {id:2}]->(:Node {name: 'Node 3', id:3})-[:CONNECTED {id:3}]->(:Node {name: 'Node 4', id:4})-[:CONNECTED {id:4}]->(:Node {name: 'Node 5', id:5})-[:CONNECTED {id:5}]->(:Node {name: 'Node 6', id:6}); diff --git a/e2e_correctness/path_test/test_combine_1/test.yml b/e2e_correctness/path_test/test_combine_1/test.yml new file mode 100644 index 000000000..ea84a6bfb --- /dev/null +++ b/e2e_correctness/path_test/test_combine_1/test.yml @@ -0,0 +1,10 @@ +memgraph_query: > + MATCH (node1:Node {name: 'Node 1'}), (node4:Node {name: 'Node 4'}), (node6:Node {name: 'Node 6'}) + MATCH path1 = (node1)-[:CONNECTED*3]->(node4) + MATCH path2 = (node4)-[:CONNECTED*2]->(node6) + RETURN path.combine(path1, path2) AS result; +neo4j_query: > + MATCH (node1:Node {name: 'Node 1'}), (node4:Node {name: 'Node 4'}), (node6:Node {name: 'Node 6'}) + MATCH path1 = (node1)-[:CONNECTED*3]->(node4) + MATCH path2 = (node4)-[:CONNECTED*2]->(node6) + RETURN apoc.path.combine(path1, path2) AS result; diff --git a/e2e_correctness/path_test/test_combine_2/config.yml b/e2e_correctness/path_test/test_combine_2/config.yml new file mode 100644 index 000000000..3c7888e88 --- /dev/null +++ b/e2e_correctness/path_test/test_combine_2/config.yml @@ -0,0 +1,2 @@ +path_option: > + True diff --git a/e2e_correctness/path_test/test_combine_2/input.cyp b/e2e_correctness/path_test/test_combine_2/input.cyp new file mode 100644 index 000000000..179230911 --- /dev/null +++ b/e2e_correctness/path_test/test_combine_2/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {name: 'Node 1', id:1})<-[:CONNECTED {id:1}]-(:Node {name: 'Node 2', id:2})-[:CONNECTED {id:2}]->(:Node {name: 'Node 3', id:3})-[:CONNECTED {id:3}]->(:Node {name: 'Node 4', id:4})<-[:CONNECTED {id:4}]-(:Node {name: 'Node 5', id:5})-[:CONNECTED {id:5}]->(:Node {name: 'Node 6', id:6}); diff --git a/e2e_correctness/path_test/test_combine_2/test.yml b/e2e_correctness/path_test/test_combine_2/test.yml new file mode 100644 index 000000000..ea84a6bfb --- /dev/null +++ b/e2e_correctness/path_test/test_combine_2/test.yml @@ -0,0 +1,10 @@ +memgraph_query: > + MATCH (node1:Node {name: 'Node 1'}), (node4:Node {name: 'Node 4'}), (node6:Node {name: 'Node 6'}) + MATCH path1 = (node1)-[:CONNECTED*3]->(node4) + MATCH path2 = (node4)-[:CONNECTED*2]->(node6) + RETURN path.combine(path1, path2) AS result; +neo4j_query: > + MATCH (node1:Node {name: 'Node 1'}), (node4:Node {name: 'Node 4'}), (node6:Node {name: 'Node 6'}) + MATCH path1 = (node1)-[:CONNECTED*3]->(node4) + MATCH path2 = (node4)-[:CONNECTED*2]->(node6) + RETURN apoc.path.combine(path1, path2) AS result; diff --git a/e2e_correctness/path_test/test_slice_1/config.yml b/e2e_correctness/path_test/test_slice_1/config.yml new file mode 100644 index 000000000..3c7888e88 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_1/config.yml @@ -0,0 +1,2 @@ +path_option: > + True diff --git a/e2e_correctness/path_test/test_slice_1/input.cyp b/e2e_correctness/path_test/test_slice_1/input.cyp new file mode 100644 index 000000000..2ebb0e8e5 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_1/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {id: 1})-[:CONNECTED {id: 1}]->(:Node {id: 2})-[:CONNECTED {id: 2}]->(:Node {id: 3})-[:CONNECTED {id: 3}]->(:Node {id: 4})-[:CONNECTED {id: 4}]->(:Node {id: 5}); diff --git a/e2e_correctness/path_test/test_slice_1/test.yml b/e2e_correctness/path_test/test_slice_1/test.yml new file mode 100644 index 000000000..8ac153e29 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_1/test.yml @@ -0,0 +1,6 @@ +memgraph_query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) + RETURN path.slice(path, 1, -1) AS result; +neo4j_query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) + RETURN apoc.path.slice(path, 1, -1) AS result; diff --git a/e2e_correctness/path_test/test_slice_2/config.yml b/e2e_correctness/path_test/test_slice_2/config.yml new file mode 100644 index 000000000..3c7888e88 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_2/config.yml @@ -0,0 +1,2 @@ +path_option: > + True diff --git a/e2e_correctness/path_test/test_slice_2/input.cyp b/e2e_correctness/path_test/test_slice_2/input.cyp new file mode 100644 index 000000000..2ebb0e8e5 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_2/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {id: 1})-[:CONNECTED {id: 1}]->(:Node {id: 2})-[:CONNECTED {id: 2}]->(:Node {id: 3})-[:CONNECTED {id: 3}]->(:Node {id: 4})-[:CONNECTED {id: 4}]->(:Node {id: 5}); diff --git a/e2e_correctness/path_test/test_slice_2/test.yml b/e2e_correctness/path_test/test_slice_2/test.yml new file mode 100644 index 000000000..91c4c0ab5 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_2/test.yml @@ -0,0 +1,6 @@ +memgraph_query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) + RETURN path.slice(path, 2, 2) AS result; +neo4j_query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) + RETURN apoc.path.slice(path, 2, 2) AS result; diff --git a/e2e_correctness/path_test/test_slice_3/config.yml b/e2e_correctness/path_test/test_slice_3/config.yml new file mode 100644 index 000000000..3c7888e88 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_3/config.yml @@ -0,0 +1,2 @@ +path_option: > + True diff --git a/e2e_correctness/path_test/test_slice_3/input.cyp b/e2e_correctness/path_test/test_slice_3/input.cyp new file mode 100644 index 000000000..2ebb0e8e5 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_3/input.cyp @@ -0,0 +1 @@ +CREATE (:Node {id: 1})-[:CONNECTED {id: 1}]->(:Node {id: 2})-[:CONNECTED {id: 2}]->(:Node {id: 3})-[:CONNECTED {id: 3}]->(:Node {id: 4})-[:CONNECTED {id: 4}]->(:Node {id: 5}); diff --git a/e2e_correctness/path_test/test_slice_3/test.yml b/e2e_correctness/path_test/test_slice_3/test.yml new file mode 100644 index 000000000..4b7537851 --- /dev/null +++ b/e2e_correctness/path_test/test_slice_3/test.yml @@ -0,0 +1,6 @@ +memgraph_query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) + RETURN path.slice(path, 1, 123) AS result; +neo4j_query: > + MATCH path = (:Node {id: 1})-[:CONNECTED*4]->(:Node {id: 5}) + RETURN apoc.path.slice(path, 1, 123) AS result; From 27c6a760d735c98044c52c43a4e0e34c2e7dc87c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Pintari=C4=87?= <99442742+mpintaric55334@users.noreply.github.com> Date: Wed, 25 Oct 2023 21:37:46 +0200 Subject: [PATCH 10/10] Delete query modules (#403) --- cpp/CMakeLists.txt | 1 - cpp/schema_module/CMakeLists.txt | 5 - cpp/schema_module/algorithm/schema.cpp | 118 ------------------ cpp/schema_module/algorithm/schema.hpp | 30 ----- cpp/schema_module/schema_module.cpp | 33 ----- e2e/convert_test/test_str2object1/file1 | 4 - e2e/convert_test/test_str2object1/input.cyp | 0 e2e/convert_test/test_str2object1/test.yml | 8 -- .../test_node_type_properties1/input.cyp | 1 - .../test_node_type_properties1/test.yml | 31 ----- .../test_node_type_properties2/input.cyp | 1 - .../test_node_type_properties2/test.yml | 18 --- .../test_node_type_properties3/input.cyp | 1 - .../test_node_type_properties3/test.yml | 14 --- .../test_rel_type_properties1/input.cyp | 1 - .../test_rel_type_properties1/test.yml | 8 -- .../test_rel_type_properties2/input.cyp | 1 - .../test_rel_type_properties2/test.yml | 19 --- .../test_rel_type_properties3/input.cyp | 2 - .../test_rel_type_properties3/test.yml | 24 ---- python/convert.py | 9 -- python/mgps.py | 8 -- 22 files changed, 337 deletions(-) delete mode 100644 cpp/schema_module/CMakeLists.txt delete mode 100644 cpp/schema_module/algorithm/schema.cpp delete mode 100644 cpp/schema_module/algorithm/schema.hpp delete mode 100644 cpp/schema_module/schema_module.cpp delete mode 100644 e2e/convert_test/test_str2object1/file1 delete mode 100644 e2e/convert_test/test_str2object1/input.cyp delete mode 100644 e2e/convert_test/test_str2object1/test.yml delete mode 100644 e2e/schema_test/test_node_type_properties1/input.cyp delete mode 100644 e2e/schema_test/test_node_type_properties1/test.yml delete mode 100644 e2e/schema_test/test_node_type_properties2/input.cyp delete mode 100644 e2e/schema_test/test_node_type_properties2/test.yml delete mode 100644 e2e/schema_test/test_node_type_properties3/input.cyp delete mode 100644 e2e/schema_test/test_node_type_properties3/test.yml delete mode 100644 e2e/schema_test/test_rel_type_properties1/input.cyp delete mode 100644 e2e/schema_test/test_rel_type_properties1/test.yml delete mode 100644 e2e/schema_test/test_rel_type_properties2/input.cyp delete mode 100644 e2e/schema_test/test_rel_type_properties2/test.yml delete mode 100644 e2e/schema_test/test_rel_type_properties3/input.cyp delete mode 100644 e2e/schema_test/test_rel_type_properties3/test.yml delete mode 100644 python/convert.py delete mode 100644 python/mgps.py diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index ba15e6377..06d32729f 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -157,6 +157,5 @@ add_subdirectory(path_module) add_subdirectory(node_module) add_subdirectory(neighbors_module) add_subdirectory(refactor_module) -add_subdirectory(schema_module) add_cugraph_subdirectory(cugraph_module) diff --git a/cpp/schema_module/CMakeLists.txt b/cpp/schema_module/CMakeLists.txt deleted file mode 100644 index 960bfe0a1..000000000 --- a/cpp/schema_module/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(schema_module_src - schema_module.cpp - algorithm/schema.cpp) - -add_query_module(schema 1 "${schema_module_src}") diff --git a/cpp/schema_module/algorithm/schema.cpp b/cpp/schema_module/algorithm/schema.cpp deleted file mode 100644 index 107e08932..000000000 --- a/cpp/schema_module/algorithm/schema.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "schema.hpp" - -/*we have << operator for type in Cpp API, but in it we return somewhat different strings than I would like in this -module, so I implemented a small function here*/ -std::string Schema::TypeOf(const mgp::Type &type) { - switch (type) { - case mgp::Type::Null: - return "Null"; - case mgp::Type::Bool: - return "Bool"; - case mgp::Type::Int: - return "Int"; - case mgp::Type::Double: - return "Double"; - case mgp::Type::String: - return "String"; - case mgp::Type::List: - return "List[Any]"; - case mgp::Type::Map: - return "Map[Any]"; - case mgp::Type::Node: - return "Vertex"; - case mgp::Type::Relationship: - return "Edge"; - case mgp::Type::Path: - return "Path"; - case mgp::Type::Date: - return "Date"; - case mgp::Type::LocalTime: - return "LocalTime"; - case mgp::Type::LocalDateTime: - return "LocalDateTime"; - case mgp::Type::Duration: - return "Duration"; - default: - throw mgp::ValueException("Unsupported type"); - } -} -template -void Schema::ProcessPropertiesNode(mgp::Record &record, const std::string &type, const mgp::List &labels, const std::string &propertyName, - const T &propertyType, const bool &mandatory) { - record.Insert(std::string(kReturnNodeType).c_str(), type); - record.Insert(std::string(kReturnLabels).c_str(), labels); - record.Insert(std::string(kReturnPropertyName).c_str(), propertyName); - record.Insert(std::string(kReturnPropertyType).c_str(), propertyType); - record.Insert(std::string(kReturnMandatory).c_str(), mandatory); -} - -template -void Schema::ProcessPropertiesRel(mgp::Record &record, const std::string_view &type, const std::string &propertyName, - const T &propertyType, const bool &mandatory) { - record.Insert(std::string(kReturnRelType).c_str(), type); - record.Insert(std::string(kReturnPropertyName).c_str(), propertyName); - record.Insert(std::string(kReturnPropertyType).c_str(), propertyType); - record.Insert(std::string(kReturnMandatory).c_str(), mandatory); -} - -void Schema::NodeTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::MemoryDispatcherGuard guard{memory};; - const auto record_factory = mgp::RecordFactory(result); - try { - const mgp::Graph graph = mgp::Graph(memgraph_graph); - for (auto node : graph.Nodes()) { - std::string type = ""; - mgp::List labels = mgp::List(); - for (auto label : node.Labels()) { - labels.AppendExtend(mgp::Value(label)); - type += ":`" + std::string(label) + "`"; - } - - - if (node.Properties().size() == 0) { - auto record = record_factory.NewRecord(); - ProcessPropertiesNode(record, type, labels, "", "", false); - continue; - } - - for (auto &[key, prop] : node.Properties()) { - auto property_type = mgp::List(); - auto record = record_factory.NewRecord(); - property_type.AppendExtend(mgp::Value(TypeOf(prop.Type()))); - ProcessPropertiesNode(record, type, labels, key, property_type, true); - } - } - - } catch (const std::exception &e) { - record_factory.SetErrorMessage(e.what()); - return; - } -} - -void Schema::RelTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { - mgp::MemoryDispatcherGuard guard{memory};; - const auto record_factory = mgp::RecordFactory(result); - try { - const mgp::Graph graph = mgp::Graph(memgraph_graph); - - for (auto rel : graph.Relationships()) { - std::string type = ":`" + std::string(rel.Type()) + "`"; - if (rel.Properties().size() == 0) { - auto record = record_factory.NewRecord(); - ProcessPropertiesRel(record, type, "","", false); - continue; - } - - for (auto &[key, prop] : rel.Properties()) { - auto property_type = mgp::List(); - auto record = record_factory.NewRecord(); - property_type.AppendExtend(mgp::Value(TypeOf(prop.Type()))); - ProcessPropertiesRel(record, type, key, property_type, true); - } - } - - } catch (const std::exception &e) { - record_factory.SetErrorMessage(e.what()); - return; - } -} diff --git a/cpp/schema_module/algorithm/schema.hpp b/cpp/schema_module/algorithm/schema.hpp deleted file mode 100644 index ce1d3b31b..000000000 --- a/cpp/schema_module/algorithm/schema.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -namespace Schema { - -/*NodeTypeProperties and RelTypeProperties constants*/ -constexpr std::string_view kReturnNodeType = "nodeType"; -constexpr std::string_view kProcedureNodeType = "node_type_properties"; -constexpr std::string_view kProcedureRelType = "rel_type_properties"; -constexpr std::string_view kReturnLabels = "nodeLabels"; -constexpr std::string_view kReturnRelType = "relType"; -constexpr std::string_view kReturnPropertyName = "propertyName"; -constexpr std::string_view kReturnPropertyType = "propertyTypes"; -constexpr std::string_view kReturnMandatory = "mandatory"; - -std::string TypeOf(const mgp::Type &type); - -template -void ProcessPropertiesNode(mgp::Record &record, const std::string &type,const mgp::List &labels, const std::string &propertyName, - const T &propertyType, const bool &mandatory); - -template -void ProcessPropertiesRel(mgp::Record &record, const std::string_view &type, const std::string &propertyName, - const T &propertyType, const bool &mandatory); - - -void NodeTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); -void RelTypeProperties(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); -} // namespace Schema diff --git a/cpp/schema_module/schema_module.cpp b/cpp/schema_module/schema_module.cpp deleted file mode 100644 index 28de5b99c..000000000 --- a/cpp/schema_module/schema_module.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include "algorithm/schema.hpp" - -extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) { - try { - mgp::MemoryDispatcherGuard guard{memory};; - - AddProcedure(Schema::NodeTypeProperties, std::string(Schema::kProcedureNodeType).c_str(), mgp::ProcedureType::Read, - {}, - {mgp::Return(std::string(Schema::kReturnNodeType).c_str(), mgp::Type::String), - mgp::Return(std::string(Schema::kReturnLabels).c_str(), {mgp::Type::List, mgp::Type::String}), - mgp::Return(std::string(Schema::kReturnPropertyName).c_str(), mgp::Type::String), - mgp::Return(std::string(Schema::kReturnPropertyType).c_str(), mgp::Type::Any), - mgp::Return(std::string(Schema::kReturnMandatory).c_str(), mgp::Type::Bool)}, - module, memory); - - AddProcedure(Schema::RelTypeProperties, std::string(Schema::kProcedureRelType).c_str(), mgp::ProcedureType::Read, - {}, - {mgp::Return(std::string(Schema::kReturnRelType).c_str(), mgp::Type::String), - mgp::Return(std::string(Schema::kReturnPropertyName).c_str(), mgp::Type::String), - mgp::Return(std::string(Schema::kReturnPropertyType).c_str(), mgp::Type::Any), - mgp::Return(std::string(Schema::kReturnMandatory).c_str(), mgp::Type::Bool)}, - module, memory); - - } catch (const std::exception &e) { - return 1; - } - - return 0; -} - -extern "C" int mgp_shutdown_module() { return 0; } diff --git a/e2e/convert_test/test_str2object1/file1 b/e2e/convert_test/test_str2object1/file1 deleted file mode 100644 index c6dc46576..000000000 --- a/e2e/convert_test/test_str2object1/file1 +++ /dev/null @@ -1,4 +0,0 @@ -"_id","_labels","a","b","prop","did_it","_start","_end","_type" -"0",":Dog","3","[""1"", ""2"", 3]","2","","","","" -"1",":Human","","[[""1"",{""key"": 5}]]","","yes","","","" -"5",":Cat","","{""prop"": {""prop2"": {""key"": 10}}}","","","0","1","loves" diff --git a/e2e/convert_test/test_str2object1/input.cyp b/e2e/convert_test/test_str2object1/input.cyp deleted file mode 100644 index e69de29bb..000000000 diff --git a/e2e/convert_test/test_str2object1/test.yml b/e2e/convert_test/test_str2object1/test.yml deleted file mode 100644 index 938976cbf..000000000 --- a/e2e/convert_test/test_str2object1/test.yml +++ /dev/null @@ -1,8 +0,0 @@ -query: > - LOAD CSV FROM "/_file1" WITH header AS row - RETURN convert.str2object(row.b) AS list; - -output: - - list: [ "1","2", 3] - - list: [["1",{"key": 5}]] - - list: {"prop": {"prop2": {"key": 10}}} diff --git a/e2e/schema_test/test_node_type_properties1/input.cyp b/e2e/schema_test/test_node_type_properties1/input.cyp deleted file mode 100644 index 949f01eca..000000000 --- a/e2e/schema_test/test_node_type_properties1/input.cyp +++ /dev/null @@ -1 +0,0 @@ -CREATE (d:Dog {name: "Rex", owner: "Carl"})-[l:LOVES]->(a:Activity {name: "Running", location: "Zadar"}); diff --git a/e2e/schema_test/test_node_type_properties1/test.yml b/e2e/schema_test/test_node_type_properties1/test.yml deleted file mode 100644 index 1b42de473..000000000 --- a/e2e/schema_test/test_node_type_properties1/test.yml +++ /dev/null @@ -1,31 +0,0 @@ -query: > - CALL schema.node_type_properties() YIELD nodeType, nodeLabels, propertyName, propertyTypes , mandatory - RETURN nodeType, nodeLabels, propertyName, propertyTypes , mandatory - ORDER BY propertyName, nodeLabels[0]; - -output: - - - nodeType: ":`Activity`" - nodeLabels: ["Activity"] - propertyName: location - propertyTypes: ["String"] - mandatory: true - - - nodeType: ":`Activity`" - nodeLabels: ["Activity"] - propertyName: name - propertyTypes: ["String"] - mandatory: true - - - nodeType: ":`Dog`" - nodeLabels: ["Dog"] - propertyName: name - propertyTypes: ["String"] - mandatory: true - - - nodeType: ":`Dog`" - nodeLabels: ["Dog"] - propertyName: owner - propertyTypes: ["String"] - mandatory: true - diff --git a/e2e/schema_test/test_node_type_properties2/input.cyp b/e2e/schema_test/test_node_type_properties2/input.cyp deleted file mode 100644 index d20df7ae0..000000000 --- a/e2e/schema_test/test_node_type_properties2/input.cyp +++ /dev/null @@ -1 +0,0 @@ -CREATE (n:NonMandatory)-[r:RELATIONSHIP]->(m:Mandatory {property: ["2",3 ,4]}); diff --git a/e2e/schema_test/test_node_type_properties2/test.yml b/e2e/schema_test/test_node_type_properties2/test.yml deleted file mode 100644 index cb4034acd..000000000 --- a/e2e/schema_test/test_node_type_properties2/test.yml +++ /dev/null @@ -1,18 +0,0 @@ -query: > - CALL schema.node_type_properties() YIELD nodeType, nodeLabels, propertyName, propertyTypes , mandatory - RETURN nodeType, nodeLabels, propertyName, propertyTypes , mandatory - ORDER BY propertyName, nodeLabels[0]; - -output: - - - nodeType: ":`NonMandatory`" - nodeLabels: ["NonMandatory"] - propertyName: '' - propertyTypes: '' - mandatory: false - - - nodeType: ":`Mandatory`" - nodeLabels: ["Mandatory"] - propertyName: property - propertyTypes: ["List[Any]"] - mandatory: true diff --git a/e2e/schema_test/test_node_type_properties3/input.cyp b/e2e/schema_test/test_node_type_properties3/input.cyp deleted file mode 100644 index 5b5aa2a36..000000000 --- a/e2e/schema_test/test_node_type_properties3/input.cyp +++ /dev/null @@ -1 +0,0 @@ -CREATE (n:NonMandatory:SecondLabel)-[r:RELATIONSHIP]->(m:Mandatory {property: ["2",3 ,4]}); diff --git a/e2e/schema_test/test_node_type_properties3/test.yml b/e2e/schema_test/test_node_type_properties3/test.yml deleted file mode 100644 index 1e5861182..000000000 --- a/e2e/schema_test/test_node_type_properties3/test.yml +++ /dev/null @@ -1,14 +0,0 @@ -query: > - CALL schema.node_type_properties() YIELD nodeType, nodeLabels, propertyName, propertyTypes , mandatory - WITH nodeType, nodeLabels, propertyName, propertyTypes , mandatory - WHERE propertyName = "" - RETURN nodeType, nodeLabels, propertyName, propertyTypes , mandatory - -output: - - - nodeType: ":`NonMandatory`:`SecondLabel`" - nodeLabels: ["NonMandatory", "SecondLabel"] - propertyName: '' - propertyTypes: '' - mandatory: false - diff --git a/e2e/schema_test/test_rel_type_properties1/input.cyp b/e2e/schema_test/test_rel_type_properties1/input.cyp deleted file mode 100644 index 949f01eca..000000000 --- a/e2e/schema_test/test_rel_type_properties1/input.cyp +++ /dev/null @@ -1 +0,0 @@ -CREATE (d:Dog {name: "Rex", owner: "Carl"})-[l:LOVES]->(a:Activity {name: "Running", location: "Zadar"}); diff --git a/e2e/schema_test/test_rel_type_properties1/test.yml b/e2e/schema_test/test_rel_type_properties1/test.yml deleted file mode 100644 index e67f19054..000000000 --- a/e2e/schema_test/test_rel_type_properties1/test.yml +++ /dev/null @@ -1,8 +0,0 @@ -query: > - CALL schema.rel_type_properties() YIELD relType,propertyName, propertyTypes , mandatory RETURN relType, propertyName, propertyTypes , mandatory; - -output: - - relType: ":`LOVES`" - propertyName: "" - propertyTypes: "" - mandatory: false diff --git a/e2e/schema_test/test_rel_type_properties2/input.cyp b/e2e/schema_test/test_rel_type_properties2/input.cyp deleted file mode 100644 index 122e1b04b..000000000 --- a/e2e/schema_test/test_rel_type_properties2/input.cyp +++ /dev/null @@ -1 +0,0 @@ -CREATE (d:Dog)-[c:CATCHES {property: [1,2,3], property2: {key: "value"}}]->(b:Ball)-[f:FALLS_FROM {speed_in_km: 100}]->(ba:Balcony); diff --git a/e2e/schema_test/test_rel_type_properties2/test.yml b/e2e/schema_test/test_rel_type_properties2/test.yml deleted file mode 100644 index 26b15f0ed..000000000 --- a/e2e/schema_test/test_rel_type_properties2/test.yml +++ /dev/null @@ -1,19 +0,0 @@ -query: > - CALL schema.rel_type_properties() YIELD relType,propertyName, propertyTypes , mandatory RETURN relType, propertyName, propertyTypes , mandatory - ORDER BY propertyName, relType; - -output: - - relType: ":`CATCHES`" - propertyName: property - propertyTypes: ["List[Any]"] - mandatory: true - - - relType: ":`CATCHES`" - propertyName: property2 - propertyTypes: ["Map[Any]"] - mandatory: true - - - relType: ":`FALLS_FROM`" - propertyName: speed_in_km - propertyTypes: ["Int"] - mandatory: true diff --git a/e2e/schema_test/test_rel_type_properties3/input.cyp b/e2e/schema_test/test_rel_type_properties3/input.cyp deleted file mode 100644 index cdce0b8e1..000000000 --- a/e2e/schema_test/test_rel_type_properties3/input.cyp +++ /dev/null @@ -1,2 +0,0 @@ -CREATE (d:Dog)-[c:CATCHES {property: [1,2,3], property2: {key: "value"}}]->(b:Ball)-[f:FALLS_FROM {speed_in_km: 100}]->(ba:Balcony); -CREATE (b:Bird)-[f:FLIES]->(s:Sky); diff --git a/e2e/schema_test/test_rel_type_properties3/test.yml b/e2e/schema_test/test_rel_type_properties3/test.yml deleted file mode 100644 index e7365f186..000000000 --- a/e2e/schema_test/test_rel_type_properties3/test.yml +++ /dev/null @@ -1,24 +0,0 @@ -query: > - CALL schema.rel_type_properties() YIELD relType,propertyName, propertyTypes , mandatory RETURN relType, propertyName, propertyTypes , mandatory - ORDER BY propertyName, relType; -output: - - - relType: ":`FLIES`" - propertyName: "" - propertyTypes: "" - mandatory: false - - - relType: ":`CATCHES`" - propertyName: property - propertyTypes: ["List[Any]"] - mandatory: true - - - relType: ":`CATCHES`" - propertyName: property2 - propertyTypes: ["Map[Any]"] - mandatory: true - - - relType: ":`FALLS_FROM`" - propertyName: speed_in_km - propertyTypes: ["Int"] - mandatory: true diff --git a/python/convert.py b/python/convert.py deleted file mode 100644 index 6db93c8c6..000000000 --- a/python/convert.py +++ /dev/null @@ -1,9 +0,0 @@ -import mgp -from json import loads - - -@mgp.function -def str2object(string: str) -> mgp.Any: - if string: - return loads(string) - return None diff --git a/python/mgps.py b/python/mgps.py deleted file mode 100644 index 14b18d7d4..000000000 --- a/python/mgps.py +++ /dev/null @@ -1,8 +0,0 @@ -import mgp - - -@mgp.read_proc -def components( - context: mgp.ProcCtx, -) -> mgp.Record(versions=list, edition=str, name=str): - return mgp.Record(versions=["5.9.0"], edition="community", name="Memgraph")