Skip to content

Commit 8580d89

Browse files
committed
Much cursor simplification
1 parent 0130dcd commit 8580d89

File tree

1 file changed

+57
-69
lines changed

1 file changed

+57
-69
lines changed

neo4j/v1/session.py

Lines changed: 57 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -152,97 +152,90 @@ class ResultCursor(object):
152152
""" A handler for the result of Cypher statement execution.
153153
"""
154154

155-
#: The statement that was executed to produce this result.
155+
#: The statement text that was executed to produce this result.
156156
statement = None
157157

158158
#: Dictionary of parameters passed with the statement.
159159
parameters = None
160160

161-
def __init__(self, connection, statement, parameters):
161+
#: The result summary (only available after the result has
162+
#: been fully consumed)
163+
summary = None
164+
165+
def __init__(self, connection, run_response, pull_all_response):
162166
super(ResultCursor, self).__init__()
163-
self.statement = statement
164-
self.parameters = parameters
167+
168+
# The Connection instance behind this cursor.
169+
self.connection = connection
170+
171+
# The keys for the records in the result stream. These are
172+
# lazily populated on request.
165173
self._keys = None
166-
self._connection = connection
167-
self._current = None
168-
self._record_buffer = deque()
169-
self._position = -1
170-
self._summary = None
174+
175+
# Buffer for incoming records to be queued before yielding. If
176+
# the result is used immediately, this buffer will be ignored.
177+
self._buffer = deque()
178+
179+
# Flag to indicate whether the entire stream has been consumed
180+
# from the network (but not necessarily yielded).
171181
self._consumed = False
172182

183+
def on_header(metadata):
184+
# Called on receipt of the result header.
185+
self._keys = metadata["fields"]
186+
187+
def on_record(values):
188+
# Called on receipt of each result record.
189+
self._buffer.append(values)
190+
191+
def on_footer(metadata):
192+
# Called on receipt of the result footer.
193+
self.summary = ResultSummary(self.statement, self.parameters, **metadata)
194+
self._consumed = True
195+
196+
def on_failure(metadata):
197+
# Called on execution failure.
198+
self._consumed = True
199+
raise CypherError(metadata)
200+
201+
run_response.on_success = on_header
202+
run_response.on_failure = on_failure
203+
204+
pull_all_response.on_record = on_record
205+
pull_all_response.on_success = on_footer
206+
pull_all_response.on_failure = on_failure
207+
173208
def __next__(self):
174-
if self._record_buffer:
175-
values = self._record_buffer.popleft()
176-
self._position += 1
177-
self._current = Record(self.keys(), tuple(map(hydrated, values)))
178-
return self._current
209+
if self._buffer:
210+
values = self._buffer.popleft()
211+
return Record(self.keys(), tuple(map(hydrated, values)))
179212
elif self._consumed:
180213
raise StopIteration()
181214
else:
182-
self._connection.fetch()
215+
self.connection.fetch()
183216
return self.__next__()
184217

185218
def __iter__(self):
186219
return self
187220

188-
def is_open(self):
189-
""" Return ``True`` if this cursor is still open, ``False`` otherwise.
190-
"""
191-
return bool(self._connection)
192-
193221
def close(self):
194222
""" Consume the remainder of this result and detach the connection
195223
from this cursor.
196224
"""
197-
if self._connection and not self._connection.closed:
198-
self._consume()
199-
self._connection = None
225+
if self.connection and not self.connection.closed:
226+
fetch = self.connection.fetch
227+
while not self._consumed:
228+
fetch()
229+
self.connection = None
200230

201231
def keys(self):
202232
""" Return the keys for the records.
203233
"""
204234
# Fetch messages until we have the header or a failure
205235
while self._keys is None and not self._consumed:
206-
self._connection.fetch()
236+
self.connection.fetch()
207237
return self._keys
208238

209-
@property
210-
def summary(self):
211-
""" Return the summary from the trailing metadata. Note that this is
212-
only available once the entire result stream has been consumed.
213-
Accessing the summary before then will return :py:const:`None`.
214-
215-
:rtype: ResultSummary or :py:const:`None`
216-
"""
217-
if self._consumed:
218-
return self._summary
219-
else:
220-
return None
221-
222-
def _consume(self):
223-
# Consume the remainder of this result, triggering all appropriate callback functions.
224-
fetch = self._connection.fetch
225-
while not self._consumed:
226-
fetch()
227-
228-
def _on_header(self, metadata):
229-
# Called on receipt of the result header.
230-
self._keys = metadata["fields"]
231-
232-
def _on_record(self, values):
233-
# Called on receipt of each result record.
234-
self._record_buffer.append(values)
235-
236-
def _on_footer(self, metadata):
237-
# Called on receipt of the result footer.
238-
self._summary = ResultSummary(self.statement, self.parameters, **metadata)
239-
self._consumed = True
240-
241-
def _on_failure(self, metadata):
242-
# Called on execution failure.
243-
self._consumed = True
244-
raise CypherError(metadata)
245-
246239

247240
class ResultSummary(object):
248241
""" A summary of execution returned with a :class:`.ResultCursor` object.
@@ -460,16 +453,11 @@ def run(self, statement, parameters=None):
460453
params[key] = value
461454
parameters = params
462455

463-
cursor = ResultCursor(self.connection, statement, parameters)
464-
465456
run_response = Response(self.connection)
466-
run_response.on_success = cursor._on_header
467-
run_response.on_failure = cursor._on_failure
468-
469457
pull_all_response = Response(self.connection)
470-
pull_all_response.on_record = cursor._on_record
471-
pull_all_response.on_success = cursor._on_footer
472-
pull_all_response.on_failure = cursor._on_failure
458+
cursor = ResultCursor(self.connection, run_response, pull_all_response)
459+
cursor.statement = statement
460+
cursor.parameters = parameters
473461

474462
self.connection.append(RUN, (statement, parameters), response=run_response)
475463
self.connection.append(PULL_ALL, response=pull_all_response)

0 commit comments

Comments
 (0)