diff --git a/tests/e2e/write_procedures/procedures/read.py b/tests/e2e/write_procedures/procedures/read.py index 5f503721d..be2d22a4f 100644 --- a/tests/e2e/write_procedures/procedures/read.py +++ b/tests/e2e/write_procedures/procedures/read.py @@ -53,3 +53,24 @@ def subgraph_get_2_hop_edges(ctx: mgp.ProcCtx, vertex: mgp.Vertex) -> mgp.Record def subgraph_get_out_edges_vertex_id(ctx: mgp.ProcCtx, vertex: mgp.Vertex) -> mgp.Record(edge=mgp.Edge): vertex = ctx.graph.get_vertex_by_id(vertex.id) return [mgp.Record(edge=edge) for edge in vertex.out_edges] + + +@mgp.read_proc +def subgraph_get_path_vertices(ctx: mgp.ProcCtx, path: mgp.Path) -> mgp.Record(node=mgp.Vertex): + return [mgp.Record(node=node) for node in path.vertices] + + +@mgp.read_proc +def subgraph_get_path_edges(ctx: mgp.ProcCtx, path: mgp.Path) -> mgp.Record(edge=mgp.Edge): + return [mgp.Record(edge=edge) for edge in path.edges] + + +@mgp.read_proc +def subgraph_get_path_vertices_in_subgraph(ctx: mgp.ProcCtx, path: mgp.Path) -> mgp.Record(node=mgp.Vertex): + path_vertices = path.vertices + graph_vertices = ctx.graph.vertices + records = [] + for path_vertex in path_vertices: + if path_vertex in graph_vertices: + records.append(mgp.Record(node=path_vertex)) + return records diff --git a/tests/e2e/write_procedures/procedures/write.py b/tests/e2e/write_procedures/procedures/write.py index e180be40e..c3d733d73 100644 --- a/tests/e2e/write_procedures/procedures/write.py +++ b/tests/e2e/write_procedures/procedures/write.py @@ -35,13 +35,12 @@ def detach_delete_vertex(ctx: mgp.ProcCtx, v: mgp.Any) -> mgp.Record(): @mgp.write_proc -def create_edge(ctx: mgp.ProcCtx, from_vertex: mgp.Vertex, - to_vertex: mgp.Vertex, - edge_type: str) -> mgp.Record(e=mgp.Any): +def create_edge( + ctx: mgp.ProcCtx, from_vertex: mgp.Vertex, to_vertex: mgp.Vertex, edge_type: str +) -> mgp.Record(e=mgp.Any): e = None try: - e = ctx.graph.create_edge( - from_vertex, to_vertex, mgp.EdgeType(edge_type)) + e = ctx.graph.create_edge(from_vertex, to_vertex, mgp.EdgeType(edge_type)) except RuntimeError as ex: return mgp.Record(e=str(ex)) return mgp.Record(e=e) @@ -54,32 +53,59 @@ def delete_edge(ctx: mgp.ProcCtx, edge: mgp.Edge) -> mgp.Record(): @mgp.write_proc -def set_property(ctx: mgp.ProcCtx, object: mgp.Any, - name: str, value: mgp.Nullable[mgp.Any]) -> mgp.Record(): +def set_property(ctx: mgp.ProcCtx, object: mgp.Any, name: str, value: mgp.Nullable[mgp.Any]) -> mgp.Record(): object.properties.set(name, value) return mgp.Record() @mgp.write_proc -def add_label(ctx: mgp.ProcCtx, object: mgp.Any, - name: str) -> mgp.Record(o=mgp.Any): +def add_label(ctx: mgp.ProcCtx, object: mgp.Any, name: str) -> mgp.Record(o=mgp.Any): object.add_label(name) return mgp.Record(o=object) @mgp.write_proc -def remove_label(ctx: mgp.ProcCtx, object: mgp.Any, - name: str) -> mgp.Record(o=mgp.Any): +def remove_label(ctx: mgp.ProcCtx, object: mgp.Any, name: str) -> mgp.Record(o=mgp.Any): object.remove_label(name) return mgp.Record(o=object) @mgp.write_proc -def underlying_graph_is_mutable(ctx: mgp.ProcCtx, - object: mgp.Any) -> mgp.Record(mutable=bool): +def underlying_graph_is_mutable(ctx: mgp.ProcCtx, object: mgp.Any) -> mgp.Record(mutable=bool): return mgp.Record(mutable=object.underlying_graph_is_mutable()) @mgp.write_proc def graph_is_mutable(ctx: mgp.ProcCtx) -> mgp.Record(mutable=bool): return mgp.Record(mutable=ctx.graph.is_mutable()) + + +@mgp.write_proc +def subgraph_insert_vertex_get_vertices(ctx: mgp.ProcCtx) -> mgp.Record(node=mgp.Vertex): + ctx.graph.create_vertex() + return [mgp.Record(node=node) for node in ctx.graph.vertices] + + +@mgp.write_proc +def subgraph_insert_edge_get_vertex_out_edges( + ctx: mgp.ProcCtx, vertex1: mgp.Vertex, vertex2: mgp.Vertex +) -> mgp.Record(edge=mgp.Edge): + ctx.graph.create_edge(vertex1, vertex2, edge_type=mgp.EdgeType("EDGE_TYPE")) + return [mgp.Record(edge=edge) for edge in vertex1.out_edges] + + +@mgp.write_proc +def subgraph_remove_edge_get_vertex_out_edges(ctx: mgp.ProcCtx, edge: mgp.Edge) -> mgp.Record(edge=mgp.Edge): + from_vertex = edge.from_vertex + ctx.graph.delete_edge(edge) + return [mgp.Record(edge=edge) for edge in from_vertex.out_edges] + + +@mgp.write_proc +def subgraph_remove_vertex_and_out_edges_get_vertices( + ctx: mgp.ProcCtx, vertex: mgp.Vertex +) -> mgp.Record(node=mgp.Vertex): + out_edges = vertex.out_edges + for edge in out_edges: + ctx.graph.delete_edge(edge) + return [mgp.Record(node=vertex) for vertex in ctx.graph.vertices] diff --git a/tests/e2e/write_procedures/read_subgraph.py b/tests/e2e/write_procedures/read_subgraph.py index cd1f22939..d5aadb482 100644 --- a/tests/e2e/write_procedures/read_subgraph.py +++ b/tests/e2e/write_procedures/read_subgraph.py @@ -31,17 +31,27 @@ def create_subgraph(cursor): execute_and_fetch_all(cursor, "MATCH (p1:Person {id: 3}) MATCH (p2:Person {id:4}) CREATE (p1)-[:KNOWS]->(p2);") +def create_smaller_subgraph(cursor): + execute_and_fetch_all(cursor, "CREATE (n:Person {id: 1});") + execute_and_fetch_all(cursor, "CREATE (n:Person {id: 2});") + execute_and_fetch_all(cursor, "CREATE (n:Team {id: 5});") + execute_and_fetch_all(cursor, "CREATE (n:Team {id: 6});") + execute_and_fetch_all(cursor, "MATCH (p:Person {id: 1}) MATCH (t:Team {id:5}) CREATE (p)-[:SUPPORTS]->(t);") + execute_and_fetch_all(cursor, "MATCH (p:Person {id: 1}) MATCH (t:Team {id:6}) CREATE (p)-[:SUPPORTS]->(t);") + execute_and_fetch_all(cursor, "MATCH (p:Person {id: 2}) MATCH (t:Team {id:6}) CREATE (p)-[:SUPPORTS]->(t);") + + def test_get_vertices(connection): cursor = connection.cursor() execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") create_subgraph(cursor) - assert has_n_result_row(cursor, "MATCH (n) RETURN n", 6) - results = execute_and_fetch_all( + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( cursor, f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) AS graph CALL read.subgraph_get_vertices(graph) YIELD node RETURN node;", + 4, ) - assert len(results) == 4 execute_and_fetch_all( cursor, @@ -54,12 +64,13 @@ def test_get_out_edges(connection): execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") create_subgraph(cursor) - assert has_n_result_row(cursor, "MATCH (n) RETURN n", 6) - results = execute_and_fetch_all( + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( cursor, f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) AS graph MATCH (n1:Person {{id:1}}) CALL read.subgraph_get_out_edges(graph, n1) YIELD edge RETURN edge;", + 2, ) - assert len(results) == 2 + execute_and_fetch_all( cursor, f"MATCH (n) DETACH DELETE n;", @@ -71,14 +82,13 @@ def test_get_in_edges(connection): execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") create_subgraph(cursor) - assert has_n_result_row(cursor, "MATCH (n) RETURN n", 6) - results = execute_and_fetch_all( + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( cursor, f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) AS graph MATCH (t1:Team {{id:6}}) CALL read.subgraph_get_in_edges(graph, t1) YIELD edge RETURN edge;", + 2, ) - assert len(results) == 2 - execute_and_fetch_all( cursor, f"MATCH (n) DETACH DELETE n;", @@ -90,12 +100,12 @@ def test_get_2_hop_edges(connection): execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") create_subgraph(cursor) - assert has_n_result_row(cursor, "MATCH (n) RETURN n", 6) - results = execute_and_fetch_all( + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( cursor, f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) AS graph MATCH (n1:Person {{id:1}}) CALL read.subgraph_get_2_hop_edges(graph, n1) YIELD edge RETURN edge;", + 0, ) - assert len(results) == 0 execute_and_fetch_all( cursor, f"MATCH (n) DETACH DELETE n;", @@ -107,12 +117,12 @@ def test_get_out_edges_vertex_id(connection): execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") create_subgraph(cursor=cursor) - assert has_n_result_row(cursor, "MATCH (n) RETURN n", 6) - results = execute_and_fetch_all( + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( cursor, f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) AS graph MATCH (n1:Person {{id:1}}) CALL read.subgraph_get_out_edges_vertex_id(graph, n1) YIELD edge RETURN edge;", + 2, ) - assert len(results) == 2 execute_and_fetch_all( cursor, @@ -120,5 +130,119 @@ def test_get_out_edges_vertex_id(connection): ) +def test_subgraph_get_path_vertices(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_subgraph(cursor) + + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph MATCH path=(a:Person {{id: 1}})-[:SUPPORTS]->(b:Team {{id:5}}) CALL read.subgraph_get_path_vertices(graph, path) YIELD node RETURN node;", + 2, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + +def test_subgraph_get_path_edges(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_subgraph(cursor) + + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph MATCH path=(:Person {{id: 1}})-[:SUPPORTS]->(:Team {{id:5}}) CALL read.subgraph_get_path_edges(graph, path) YIELD edge RETURN edge;", + 1, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + +def test_subgraph_get_path_vertices_in_subgraph(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_subgraph(cursor) + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph MATCH path=(:Person {{id: 1}})-[:SUPPORTS]->(:Team {{id:5}}) CALL read.subgraph_get_path_vertices_in_subgraph(graph, path) YIELD node RETURN node;", + 2, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + +def test_subgraph_insert_vertex_get_vertices(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_subgraph(cursor) + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph CALL write.subgraph_insert_vertex_get_vertices(graph) YIELD node RETURN node;", + 5, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + +def test_subgraph_insert_edge_get_vertex_out_edges(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_subgraph(cursor) + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph MATCH (p1:Person {{id:2}}) MATCH (t1:Team {{id:6}}) CALL write.subgraph_insert_edge_get_vertex_out_edges(graph, p1, t1) YIELD edge RETURN edge;", + 2, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + +def test_subgraph_remove_edge_get_vertex_out_edges(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_subgraph(cursor) + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 6) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph MATCH (p1:Person {{id:1}})-[e:SUPPORTS]->(t1:Team {{id:5}}) CALL write.subgraph_remove_edge_get_vertex_out_edges(graph, e) YIELD edge RETURN edge;", + 1, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + +def test_subgraph_remove_vertex_and_out_edges_get_vertices(connection): + cursor = connection.cursor() + execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;") + create_smaller_subgraph(cursor) + assert has_n_result_row(cursor, "MATCH (n) RETURN n;", 4) + assert has_n_result_row( + cursor, + f"MATCH p=(n:Person)-[:SUPPORTS]->(m:Team) WITH project(p) as graph MATCH (p1:Person {{id:1}}) CALL write.subgraph_remove_vertex_and_out_edges_get_vertices(graph, p1) YIELD node RETURN node;", + 3, + ) + execute_and_fetch_all( + cursor, + f"MATCH (n) DETACH DELETE n;", + ) + + if __name__ == "__main__": sys.exit(pytest.main([__file__, "-rA"]))