19
19
package org .neo4j .driver .internal ;
20
20
21
21
import java .util .ArrayList ;
22
- import java .util .Iterator ;
23
22
import java .util .List ;
24
23
24
+ import org .neo4j .driver .v1 .Entry ;
25
25
import org .neo4j .driver .v1 .Function ;
26
26
import org .neo4j .driver .v1 .Record ;
27
27
import org .neo4j .driver .v1 .RecordAccessor ;
28
28
import org .neo4j .driver .v1 .ResultCursor ;
29
29
import org .neo4j .driver .v1 .ResultSummary ;
30
30
import org .neo4j .driver .v1 .Value ;
31
31
import org .neo4j .driver .v1 .exceptions .ClientException ;
32
+ import org .neo4j .driver .v1 .exceptions .NoRecordException ;
32
33
34
+ import static java .lang .String .format ;
33
35
import static java .util .Collections .emptyList ;
34
36
35
37
import static org .neo4j .driver .v1 .Records .recordAsIs ;
36
38
37
39
public class InternalResultCursor extends InternalRecordAccessor implements ResultCursor
38
40
{
39
41
private final List <String > keys ;
40
- private final Iterator <Record > iter ;
42
+ private final PeekingIterator <Record > iter ;
41
43
private final ResultSummary summary ;
42
44
43
45
private boolean open = true ;
@@ -47,7 +49,7 @@ public class InternalResultCursor extends InternalRecordAccessor implements Resu
47
49
public InternalResultCursor ( List <String > keys , List <Record > body , ResultSummary summary )
48
50
{
49
51
this .keys = keys ;
50
- this .iter = body .iterator ();
52
+ this .iter = new PeekingIterator <>( body .iterator () );
51
53
this .summary = summary ;
52
54
}
53
55
@@ -90,23 +92,27 @@ public int size()
90
92
return keys .size ();
91
93
}
92
94
93
- private Value throwNoRecord ()
95
+ @ Override
96
+ public boolean hasRecord ()
94
97
{
95
- throw new ClientException (
96
- "In order to access fields of a record in a result, " +
97
- "you must first call next() to point the result to the next record in the result stream."
98
- );
98
+ assertOpen ();
99
+ return current != null && current .hasRecord ();
99
100
}
100
101
101
102
@ Override
102
103
public Record record ()
103
104
{
104
- assertOpen ();
105
- if ( current == null )
105
+ if ( hasRecord () )
106
106
{
107
- throwNoRecord ();
107
+ return current ;
108
+ }
109
+ else
110
+ {
111
+ throw new NoRecordException (
112
+ "In order to access the fields of a record in a result, " +
113
+ "you must first call next() to point the result to the next record in the result stream."
114
+ );
108
115
}
109
- return current ;
110
116
}
111
117
112
118
@ Override
@@ -144,7 +150,7 @@ public long skip( long elements )
144
150
{
145
151
if ( elements < 0 )
146
152
{
147
- throw new IllegalArgumentException ( "Cannot skip negative number of elements" );
153
+ throw new ClientException ( "Cannot skip negative number of elements" );
148
154
}
149
155
else
150
156
{
@@ -170,6 +176,12 @@ public boolean single()
170
176
return first () && atEnd ();
171
177
}
172
178
179
+ @ Override
180
+ public RecordAccessor peek ()
181
+ {
182
+ return new PeekingRecordAccessor ();
183
+ }
184
+
173
185
@ Override
174
186
public List <Record > retain ()
175
187
{
@@ -192,14 +204,14 @@ else if ( first() )
192
204
result .add ( mapFunction .apply ( this ) );
193
205
}
194
206
while ( next () );
207
+ discard ();
195
208
return result ;
196
209
}
197
210
else
198
211
{
199
- throw new
200
- ClientException ( String .format (
201
- "Can't retain records when cursor is not pointing at the first record (currently at position %d)" ,
202
- position ) );
212
+ throw new ClientException (
213
+ format ( "Can't retain records when cursor is not pointing at the first record (currently at position %d)" , position )
214
+ );
203
215
}
204
216
}
205
217
@@ -208,6 +220,7 @@ else if ( first() )
208
220
public ResultSummary summarize ()
209
221
{
210
222
while ( next () ) ;
223
+ discard ();
211
224
return summary ;
212
225
}
213
226
@@ -216,11 +229,20 @@ public void close()
216
229
{
217
230
if ( open )
218
231
{
232
+ discard ();
219
233
open = false ;
220
234
}
221
235
else
222
236
{
223
- throw new IllegalStateException ( "Already closed" );
237
+ throw new ClientException ( "Already closed" );
238
+ }
239
+ }
240
+
241
+ private void assertOpen ()
242
+ {
243
+ if ( !open )
244
+ {
245
+ throw new ClientException ( "Cursor already closed" );
224
246
}
225
247
}
226
248
@@ -229,11 +251,73 @@ private boolean isEmpty()
229
251
return position == -1 && !iter .hasNext ();
230
252
}
231
253
232
- private void assertOpen ()
254
+ private void discard ()
233
255
{
234
- if ( !open )
256
+ iter .discard ();
257
+ }
258
+
259
+ private class PeekingRecordAccessor implements RecordAccessor
260
+ {
261
+ @ Override
262
+ public List <String > keys ()
263
+ {
264
+ return InternalResultCursor .this .keys ();
265
+ }
266
+
267
+ @ Override
268
+ public boolean containsKey ( String key )
269
+ {
270
+ return InternalResultCursor .this .containsKey ( key );
271
+ }
272
+
273
+ @ Override
274
+ public int index ( String key )
275
+ {
276
+ return InternalResultCursor .this .index ( key );
277
+ }
278
+
279
+ @ Override
280
+ public Value value ( String key )
281
+ {
282
+ return record ().value ( key );
283
+ }
284
+
285
+ @ Override
286
+ public int size ()
287
+ {
288
+ return InternalResultCursor .this .size ();
289
+ }
290
+
291
+ @ Override
292
+ public List <Entry <Value >> fields ()
293
+ {
294
+ return record ().fields ();
295
+ }
296
+
297
+ @ Override
298
+ public boolean hasRecord ()
299
+ {
300
+ return iter .hasNext ();
301
+ }
302
+
303
+ @ Override
304
+ public Record record ()
305
+ {
306
+ Record record = iter .peek ();
307
+ if ( record == null )
308
+ {
309
+ throw new NoRecordException ( "Cannot peek past last record" );
310
+ }
311
+ else
312
+ {
313
+ return record ;
314
+ }
315
+ }
316
+
317
+ @ Override
318
+ public Value value ( int index )
235
319
{
236
- throw new IllegalStateException ( "Cursor already closed" );
320
+ return record (). value ( index );
237
321
}
238
322
}
239
323
}
0 commit comments