@@ -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
247240class 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