1
1
import { Readable , Transform } from 'stream' ;
2
- import { promisify } from 'util' ;
3
2
4
3
import { type BSONSerializeOptions , type Document , Long , pluckBSONSerializeOptions } from '../bson' ;
5
4
import {
@@ -21,7 +20,7 @@ import { ReadConcern, type ReadConcernLike } from '../read_concern';
21
20
import { ReadPreference , type ReadPreferenceLike } from '../read_preference' ;
22
21
import type { Server } from '../sdam/server' ;
23
22
import { ClientSession , maybeClearPinnedConnection } from '../sessions' ;
24
- import { type Callback , List , type MongoDBNamespace , ns } from '../utils' ;
23
+ import { List , type MongoDBNamespace , ns } from '../utils' ;
25
24
26
25
/** @internal */
27
26
const kId = Symbol ( 'id' ) ;
@@ -310,7 +309,7 @@ export abstract class AbstractCursor<
310
309
const message =
311
310
'Cursor returned a `null` document, but the cursor is not exhausted. Mapping documents to `null` is not supported in the cursor transform.' ;
312
311
313
- await cleanupCursorAsync ( this , { needsToEmitClosed : true } ) . catch ( ( ) => null ) ;
312
+ await cleanupCursor ( this , { needsToEmitClosed : true } ) . catch ( ( ) => null ) ;
314
313
315
314
throw new MongoAPIError ( message ) ;
316
315
}
@@ -419,7 +418,7 @@ export abstract class AbstractCursor<
419
418
async close ( ) : Promise < void > {
420
419
const needsToEmitClosed = ! this [ kClosed ] ;
421
420
this [ kClosed ] = true ;
422
- await cleanupCursorAsync ( this , { needsToEmitClosed } ) ;
421
+ await cleanupCursor ( this , { needsToEmitClosed } ) ;
423
422
}
424
423
425
424
/**
@@ -613,21 +612,18 @@ export abstract class AbstractCursor<
613
612
abstract clone ( ) : AbstractCursor < TSchema > ;
614
613
615
614
/** @internal */
616
- protected abstract _initialize (
617
- session : ClientSession | undefined ,
618
- callback : Callback < ExecutionResult >
619
- ) : void ;
615
+ protected abstract _initialize ( session : ClientSession | undefined ) : Promise < ExecutionResult > ;
620
616
621
617
/** @internal */
622
- _getMore ( batchSize : number , callback : Callback < Document > ) : void {
618
+ async getMore ( batchSize : number ) : Promise < Document | null > {
623
619
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
624
620
const getMoreOperation = new GetMoreOperation ( this [ kNamespace ] , this [ kId ] ! , this [ kServer ] ! , {
625
621
...this [ kOptions ] ,
626
622
session : this [ kSession ] ,
627
623
batchSize
628
624
} ) ;
629
625
630
- executeOperation ( this [ kClient ] , getMoreOperation , callback ) ;
626
+ return executeOperation ( this [ kClient ] , getMoreOperation ) ;
631
627
}
632
628
633
629
/**
@@ -637,51 +633,50 @@ export abstract class AbstractCursor<
637
633
* operation. We cannot refactor to use the abstract _initialize method without
638
634
* a significant refactor.
639
635
*/
640
- [ kInit ] ( callback : Callback < TSchema | null > ) : void {
641
- this . _initialize ( this [ kSession ] , ( error , state ) => {
642
- if ( state ) {
643
- const response = state . response ;
644
- this [ kServer ] = state . server ;
645
-
646
- if ( response . cursor ) {
647
- // TODO(NODE-2674): Preserve int64 sent from MongoDB
648
- this [ kId ] =
649
- typeof response . cursor . id === 'number'
650
- ? Long . fromNumber ( response . cursor . id )
651
- : typeof response . cursor . id === 'bigint'
652
- ? Long . fromBigInt ( response . cursor . id )
653
- : response . cursor . id ;
654
-
655
- if ( response . cursor . ns ) {
656
- this [ kNamespace ] = ns ( response . cursor . ns ) ;
657
- }
636
+ async [ kInit ] ( ) : Promise < void > {
637
+ try {
638
+ const state = await this . _initialize ( this [ kSession ] ) ;
639
+ const response = state . response ;
640
+ this [ kServer ] = state . server ;
641
+ if ( response . cursor ) {
642
+ // TODO(NODE-2674): Preserve int64 sent from MongoDB
643
+ this [ kId ] =
644
+ typeof response . cursor . id === 'number'
645
+ ? Long . fromNumber ( response . cursor . id )
646
+ : typeof response . cursor . id === 'bigint'
647
+ ? Long . fromBigInt ( response . cursor . id )
648
+ : response . cursor . id ;
658
649
659
- this [ kDocuments ] . pushMany ( response . cursor . firstBatch ) ;
650
+ if ( response . cursor . ns ) {
651
+ this [ kNamespace ] = ns ( response . cursor . ns ) ;
660
652
}
661
653
662
- // When server responses return without a cursor document, we close this cursor
663
- // and return the raw server response. This is often the case for explain commands
664
- // for example
665
- if ( this [ kId ] == null ) {
666
- this [ kId ] = Long . ZERO ;
667
- // TODO(NODE-3286): ExecutionResult needs to accept a generic parameter
668
- this [ kDocuments ] . push ( state . response as TODO_NODE_3286 ) ;
669
- }
654
+ this [ kDocuments ] . pushMany ( response . cursor . firstBatch ) ;
670
655
}
671
656
672
- // the cursor is now initialized, even if an error occurred or it is dead
673
- this [ kInitialized ] = true ;
674
-
675
- if ( error ) {
676
- return cleanupCursor ( this , { error } , ( ) => callback ( error , undefined ) ) ;
657
+ // When server responses return without a cursor document, we close this cursor
658
+ // and return the raw server response. This is often the case for explain commands
659
+ // for example
660
+ if ( this [ kId ] == null ) {
661
+ this [ kId ] = Long . ZERO ;
662
+ // TODO(NODE-3286): ExecutionResult needs to accept a generic parameter
663
+ this [ kDocuments ] . push ( state . response as TODO_NODE_3286 ) ;
677
664
}
678
665
679
- if ( this . isDead ) {
680
- return cleanupCursor ( this , undefined , ( ) => callback ( ) ) ;
681
- }
666
+ // the cursor is now initialized, even if it is dead
667
+ this [ kInitialized ] = true ;
668
+ } catch ( error ) {
669
+ // the cursor is now initialized, even if an error occurred
670
+ this [ kInitialized ] = true ;
671
+ await cleanupCursor ( this , { error } ) ;
672
+ throw error ;
673
+ }
682
674
683
- callback ( ) ;
684
- } ) ;
675
+ if ( this . isDead ) {
676
+ await cleanupCursor ( this , undefined ) ;
677
+ }
678
+
679
+ return ;
685
680
}
686
681
}
687
682
@@ -713,7 +708,7 @@ async function next<T>(
713
708
do {
714
709
if ( cursor [ kId ] == null ) {
715
710
// All cursors must operate within a session, one must be made implicitly if not explicitly provided
716
- await promisify ( cursor [ kInit ] . bind ( cursor ) ) ( ) ;
711
+ await cursor [ kInit ] ( ) ;
717
712
}
718
713
719
714
if ( cursor [ kDocuments ] . length !== 0 ) {
@@ -725,7 +720,7 @@ async function next<T>(
725
720
} catch ( error ) {
726
721
// `cleanupCursorAsync` should never throw, but if it does we want to throw the original
727
722
// error instead.
728
- await cleanupCursorAsync ( cursor , { error, needsToEmitClosed : true } ) . catch ( ( ) => null ) ;
723
+ await cleanupCursor ( cursor , { error, needsToEmitClosed : true } ) . catch ( ( ) => null ) ;
729
724
throw error ;
730
725
}
731
726
}
@@ -737,15 +732,15 @@ async function next<T>(
737
732
// if the cursor is dead, we clean it up
738
733
// cleanupCursorAsync should never throw, but if it does it indicates a bug in the driver
739
734
// and we should surface the error
740
- await cleanupCursorAsync ( cursor , { } ) ;
735
+ await cleanupCursor ( cursor , { } ) ;
741
736
return null ;
742
737
}
743
738
744
739
// otherwise need to call getMore
745
740
const batchSize = cursor [ kOptions ] . batchSize || 1000 ;
746
741
747
742
try {
748
- const response = await promisify ( cursor . _getMore . bind ( cursor ) ) ( batchSize ) ;
743
+ const response = await cursor . getMore ( batchSize ) ;
749
744
750
745
if ( response ) {
751
746
const cursorId =
@@ -761,7 +756,7 @@ async function next<T>(
761
756
} catch ( error ) {
762
757
// `cleanupCursorAsync` should never throw, but if it does we want to throw the original
763
758
// error instead.
764
- await cleanupCursorAsync ( cursor , { error } ) . catch ( ( ) => null ) ;
759
+ await cleanupCursor ( cursor , { error } ) . catch ( ( ) => null ) ;
765
760
throw error ;
766
761
}
767
762
@@ -773,7 +768,7 @@ async function next<T>(
773
768
//
774
769
// cleanupCursorAsync should never throw, but if it does it indicates a bug in the driver
775
770
// and we should surface the error
776
- await cleanupCursorAsync ( cursor , { } ) ;
771
+ await cleanupCursor ( cursor , { } ) ;
777
772
}
778
773
779
774
if ( cursor [ kDocuments ] . length === 0 && blocking === false ) {
@@ -784,13 +779,10 @@ async function next<T>(
784
779
return null ;
785
780
}
786
781
787
- const cleanupCursorAsync = promisify ( cleanupCursor ) ;
788
-
789
- function cleanupCursor (
782
+ async function cleanupCursor (
790
783
cursor : AbstractCursor ,
791
- options : { error ?: AnyError | undefined ; needsToEmitClosed ?: boolean } | undefined ,
792
- callback : Callback
793
- ) : void {
784
+ options : { error ?: AnyError | undefined ; needsToEmitClosed ?: boolean } | undefined
785
+ ) : Promise < void > {
794
786
const cursorId = cursor [ kId ] ;
795
787
const cursorNs = cursor [ kNamespace ] ;
796
788
const server = cursor [ kServer ] ;
@@ -817,9 +809,7 @@ function cleanupCursor(
817
809
818
810
if ( session ) {
819
811
if ( session . owner === cursor ) {
820
- session . endSession ( { error } ) . finally ( ( ) => {
821
- callback ( ) ;
822
- } ) ;
812
+ await session . endSession ( { error } ) ;
823
813
return ;
824
814
}
825
815
@@ -828,16 +818,17 @@ function cleanupCursor(
828
818
}
829
819
}
830
820
831
- return callback ( ) ;
821
+ return ;
832
822
}
833
823
834
- function completeCleanup ( ) {
824
+ async function completeCleanup ( ) {
835
825
if ( session ) {
836
826
if ( session . owner === cursor ) {
837
- session . endSession ( { error } ) . finally ( ( ) => {
827
+ try {
828
+ await session . endSession ( { error } ) ;
829
+ } finally {
838
830
cursor . emit ( AbstractCursor . CLOSE ) ;
839
- callback ( ) ;
840
- } ) ;
831
+ }
841
832
return ;
842
833
}
843
834
@@ -847,7 +838,7 @@ function cleanupCursor(
847
838
}
848
839
849
840
cursor . emit ( AbstractCursor . CLOSE ) ;
850
- return callback ( ) ;
841
+ return ;
851
842
}
852
843
853
844
cursor [ kKilled ] = true ;
@@ -856,12 +847,14 @@ function cleanupCursor(
856
847
return completeCleanup ( ) ;
857
848
}
858
849
859
- executeOperation (
860
- cursor [ kClient ] ,
861
- new KillCursorsOperation ( cursorId , cursorNs , server , { session } )
862
- )
863
- . catch ( ( ) => null )
864
- . finally ( completeCleanup ) ;
850
+ try {
851
+ await executeOperation (
852
+ cursor [ kClient ] ,
853
+ new KillCursorsOperation ( cursorId , cursorNs , server , { session } )
854
+ ) . catch ( ( ) => null ) ;
855
+ } finally {
856
+ await completeCleanup ( ) ;
857
+ }
865
858
}
866
859
867
860
/** @internal */
0 commit comments