From 3376cd13a2a89c37911b7dadce7b2487b2370078 Mon Sep 17 00:00:00 2001 From: Jeffrey Lovitz Date: Fri, 4 Dec 2020 12:50:13 -0500 Subject: [PATCH 1/2] Add handling for metadata footers --- redisgraph/graph.py | 6 ++++++ redisgraph/query_result.py | 34 +++++++++++++++++++++++++++++++++- tests/functional/test_all.py | 12 ++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/redisgraph/graph.py b/redisgraph/graph.py index f4d802f..6284a63 100644 --- a/redisgraph/graph.py +++ b/redisgraph/graph.py @@ -58,6 +58,12 @@ def _refresh_attributes(self): for i, p in enumerate(props): self._properties[i] = p[0] + def refresh_metadata(self, version, labels, reltypes, properties): + self.version = version + self._labels = labels + self._relationshipTypes = reltypes + self._properties = properties + def get_label(self, idx): try: label = self._labels[idx] diff --git a/redisgraph/query_result.py b/redisgraph/query_result.py index 4d92f1f..6a0e1e2 100644 --- a/redisgraph/query_result.py +++ b/redisgraph/query_result.py @@ -57,8 +57,10 @@ def __init__(self, graph, response): self.parse_statistics(response[0]) else: # start by parsing statistics, matches the one we have - self.parse_statistics(response[-1]) # Last element. + self.parse_statistics(response[2]) # Third element, after header and records. self.parse_results(response) + if len(response) == 4: + self.parse_metadata(response[3]) def _check_for_errors(self, response): if isinstance(response[0], ResponseError): @@ -94,6 +96,36 @@ def parse_statistics(self, raw_statistics): if v is not None: self.statistics[s] = v + def parse_metadata(self, raw_metadata): + # Decode metadata: + # [ + # ["version", VERSION], + # ["labels", [[VALUE_STRING, "label_1"] ... ]], + # ["relationship types ", [[VALUE_STRING, "reltype_1"] ... ]], + # ["property keys", [[VALUE_STRING, "prop_1"] ... ]] + # ] + version = raw_metadata[0][1] + raw_labels = raw_metadata[1][1] + raw_reltypes = raw_metadata[2][1] + raw_props = raw_metadata[3][1] + + # Arrays to be passed into the internal graph structure. + labels = [None] * len(raw_labels) + reltypes = [None] * len(raw_reltypes) + properties = [None] * len(raw_props) + + for idx, label in enumerate(raw_labels): + labels[idx] = self.parse_scalar(label) + + for idx, reltype in enumerate(raw_reltypes): + reltypes[idx] = self.parse_scalar(reltype) + + for idx, prop in enumerate(raw_props): + properties[idx] = self.parse_scalar(prop) + + # Update the graph's internal metadata. + self.graph.refresh_metadata(version, labels, reltypes, properties) + def parse_header(self, raw_result_set): # An array of column name/column type pairs. header = raw_result_set[0] diff --git a/tests/functional/test_all.py b/tests/functional/test_all.py index 422448a..0cbc92a 100644 --- a/tests/functional/test_all.py +++ b/tests/functional/test_all.py @@ -328,6 +328,18 @@ def test_cache_sync(self): assert(A._relationshipTypes[0] == 'S') assert(A._relationshipTypes[1] == 'R') + def test_metadata(self): + A = Graph('metadata', self.r) + # Since this query modifies schemas and returns data, it should + # update all graph metadata in a single call. + A.query("CREATE (l:L {v: 1}) RETURN l") + assert(len(A._labels) == 1) + assert(len(A._properties) == 1) + assert(len(A._relationshipTypes) == 0) + assert(A._labels[0] == 'L') + assert(A._properties[0] == 'v') + assert(A.version != 0) + if __name__ == '__main__': unittest.main() From 652a58e8db235091635cc58ca262538fe5307242 Mon Sep 17 00:00:00 2001 From: Jeffrey Lovitz Date: Mon, 25 Jan 2021 12:15:19 -0500 Subject: [PATCH 2/2] Receive metadata as a map --- redisgraph/graph.py | 4 ++-- redisgraph/query_result.py | 35 +++++++++++------------------------ 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/redisgraph/graph.py b/redisgraph/graph.py index 6284a63..2b5677d 100644 --- a/redisgraph/graph.py +++ b/redisgraph/graph.py @@ -167,8 +167,8 @@ def query(self, q, params=None, timeout=None, read_only=False): # ask for compact result-set format # specify known graph version cmd = "GRAPH.RO_QUERY" if read_only else "GRAPH.QUERY" - # command = [cmd, self.name, query, "--compact", "version", self.version] - command = [cmd, self.name, query, "--compact"] + command = [cmd, self.name, query, "--compact", "version", self.version] + # command = [cmd, self.name, query, "--compact"] # include timeout is specified if timeout: diff --git a/redisgraph/query_result.py b/redisgraph/query_result.py index 6a0e1e2..8cdbdc3 100644 --- a/redisgraph/query_result.py +++ b/redisgraph/query_result.py @@ -98,30 +98,17 @@ def parse_statistics(self, raw_statistics): def parse_metadata(self, raw_metadata): # Decode metadata: - # [ - # ["version", VERSION], - # ["labels", [[VALUE_STRING, "label_1"] ... ]], - # ["relationship types ", [[VALUE_STRING, "reltype_1"] ... ]], - # ["property keys", [[VALUE_STRING, "prop_1"] ... ]] - # ] - version = raw_metadata[0][1] - raw_labels = raw_metadata[1][1] - raw_reltypes = raw_metadata[2][1] - raw_props = raw_metadata[3][1] - - # Arrays to be passed into the internal graph structure. - labels = [None] * len(raw_labels) - reltypes = [None] * len(raw_reltypes) - properties = [None] * len(raw_props) - - for idx, label in enumerate(raw_labels): - labels[idx] = self.parse_scalar(label) - - for idx, reltype in enumerate(raw_reltypes): - reltypes[idx] = self.parse_scalar(reltype) - - for idx, prop in enumerate(raw_props): - properties[idx] = self.parse_scalar(prop) + # { + # "version", VERSION, + # "labels", [[VALUE_STRING, "label_1"] ... ], + # "relationship types ", [[VALUE_STRING, "reltype_1"] ... ], + # "property keys", [[VALUE_STRING, "prop_1"] ... ] + # } + metadata = self.parse_map(raw_metadata) + version = metadata["version"] + labels = metadata["labels"] + reltypes = metadata["relationship types"] + properties = metadata["property keys"] # Update the graph's internal metadata. self.graph.refresh_metadata(version, labels, reltypes, properties)