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