Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
mpintaric55334 committed Oct 24, 2023
2 parents 8834525 + 3ba3de0 commit 32e5695
Show file tree
Hide file tree
Showing 26 changed files with 314 additions and 3 deletions.
2 changes: 1 addition & 1 deletion cpp/memgraph
Submodule memgraph updated 406 files
181 changes: 179 additions & 2 deletions cpp/refactor_module/algorithm/refactor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "refactor.hpp"

#include <string_view>
#include <unordered_set>

#include <fmt/format.h>
Expand Down Expand Up @@ -401,7 +402,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 {
Expand Down Expand Up @@ -446,7 +447,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 {
Expand Down Expand Up @@ -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");
}
}

void Refactor::RenameTypeProperty(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
mgp::MemoryDispatcherGuard guard{memory};
const auto arguments = mgp::List(args);
Expand Down Expand Up @@ -549,6 +590,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<int64_t> 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<mgp::Node> 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<int64_t>(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<int64_t>(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);
Expand Down Expand Up @@ -652,3 +801,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;
}
}
33 changes: 33 additions & 0 deletions cpp/refactor_module/algorithm/refactor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -93,6 +107,21 @@ 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";
constexpr std::string_view kRenameTypeArg2 = "labels";
constexpr std::string_view kRenameTypeArg3 = "outType";
constexpr std::string_view kResultRenameType = "relationships_changed";

/* rename_node_property constants */
constexpr std::string_view kProcedureRenameTypeProperty = "rename_type_property";
constexpr std::string_view kRenameTypePropertyArg1 = "old_property";
Expand Down Expand Up @@ -133,9 +162,13 @@ 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 RenameTypeProperty(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);

void RenameType(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory);
} // namespace Refactor
14 changes: 14 additions & 0 deletions cpp/refactor_module/refactor_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}),
Expand All @@ -101,6 +109,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);

AddProcedure(Refactor::RenameTypeProperty, std::string(Refactor::kProcedureRenameTypeProperty).c_str(),
mgp::ProcedureType::Write,
{mgp::Parameter(std::string(Refactor::kRenameTypePropertyArg1).c_str(), mgp::Type::String),
Expand Down
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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"});
Original file line number Diff line number Diff line change
@@ -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;
Loading

0 comments on commit 32e5695

Please sign in to comment.