Skip to content

Commit 10146a4

Browse files
baileympearsonW-A-Jamesnbbeeken
authored
fix(NODE-5044): Write Concern 0 Must Not Affect Read Operations (#3541) (#3575)
Co-authored-by: Warren James <[email protected]> Co-authored-by: Neal Beeken <[email protected]>
1 parent 722a4a6 commit 10146a4

File tree

9 files changed

+235
-92
lines changed

9 files changed

+235
-92
lines changed

src/change_stream.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export type OperationTime = Timestamp;
8282
* Options that can be passed to a ChangeStream. Note that startAfter, resumeAfter, and startAtOperationTime are all mutually exclusive, and the server will error if more than one is specified.
8383
* @public
8484
*/
85-
export interface ChangeStreamOptions extends AggregateOptions {
85+
export interface ChangeStreamOptions extends Omit<AggregateOptions, 'writeConcern'> {
8686
/**
8787
* Allowed values: 'updateLookup', 'whenAvailable', 'required'.
8888
*
@@ -533,7 +533,14 @@ export class ChangeStream<
533533
TChange extends Document = ChangeStreamDocument<TSchema>
534534
> extends TypedEventEmitter<ChangeStreamEvents<TSchema, TChange>> {
535535
pipeline: Document[];
536-
options: ChangeStreamOptions;
536+
/**
537+
* @remarks WriteConcern can still be present on the options because
538+
* we inherit options from the client/db/collection. The
539+
* key must be present on the options in order to delete it.
540+
* This allows typescript to delete the key but will
541+
* not allow a writeConcern to be assigned as a property on options.
542+
*/
543+
options: ChangeStreamOptions & { writeConcern?: never };
537544
parent: MongoClient | Db | Collection;
538545
namespace: MongoDBNamespace;
539546
type: symbol;
@@ -586,7 +593,8 @@ export class ChangeStream<
586593
super();
587594

588595
this.pipeline = pipeline;
589-
this.options = options;
596+
this.options = { ...options };
597+
delete this.options.writeConcern;
590598

591599
if (parent instanceof Collection) {
592600
this.type = CHANGE_DOMAIN_TYPES.COLLECTION;

src/operations/aggregate.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class AggregateOperation<T = Document> extends CommandOperation<T> {
4444
constructor(ns: MongoDBNamespace, pipeline: Document[], options?: AggregateOptions) {
4545
super(undefined, { ...options, dbName: ns.db });
4646

47-
this.options = options ?? {};
47+
this.options = { ...options };
4848

4949
// Covers when ns.collection is null, undefined or the empty string, use DB_AGGREGATE_COLLECTION
5050
this.target = ns.collection || DB_AGGREGATE_COLLECTION;
@@ -65,6 +65,8 @@ export class AggregateOperation<T = Document> extends CommandOperation<T> {
6565

6666
if (this.hasWriteStage) {
6767
this.trySecondaryWrite = true;
68+
} else {
69+
delete this.options.writeConcern;
6870
}
6971

7072
if (this.explain && this.writeConcern) {

src/operations/find.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import { Aspect, defineAspects, Hint } from './operation';
1414
* @typeParam TSchema - Unused schema definition, deprecated usage, only specify `FindOptions` with no generic
1515
*/
1616
// eslint-disable-next-line @typescript-eslint/no-unused-vars
17-
export interface FindOptions<TSchema extends Document = Document> extends CommandOperationOptions {
17+
export interface FindOptions<TSchema extends Document = Document>
18+
extends Omit<CommandOperationOptions, 'writeConcern'> {
1819
/** Sets the limit of documents returned in the query. */
1920
limit?: number;
2021
/** Set to sort the documents coming back from the query. Array of indexes, `[['a', 1]]` etc. */
@@ -66,7 +67,14 @@ export interface FindOptions<TSchema extends Document = Document> extends Comman
6667

6768
/** @internal */
6869
export class FindOperation extends CommandOperation<Document> {
69-
override options: FindOptions;
70+
/**
71+
* @remarks WriteConcern can still be present on the options because
72+
* we inherit options from the client/db/collection. The
73+
* key must be present on the options in order to delete it.
74+
* This allows typescript to delete the key but will
75+
* not allow a writeConcern to be assigned as a property on options.
76+
*/
77+
override options: FindOptions & { writeConcern?: never };
7078
filter: Document;
7179

7280
constructor(
@@ -77,7 +85,8 @@ export class FindOperation extends CommandOperation<Document> {
7785
) {
7886
super(collection, options);
7987

80-
this.options = options;
88+
this.options = { ...options };
89+
delete this.options.writeConcern;
8190
this.ns = ns;
8291

8392
if (typeof filter !== 'object' || Array.isArray(filter)) {

src/operations/indexes.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export interface IndexDescription
102102
}
103103

104104
/** @public */
105-
export interface CreateIndexesOptions extends CommandOperationOptions {
105+
export interface CreateIndexesOptions extends Omit<CommandOperationOptions, 'writeConcern'> {
106106
/** Creates the index in the background, yielding whenever possible. */
107107
background?: boolean;
108108
/** Creates an unique index. */
@@ -382,20 +382,28 @@ export class DropIndexesOperation extends DropIndexOperation {
382382
}
383383

384384
/** @public */
385-
export interface ListIndexesOptions extends CommandOperationOptions {
385+
export interface ListIndexesOptions extends Omit<CommandOperationOptions, 'writeConcern'> {
386386
/** The batchSize for the returned command cursor or if pre 2.8 the systems batch collection */
387387
batchSize?: number;
388388
}
389389

390390
/** @internal */
391391
export class ListIndexesOperation extends CommandOperation<Document> {
392-
override options: ListIndexesOptions;
392+
/**
393+
* @remarks WriteConcern can still be present on the options because
394+
* we inherit options from the client/db/collection. The
395+
* key must be present on the options in order to delete it.
396+
* This allows typescript to delete the key but will
397+
* not allow a writeConcern to be assigned as a property on options.
398+
*/
399+
override options: ListIndexesOptions & { writeConcern?: never };
393400
collectionNamespace: MongoDBNamespace;
394401

395402
constructor(collection: Collection, options?: ListIndexesOptions) {
396403
super(collection, options);
397404

398-
this.options = options ?? {};
405+
this.options = { ...options };
406+
delete this.options.writeConcern;
399407
this.collectionNamespace = collection.s.namespace;
400408
}
401409

src/operations/list_collections.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { CommandOperation, CommandOperationOptions } from './command';
77
import { Aspect, defineAspects } from './operation';
88

99
/** @public */
10-
export interface ListCollectionsOptions extends CommandOperationOptions {
10+
export interface ListCollectionsOptions extends Omit<CommandOperationOptions, 'writeConcern'> {
1111
/** Since 4.0: If true, will only return the collection name in the response, and will omit additional info */
1212
nameOnly?: boolean;
1313
/** Since 4.0: If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */
@@ -18,7 +18,14 @@ export interface ListCollectionsOptions extends CommandOperationOptions {
1818

1919
/** @internal */
2020
export class ListCollectionsOperation extends CommandOperation<string[]> {
21-
override options: ListCollectionsOptions;
21+
/**
22+
* @remarks WriteConcern can still be present on the options because
23+
* we inherit options from the client/db/collection. The
24+
* key must be present on the options in order to delete it.
25+
* This allows typescript to delete the key but will
26+
* not allow a writeConcern to be assigned as a property on options.
27+
*/
28+
override options: ListCollectionsOptions & { writeConcern?: never };
2229
db: Db;
2330
filter: Document;
2431
nameOnly: boolean;
@@ -28,7 +35,8 @@ export class ListCollectionsOperation extends CommandOperation<string[]> {
2835
constructor(db: Db, filter: Document, options?: ListCollectionsOptions) {
2936
super(db, options);
3037

31-
this.options = options ?? {};
38+
this.options = { ...options };
39+
delete this.options.writeConcern;
3240
this.db = db;
3341
this.filter = filter;
3442
this.nameOnly = !!this.options.nameOnly;

test/integration/read-write-concern/write_concern.test.js

-75
This file was deleted.

0 commit comments

Comments
 (0)