4242import org .neo4j .driver .v1 .util .Function ;
4343import org .neo4j .driver .v1 .util .Functions ;
4444
45- import static java .lang .String .format ;
4645import static java .util .Collections .emptyList ;
4746
4847public class InternalStatementResult implements StatementResult
@@ -55,7 +54,6 @@ public class InternalStatementResult implements StatementResult
5554 private List <String > keys = null ;
5655 private ResultSummary summary = null ;
5756
58- private boolean open = true ;
5957 private long position = -1 ;
6058 private boolean done = false ;
6159
@@ -170,26 +168,17 @@ StreamCollector pullAllResponseCollector()
170168 @ Override
171169 public List <String > keys ()
172170 {
173- tryFetching ();
171+ if ( keys == null )
172+ {
173+ tryFetchNext ();
174+ }
174175 return keys ;
175176 }
176177
177178 @ Override
178179 public boolean hasNext ()
179180 {
180- if (!recordBuffer .isEmpty ())
181- {
182- return true ;
183- }
184- else if (done )
185- {
186- return false ;
187- }
188- else
189- {
190- tryFetching ();
191- return hasNext ();
192- }
181+ return tryFetchNext ();
193182 }
194183
195184 @ Override
@@ -201,67 +190,52 @@ public Record next()
201190 // in a way that makes the two equivalent in performance.
202191 // To get the intended benefit, we need to allocate Record in this method,
203192 // and have it copy out its fields from some lower level data structure.
204- assertOpen ();
205- Record nextRecord = recordBuffer .poll ();
206- if ( nextRecord != null )
193+ if ( tryFetchNext () )
207194 {
208195 position += 1 ;
209- return nextRecord ;
210- }
211- else if ( done )
212- {
213- return null ;
196+ return recordBuffer .poll ();
214197 }
215198 else
216199 {
217- tryFetching ();
218- return next ();
200+ throw new NoSuchRecordException ( "No more records" );
219201 }
220202 }
221203
222204 @ Override
223205 public Record single ()
224206 {
225- if ( position > 0 )
207+ if ( hasNext () )
226208 {
227- throw new NoSuchRecordException (
228- "Cannot retrieve the first record, because other operations have already used the first record. " +
229- "Please ensure you are not calling `first` multiple times, or are mixing it with calls " +
230- "to `next`, `single`, `list` or any other method that changes the position of the cursor." );
231- }
209+ Record single = next ();
210+ boolean hasMoreThanOne = hasNext ();
232211
233- if ( !hasNext () )
234- {
235- throw new NoSuchRecordException ( "Cannot retrieve the first record, because this result is empty." );
236- }
212+ consume ();
213+
214+ if ( hasMoreThanOne )
215+ {
216+ throw new NoSuchRecordException ( "Expected a result with a single record, but this result contains at least one more. " +
217+ "Ensure your query returns only one record, or use `first` instead of `single` if " +
218+ "you do not care about the number of records in the result." );
219+ }
237220
238- Record first = next ();
239- if ( hasNext () )
221+ return single ;
222+ }
223+ else
240224 {
241- throw new NoSuchRecordException ( "Expected a result with a single record, but this result contains at least one more. " +
242- "Ensure your query returns only one record, or use `first` instead of `single` if " +
243- "you do not care about the number of records in the result." );
225+ throw new NoSuchRecordException ( "Cannot retrieve a single record, because this result is empty." );
244226 }
245- return first ;
246227 }
247228
248229 @ Override
249230 public Record peek ()
250231 {
251- assertOpen ();
252- Record nextRecord = recordBuffer .peek ();
253- if ( nextRecord != null )
254- {
255- return nextRecord ;
256- }
257- else if ( done )
232+ if ( tryFetchNext () )
258233 {
259- return null ;
234+ return recordBuffer . peek () ;
260235 }
261236 else
262237 {
263- tryFetching ();
264- return peek ();
238+ throw new NoSuchRecordException ( "Cannot peek past the last record" );
265239 }
266240 }
267241
@@ -274,46 +248,41 @@ public List<Record> list()
274248 @ Override
275249 public <T > List <T > list ( Function <Record , T > mapFunction )
276250 {
277- if ( isEmpty () )
278- {
279- assertOpen ();
280- return emptyList ();
281- }
282- else if ( position == -1 && hasNext () )
251+ if ( hasNext () )
283252 {
284253 List <T > result = new ArrayList <>();
254+
285255 do
286256 {
287257 result .add ( mapFunction .apply ( next () ) );
288258 }
289259 while ( hasNext () );
290260
291- consume ();
292261 return result ;
293262 }
294263 else
295264 {
296- throw new ClientException (
297- format ( "Can't retain records when cursor is not pointing at the first record (currently at position %d)" , position )
298- );
265+ return emptyList ();
299266 }
300267 }
301268
302- @ SuppressWarnings ("StatementWithEmptyBody" )
303269 @ Override
304270 public ResultSummary consume ()
305271 {
306- if (! open )
272+ if ( done )
307273 {
308- return summary ;
274+ recordBuffer . clear () ;
309275 }
310-
311- while ( !done )
276+ else
312277 {
313- connection .receiveOne ();
278+ do
279+ {
280+ connection .receiveOne ();
281+ recordBuffer .clear ();
282+ }
283+ while ( !done );
314284 }
315- recordBuffer .clear ();
316- open = false ;
285+
317286 return summary ;
318287 }
319288
@@ -323,26 +292,17 @@ public void remove()
323292 throw new ClientException ( "Removing records from a result is not supported." );
324293 }
325294
326- private void assertOpen ()
295+ private boolean tryFetchNext ()
327296 {
328- if ( !open )
329- {
330- throw new ClientException ( "Result has been closed" );
331- }
332- }
333-
334- private boolean isEmpty ()
335- {
336- tryFetching ();
337- return position == -1 && recordBuffer .isEmpty () && done ;
338- }
339-
340- private void tryFetching ()
341- {
342- while ( recordBuffer .isEmpty () && !done )
297+ while ( recordBuffer .isEmpty () )
343298 {
299+ if ( done )
300+ {
301+ return false ;
302+ }
344303 connection .receiveOne ();
345304 }
346- }
347305
306+ return true ;
307+ }
348308}
0 commit comments