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 1/3] 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 6e22db28c6ae849de6117c7d5559b8999925c585 Mon Sep 17 00:00:00 2001 From: imilinovic <44698587+imilinovic@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:41:50 +0200 Subject: [PATCH 2/3] Implement refactor rename_type (#396) --- cpp/memgraph | 2 +- cpp/refactor_module/algorithm/refactor.cpp | 32 +++++++++++++++++-- cpp/refactor_module/algorithm/refactor.hpp | 9 ++++++ cpp/refactor_module/refactor_module.cpp | 6 ++++ .../test_rename_type_1/input.cyp | 1 + .../refactor_test/test_rename_type_1/test.yml | 6 ++++ .../test_rename_type_2/input.cyp | 1 + .../refactor_test/test_rename_type_2/test.yml | 6 ++++ .../test_rename_type_3/input.cyp | 1 + .../refactor_test/test_rename_type_3/test.yml | 8 +++++ 10 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 e2e_correctness/refactor_test/test_rename_type_1/input.cyp create mode 100644 e2e_correctness/refactor_test/test_rename_type_1/test.yml create mode 100644 e2e_correctness/refactor_test/test_rename_type_2/input.cyp create mode 100644 e2e_correctness/refactor_test/test_rename_type_2/test.yml create mode 100644 e2e_correctness/refactor_test/test_rename_type_3/input.cyp create mode 100644 e2e_correctness/refactor_test/test_rename_type_3/test.yml 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 diff --git a/cpp/refactor_module/algorithm/refactor.cpp b/cpp/refactor_module/algorithm/refactor.cpp index 4f8cc966d..e4f14e397 100644 --- a/cpp/refactor_module/algorithm/refactor.cpp +++ b/cpp/refactor_module/algorithm/refactor.cpp @@ -401,7 +401,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::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -446,7 +446,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::MemoryDispatcherGuard guard{memory};; + mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); const auto record_factory = mgp::RecordFactory(result); try { @@ -620,3 +620,31 @@ void Refactor::ExtractNode(mgp_list *args, mgp_graph *memgraph_graph, mgp_result return; } } + +void Refactor::RenameType(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard{memory}; + const auto arguments = mgp::List(args); + const auto record_factory = mgp::RecordFactory(result); + try { + const auto old_type{arguments[0].ValueString()}; + const auto new_type{arguments[1].ValueString()}; + const auto relationships{arguments[2].ValueList()}; + auto graph{mgp::Graph(memgraph_graph)}; + + int64_t rels_changed{0}; + for (auto &relationship_value : relationships) { + auto relationship{relationship_value.ValueRelationship()}; + if (relationship.Type() == old_type) { + graph.ChangeType(relationship, new_type); + ++rels_changed; + } + } + + auto record = record_factory.NewRecord(); + record.Insert(std::string(kResultRenameType).c_str(), rels_changed); + + } catch (const std::exception &e) { + record_factory.SetErrorMessage(e.what()); + return; + } +} diff --git a/cpp/refactor_module/algorithm/refactor.hpp b/cpp/refactor_module/algorithm/refactor.hpp index a23144154..bdbb3ee35 100644 --- a/cpp/refactor_module/algorithm/refactor.hpp +++ b/cpp/refactor_module/algorithm/refactor.hpp @@ -93,6 +93,13 @@ constexpr std::string_view kResultExtractNode1 = "input"; constexpr std::string_view kResultExtractNode2 = "output"; constexpr std::string_view kResultExtractNode3 = "error"; +/* rename_type constants */ +constexpr std::string_view kProcedureRenameType = "rename_type"; +constexpr std::string_view kRenameTypeArg1 = "relationships"; +constexpr std::string_view kRenameTypeArg2 = "labels"; +constexpr std::string_view kRenameTypeArg3 = "outType"; +constexpr std::string_view kResultRenameType = "relationships_changed"; + void From(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); void To(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); @@ -130,4 +137,6 @@ void NormalizeAsBoolean(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *r void ExtractNode(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); +void RenameType(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); + } // namespace Refactor diff --git a/cpp/refactor_module/refactor_module.cpp b/cpp/refactor_module/refactor_module.cpp index 1d920196a..8275a621c 100644 --- a/cpp/refactor_module/refactor_module.cpp +++ b/cpp/refactor_module/refactor_module.cpp @@ -101,6 +101,12 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem mgp::Parameter(Refactor::kNormalizeAsBooleanArg4, {mgp::Type::List, mgp::Type::Any})}, {}, module, memory); + AddProcedure(Refactor::RenameType, Refactor::kProcedureRenameType, mgp::ProcedureType::Write, + {mgp::Parameter(Refactor::kRenameTypeArg1, mgp::Type::String), + mgp::Parameter(Refactor::kRenameTypeArg2, mgp::Type::String), + mgp::Parameter(Refactor::kRenameTypeArg3, {mgp::Type::List, mgp::Type::Relationship})}, + {mgp::Return(Refactor::kResultRenameType, mgp::Type::Int)}, module, memory); + } catch (const std::exception &e) { return 1; } diff --git a/e2e_correctness/refactor_test/test_rename_type_1/input.cyp b/e2e_correctness/refactor_test/test_rename_type_1/input.cyp new file mode 100644 index 000000000..863e5070c --- /dev/null +++ b/e2e_correctness/refactor_test/test_rename_type_1/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog {id:0}),(h:Human {id:1}), (c:Car {id:2}),(d)-[r:Drives {speed: 100, id:0}]->(h),(h)-[dr:Runs {speed: 150, id: 1}]->(c); diff --git a/e2e_correctness/refactor_test/test_rename_type_1/test.yml b/e2e_correctness/refactor_test/test_rename_type_1/test.yml new file mode 100644 index 000000000..891d498b6 --- /dev/null +++ b/e2e_correctness/refactor_test/test_rename_type_1/test.yml @@ -0,0 +1,6 @@ +memgraph_query: > + MATCH ()-[r]-() + WITH collect(distinct(r)) AS rels + CALL refactor.rename_type("Drives", "Glides", rels) YIELD relationships_changed RETURN relationships_changed; +neo4j_query: > + CALL apoc.refactor.rename.type("Drives","Glides") YIELD total RETURN total; diff --git a/e2e_correctness/refactor_test/test_rename_type_2/input.cyp b/e2e_correctness/refactor_test/test_rename_type_2/input.cyp new file mode 100644 index 000000000..86b861930 --- /dev/null +++ b/e2e_correctness/refactor_test/test_rename_type_2/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog {id:0}),(h:Human {id:1}), (c:Car {id:2}),(d)-[r:Drives {speed: 100, id:0}]->(h),(h)-[dr:Drives {speed: 150, id: 1}]->(c); diff --git a/e2e_correctness/refactor_test/test_rename_type_2/test.yml b/e2e_correctness/refactor_test/test_rename_type_2/test.yml new file mode 100644 index 000000000..891d498b6 --- /dev/null +++ b/e2e_correctness/refactor_test/test_rename_type_2/test.yml @@ -0,0 +1,6 @@ +memgraph_query: > + MATCH ()-[r]-() + WITH collect(distinct(r)) AS rels + CALL refactor.rename_type("Drives", "Glides", rels) YIELD relationships_changed RETURN relationships_changed; +neo4j_query: > + CALL apoc.refactor.rename.type("Drives","Glides") YIELD total RETURN total; diff --git a/e2e_correctness/refactor_test/test_rename_type_3/input.cyp b/e2e_correctness/refactor_test/test_rename_type_3/input.cyp new file mode 100644 index 000000000..863e5070c --- /dev/null +++ b/e2e_correctness/refactor_test/test_rename_type_3/input.cyp @@ -0,0 +1 @@ +CREATE (d:Dog {id:0}),(h:Human {id:1}), (c:Car {id:2}),(d)-[r:Drives {speed: 100, id:0}]->(h),(h)-[dr:Runs {speed: 150, id: 1}]->(c); diff --git a/e2e_correctness/refactor_test/test_rename_type_3/test.yml b/e2e_correctness/refactor_test/test_rename_type_3/test.yml new file mode 100644 index 000000000..a89458ec1 --- /dev/null +++ b/e2e_correctness/refactor_test/test_rename_type_3/test.yml @@ -0,0 +1,8 @@ +memgraph_query: > + MATCH ()-[r]-() WHERE r.id = 0 + WITH collect(distinct(r)) AS rels + CALL refactor.rename_type("Drives", "Glides", rels) YIELD relationships_changed RETURN relationships_changed; +neo4j_query: > + MATCH ()-[r]-() WHERE r.id = 0 + WITH collect(distinct(r)) AS rels + CALL apoc.refactor.rename.type("Drives","Glides", rels) YIELD total RETURN total; From 3ba3de09cd4f9e9bdc9db0f6303eb5b5b4e91be9 Mon Sep 17 00:00:00 2001 From: imilinovic <44698587+imilinovic@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:29:01 +0200 Subject: [PATCH 3/3] [E-refactor < T662] Implement refactor.delete_and_reconnect (#373) --- cpp/refactor_module/algorithm/refactor.cpp | 149 ++++++++++++++++++ cpp/refactor_module/algorithm/refactor.hpp | 24 +++ cpp/refactor_module/refactor_module.cpp | 8 + .../test_delete_and_reconnect_1/input.cyp | 1 + .../test_delete_and_reconnect_1/test.yml | 7 + .../test_delete_and_reconnect_2/input.cyp | 1 + .../test_delete_and_reconnect_2/test.yml | 7 + .../test_delete_and_reconnect_3/input.cyp | 1 + .../test_delete_and_reconnect_3/test.yml | 7 + .../test_delete_and_reconnect_4/input.cyp | 1 + .../test_delete_and_reconnect_4/test.yml | 7 + .../test_delete_and_reconnect_5/input.cyp | 1 + .../test_delete_and_reconnect_5/test.yml | 7 + .../test_delete_and_reconnect_6/input.cyp | 1 + .../test_delete_and_reconnect_6/test.yml | 7 + .../test_delete_and_reconnect_7/input.cyp | 1 + .../test_delete_and_reconnect_7/test.yml | 7 + .../test_delete_and_reconnect_8/input.cyp | 1 + .../test_delete_and_reconnect_8/test.yml | 7 + 19 files changed, 245 insertions(+) create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_1/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_1/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_2/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_2/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_3/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_3/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_4/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_4/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_5/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_5/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_6/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_6/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_7/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_7/test.yml create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_8/input.cyp create mode 100644 e2e_correctness/refactor_test/test_delete_and_reconnect_8/test.yml diff --git a/cpp/refactor_module/algorithm/refactor.cpp b/cpp/refactor_module/algorithm/refactor.cpp index e4f14e397..699108018 100644 --- a/cpp/refactor_module/algorithm/refactor.cpp +++ b/cpp/refactor_module/algorithm/refactor.cpp @@ -1,5 +1,6 @@ #include "refactor.hpp" +#include #include #include @@ -486,6 +487,46 @@ void Refactor::CollapseNode(mgp_list *args, mgp_graph *memgraph_graph, mgp_resul } } +Refactor::Config::Config(const mgp::Map &config) { + auto rel_strategy_string = config.At("relationshipSelectionStrategy"); + auto prop_strategy_string = config.At("properties"); + + if (rel_strategy_string.IsNull()) { + SetRelStrategy("incoming"); + return; + } + SetRelStrategy(rel_strategy_string.ValueString()); + if (prop_strategy_string.IsNull()) { + SetPropStrategy("combine"); + return; + } + SetPropStrategy(prop_strategy_string.ValueString()); +} + +void Refactor::Config::SetRelStrategy(std::string_view strategy) { + if (strategy == "incoming") { + rel_strategy = RelSelectStrategy::INCOMING; + } else if (strategy == "outgoing") { + rel_strategy = RelSelectStrategy::OUTGOING; + } else if (strategy == "merge") { + rel_strategy = RelSelectStrategy::MERGE; + } else { + throw mgp::ValueException("Invalid relationship selection strategy"); + } +} + +void Refactor::Config::SetPropStrategy(std::string_view strategy) { + if (strategy == "discard") { + prop_strategy = PropertiesStrategy::DISCARD; + } else if (strategy == "overwrite" || strategy == "override") { + prop_strategy = PropertiesStrategy::OVERRIDE; + } else if (strategy == "combine") { + prop_strategy = PropertiesStrategy::COMBINE; + } else { + throw mgp::ValueException("Invalid properties selection strategy"); + } +} + namespace { template @@ -517,6 +558,114 @@ void NormalizeToBoolean(NodeOrRel object, const std::string &property_key, } // namespace +void Refactor::DeleteAndReconnect(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { + mgp::MemoryDispatcherGuard guard{memory}; + const auto arguments = mgp::List(args); + const auto record_factory = mgp::RecordFactory(result); + try { + const auto path{arguments[0].ValuePath()}; + const auto nodes_to_delete_list{arguments[1].ValueList()}; + const auto config_map{arguments[2].ValueMap()}; + + std::unordered_set nodes_to_delete; + for (const auto &node : nodes_to_delete_list) { + nodes_to_delete.insert(node.ValueNode().Id().AsInt()); + } + + Config config{config_map}; + mgp::List nodes; + mgp::List relationships; + int64_t prev_non_deleted_path_index{-1}; + int64_t prev_non_deleted_node_id{-1}; + std::unordered_set to_be_deleted; + auto graph = mgp::Graph{memgraph_graph}; + + for (size_t i = 0; i < path.Length() + 1; ++i) { + auto node = path.GetNodeAt(i); + int64_t id = node.Id().AsInt(); + auto delete_node = nodes_to_delete.contains(id); + + const auto modify_relationship = [&graph, &relationships](mgp::Relationship relationship, const mgp::Node &node, + int64_t other_node_id) { + if (relationship.From().Id().AsInt() == other_node_id) { + graph.SetTo(relationship, node); + } else { + graph.SetFrom(relationship, node); + } + relationships.AppendExtend(mgp::Value(relationship)); + }; + + const auto merge_relationships = [](mgp::Relationship &rel, mgp::Relationship &other, bool combine = false) { + for (const auto &[key, value] : other.Properties()) { + auto old_property = rel.GetProperty(key); + if (!old_property.IsNull()) { + if (combine) { + rel.SetProperty(key, mgp::Value(mgp::List{old_property, value})); + } + continue; + } + rel.SetProperty(key, value); + } + }; + + if (!delete_node && prev_non_deleted_path_index != -1 && + (prev_non_deleted_path_index != static_cast(i - 1))) { // there was a deleted node in between + if (config.rel_strategy == RelSelectStrategy::INCOMING) { + modify_relationship(path.GetRelationshipAt(prev_non_deleted_path_index), node, prev_non_deleted_node_id); + } else if (config.rel_strategy == RelSelectStrategy::OUTGOING) { + modify_relationship(path.GetRelationshipAt(i - 1), path.GetNodeAt(prev_non_deleted_path_index), id); + } else { // RelSelectStrategy::MERGE + auto new_rel = path.GetRelationshipAt( + config.prop_strategy == PropertiesStrategy::OVERRIDE ? i - 1 : prev_non_deleted_path_index); + auto old_rel = path.GetRelationshipAt( + config.prop_strategy == PropertiesStrategy::OVERRIDE ? prev_non_deleted_path_index : i - 1); + + std::string new_type; + if (config.prop_strategy == PropertiesStrategy::OVERRIDE) { + new_type = std::string(new_rel.Type()) + "_" + std::string(old_rel.Type()); + } else { + new_type = std::string(old_rel.Type()) + "_" + std::string(new_rel.Type()); + } + graph.ChangeType(new_rel, new_type); + + if (config.prop_strategy == PropertiesStrategy::DISCARD) { + modify_relationship(new_rel, node, prev_non_deleted_node_id); + merge_relationships(new_rel, old_rel); + } else if (config.prop_strategy == PropertiesStrategy::OVERRIDE) { + modify_relationship(new_rel, path.GetNodeAt(prev_non_deleted_path_index), id); + merge_relationships(new_rel, old_rel); + } else { // PropertiesStrategy::COMBINE + modify_relationship(new_rel, node, prev_non_deleted_node_id); + merge_relationships(new_rel, old_rel, true); + } + } + } else if (!delete_node && prev_non_deleted_path_index != -1) { + relationships.AppendExtend(mgp::Value(path.GetRelationshipAt(prev_non_deleted_path_index))); + } + + if (!delete_node) { + nodes.AppendExtend(mgp::Value(node)); + prev_non_deleted_path_index = static_cast(i); + prev_non_deleted_node_id = id; + } else { + to_be_deleted.insert(node); + } + } + + for (const auto &node : to_be_deleted) { + graph.DetachDeleteNode(node); + } + + auto record = record_factory.NewRecord(); + record.Insert(std::string(kReturnDeleteAndReconnect1).c_str(), nodes); + record.Insert(std::string(kReturnDeleteAndReconnect2).c_str(), relationships); + + } catch (const std::exception &e) { + record_factory.SetErrorMessage(e.what()); + return; + } +} + void Refactor::NormalizeAsBoolean(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) { mgp::MemoryDispatcherGuard guard{memory}; const auto arguments = mgp::List(args); diff --git a/cpp/refactor_module/algorithm/refactor.hpp b/cpp/refactor_module/algorithm/refactor.hpp index bdbb3ee35..6d43ecd7a 100644 --- a/cpp/refactor_module/algorithm/refactor.hpp +++ b/cpp/refactor_module/algorithm/refactor.hpp @@ -4,6 +4,20 @@ namespace Refactor { +enum class RelSelectStrategy { INCOMING = 0, OUTGOING = 1, MERGE = 2 }; + +enum class PropertiesStrategy { DISCARD = 0, OVERRIDE = 1, COMBINE = 2 }; + +struct Config { + explicit Config(const mgp::Map &config); + + void SetRelStrategy(std::string_view strategy); + void SetPropStrategy(std::string_view strategy); + + RelSelectStrategy rel_strategy; + PropertiesStrategy prop_strategy; +}; + /* categorize constants */ constexpr const std::string_view kProcedureCategorize = "categorize"; constexpr const std::string_view kReturnCategorize = "status"; @@ -93,6 +107,14 @@ constexpr std::string_view kResultExtractNode1 = "input"; constexpr std::string_view kResultExtractNode2 = "output"; constexpr std::string_view kResultExtractNode3 = "error"; +/* delete_and_reconnect constants */ +constexpr std::string_view kProcedureDeleteAndReconnect = "delete_and_reconnect"; +constexpr std::string_view kDeleteAndReconnectArg1 = "path"; +constexpr std::string_view kDeleteAndReconnectArg2 = "nodes"; +constexpr std::string_view kDeleteAndReconnectArg3 = "config"; +constexpr std::string_view kReturnDeleteAndReconnect1 = "nodes"; +constexpr std::string_view kReturnDeleteAndReconnect2 = "relationships"; + /* rename_type constants */ constexpr std::string_view kProcedureRenameType = "rename_type"; constexpr std::string_view kRenameTypeArg1 = "relationships"; @@ -133,6 +155,8 @@ void Invert(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_m void InvertRel(mgp::Graph &graph, mgp::Relationship &rel); +void DeleteAndReconnect(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); + void NormalizeAsBoolean(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); void ExtractNode(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory); diff --git a/cpp/refactor_module/refactor_module.cpp b/cpp/refactor_module/refactor_module.cpp index 8275a621c..09a814aad 100644 --- a/cpp/refactor_module/refactor_module.cpp +++ b/cpp/refactor_module/refactor_module.cpp @@ -84,6 +84,14 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem mgp::Return(std::string(Refactor::kReturnRelationshipCollapseNode).c_str(), mgp::Type::Relationship)}, module, memory); + AddProcedure(Refactor::DeleteAndReconnect, Refactor::kProcedureDeleteAndReconnect, mgp::ProcedureType::Write, + {mgp::Parameter(Refactor::kDeleteAndReconnectArg1, mgp::Type::Path), + mgp::Parameter(Refactor::kDeleteAndReconnectArg2, {mgp::Type::List, mgp::Type::Node}), + mgp::Parameter(Refactor::kDeleteAndReconnectArg3, mgp::Type::Map, mgp::Value(mgp::Map()))}, + {mgp::Return(Refactor::kReturnDeleteAndReconnect1, {mgp::Type::List, mgp::Type::Node}), + mgp::Return(Refactor::kReturnDeleteAndReconnect2, {mgp::Type::List, mgp::Type::Relationship})}, + module, memory); + AddProcedure(Refactor::ExtractNode, Refactor::kProcedureExtractNode, mgp::ProcedureType::Write, {mgp::Parameter(Refactor::kExtractNodeArg1, mgp::Type::Any), mgp::Parameter(Refactor::kExtractNodeArg2, {mgp::Type::List, mgp::Type::String}), diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_1/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_1/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_1/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_1/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_1/test.yml new file mode 100644 index 000000000..8fd60d7f4 --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_1/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_2/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_2/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_2/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_2/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_2/test.yml new file mode 100644 index 000000000..8f6819038 --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_2/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "incoming"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "incoming"}) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_3/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_3/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_3/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_3/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_3/test.yml new file mode 100644 index 000000000..8f58a0465 --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_3/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "outgoing"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "outgoing"}) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_4/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_4/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_4/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_4/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_4/test.yml new file mode 100644 index 000000000..8f17eeeef --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_4/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "merge"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "merge"}) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_5/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_5/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_5/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_5/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_5/test.yml new file mode 100644 index 000000000..6bb85abc4 --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_5/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "discard"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "discard"}) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_6/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_6/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_6/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_6/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_6/test.yml new file mode 100644 index 000000000..41f1ad52c --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_6/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "combine"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "combine"}) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_7/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_7/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_7/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_7/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_7/test.yml new file mode 100644 index 000000000..09cb8cac7 --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_7/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "overwrite"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [b,d] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "overwrite"}) YIELD nodes, relationships RETURN nodes, relationships; diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_8/input.cyp b/e2e_correctness/refactor_test/test_delete_and_reconnect_8/input.cyp new file mode 100644 index 000000000..cace844ce --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_8/input.cyp @@ -0,0 +1 @@ +CREATE (n1:Node {id: 1, name: "Node 1"})-[:CONNECTED_TO {relationship_id: 1, name: "Rel1"}]->(n2:Node {id: 2, name: "Node 2"})-[:CONNECTED_TO {relationship_id: 2, name: "Rel2"}]->(n3:Node {id: 3, name: "Node 3"})-[:CONNECTED_TO {relationship_id: 3, name: "Rel3"}]->(n4:Node {id: 4, name: "Node 4"})-[:CONNECTED_TO {relationship_id: 4, name: "Rel4"}]->(n5:Node {id: 5, name: "Node 5"}); diff --git a/e2e_correctness/refactor_test/test_delete_and_reconnect_8/test.yml b/e2e_correctness/refactor_test/test_delete_and_reconnect_8/test.yml new file mode 100644 index 000000000..d41beb708 --- /dev/null +++ b/e2e_correctness/refactor_test/test_delete_and_reconnect_8/test.yml @@ -0,0 +1,7 @@ +memgraph_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [a, b, c, d, e] as l CALL refactor.delete_and_reconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "discard"}) YIELD nodes, relationships RETURN nodes, relationships; + +neo4j_query: > + MATCH p=(a:Node)-->(b:Node)-->(c:Node)-->(d:Node)-->(e:Node) + WITH p, [a, b, c, d, e] as l CALL apoc.refactor.deleteAndReconnect(p, l, {relationshipSelectionStrategy: "merge", properties: "discard"}) YIELD nodes, relationships RETURN nodes, relationships;