@@ -34,6 +34,8 @@ const kResumeQueue = Symbol('resumeQueue');
34
34
const kCursorStream = Symbol ( 'cursorStream' ) ;
35
35
/** @internal */
36
36
const kClosed = Symbol ( 'closed' ) ;
37
+ /** @internal */
38
+ const kMode = Symbol ( 'mode' ) ;
37
39
38
40
const CHANGE_STREAM_OPTIONS = [ 'resumeAfter' , 'startAfter' , 'startAtOperationTime' , 'fullDocument' ] ;
39
41
const CURSOR_OPTIONS = [ 'batchSize' , 'maxAwaitTimeMS' , 'collation' , 'readPreference' ] . concat (
@@ -206,6 +208,8 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
206
208
[ kCursorStream ] ?: Readable ;
207
209
/** @internal */
208
210
[ kClosed ] : boolean ;
211
+ /** @internal */
212
+ [ kMode ] : false | 'iterator' | 'emitter' ;
209
213
210
214
/** @event */
211
215
static readonly RESPONSE = 'response' as const ;
@@ -272,6 +276,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
272
276
this . cursor = createChangeStreamCursor ( this , options ) ;
273
277
274
278
this [ kClosed ] = false ;
279
+ this [ kMode ] = false ;
275
280
276
281
// Listen for any `change` listeners being added to ChangeStream
277
282
this . on ( 'newListener' , eventName => {
@@ -299,6 +304,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
299
304
300
305
/** Check if there is any document still available in the Change Stream */
301
306
hasNext ( callback ?: Callback ) : Promise < void > | void {
307
+ setIsIterator ( this ) ;
302
308
return maybePromise ( callback , cb => {
303
309
getCursor ( this , ( err , cursor ) => {
304
310
if ( err || ! cursor ) return cb ( err ) ; // failed to resume, raise an error
@@ -313,6 +319,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
313
319
next (
314
320
callback ?: Callback < ChangeStreamDocument < TSchema > >
315
321
) : Promise < ChangeStreamDocument < TSchema > > | void {
322
+ setIsIterator ( this ) ;
316
323
return maybePromise ( callback , cb => {
317
324
getCursor ( this , ( err , cursor ) => {
318
325
if ( err || ! cursor ) return cb ( err ) ; // failed to resume, raise an error
@@ -367,6 +374,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
367
374
tryNext ( ) : Promise < Document | null > ;
368
375
tryNext ( callback : Callback < Document | null > ) : void ;
369
376
tryNext ( callback ?: Callback < Document | null > ) : Promise < Document | null > | void {
377
+ setIsIterator ( this ) ;
370
378
return maybePromise ( callback , cb => {
371
379
getCursor ( this , ( err , cursor ) => {
372
380
if ( err || ! cursor ) return cb ( err ) ; // failed to resume, raise an error
@@ -535,6 +543,23 @@ const CHANGE_STREAM_EVENTS = [
535
543
ChangeStream . CLOSE
536
544
] ;
537
545
546
+ function setIsEmitter < TSchema > ( changeStream : ChangeStream < TSchema > ) : void {
547
+ if ( changeStream [ kMode ] === 'iterator' ) {
548
+ throw new MongoDriverError (
549
+ 'Cannot use ChangeStream as an EventEmitter after using as an iterator'
550
+ ) ;
551
+ }
552
+ changeStream [ kMode ] = 'emitter' ;
553
+ }
554
+
555
+ function setIsIterator < TSchema > ( changeStream : ChangeStream < TSchema > ) : void {
556
+ if ( changeStream [ kMode ] === 'emitter' ) {
557
+ throw new MongoDriverError (
558
+ 'Cannot use ChangeStream as iterator after using as an EventEmitter'
559
+ ) ;
560
+ }
561
+ changeStream [ kMode ] = 'iterator' ;
562
+ }
538
563
/**
539
564
* Create a new change stream cursor based on self's configuration
540
565
* @internal
@@ -630,6 +655,7 @@ function streamEvents<TSchema>(
630
655
changeStream : ChangeStream < TSchema > ,
631
656
cursor : ChangeStreamCursor < TSchema >
632
657
) : void {
658
+ setIsEmitter ( changeStream ) ;
633
659
const stream = changeStream [ kCursorStream ] || cursor . stream ( ) ;
634
660
changeStream [ kCursorStream ] = stream ;
635
661
stream . on ( 'data' , change => processNewChange ( changeStream , change ) ) ;
0 commit comments