19
19
20
20
import ResultSummary from './result-summary'
21
21
import Record from './record'
22
- import { Query } from './types'
22
+ import { Query , PeekableAsyncIterator } from './types'
23
23
import { observer , util , connectionHolder } from './internal'
24
24
25
25
const { EMPTY_CONNECTION_HOLDER } = connectionHolder
@@ -87,25 +87,15 @@ interface ResultObserver {
87
87
onError ?: ( error : Error ) => void
88
88
}
89
89
90
- /**
91
- * Defines the elements in the queue result observer
92
- * @access private
93
- */
94
- type QueuedResultElement = {
95
- done : false
96
- record : Record
97
- } | {
98
- done : true
99
- summary : ResultSummary
100
- }
101
90
102
91
/**
103
92
* Defines a ResultObserver interface which can be used to enqueue records and dequeue
104
93
* them until the result is fully received.
105
94
* @access private
106
95
*/
107
96
interface QueuedResultObserver extends ResultObserver {
108
- dequeue ( ) : Promise < QueuedResultElement >
97
+ dequeue ( ) : Promise < IteratorResult < Record , ResultSummary > >
98
+ head ( ) : Promise < IteratorResult < Record , ResultSummary > >
109
99
get size ( ) : number
110
100
}
111
101
@@ -239,35 +229,60 @@ class Result implements Promise<QueryResult> {
239
229
* *Should not be combined with {@link Result#subscribe} or ${@link Result#then} functions.*
240
230
*
241
231
* @public
242
- * @returns {AsyncIterator <Record, ResultSummary> } The async iterator for the Results
232
+ * @returns {PeekableAsyncIterator <Record, ResultSummary> } The async iterator for the Results
243
233
*/
244
- async * [ Symbol . asyncIterator ] ( ) : AsyncIterator < Record , ResultSummary > {
245
- const queuedObserver = this . _createQueuedResultObserver ( )
246
-
247
- const status = { paused : true , firstRun : true }
248
-
249
- const streaming : observer . ResultStreamObserver | null =
250
- // the error will be send to the onError callback
251
- await this . _subscribe ( queuedObserver , true ) . catch ( ( ) => null )
252
-
253
- const controlFlow = ( ) => {
254
- if ( queuedObserver . size >= this . _watermarks . high && ! status . paused ) {
255
- status . paused = true
256
- streaming ?. pause ( )
257
- } else if ( queuedObserver . size <= this . _watermarks . low && status . paused || status . firstRun ) {
258
- status . firstRun = false
259
- status . paused = false
260
- streaming ?. resume ( )
234
+ [ Symbol . asyncIterator ] ( ) : PeekableAsyncIterator < Record , ResultSummary > {
235
+ const state : {
236
+ paused : boolean ,
237
+ firstRun : boolean ,
238
+ finished : boolean ,
239
+ queuedObserver ?: QueuedResultObserver ,
240
+ streaming ?: observer . ResultStreamObserver ,
241
+ summary ?: ResultSummary ,
242
+ } = { paused : true , firstRun : true , finished : false }
243
+
244
+
245
+ const controlFlow = async ( ) => {
246
+ if ( state . queuedObserver === undefined ) {
247
+ state . queuedObserver = this . _createQueuedResultObserver ( )
248
+ state . streaming = await this . _subscribe ( state . queuedObserver , true ) . catch ( ( ) => undefined )
249
+ }
250
+ if ( state . queuedObserver . size >= this . _watermarks . high && ! state . paused ) {
251
+ state . paused = true
252
+ state . streaming ?. pause ( )
253
+ } else if ( state . queuedObserver . size <= this . _watermarks . low && state . paused || state . firstRun ) {
254
+ state . firstRun = false
255
+ state . paused = false
256
+ state . streaming ?. resume ( )
261
257
}
262
258
}
263
259
264
- while ( true ) {
265
- controlFlow ( )
266
- const next = await queuedObserver . dequeue ( )
267
- if ( next . done ) {
268
- return next . summary
260
+ return {
261
+ next : async ( ) => {
262
+ if ( state . finished ) {
263
+ return { done : true , value : state . summary ! }
264
+ }
265
+ await controlFlow ( )
266
+ const next = await state . queuedObserver ! . dequeue ( )
267
+ if ( next . done ) {
268
+ state . finished = next . done
269
+ state . summary = next . value
270
+ }
271
+ return next
272
+ } ,
273
+ return : async ( value : ResultSummary ) => {
274
+ state . finished = true
275
+ state . summary = value
276
+ state . streaming ?. cancel ( )
277
+ return { done : true , value : value }
278
+ } ,
279
+ peek : async ( ) => {
280
+ if ( state . finished ) {
281
+ return { done : true , value : state . summary ! }
282
+ }
283
+ await controlFlow ( )
284
+ return await state . queuedObserver ! . head ( )
269
285
}
270
- yield next . record
271
286
}
272
287
}
273
288
@@ -453,7 +468,7 @@ class Result implements Promise<QueryResult> {
453
468
reject : ( arg : Error ) => any | undefined
454
469
}
455
470
456
- function createResolvablePromise ( ) : ResolvablePromise < QueuedResultElement > {
471
+ function createResolvablePromise ( ) : ResolvablePromise < IteratorResult < Record , ResultSummary > > {
457
472
const resolvablePromise : any = { }
458
473
resolvablePromise . promise = new Promise ( ( resolve , reject ) => {
459
474
resolvablePromise . resolve = resolve
@@ -462,22 +477,23 @@ class Result implements Promise<QueryResult> {
462
477
return resolvablePromise ;
463
478
}
464
479
465
- type QueuedResultElementOrError = QueuedResultElement | Error
480
+ type QueuedResultElementOrError = IteratorResult < Record , ResultSummary > | Error
466
481
467
482
function isError ( elementOrError : QueuedResultElementOrError ) : elementOrError is Error {
468
483
return elementOrError instanceof Error
469
484
}
470
485
471
486
const buffer : QueuedResultElementOrError [ ] = [ ]
472
- const promiseHolder : { resolvable : ResolvablePromise < QueuedResultElement > | null } = { resolvable : null }
473
-
487
+ const promiseHolder : {
488
+ resolvable : ResolvablePromise < IteratorResult < Record , ResultSummary > > | null
489
+ } = { resolvable : null }
474
490
475
491
const observer = {
476
492
onNext : ( record : Record ) => {
477
- observer . _push ( { done : false , record } )
493
+ observer . _push ( { done : false , value : record } )
478
494
} ,
479
495
onCompleted : ( summary : ResultSummary ) => {
480
- observer . _push ( { done : true , summary } )
496
+ observer . _push ( { done : true , value : summary } )
481
497
} ,
482
498
onError : ( error : Error ) => {
483
499
observer . _push ( error )
@@ -506,6 +522,24 @@ class Result implements Promise<QueryResult> {
506
522
promiseHolder . resolvable = createResolvablePromise ( )
507
523
return await promiseHolder . resolvable . promise
508
524
} ,
525
+ head : async ( ) => {
526
+ if ( buffer . length > 0 ) {
527
+ const element = buffer [ 0 ]
528
+ if ( isError ( element ) ) {
529
+ throw element
530
+ }
531
+ return element
532
+ }
533
+ promiseHolder . resolvable = createResolvablePromise ( )
534
+ try {
535
+ const element = await promiseHolder . resolvable . promise
536
+ buffer . unshift ( element )
537
+ return element
538
+ } catch ( error ) {
539
+ buffer . unshift ( error )
540
+ throw error
541
+ }
542
+ } ,
509
543
get size ( ) : number {
510
544
return buffer . length
511
545
}
0 commit comments