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,48 @@ 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 ) ;
655
+ }
656
+
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 ) ;
670
664
}
671
665
672
666
// the cursor is now initialized, even if an error occurred or it is dead
673
667
this [ kInitialized ] = true ;
668
+ } catch ( error ) {
669
+ await cleanupCursor ( this , { error } ) ;
670
+ throw error ;
671
+ }
674
672
675
- if ( error ) {
676
- return cleanupCursor ( this , { error } , ( ) => callback ( error , undefined ) ) ;
677
- }
678
-
679
- if ( this . isDead ) {
680
- return cleanupCursor ( this , undefined , ( ) => callback ( ) ) ;
681
- }
673
+ if ( this . isDead ) {
674
+ await cleanupCursor ( this , undefined ) ;
675
+ }
682
676
683
- callback ( ) ;
684
- } ) ;
677
+ return ;
685
678
}
686
679
}
687
680
@@ -713,7 +706,7 @@ async function next<T>(
713
706
do {
714
707
if ( cursor [ kId ] == null ) {
715
708
// All cursors must operate within a session, one must be made implicitly if not explicitly provided
716
- await promisify ( cursor [ kInit ] . bind ( cursor ) ) ( ) ;
709
+ await cursor [ kInit ] ( ) ;
717
710
}
718
711
719
712
if ( cursor [ kDocuments ] . length !== 0 ) {
@@ -725,7 +718,7 @@ async function next<T>(
725
718
} catch ( error ) {
726
719
// `cleanupCursorAsync` should never throw, but if it does we want to throw the original
727
720
// error instead.
728
- await cleanupCursorAsync ( cursor , { error, needsToEmitClosed : true } ) . catch ( ( ) => null ) ;
721
+ await cleanupCursor ( cursor , { error, needsToEmitClosed : true } ) . catch ( ( ) => null ) ;
729
722
throw error ;
730
723
}
731
724
}
@@ -737,15 +730,15 @@ async function next<T>(
737
730
// if the cursor is dead, we clean it up
738
731
// cleanupCursorAsync should never throw, but if it does it indicates a bug in the driver
739
732
// and we should surface the error
740
- await cleanupCursorAsync ( cursor , { } ) ;
733
+ await cleanupCursor ( cursor , { } ) ;
741
734
return null ;
742
735
}
743
736
744
737
// otherwise need to call getMore
745
738
const batchSize = cursor [ kOptions ] . batchSize || 1000 ;
746
739
747
740
try {
748
- const response = await promisify ( cursor . _getMore . bind ( cursor ) ) ( batchSize ) ;
741
+ const response = await cursor . getMore ( batchSize ) ;
749
742
750
743
if ( response ) {
751
744
const cursorId =
@@ -761,7 +754,7 @@ async function next<T>(
761
754
} catch ( error ) {
762
755
// `cleanupCursorAsync` should never throw, but if it does we want to throw the original
763
756
// error instead.
764
- await cleanupCursorAsync ( cursor , { error } ) . catch ( ( ) => null ) ;
757
+ await cleanupCursor ( cursor , { error } ) . catch ( ( ) => null ) ;
765
758
throw error ;
766
759
}
767
760
@@ -773,7 +766,7 @@ async function next<T>(
773
766
//
774
767
// cleanupCursorAsync should never throw, but if it does it indicates a bug in the driver
775
768
// and we should surface the error
776
- await cleanupCursorAsync ( cursor , { } ) ;
769
+ await cleanupCursor ( cursor , { } ) ;
777
770
}
778
771
779
772
if ( cursor [ kDocuments ] . length === 0 && blocking === false ) {
@@ -784,13 +777,10 @@ async function next<T>(
784
777
return null ;
785
778
}
786
779
787
- const cleanupCursorAsync = promisify ( cleanupCursor ) ;
788
-
789
- function cleanupCursor (
780
+ async function cleanupCursor (
790
781
cursor : AbstractCursor ,
791
- options : { error ?: AnyError | undefined ; needsToEmitClosed ?: boolean } | undefined ,
792
- callback : Callback
793
- ) : void {
782
+ options : { error ?: AnyError | undefined ; needsToEmitClosed ?: boolean } | undefined
783
+ ) : Promise < void > {
794
784
const cursorId = cursor [ kId ] ;
795
785
const cursorNs = cursor [ kNamespace ] ;
796
786
const server = cursor [ kServer ] ;
@@ -817,9 +807,7 @@ function cleanupCursor(
817
807
818
808
if ( session ) {
819
809
if ( session . owner === cursor ) {
820
- session . endSession ( { error } ) . finally ( ( ) => {
821
- callback ( ) ;
822
- } ) ;
810
+ await session . endSession ( { error } ) ;
823
811
return ;
824
812
}
825
813
@@ -828,16 +816,17 @@ function cleanupCursor(
828
816
}
829
817
}
830
818
831
- return callback ( ) ;
819
+ return ;
832
820
}
833
821
834
- function completeCleanup ( ) {
822
+ async function completeCleanup ( ) {
835
823
if ( session ) {
836
824
if ( session . owner === cursor ) {
837
- session . endSession ( { error } ) . finally ( ( ) => {
825
+ try {
826
+ await session . endSession ( { error } ) ;
827
+ } finally {
838
828
cursor . emit ( AbstractCursor . CLOSE ) ;
839
- callback ( ) ;
840
- } ) ;
829
+ }
841
830
return ;
842
831
}
843
832
@@ -847,7 +836,7 @@ function cleanupCursor(
847
836
}
848
837
849
838
cursor . emit ( AbstractCursor . CLOSE ) ;
850
- return callback ( ) ;
839
+ return ;
851
840
}
852
841
853
842
cursor [ kKilled ] = true ;
@@ -856,12 +845,14 @@ function cleanupCursor(
856
845
return completeCleanup ( ) ;
857
846
}
858
847
859
- executeOperation (
860
- cursor [ kClient ] ,
861
- new KillCursorsOperation ( cursorId , cursorNs , server , { session } )
862
- )
863
- . catch ( ( ) => null )
864
- . finally ( completeCleanup ) ;
848
+ try {
849
+ await executeOperation (
850
+ cursor [ kClient ] ,
851
+ new KillCursorsOperation ( cursorId , cursorNs , server , { session } )
852
+ ) . catch ( ( ) => null ) ;
853
+ } finally {
854
+ await completeCleanup ( ) ;
855
+ }
865
856
}
866
857
867
858
/** @internal */
0 commit comments