Skip to content

Commit 3b58ca1

Browse files
authored
fix(NODE-5213): ChangeStream.tryNext() should return TChange type (#3649)
1 parent b12922a commit 3b58ca1

File tree

2 files changed

+39
-17
lines changed

2 files changed

+39
-17
lines changed

src/change_stream.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ export class ChangeStream<
700700
/**
701701
* Try to get the next available document from the Change Stream's cursor or `null` if an empty batch is returned
702702
*/
703-
async tryNext(): Promise<Document | null> {
703+
async tryNext(): Promise<TChange | null> {
704704
this._setIsIterator();
705705
// Change streams must resume indefinitely while each resume event succeeds.
706706
// This loop continues until either a change event is received or until a resume attempt

test/types/change_stream.test-d.ts

+38-16
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,18 @@ import type {
1515
ChangeStreamInvalidateDocument,
1616
ChangeStreamNameSpace,
1717
ChangeStreamOptions,
18+
ChangeStreamRefineCollectionShardKeyDocument,
1819
ChangeStreamRenameDocument,
1920
ChangeStreamReplaceDocument,
21+
ChangeStreamReshardCollectionDocument,
22+
ChangeStreamShardCollectionDocument,
2023
ChangeStreamUpdateDocument,
2124
Collection,
2225
Document,
2326
ResumeToken,
2427
ServerSessionId,
2528
Timestamp,
2629
UpdateDescription
27-
} from '../../src';
28-
import type {
29-
ChangeStreamRefineCollectionShardKeyDocument,
30-
ChangeStreamReshardCollectionDocument,
31-
ChangeStreamShardCollectionDocument
3230
} from '../mongodb';
3331

3432
declare const changeStreamOptions: ChangeStreamOptions;
@@ -181,8 +179,8 @@ switch (change.operationType) {
181179
// New fields can be added with $addFields, but you have to use TChange to type it
182180
expectError(change.randomKeyAlwaysAccessibleBecauseOfPipelineFlexibilty);
183181

184-
declare const collection: Collection<Schema>;
185-
const pipelineChangeStream = collection.watch<
182+
declare const collectionWithSchema: Collection<Schema>;
183+
const pipelineChangeStream = collectionWithSchema.watch<
186184
Schema,
187185
ChangeStreamInsertDocument<Schema> & { comment: string }
188186
>([{ $addFields: { comment: 'big changes' } }, { $match: { operationType: 'insert' } }]);
@@ -193,28 +191,52 @@ pipelineChangeStream.on('change', change => {
193191
expectType<Schema>(change.fullDocument);
194192
});
195193

196-
collection.watch().on('change', change => expectType<ChangeStreamDocument<Schema>>(change));
194+
collectionWithSchema
195+
.watch()
196+
.on('change', change => expectType<ChangeStreamDocument<Schema>>(change));
197197

198198
// Just overriding the schema provides a typed changestream OF that schema
199-
collection
199+
collectionWithSchema
200200
.watch<Document>()
201201
.on('change', change => expectType<ChangeStreamDocument<Document>>(change));
202202

203-
// both schema and Tchange can be made as flexible as possible (Document)
204-
collection.watch<Document, Document>().on('change', change => expectType<Document>(change));
203+
// both schema and TChange can be made as flexible as possible (Document)
204+
collectionWithSchema
205+
.watch<Document, Document>()
206+
.on('change', change => expectType<Document>(change));
205207

206208
// first argument does not stop you from making second more generic
207-
collection.watch<{ a: number }, Document>().on('change', change => expectType<Document>(change));
209+
collectionWithSchema
210+
.watch<{ a: number }, Document>()
211+
.on('change', change => expectType<Document>(change));
208212

209213
// Arguments must be objects
210-
expectError(collection.watch<Document, number>());
211-
expectError(collection.watch<number, number>());
214+
expectError(collectionWithSchema.watch<Document, number>());
215+
expectError(collectionWithSchema.watch<number, number>());
212216

213217
// First argument no longer relates to second
214-
collection
218+
collectionWithSchema
215219
.watch<{ a: number }, { b: boolean }>()
216220
.on('change', change => expectType<{ b: boolean }>(change));
217221

218222
expectType<AsyncGenerator<ChangeStreamDocument<Schema>, void, void>>(
219-
collection.watch()[Symbol.asyncIterator]()
223+
collectionWithSchema.watch()[Symbol.asyncIterator]()
224+
);
225+
226+
// Change type returned to user is equivalent across next/tryNext/on/once/addListener
227+
const changeStream = collectionWithSchema.watch();
228+
expectType<ChangeStreamDocument<Schema> | null>(await changeStream.tryNext());
229+
expectType<ChangeStreamDocument<Schema>>(await changeStream.next());
230+
changeStream.on('change', change => expectType<ChangeStreamDocument<Schema>>(change));
231+
changeStream.once('change', change => expectType<ChangeStreamDocument<Schema>>(change));
232+
changeStream.addListener('change', change => expectType<ChangeStreamDocument<Schema>>(change));
233+
234+
declare const noSchemaCollection: Collection;
235+
const changeStreamNoSchema = noSchemaCollection.watch();
236+
expectType<ChangeStreamDocument<Document> | null>(await changeStreamNoSchema.tryNext());
237+
expectType<ChangeStreamDocument<Document>>(await changeStreamNoSchema.next());
238+
changeStreamNoSchema.on('change', change => expectType<ChangeStreamDocument<Document>>(change));
239+
changeStreamNoSchema.once('change', change => expectType<ChangeStreamDocument<Document>>(change));
240+
changeStreamNoSchema.addListener('change', change =>
241+
expectType<ChangeStreamDocument<Document>>(change)
220242
);

0 commit comments

Comments
 (0)