@@ -87,6 +87,28 @@ 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
+
102
+ /**
103
+ * Defines a ResultObserver interface which can be used to enqueue records and dequeue
104
+ * them until the result is fully received.
105
+ * @access private
106
+ */
107
+ interface QueuedResultObserver extends ResultObserver {
108
+ dequeue ( ) : Promise < QueuedResultElement >
109
+ get size ( ) : number
110
+ }
111
+
90
112
/**
91
113
* A stream of {@link Record} representing the result of a query.
92
114
* Can be consumed eagerly as {@link Promise} resolved with array of records and {@link ResultSummary}
@@ -211,78 +233,45 @@ class Result implements Promise<QueryResult> {
211
233
return this . _p
212
234
}
213
235
236
+ /**
237
+ * Provides a async iterator over the records in the result.
238
+ *
239
+ * *Should not be combined with {@link Result#subscribe} or ${@link Result#then} functions.*
240
+ *
241
+ * @public
242
+ * @returns {AsyncIterator<Record, ResultSummary> } The async iterator for the Results
243
+ */
214
244
async * [ Symbol . asyncIterator ] ( ) : AsyncIterator < Record , ResultSummary > {
215
- interface ConsumedValue {
216
- done : boolean
217
- record ?: Record
218
- summary ?: ResultSummary
219
- }
220
-
221
- interface ResolvablePromise < T > {
222
- promise : Promise < T >
223
- resolve : ( arg : T ) => any | undefined
224
- reject : ( arg : Error ) => any | undefined
225
- }
226
-
227
- function createResolvablePromise ( ) : ResolvablePromise < ConsumedValue > {
228
- const resolvablePromise : any = { }
229
- resolvablePromise . promise = new Promise ( ( resolve , reject ) => {
230
- resolvablePromise . resolve = resolve
231
- resolvablePromise . reject = reject
232
- } ) ;
233
- return resolvablePromise ;
234
- }
235
-
236
- const observer = {
237
- _buffer : [ createResolvablePromise ( ) ] ,
238
- onNext : ( record : Record ) => {
239
- observer . _buffer [ observer . _buffer . length - 1 ] . resolve ( { record, done : false } ) ;
240
- observer . _buffer . push ( createResolvablePromise ( ) ) ;
241
- } ,
242
- onCompleted : ( summary : ResultSummary ) => {
243
- observer . _buffer [ observer . _buffer . length - 1 ] . resolve ( { summary, done : true } ) ;
244
- } ,
245
- onError : ( error : Error ) => {
246
- observer . _buffer [ observer . _buffer . length - 1 ] . reject ( error ) ;
247
- } ,
248
- consume : async ( ) => {
249
- const value = await observer . _buffer [ 0 ] . promise
250
- observer . _buffer . shift ( ) ;
251
- return value
252
- } ,
253
- get queueSize ( ) : number {
254
- return observer . _buffer . length - 1
255
- }
256
- }
245
+ const queuedObserver = this . _createQueuedResultObserver ( )
257
246
258
247
const status = { paused : false }
259
248
260
249
let streaming : observer . ResultStreamObserver | null = null
261
250
262
251
try {
263
- streaming = await this . _subscribe ( observer , true )
252
+ streaming = await this . _subscribe ( queuedObserver , true )
264
253
} catch ( e ) {
265
254
// ignore, we will handle it in consume since the error is notifies in the onError callback
266
255
}
267
256
268
257
const pullIfNeeded = ( ) => {
269
- if ( observer . queueSize >= this . _watermarks . high ) {
258
+ if ( queuedObserver . size >= this . _watermarks . high ) {
270
259
status . paused = true
271
- } else if ( observer . queueSize <= this . _watermarks . low ) {
260
+ } else if ( queuedObserver . size <= this . _watermarks . low ) {
272
261
status . paused = false
273
262
}
274
- if ( ! status . paused && observer . queueSize < this . _watermarks . high && streaming ) {
263
+ if ( ! status . paused && queuedObserver . size < this . _watermarks . high && streaming ) {
275
264
streaming . pull ( )
276
265
}
277
266
}
278
267
279
268
while ( true ) {
280
269
pullIfNeeded ( )
281
- const value = await observer . consume ( )
282
- if ( value . done ) {
283
- return value . summary !
270
+ const next = await queuedObserver . dequeue ( )
271
+ if ( next . done ) {
272
+ return next . summary
284
273
}
285
- yield value . record !
274
+ yield next . record
286
275
}
287
276
}
288
277
@@ -347,6 +336,15 @@ class Result implements Promise<QueryResult> {
347
336
. catch ( ( ) => { } )
348
337
}
349
338
339
+ /**
340
+ * Stream records to observer as they come in, this is a more efficient method
341
+ * of handling the results, and allows you to handle arbitrarily large results.
342
+ *
343
+ * @access private
344
+ * @param {ResultObserver } observer The observer to send records to.
345
+ * @param {boolean } explicityPull The flag to indicate if the pull should be called explicitly.
346
+ * @returns {Promise<observer.ResultStreamObserver> } The result stream observer.
347
+ */
350
348
_subscribe ( observer : ResultObserver , explicityPull : boolean = false ) : Promise < observer . ResultStreamObserver > {
351
349
const _observer = this . _decorateObserver ( observer )
352
350
@@ -362,6 +360,13 @@ class Result implements Promise<QueryResult> {
362
360
} )
363
361
}
364
362
363
+ /**
364
+ * Decorates the ResultObserver with the necessary methods.
365
+ *
366
+ * @access private
367
+ * @param {ResultObserver } observer The ResultObserver to decorate.
368
+ * @returns The decorated result observer
369
+ */
365
370
_decorateObserver ( observer : ResultObserver ) : ResultObserver {
366
371
const onCompletedOriginal = observer . onCompleted || DEFAULT_ON_COMPLETED
367
372
const onCompletedWrapper = ( metadata : any ) => {
@@ -407,6 +412,11 @@ class Result implements Promise<QueryResult> {
407
412
this . _streamObserverPromise . then ( o => o . cancel ( ) )
408
413
}
409
414
415
+ /**
416
+ * @access private
417
+ * @param metadata
418
+ * @returns
419
+ */
410
420
private _createSummary ( metadata : any ) : Promise < ResultSummary > {
411
421
const {
412
422
validatedQuery : query ,
@@ -434,6 +444,50 @@ class Result implements Promise<QueryResult> {
434
444
new ResultSummary ( query , parameters , metadata , protocolVersion )
435
445
)
436
446
}
447
+
448
+ /**
449
+ * @access private
450
+ */
451
+ private _createQueuedResultObserver ( ) : QueuedResultObserver {
452
+ interface ResolvablePromise < T > {
453
+ promise : Promise < T >
454
+ resolve : ( arg : T ) => any | undefined
455
+ reject : ( arg : Error ) => any | undefined
456
+ }
457
+
458
+ function createResolvablePromise ( ) : ResolvablePromise < QueuedResultElement > {
459
+ const resolvablePromise : any = { }
460
+ resolvablePromise . promise = new Promise ( ( resolve , reject ) => {
461
+ resolvablePromise . resolve = resolve
462
+ resolvablePromise . reject = reject
463
+ } ) ;
464
+ return resolvablePromise ;
465
+ }
466
+
467
+ const observer = {
468
+ _buffer : [ createResolvablePromise ( ) ] ,
469
+ onNext : ( record : Record ) => {
470
+ observer . _buffer [ observer . _buffer . length - 1 ] . resolve ( { done : false , record } ) ;
471
+ observer . _buffer . push ( createResolvablePromise ( ) ) ;
472
+ } ,
473
+ onCompleted : ( summary : ResultSummary ) => {
474
+ observer . _buffer [ observer . _buffer . length - 1 ] . resolve ( { done : true , summary } ) ;
475
+ } ,
476
+ onError : ( error : Error ) => {
477
+ observer . _buffer [ observer . _buffer . length - 1 ] . reject ( error ) ;
478
+ } ,
479
+ dequeue : async ( ) => {
480
+ const value = await observer . _buffer [ 0 ] . promise
481
+ observer . _buffer . shift ( ) ;
482
+ return value
483
+ } ,
484
+ get size ( ) : number {
485
+ return observer . _buffer . length - 1
486
+ }
487
+ }
488
+
489
+ return observer ;
490
+ }
437
491
}
438
492
439
493
function captureStacktrace ( ) : string | null {
0 commit comments