redis 5.3.0b5__py3-none-any.whl → 6.0.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- redis/__init__.py +2 -11
- redis/_parsers/base.py +14 -2
- redis/asyncio/client.py +27 -14
- redis/asyncio/cluster.py +85 -59
- redis/asyncio/connection.py +76 -23
- redis/asyncio/lock.py +26 -5
- redis/asyncio/sentinel.py +11 -1
- redis/asyncio/utils.py +1 -1
- redis/auth/token.py +6 -2
- redis/backoff.py +15 -0
- redis/client.py +23 -14
- redis/cluster.py +112 -48
- redis/commands/cluster.py +1 -11
- redis/commands/core.py +219 -207
- redis/commands/helpers.py +0 -70
- redis/commands/redismodules.py +5 -17
- redis/commands/search/aggregation.py +3 -1
- redis/commands/search/commands.py +41 -14
- redis/commands/search/dialect.py +3 -0
- redis/commands/search/profile_information.py +14 -0
- redis/commands/search/query.py +5 -1
- redis/commands/vectorset/__init__.py +46 -0
- redis/commands/vectorset/commands.py +367 -0
- redis/commands/vectorset/utils.py +94 -0
- redis/connection.py +76 -27
- redis/exceptions.py +4 -1
- redis/lock.py +24 -4
- redis/ocsp.py +2 -1
- redis/sentinel.py +3 -1
- redis/utils.py +114 -1
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/METADATA +57 -23
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/RECORD +35 -39
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/WHEEL +1 -2
- redis/commands/graph/__init__.py +0 -263
- redis/commands/graph/commands.py +0 -313
- redis/commands/graph/edge.py +0 -91
- redis/commands/graph/exceptions.py +0 -3
- redis/commands/graph/execution_plan.py +0 -211
- redis/commands/graph/node.py +0 -88
- redis/commands/graph/path.py +0 -78
- redis/commands/graph/query_result.py +0 -588
- redis-5.3.0b5.dist-info/top_level.txt +0 -1
- /redis/commands/search/{indexDefinition.py → index_definition.py} +0 -0
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info/licenses}/LICENSE +0 -0
redis/commands/graph/path.py
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
from .edge import Edge
|
|
2
|
-
from .node import Node
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Path:
|
|
6
|
-
def __init__(self, nodes, edges):
|
|
7
|
-
if not (isinstance(nodes, list) and isinstance(edges, list)):
|
|
8
|
-
raise TypeError("nodes and edges must be list")
|
|
9
|
-
|
|
10
|
-
self._nodes = nodes
|
|
11
|
-
self._edges = edges
|
|
12
|
-
self.append_type = Node
|
|
13
|
-
|
|
14
|
-
@classmethod
|
|
15
|
-
def new_empty_path(cls):
|
|
16
|
-
return cls([], [])
|
|
17
|
-
|
|
18
|
-
def nodes(self):
|
|
19
|
-
return self._nodes
|
|
20
|
-
|
|
21
|
-
def edges(self):
|
|
22
|
-
return self._edges
|
|
23
|
-
|
|
24
|
-
def get_node(self, index):
|
|
25
|
-
return self._nodes[index]
|
|
26
|
-
|
|
27
|
-
def get_relationship(self, index):
|
|
28
|
-
return self._edges[index]
|
|
29
|
-
|
|
30
|
-
def first_node(self):
|
|
31
|
-
return self._nodes[0]
|
|
32
|
-
|
|
33
|
-
def last_node(self):
|
|
34
|
-
return self._nodes[-1]
|
|
35
|
-
|
|
36
|
-
def edge_count(self):
|
|
37
|
-
return len(self._edges)
|
|
38
|
-
|
|
39
|
-
def nodes_count(self):
|
|
40
|
-
return len(self._nodes)
|
|
41
|
-
|
|
42
|
-
def add_node(self, node):
|
|
43
|
-
if not isinstance(node, self.append_type):
|
|
44
|
-
raise AssertionError("Add Edge before adding Node")
|
|
45
|
-
self._nodes.append(node)
|
|
46
|
-
self.append_type = Edge
|
|
47
|
-
return self
|
|
48
|
-
|
|
49
|
-
def add_edge(self, edge):
|
|
50
|
-
if not isinstance(edge, self.append_type):
|
|
51
|
-
raise AssertionError("Add Node before adding Edge")
|
|
52
|
-
self._edges.append(edge)
|
|
53
|
-
self.append_type = Node
|
|
54
|
-
return self
|
|
55
|
-
|
|
56
|
-
def __eq__(self, other):
|
|
57
|
-
# Type checking
|
|
58
|
-
if not isinstance(other, Path):
|
|
59
|
-
return False
|
|
60
|
-
|
|
61
|
-
return self.nodes() == other.nodes() and self.edges() == other.edges()
|
|
62
|
-
|
|
63
|
-
def __str__(self):
|
|
64
|
-
res = "<"
|
|
65
|
-
edge_count = self.edge_count()
|
|
66
|
-
for i in range(0, edge_count):
|
|
67
|
-
node_id = self.get_node(i).id
|
|
68
|
-
res += "(" + str(node_id) + ")"
|
|
69
|
-
edge = self.get_relationship(i)
|
|
70
|
-
res += (
|
|
71
|
-
"-[" + str(int(edge.id)) + "]->"
|
|
72
|
-
if edge.src_node == node_id
|
|
73
|
-
else "<-[" + str(int(edge.id)) + "]-"
|
|
74
|
-
)
|
|
75
|
-
node_id = self.get_node(edge_count).id
|
|
76
|
-
res += "(" + str(node_id) + ")"
|
|
77
|
-
res += ">"
|
|
78
|
-
return res
|
|
@@ -1,588 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from collections import OrderedDict
|
|
3
|
-
|
|
4
|
-
# from prettytable import PrettyTable
|
|
5
|
-
from redis import ResponseError
|
|
6
|
-
|
|
7
|
-
from .edge import Edge
|
|
8
|
-
from .exceptions import VersionMismatchException
|
|
9
|
-
from .node import Node
|
|
10
|
-
from .path import Path
|
|
11
|
-
|
|
12
|
-
LABELS_ADDED = "Labels added"
|
|
13
|
-
LABELS_REMOVED = "Labels removed"
|
|
14
|
-
NODES_CREATED = "Nodes created"
|
|
15
|
-
NODES_DELETED = "Nodes deleted"
|
|
16
|
-
RELATIONSHIPS_DELETED = "Relationships deleted"
|
|
17
|
-
PROPERTIES_SET = "Properties set"
|
|
18
|
-
PROPERTIES_REMOVED = "Properties removed"
|
|
19
|
-
RELATIONSHIPS_CREATED = "Relationships created"
|
|
20
|
-
INDICES_CREATED = "Indices created"
|
|
21
|
-
INDICES_DELETED = "Indices deleted"
|
|
22
|
-
CACHED_EXECUTION = "Cached execution"
|
|
23
|
-
INTERNAL_EXECUTION_TIME = "internal execution time"
|
|
24
|
-
|
|
25
|
-
STATS = [
|
|
26
|
-
LABELS_ADDED,
|
|
27
|
-
LABELS_REMOVED,
|
|
28
|
-
NODES_CREATED,
|
|
29
|
-
PROPERTIES_SET,
|
|
30
|
-
PROPERTIES_REMOVED,
|
|
31
|
-
RELATIONSHIPS_CREATED,
|
|
32
|
-
NODES_DELETED,
|
|
33
|
-
RELATIONSHIPS_DELETED,
|
|
34
|
-
INDICES_CREATED,
|
|
35
|
-
INDICES_DELETED,
|
|
36
|
-
CACHED_EXECUTION,
|
|
37
|
-
INTERNAL_EXECUTION_TIME,
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class ResultSetColumnTypes:
|
|
42
|
-
COLUMN_UNKNOWN = 0
|
|
43
|
-
COLUMN_SCALAR = 1
|
|
44
|
-
COLUMN_NODE = 2 # Unused as of RedisGraph v2.1.0, retained for backwards compatibility. # noqa
|
|
45
|
-
COLUMN_RELATION = 3 # Unused as of RedisGraph v2.1.0, retained for backwards compatibility. # noqa
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class ResultSetScalarTypes:
|
|
49
|
-
VALUE_UNKNOWN = 0
|
|
50
|
-
VALUE_NULL = 1
|
|
51
|
-
VALUE_STRING = 2
|
|
52
|
-
VALUE_INTEGER = 3
|
|
53
|
-
VALUE_BOOLEAN = 4
|
|
54
|
-
VALUE_DOUBLE = 5
|
|
55
|
-
VALUE_ARRAY = 6
|
|
56
|
-
VALUE_EDGE = 7
|
|
57
|
-
VALUE_NODE = 8
|
|
58
|
-
VALUE_PATH = 9
|
|
59
|
-
VALUE_MAP = 10
|
|
60
|
-
VALUE_POINT = 11
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class QueryResult:
|
|
64
|
-
def __init__(self, graph, response, profile=False):
|
|
65
|
-
"""
|
|
66
|
-
A class that represents a result of the query operation.
|
|
67
|
-
|
|
68
|
-
Args:
|
|
69
|
-
|
|
70
|
-
graph:
|
|
71
|
-
The graph on which the query was executed.
|
|
72
|
-
response:
|
|
73
|
-
The response from the server.
|
|
74
|
-
profile:
|
|
75
|
-
A boolean indicating if the query command was "GRAPH.PROFILE"
|
|
76
|
-
"""
|
|
77
|
-
self.graph = graph
|
|
78
|
-
self.header = []
|
|
79
|
-
self.result_set = []
|
|
80
|
-
|
|
81
|
-
# in case of an error an exception will be raised
|
|
82
|
-
self._check_for_errors(response)
|
|
83
|
-
|
|
84
|
-
if len(response) == 1:
|
|
85
|
-
self.parse_statistics(response[0])
|
|
86
|
-
elif profile:
|
|
87
|
-
self.parse_profile(response)
|
|
88
|
-
else:
|
|
89
|
-
# start by parsing statistics, matches the one we have
|
|
90
|
-
self.parse_statistics(response[-1]) # Last element.
|
|
91
|
-
self.parse_results(response)
|
|
92
|
-
|
|
93
|
-
def _check_for_errors(self, response):
|
|
94
|
-
"""
|
|
95
|
-
Check if the response contains an error.
|
|
96
|
-
"""
|
|
97
|
-
if isinstance(response[0], ResponseError):
|
|
98
|
-
error = response[0]
|
|
99
|
-
if str(error) == "version mismatch":
|
|
100
|
-
version = response[1]
|
|
101
|
-
error = VersionMismatchException(version)
|
|
102
|
-
raise error
|
|
103
|
-
|
|
104
|
-
# If we encountered a run-time error, the last response
|
|
105
|
-
# element will be an exception
|
|
106
|
-
if isinstance(response[-1], ResponseError):
|
|
107
|
-
raise response[-1]
|
|
108
|
-
|
|
109
|
-
def parse_results(self, raw_result_set):
|
|
110
|
-
"""
|
|
111
|
-
Parse the query execution result returned from the server.
|
|
112
|
-
"""
|
|
113
|
-
self.header = self.parse_header(raw_result_set)
|
|
114
|
-
|
|
115
|
-
# Empty header.
|
|
116
|
-
if len(self.header) == 0:
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
self.result_set = self.parse_records(raw_result_set)
|
|
120
|
-
|
|
121
|
-
def parse_statistics(self, raw_statistics):
|
|
122
|
-
"""
|
|
123
|
-
Parse the statistics returned in the response.
|
|
124
|
-
"""
|
|
125
|
-
self.statistics = {}
|
|
126
|
-
|
|
127
|
-
# decode statistics
|
|
128
|
-
for idx, stat in enumerate(raw_statistics):
|
|
129
|
-
if isinstance(stat, bytes):
|
|
130
|
-
raw_statistics[idx] = stat.decode()
|
|
131
|
-
|
|
132
|
-
for s in STATS:
|
|
133
|
-
v = self._get_value(s, raw_statistics)
|
|
134
|
-
if v is not None:
|
|
135
|
-
self.statistics[s] = v
|
|
136
|
-
|
|
137
|
-
def parse_header(self, raw_result_set):
|
|
138
|
-
"""
|
|
139
|
-
Parse the header of the result.
|
|
140
|
-
"""
|
|
141
|
-
# An array of column name/column type pairs.
|
|
142
|
-
header = raw_result_set[0]
|
|
143
|
-
return header
|
|
144
|
-
|
|
145
|
-
def parse_records(self, raw_result_set):
|
|
146
|
-
"""
|
|
147
|
-
Parses the result set and returns a list of records.
|
|
148
|
-
"""
|
|
149
|
-
records = [
|
|
150
|
-
[
|
|
151
|
-
self.parse_record_types[self.header[idx][0]](cell)
|
|
152
|
-
for idx, cell in enumerate(row)
|
|
153
|
-
]
|
|
154
|
-
for row in raw_result_set[1]
|
|
155
|
-
]
|
|
156
|
-
|
|
157
|
-
return records
|
|
158
|
-
|
|
159
|
-
def parse_entity_properties(self, props):
|
|
160
|
-
"""
|
|
161
|
-
Parse node / edge properties.
|
|
162
|
-
"""
|
|
163
|
-
# [[name, value type, value] X N]
|
|
164
|
-
properties = {}
|
|
165
|
-
for prop in props:
|
|
166
|
-
prop_name = self.graph.get_property(prop[0])
|
|
167
|
-
prop_value = self.parse_scalar(prop[1:])
|
|
168
|
-
properties[prop_name] = prop_value
|
|
169
|
-
|
|
170
|
-
return properties
|
|
171
|
-
|
|
172
|
-
def parse_string(self, cell):
|
|
173
|
-
"""
|
|
174
|
-
Parse the cell as a string.
|
|
175
|
-
"""
|
|
176
|
-
if isinstance(cell, bytes):
|
|
177
|
-
return cell.decode()
|
|
178
|
-
elif not isinstance(cell, str):
|
|
179
|
-
return str(cell)
|
|
180
|
-
else:
|
|
181
|
-
return cell
|
|
182
|
-
|
|
183
|
-
def parse_node(self, cell):
|
|
184
|
-
"""
|
|
185
|
-
Parse the cell to a node.
|
|
186
|
-
"""
|
|
187
|
-
# Node ID (integer),
|
|
188
|
-
# [label string offset (integer)],
|
|
189
|
-
# [[name, value type, value] X N]
|
|
190
|
-
|
|
191
|
-
node_id = int(cell[0])
|
|
192
|
-
labels = None
|
|
193
|
-
if len(cell[1]) > 0:
|
|
194
|
-
labels = []
|
|
195
|
-
for inner_label in cell[1]:
|
|
196
|
-
labels.append(self.graph.get_label(inner_label))
|
|
197
|
-
properties = self.parse_entity_properties(cell[2])
|
|
198
|
-
return Node(node_id=node_id, label=labels, properties=properties)
|
|
199
|
-
|
|
200
|
-
def parse_edge(self, cell):
|
|
201
|
-
"""
|
|
202
|
-
Parse the cell to an edge.
|
|
203
|
-
"""
|
|
204
|
-
# Edge ID (integer),
|
|
205
|
-
# reltype string offset (integer),
|
|
206
|
-
# src node ID offset (integer),
|
|
207
|
-
# dest node ID offset (integer),
|
|
208
|
-
# [[name, value, value type] X N]
|
|
209
|
-
|
|
210
|
-
edge_id = int(cell[0])
|
|
211
|
-
relation = self.graph.get_relation(cell[1])
|
|
212
|
-
src_node_id = int(cell[2])
|
|
213
|
-
dest_node_id = int(cell[3])
|
|
214
|
-
properties = self.parse_entity_properties(cell[4])
|
|
215
|
-
return Edge(
|
|
216
|
-
src_node_id, relation, dest_node_id, edge_id=edge_id, properties=properties
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
def parse_path(self, cell):
|
|
220
|
-
"""
|
|
221
|
-
Parse the cell to a path.
|
|
222
|
-
"""
|
|
223
|
-
nodes = self.parse_scalar(cell[0])
|
|
224
|
-
edges = self.parse_scalar(cell[1])
|
|
225
|
-
return Path(nodes, edges)
|
|
226
|
-
|
|
227
|
-
def parse_map(self, cell):
|
|
228
|
-
"""
|
|
229
|
-
Parse the cell as a map.
|
|
230
|
-
"""
|
|
231
|
-
m = OrderedDict()
|
|
232
|
-
n_entries = len(cell)
|
|
233
|
-
|
|
234
|
-
# A map is an array of key value pairs.
|
|
235
|
-
# 1. key (string)
|
|
236
|
-
# 2. array: (value type, value)
|
|
237
|
-
for i in range(0, n_entries, 2):
|
|
238
|
-
key = self.parse_string(cell[i])
|
|
239
|
-
m[key] = self.parse_scalar(cell[i + 1])
|
|
240
|
-
|
|
241
|
-
return m
|
|
242
|
-
|
|
243
|
-
def parse_point(self, cell):
|
|
244
|
-
"""
|
|
245
|
-
Parse the cell to point.
|
|
246
|
-
"""
|
|
247
|
-
p = {}
|
|
248
|
-
# A point is received an array of the form: [latitude, longitude]
|
|
249
|
-
# It is returned as a map of the form: {"latitude": latitude, "longitude": longitude} # noqa
|
|
250
|
-
p["latitude"] = float(cell[0])
|
|
251
|
-
p["longitude"] = float(cell[1])
|
|
252
|
-
return p
|
|
253
|
-
|
|
254
|
-
def parse_null(self, cell):
|
|
255
|
-
"""
|
|
256
|
-
Parse a null value.
|
|
257
|
-
"""
|
|
258
|
-
return None
|
|
259
|
-
|
|
260
|
-
def parse_integer(self, cell):
|
|
261
|
-
"""
|
|
262
|
-
Parse the integer value from the cell.
|
|
263
|
-
"""
|
|
264
|
-
return int(cell)
|
|
265
|
-
|
|
266
|
-
def parse_boolean(self, value):
|
|
267
|
-
"""
|
|
268
|
-
Parse the cell value as a boolean.
|
|
269
|
-
"""
|
|
270
|
-
value = value.decode() if isinstance(value, bytes) else value
|
|
271
|
-
try:
|
|
272
|
-
scalar = True if strtobool(value) else False
|
|
273
|
-
except ValueError:
|
|
274
|
-
sys.stderr.write("unknown boolean type\n")
|
|
275
|
-
scalar = None
|
|
276
|
-
return scalar
|
|
277
|
-
|
|
278
|
-
def parse_double(self, cell):
|
|
279
|
-
"""
|
|
280
|
-
Parse the cell as a double.
|
|
281
|
-
"""
|
|
282
|
-
return float(cell)
|
|
283
|
-
|
|
284
|
-
def parse_array(self, value):
|
|
285
|
-
"""
|
|
286
|
-
Parse an array of values.
|
|
287
|
-
"""
|
|
288
|
-
scalar = [self.parse_scalar(value[i]) for i in range(len(value))]
|
|
289
|
-
return scalar
|
|
290
|
-
|
|
291
|
-
def parse_unknown(self, cell):
|
|
292
|
-
"""
|
|
293
|
-
Parse a cell of unknown type.
|
|
294
|
-
"""
|
|
295
|
-
sys.stderr.write("Unknown type\n")
|
|
296
|
-
return None
|
|
297
|
-
|
|
298
|
-
def parse_scalar(self, cell):
|
|
299
|
-
"""
|
|
300
|
-
Parse a scalar value from a cell in the result set.
|
|
301
|
-
"""
|
|
302
|
-
scalar_type = int(cell[0])
|
|
303
|
-
value = cell[1]
|
|
304
|
-
scalar = self.parse_scalar_types[scalar_type](value)
|
|
305
|
-
|
|
306
|
-
return scalar
|
|
307
|
-
|
|
308
|
-
def parse_profile(self, response):
|
|
309
|
-
self.result_set = [x[0 : x.index(",")].strip() for x in response]
|
|
310
|
-
|
|
311
|
-
def is_empty(self):
|
|
312
|
-
return len(self.result_set) == 0
|
|
313
|
-
|
|
314
|
-
@staticmethod
|
|
315
|
-
def _get_value(prop, statistics):
|
|
316
|
-
for stat in statistics:
|
|
317
|
-
if prop in stat:
|
|
318
|
-
return float(stat.split(": ")[1].split(" ")[0])
|
|
319
|
-
|
|
320
|
-
return None
|
|
321
|
-
|
|
322
|
-
def _get_stat(self, stat):
|
|
323
|
-
return self.statistics[stat] if stat in self.statistics else 0
|
|
324
|
-
|
|
325
|
-
@property
|
|
326
|
-
def labels_added(self):
|
|
327
|
-
"""Returns the number of labels added in the query"""
|
|
328
|
-
return self._get_stat(LABELS_ADDED)
|
|
329
|
-
|
|
330
|
-
@property
|
|
331
|
-
def labels_removed(self):
|
|
332
|
-
"""Returns the number of labels removed in the query"""
|
|
333
|
-
return self._get_stat(LABELS_REMOVED)
|
|
334
|
-
|
|
335
|
-
@property
|
|
336
|
-
def nodes_created(self):
|
|
337
|
-
"""Returns the number of nodes created in the query"""
|
|
338
|
-
return self._get_stat(NODES_CREATED)
|
|
339
|
-
|
|
340
|
-
@property
|
|
341
|
-
def nodes_deleted(self):
|
|
342
|
-
"""Returns the number of nodes deleted in the query"""
|
|
343
|
-
return self._get_stat(NODES_DELETED)
|
|
344
|
-
|
|
345
|
-
@property
|
|
346
|
-
def properties_set(self):
|
|
347
|
-
"""Returns the number of properties set in the query"""
|
|
348
|
-
return self._get_stat(PROPERTIES_SET)
|
|
349
|
-
|
|
350
|
-
@property
|
|
351
|
-
def properties_removed(self):
|
|
352
|
-
"""Returns the number of properties removed in the query"""
|
|
353
|
-
return self._get_stat(PROPERTIES_REMOVED)
|
|
354
|
-
|
|
355
|
-
@property
|
|
356
|
-
def relationships_created(self):
|
|
357
|
-
"""Returns the number of relationships created in the query"""
|
|
358
|
-
return self._get_stat(RELATIONSHIPS_CREATED)
|
|
359
|
-
|
|
360
|
-
@property
|
|
361
|
-
def relationships_deleted(self):
|
|
362
|
-
"""Returns the number of relationships deleted in the query"""
|
|
363
|
-
return self._get_stat(RELATIONSHIPS_DELETED)
|
|
364
|
-
|
|
365
|
-
@property
|
|
366
|
-
def indices_created(self):
|
|
367
|
-
"""Returns the number of indices created in the query"""
|
|
368
|
-
return self._get_stat(INDICES_CREATED)
|
|
369
|
-
|
|
370
|
-
@property
|
|
371
|
-
def indices_deleted(self):
|
|
372
|
-
"""Returns the number of indices deleted in the query"""
|
|
373
|
-
return self._get_stat(INDICES_DELETED)
|
|
374
|
-
|
|
375
|
-
@property
|
|
376
|
-
def cached_execution(self):
|
|
377
|
-
"""Returns whether or not the query execution plan was cached"""
|
|
378
|
-
return self._get_stat(CACHED_EXECUTION) == 1
|
|
379
|
-
|
|
380
|
-
@property
|
|
381
|
-
def run_time_ms(self):
|
|
382
|
-
"""Returns the server execution time of the query"""
|
|
383
|
-
return self._get_stat(INTERNAL_EXECUTION_TIME)
|
|
384
|
-
|
|
385
|
-
@property
|
|
386
|
-
def parse_scalar_types(self):
|
|
387
|
-
return {
|
|
388
|
-
ResultSetScalarTypes.VALUE_NULL: self.parse_null,
|
|
389
|
-
ResultSetScalarTypes.VALUE_STRING: self.parse_string,
|
|
390
|
-
ResultSetScalarTypes.VALUE_INTEGER: self.parse_integer,
|
|
391
|
-
ResultSetScalarTypes.VALUE_BOOLEAN: self.parse_boolean,
|
|
392
|
-
ResultSetScalarTypes.VALUE_DOUBLE: self.parse_double,
|
|
393
|
-
ResultSetScalarTypes.VALUE_ARRAY: self.parse_array,
|
|
394
|
-
ResultSetScalarTypes.VALUE_NODE: self.parse_node,
|
|
395
|
-
ResultSetScalarTypes.VALUE_EDGE: self.parse_edge,
|
|
396
|
-
ResultSetScalarTypes.VALUE_PATH: self.parse_path,
|
|
397
|
-
ResultSetScalarTypes.VALUE_MAP: self.parse_map,
|
|
398
|
-
ResultSetScalarTypes.VALUE_POINT: self.parse_point,
|
|
399
|
-
ResultSetScalarTypes.VALUE_UNKNOWN: self.parse_unknown,
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
@property
|
|
403
|
-
def parse_record_types(self):
|
|
404
|
-
return {
|
|
405
|
-
ResultSetColumnTypes.COLUMN_SCALAR: self.parse_scalar,
|
|
406
|
-
ResultSetColumnTypes.COLUMN_NODE: self.parse_node,
|
|
407
|
-
ResultSetColumnTypes.COLUMN_RELATION: self.parse_edge,
|
|
408
|
-
ResultSetColumnTypes.COLUMN_UNKNOWN: self.parse_unknown,
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
class AsyncQueryResult(QueryResult):
|
|
413
|
-
"""
|
|
414
|
-
Async version for the QueryResult class - a class that
|
|
415
|
-
represents a result of the query operation.
|
|
416
|
-
"""
|
|
417
|
-
|
|
418
|
-
def __init__(self):
|
|
419
|
-
"""
|
|
420
|
-
To init the class you must call self.initialize()
|
|
421
|
-
"""
|
|
422
|
-
pass
|
|
423
|
-
|
|
424
|
-
async def initialize(self, graph, response, profile=False):
|
|
425
|
-
"""
|
|
426
|
-
Initializes the class.
|
|
427
|
-
Args:
|
|
428
|
-
|
|
429
|
-
graph:
|
|
430
|
-
The graph on which the query was executed.
|
|
431
|
-
response:
|
|
432
|
-
The response from the server.
|
|
433
|
-
profile:
|
|
434
|
-
A boolean indicating if the query command was "GRAPH.PROFILE"
|
|
435
|
-
"""
|
|
436
|
-
self.graph = graph
|
|
437
|
-
self.header = []
|
|
438
|
-
self.result_set = []
|
|
439
|
-
|
|
440
|
-
# in case of an error an exception will be raised
|
|
441
|
-
self._check_for_errors(response)
|
|
442
|
-
|
|
443
|
-
if len(response) == 1:
|
|
444
|
-
self.parse_statistics(response[0])
|
|
445
|
-
elif profile:
|
|
446
|
-
self.parse_profile(response)
|
|
447
|
-
else:
|
|
448
|
-
# start by parsing statistics, matches the one we have
|
|
449
|
-
self.parse_statistics(response[-1]) # Last element.
|
|
450
|
-
await self.parse_results(response)
|
|
451
|
-
|
|
452
|
-
return self
|
|
453
|
-
|
|
454
|
-
async def parse_node(self, cell):
|
|
455
|
-
"""
|
|
456
|
-
Parses a node from the cell.
|
|
457
|
-
"""
|
|
458
|
-
# Node ID (integer),
|
|
459
|
-
# [label string offset (integer)],
|
|
460
|
-
# [[name, value type, value] X N]
|
|
461
|
-
|
|
462
|
-
labels = None
|
|
463
|
-
if len(cell[1]) > 0:
|
|
464
|
-
labels = []
|
|
465
|
-
for inner_label in cell[1]:
|
|
466
|
-
labels.append(await self.graph.get_label(inner_label))
|
|
467
|
-
properties = await self.parse_entity_properties(cell[2])
|
|
468
|
-
node_id = int(cell[0])
|
|
469
|
-
return Node(node_id=node_id, label=labels, properties=properties)
|
|
470
|
-
|
|
471
|
-
async def parse_scalar(self, cell):
|
|
472
|
-
"""
|
|
473
|
-
Parses a scalar value from the server response.
|
|
474
|
-
"""
|
|
475
|
-
scalar_type = int(cell[0])
|
|
476
|
-
value = cell[1]
|
|
477
|
-
try:
|
|
478
|
-
scalar = await self.parse_scalar_types[scalar_type](value)
|
|
479
|
-
except TypeError:
|
|
480
|
-
# Not all of the functions are async
|
|
481
|
-
scalar = self.parse_scalar_types[scalar_type](value)
|
|
482
|
-
|
|
483
|
-
return scalar
|
|
484
|
-
|
|
485
|
-
async def parse_records(self, raw_result_set):
|
|
486
|
-
"""
|
|
487
|
-
Parses the result set and returns a list of records.
|
|
488
|
-
"""
|
|
489
|
-
records = []
|
|
490
|
-
for row in raw_result_set[1]:
|
|
491
|
-
record = [
|
|
492
|
-
await self.parse_record_types[self.header[idx][0]](cell)
|
|
493
|
-
for idx, cell in enumerate(row)
|
|
494
|
-
]
|
|
495
|
-
records.append(record)
|
|
496
|
-
|
|
497
|
-
return records
|
|
498
|
-
|
|
499
|
-
async def parse_results(self, raw_result_set):
|
|
500
|
-
"""
|
|
501
|
-
Parse the query execution result returned from the server.
|
|
502
|
-
"""
|
|
503
|
-
self.header = self.parse_header(raw_result_set)
|
|
504
|
-
|
|
505
|
-
# Empty header.
|
|
506
|
-
if len(self.header) == 0:
|
|
507
|
-
return
|
|
508
|
-
|
|
509
|
-
self.result_set = await self.parse_records(raw_result_set)
|
|
510
|
-
|
|
511
|
-
async def parse_entity_properties(self, props):
|
|
512
|
-
"""
|
|
513
|
-
Parse node / edge properties.
|
|
514
|
-
"""
|
|
515
|
-
# [[name, value type, value] X N]
|
|
516
|
-
properties = {}
|
|
517
|
-
for prop in props:
|
|
518
|
-
prop_name = await self.graph.get_property(prop[0])
|
|
519
|
-
prop_value = await self.parse_scalar(prop[1:])
|
|
520
|
-
properties[prop_name] = prop_value
|
|
521
|
-
|
|
522
|
-
return properties
|
|
523
|
-
|
|
524
|
-
async def parse_edge(self, cell):
|
|
525
|
-
"""
|
|
526
|
-
Parse the cell to an edge.
|
|
527
|
-
"""
|
|
528
|
-
# Edge ID (integer),
|
|
529
|
-
# reltype string offset (integer),
|
|
530
|
-
# src node ID offset (integer),
|
|
531
|
-
# dest node ID offset (integer),
|
|
532
|
-
# [[name, value, value type] X N]
|
|
533
|
-
|
|
534
|
-
edge_id = int(cell[0])
|
|
535
|
-
relation = await self.graph.get_relation(cell[1])
|
|
536
|
-
src_node_id = int(cell[2])
|
|
537
|
-
dest_node_id = int(cell[3])
|
|
538
|
-
properties = await self.parse_entity_properties(cell[4])
|
|
539
|
-
return Edge(
|
|
540
|
-
src_node_id, relation, dest_node_id, edge_id=edge_id, properties=properties
|
|
541
|
-
)
|
|
542
|
-
|
|
543
|
-
async def parse_path(self, cell):
|
|
544
|
-
"""
|
|
545
|
-
Parse the cell to a path.
|
|
546
|
-
"""
|
|
547
|
-
nodes = await self.parse_scalar(cell[0])
|
|
548
|
-
edges = await self.parse_scalar(cell[1])
|
|
549
|
-
return Path(nodes, edges)
|
|
550
|
-
|
|
551
|
-
async def parse_map(self, cell):
|
|
552
|
-
"""
|
|
553
|
-
Parse the cell to a map.
|
|
554
|
-
"""
|
|
555
|
-
m = OrderedDict()
|
|
556
|
-
n_entries = len(cell)
|
|
557
|
-
|
|
558
|
-
# A map is an array of key value pairs.
|
|
559
|
-
# 1. key (string)
|
|
560
|
-
# 2. array: (value type, value)
|
|
561
|
-
for i in range(0, n_entries, 2):
|
|
562
|
-
key = self.parse_string(cell[i])
|
|
563
|
-
m[key] = await self.parse_scalar(cell[i + 1])
|
|
564
|
-
|
|
565
|
-
return m
|
|
566
|
-
|
|
567
|
-
async def parse_array(self, value):
|
|
568
|
-
"""
|
|
569
|
-
Parse array value.
|
|
570
|
-
"""
|
|
571
|
-
scalar = [await self.parse_scalar(value[i]) for i in range(len(value))]
|
|
572
|
-
return scalar
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
def strtobool(val):
|
|
576
|
-
"""
|
|
577
|
-
Convert a string representation of truth to true (1) or false (0).
|
|
578
|
-
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
|
|
579
|
-
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
|
|
580
|
-
'val' is anything else.
|
|
581
|
-
"""
|
|
582
|
-
val = val.lower()
|
|
583
|
-
if val in ("y", "yes", "t", "true", "on", "1"):
|
|
584
|
-
return True
|
|
585
|
-
elif val in ("n", "no", "f", "false", "off", "0"):
|
|
586
|
-
return False
|
|
587
|
-
else:
|
|
588
|
-
raise ValueError(f"invalid truth value {val!r}")
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
redis
|
|
File without changes
|
|
File without changes
|