From 529502ea036dc568dd49fa4e278258f5563d8000 Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Mon, 28 Oct 2019 08:45:31 +0200 Subject: [PATCH 1/7] add support for path type --- redisgraph/__init__.py | 1 + redisgraph/path.py | 27 +++++++++++++++++++++++++++ redisgraph/query_result.py | 11 +++++++++++ test.py | 20 ++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 redisgraph/path.py diff --git a/redisgraph/__init__.py b/redisgraph/__init__.py index adc7377..0b06119 100644 --- a/redisgraph/__init__.py +++ b/redisgraph/__init__.py @@ -1,3 +1,4 @@ from .node import Node from .edge import Edge from .graph import Graph +from .path import Path diff --git a/redisgraph/path.py b/redisgraph/path.py new file mode 100644 index 0000000..e49a67e --- /dev/null +++ b/redisgraph/path.py @@ -0,0 +1,27 @@ + +class Path(object): + + def __init__(self, nodes, relationships): + self.nodes = nodes + self.relationships = relationships + + def nodes(self): + return self.nodes + + def relationships(self): + return self.relationships + + def get_node(self, index): + return self.nodes[index] + + def get_relationship(self, index): + return self.relationships[index] + + def first_node(self): + return self.nodes[0] + + def last_node(self): + return self.nodes[-1] + + def __eq__(self, other): + return self.nodes == other.nodes and self.relationships == other.relationships diff --git a/redisgraph/query_result.py b/redisgraph/query_result.py index 2f437bf..4cdb2e0 100644 --- a/redisgraph/query_result.py +++ b/redisgraph/query_result.py @@ -1,5 +1,6 @@ from .node import Node from .edge import Edge +from .path import Path from prettytable import PrettyTable from redis import ResponseError @@ -21,6 +22,7 @@ class ResultSetScalarTypes(object): VALUE_ARRAY = 6 VALUE_EDGE = 7 VALUE_NODE = 8 + VALUE_PATH = 9 class QueryResult(object): LABELS_ADDED = 'Labels added' @@ -124,6 +126,12 @@ def parse_edge(self, cell): properties = self.parse_entity_properties(cell[4]) return Edge(src_node_id, relation, dest_node_id, edge_id=edge_id, properties=properties) + + def parse_path(self, cell): + nodes = self.parse_scalar(cell[0]) + relationships = self.parse_scalar(cell[1]) + return Path(nodes, relationships) + def parse_scalar(self, cell): scalar_type = int(cell[0]) value = cell[1] @@ -162,6 +170,9 @@ def parse_scalar(self, cell): elif scalar_type == ResultSetScalarTypes.VALUE_EDGE: scalar = self.parse_edge(value) + elif scalar_type == ResultSetScalarTypes.VALUE_PATH: + scalar = self.parse_path(value) + elif scalar_type == ResultSetScalarTypes.VALUE_UNKNOWN: print("Unknown scalar type\n") diff --git a/test.py b/test.py index 31f677f..2b4fe10 100644 --- a/test.py +++ b/test.py @@ -65,5 +65,25 @@ def test_array_functions(self): # All done, remove graph. redis_graph.delete() + + def test_path(self): + redis_graph = Graph('social', self.r) + + query = """CREATE (a:L1)-[:R1 {value:1}]->(b:L1)-[:R1 {value:2}]->(c:L1)""" + redis_graph.query(query) + query = "MATCH p=(:L1)-[:R1]->(:L1) RETURN p" + node0 = Node(node_id=0, label="L1") + edge01 = Edge(0, "R1", 1, edge_id=0, properties={'value': 1}) + node1 = Node(node_id=1, label="L1") + edge12 = Edge(1, "R1", 2, edge_id=1, properties={'value': 2}) + node2 = Node(node_id=2, label="L1") + + path01 = Path([node0, node1], [edge01]) + path12 = Path([node1, node2], [edge12]) + expected_results = [[path01], [path12]] + result = redis_graph.query(query) + self.assertEqual(expected_results, result.result_set) + + if __name__ == '__main__': unittest.main() From 24abf0a8ec8213b70fb355ee903167dad5438eb9 Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Mon, 28 Oct 2019 10:11:13 +0200 Subject: [PATCH 2/7] fixed PR comments --- redisgraph/path.py | 42 ++++++++++++++++++++++++++++++++------ redisgraph/query_result.py | 5 ++--- test.py | 24 +++++++++++++++------- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/redisgraph/path.py b/redisgraph/path.py index e49a67e..e096e98 100644 --- a/redisgraph/path.py +++ b/redisgraph/path.py @@ -1,21 +1,33 @@ +from .node import Node +from .edge import Edge class Path(object): - def __init__(self, nodes, relationships): + def __init__(self, nodes, edges): + assert(isinstance(nodes, list) and isinstance(edges, list)) self.nodes = nodes - self.relationships = relationships + self.edges = edges + self.append_type = Node + + @classmethod + def new_empty_path(cls): + return cls([], []) + + @classmethod + def new_path(cls, nodes, edges): + return cls(nodes, edges) def nodes(self): return self.nodes - def relationships(self): - return self.relationships + def edges(self): + return self.edges def get_node(self, index): return self.nodes[index] def get_relationship(self, index): - return self.relationships[index] + return self.edges[index] def first_node(self): return self.nodes[0] @@ -23,5 +35,23 @@ def first_node(self): def last_node(self): return self.nodes[-1] + def edge_count(self): + return len(self.edges) + + def nodes_count(self): + return len(self.nodes) + + def add_node(self, node): + assert(isinstance(node, self.append_type)) + self.nodes.append(node) + self.append_type = Edge + return self + + def add_edge(self, edge): + assert(isinstance(edge, self.append_type)) + self.edges.append(edge) + self.append_type = Node + return self + def __eq__(self, other): - return self.nodes == other.nodes and self.relationships == other.relationships + return self.nodes == other.nodes and self.edges == other.edges diff --git a/redisgraph/query_result.py b/redisgraph/query_result.py index 4cdb2e0..7396d81 100644 --- a/redisgraph/query_result.py +++ b/redisgraph/query_result.py @@ -126,11 +126,10 @@ def parse_edge(self, cell): properties = self.parse_entity_properties(cell[4]) return Edge(src_node_id, relation, dest_node_id, edge_id=edge_id, properties=properties) - def parse_path(self, cell): nodes = self.parse_scalar(cell[0]) - relationships = self.parse_scalar(cell[1]) - return Path(nodes, relationships) + edges = self.parse_scalar(cell[1]) + return Path.new_path(nodes, edges) def parse_scalar(self, cell): scalar_type = int(cell[0]) diff --git a/test.py b/test.py index 2b4fe10..83d7573 100644 --- a/test.py +++ b/test.py @@ -69,21 +69,31 @@ def test_array_functions(self): def test_path(self): redis_graph = Graph('social', self.r) - query = """CREATE (a:L1)-[:R1 {value:1}]->(b:L1)-[:R1 {value:2}]->(c:L1)""" - redis_graph.query(query) - query = "MATCH p=(:L1)-[:R1]->(:L1) RETURN p" node0 = Node(node_id=0, label="L1") - edge01 = Edge(0, "R1", 1, edge_id=0, properties={'value': 1}) node1 = Node(node_id=1, label="L1") - edge12 = Edge(1, "R1", 2, edge_id=1, properties={'value': 2}) node2 = Node(node_id=2, label="L1") + edge01 = Edge(node0, "R1", node1, edge_id=0, properties={'value': 1}) + edge12 = Edge(node1, "R1", node2, edge_id=1, properties={'value': 2}) + + redis_graph.add_node(node0) + redis_graph.add_node(node1) + redis_graph.add_node(node2) + redis_graph.add_edge(edge01) + redis_graph.add_edge(edge12) + + redis_graph.commit() - path01 = Path([node0, node1], [edge01]) - path12 = Path([node1, node2], [edge12]) + path01 = Path.new_empty_path().add_node(node0).add_edge(edge01).add_node(node1) + path12 = Path.new_empty_path().add_node(node1).add_edge(edge12).add_node(node2) expected_results = [[path01], [path12]] + + query = "MATCH p=(:L1)-[:R1]->(:L1) RETURN p" result = redis_graph.query(query) self.assertEqual(expected_results, result.result_set) + # All done, remove graph. + redis_graph.delete() + if __name__ == '__main__': unittest.main() From 229b3d67cd81615943818e69a174adeaae1ae303 Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Mon, 28 Oct 2019 15:45:22 +0200 Subject: [PATCH 3/7] fixed PR comments --- redisgraph/path.py | 4 ---- redisgraph/query_result.py | 2 +- test.py | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/redisgraph/path.py b/redisgraph/path.py index e096e98..b774660 100644 --- a/redisgraph/path.py +++ b/redisgraph/path.py @@ -13,10 +13,6 @@ def __init__(self, nodes, edges): def new_empty_path(cls): return cls([], []) - @classmethod - def new_path(cls, nodes, edges): - return cls(nodes, edges) - def nodes(self): return self.nodes diff --git a/redisgraph/query_result.py b/redisgraph/query_result.py index 7396d81..2c8b479 100644 --- a/redisgraph/query_result.py +++ b/redisgraph/query_result.py @@ -129,7 +129,7 @@ def parse_edge(self, cell): def parse_path(self, cell): nodes = self.parse_scalar(cell[0]) edges = self.parse_scalar(cell[1]) - return Path.new_path(nodes, edges) + return Path(nodes, edges) def parse_scalar(self, cell): scalar_type = int(cell[0]) diff --git a/test.py b/test.py index 83d7573..9a372f2 100644 --- a/test.py +++ b/test.py @@ -81,7 +81,7 @@ def test_path(self): redis_graph.add_edge(edge01) redis_graph.add_edge(edge12) - redis_graph.commit() + redis_graph.flush() path01 = Path.new_empty_path().add_node(node0).add_edge(edge01).add_node(node1) path12 = Path.new_empty_path().add_node(node1).add_edge(edge12).add_node(node2) From 8fa3bdf8ee908f905f09e7004b8e2517ceaf1c12 Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Thu, 31 Oct 2019 08:20:18 +0200 Subject: [PATCH 4/7] fixed PR comments --- redisgraph/path.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redisgraph/path.py b/redisgraph/path.py index b774660..bcec3b5 100644 --- a/redisgraph/path.py +++ b/redisgraph/path.py @@ -38,13 +38,13 @@ def nodes_count(self): return len(self.nodes) def add_node(self, node): - assert(isinstance(node, self.append_type)) + assert(type(node) == self.append_type) self.nodes.append(node) self.append_type = Edge return self def add_edge(self, edge): - assert(isinstance(edge, self.append_type)) + assert(type(edge) == self.append_type) self.edges.append(edge) self.append_type = Node return self From 7db8259ec16ee372709708ea3d04e97a50abbe0a Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Fri, 1 Nov 2019 01:04:27 +0200 Subject: [PATCH 5/7] added example --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 39c5b77..7f4d636 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ RedisGraph python client ```python import redis -from redisgraph import Node, Edge, Graph +from redisgraph import Node, Edge, Graph, Path r = redis.Redis(host='localhost', port=6379) @@ -47,6 +47,16 @@ for record in result.result_set: person_age = record[1] visit_purpose = record[2] country_name = record[3] + +query = """MATCH p = (:person)-[:visited {purpose:"pleasure"}]->(:country) RETURN p""" + +result = redis_graph.query(query) + +# Iterate through resultset +for record in result.result_set: + path = record[0] + # See path.py for more path API. + print(path.edge_count(), path.nodes_count()) # All done, remove graph. From 4a9bf1825791c1037bafb438add551e0b0d4bb98 Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Sun, 3 Nov 2019 13:38:03 +0200 Subject: [PATCH 6/7] changed readme --- README.md | 3 +-- redisgraph/path.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f4d636..ce45f25 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,7 @@ result = redis_graph.query(query) # Iterate through resultset for record in result.result_set: path = record[0] - # See path.py for more path API. - print(path.edge_count(), path.nodes_count()) + print(path) # All done, remove graph. diff --git a/redisgraph/path.py b/redisgraph/path.py index bcec3b5..d3008ec 100644 --- a/redisgraph/path.py +++ b/redisgraph/path.py @@ -51,3 +51,17 @@ def add_edge(self, edge): def __eq__(self, other): return self.nodes == other.nodes and self.edges == other.edges + + def __str__(self): + res = "<" + edge_count = self.edge_count() + for i in range(0, edge_count): + node_id = self.get_node(i).id + res += "(" + str(node_id) + ")" + edge = self.get_relationship(i) + res += "-[" + str(int(edge.id)) + "]->" if edge.src_node == node_id else "<-[" + str(int(edge.id)) + "]-" + node_id = self.get_node(edge_count).id + res += "(" + str(node_id) + ")" + res += ">" + return res + \ No newline at end of file From a01df09b31ec15f3d7e2f4ea4976618adb082931 Mon Sep 17 00:00:00 2001 From: DvirDukhan Date: Sun, 3 Nov 2019 14:21:53 +0200 Subject: [PATCH 7/7] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 136b36d..1885543 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages setup( name='redisgraph', - version='2.0', + version='2.1', description='RedisGraph Python Client', url='https://github.com/redislabs/redisgraph-py',