Skip to content

Commit 6914e87

Browse files
authored
feat!: remove top-level write concern options (#2642)
WriteConcern options are no longer accepted spread across the top-level options object they must be provided as in a sub-object under the writeConcern key. NODE-1722
1 parent 2c03b78 commit 6914e87

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1033
-790
lines changed

src/bulk/common.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,7 @@ export abstract class BulkOperationBase {
10841084
* bulkOp.find({ h: 8 }).delete();
10851085
*
10861086
* // Add a replaceOne
1087-
* bulkOp.find({ i: 9 }).replaceOne({ j: 10 });
1087+
* bulkOp.find({ i: 9 }).replaceOne({writeConcern: { j: 10 }});
10881088
*
10891089
* // Update using a pipeline (requires Mongodb 4.2 or higher)
10901090
* bulk.find({ k: 11, y: { $exists: true }, z: { $exists: true } }).updateOne([

src/connection_string.ts

+25-14
Original file line numberDiff line numberDiff line change
@@ -1199,8 +1199,10 @@ export const OPTIONS = {
11991199
target: 'writeConcern',
12001200
transform({ name, options, values: [value] }): WriteConcern {
12011201
const wc = WriteConcern.fromOptions({
1202-
...options.writeConcern,
1203-
fsync: getBoolean(name, value)
1202+
writeConcern: {
1203+
...options.writeConcern,
1204+
fsync: getBoolean(name, value)
1205+
}
12041206
});
12051207
if (!wc) throw new TypeError(`Unable to make a writeConcern from fsync=${value}`);
12061208
return wc;
@@ -1216,10 +1218,11 @@ export const OPTIONS = {
12161218
j: {
12171219
target: 'writeConcern',
12181220
transform({ name, options, values: [value] }): WriteConcern {
1219-
console.warn('j is deprecated');
12201221
const wc = WriteConcern.fromOptions({
1221-
...options.writeConcern,
1222-
journal: getBoolean(name, value)
1222+
writeConcern: {
1223+
...options.writeConcern,
1224+
journal: getBoolean(name, value)
1225+
}
12231226
});
12241227
if (!wc) throw new TypeError(`Unable to make a writeConcern from journal=${value}`);
12251228
return wc;
@@ -1229,8 +1232,10 @@ export const OPTIONS = {
12291232
target: 'writeConcern',
12301233
transform({ name, options, values: [value] }): WriteConcern {
12311234
const wc = WriteConcern.fromOptions({
1232-
...options.writeConcern,
1233-
journal: getBoolean(name, value)
1235+
writeConcern: {
1236+
...options.writeConcern,
1237+
journal: getBoolean(name, value)
1238+
}
12341239
});
12351240
if (!wc) throw new TypeError(`Unable to make a writeConcern from journal=${value}`);
12361241
return wc;
@@ -1516,7 +1521,7 @@ export const OPTIONS = {
15161521
w: {
15171522
target: 'writeConcern',
15181523
transform({ values: [value], options }) {
1519-
return WriteConcern.fromOptions({ ...options.writeConcern, w: value as W });
1524+
return WriteConcern.fromOptions({ writeConcern: { ...options.writeConcern, w: value as W } });
15201525
}
15211526
},
15221527
waitQueueTimeoutMS: {
@@ -1528,8 +1533,10 @@ export const OPTIONS = {
15281533
transform({ values: [value], options }) {
15291534
if (isRecord(value) || value instanceof WriteConcern) {
15301535
return WriteConcern.fromOptions({
1531-
...options.writeConcern,
1532-
...value
1536+
writeConcern: {
1537+
...options.writeConcern,
1538+
...value
1539+
}
15331540
});
15341541
}
15351542

@@ -1540,8 +1547,10 @@ export const OPTIONS = {
15401547
target: 'writeConcern',
15411548
transform({ values: [value], options }) {
15421549
const wc = WriteConcern.fromOptions({
1543-
...options.writeConcern,
1544-
wtimeout: getUint('wtimeout', value)
1550+
writeConcern: {
1551+
...options.writeConcern,
1552+
wtimeout: getUint('wtimeout', value)
1553+
}
15451554
});
15461555
if (wc) return wc;
15471556
throw new MongoParseError(`Cannot make WriteConcern from wtimeout`);
@@ -1551,8 +1560,10 @@ export const OPTIONS = {
15511560
target: 'writeConcern',
15521561
transform({ values: [value], options }) {
15531562
const wc = WriteConcern.fromOptions({
1554-
...options.writeConcern,
1555-
wtimeoutMS: getUint('wtimeoutMS', value)
1563+
writeConcern: {
1564+
...options.writeConcern,
1565+
wtimeoutMS: getUint('wtimeoutMS', value)
1566+
}
15561567
});
15571568
if (wc) return wc;
15581569
throw new MongoParseError(`Cannot make WriteConcern from wtimeout`);

src/db.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,7 @@ import type { Admin } from './admin';
5555

5656
// Allowed parameters
5757
const legalOptionNames = [
58-
'w',
59-
'wtimeout',
60-
'fsync',
61-
'j',
58+
'writeConcern',
6259
'readPreference',
6360
'readPreferenceTags',
6461
'native_parser',

src/gridfs-stream/upload.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,11 @@ function doWrite(
515515
function getWriteOptions(stream: GridFSBucketWriteStream): WriteConcernOptions {
516516
const obj: WriteConcernOptions = {};
517517
if (stream.writeConcern) {
518-
obj.w = stream.writeConcern.w;
519-
obj.wtimeout = stream.writeConcern.wtimeout;
520-
obj.j = stream.writeConcern.j;
518+
obj.writeConcern = {
519+
w: stream.writeConcern.w,
520+
wtimeout: stream.writeConcern.wtimeout,
521+
j: stream.writeConcern.j
522+
};
521523
}
522524
return obj;
523525
}

src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export type {
298298
InterruptibleAsyncInterval,
299299
BufferPool
300300
} from './utils';
301-
export type { WriteConcern, W, WriteConcernOptions } from './write_concern';
301+
export type { WriteConcern, W, WriteConcernOptions, WriteConcernSettings } from './write_concern';
302302
export type { ExecutionResult } from './operations/execute_operation';
303303
export type { InternalAbstractCursorOptions } from './cursor/abstract_cursor';
304304
export type {

src/mongo_client.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EventEmitter } from 'events';
33
import { ChangeStream, ChangeStreamOptions } from './change_stream';
44
import { ReadPreference, ReadPreferenceModeId } from './read_preference';
55
import { MongoError, AnyError } from './error';
6-
import { WriteConcern, WriteConcernOptions } from './write_concern';
6+
import { WriteConcern, W, WriteConcernSettings } from './write_concern';
77
import { maybePromise, MongoDBNamespace, Callback, resolveOptions } from './utils';
88
import { deprecate } from 'util';
99
import { connect, validOptions } from './operations/connect';
@@ -60,7 +60,7 @@ type CleanUpHandlerFunction = (err?: AnyError, result?: any, opts?: any) => Prom
6060
* @public
6161
* @see https://docs.mongodb.com/manual/reference/connection-string
6262
*/
63-
export interface MongoURIOptions extends Pick<WriteConcernOptions, 'journal' | 'w' | 'wtimeoutMS'> {
63+
export interface MongoURIOptions {
6464
/** Specifies the name of the replica set, if the mongod is a member of a replica set. */
6565
replicaSet?: string;
6666
/** Enables or disables TLS/SSL for the connection. */
@@ -134,13 +134,19 @@ export interface MongoURIOptions extends Pick<WriteConcernOptions, 'journal' | '
134134
// username and password in Authority section not query string.
135135
username?: string;
136136
password?: string;
137+
138+
// remove in NODE-2704
139+
fsync?: boolean;
140+
w?: W;
141+
j?: boolean;
142+
journal?: boolean;
143+
wtimeout?: number;
144+
wtimeoutMS?: number;
145+
writeConcern?: WriteConcern | WriteConcernSettings;
137146
}
138147

139148
/** @public */
140-
export interface MongoClientOptions
141-
extends WriteConcernOptions,
142-
MongoURIOptions,
143-
BSONSerializeOptions {
149+
export interface MongoClientOptions extends MongoURIOptions, BSONSerializeOptions {
144150
/** Validate mongod server certificate against Certificate Authority */
145151
sslValidate?: boolean;
146152
/** SSL Certificate store binary buffer. */

src/operations/connect.ts

+16-11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { MongoClient } from '../mongo_client';
1414
import { ConnectionOptions, Connection } from '../cmap/connection';
1515
import { AuthMechanism, AuthMechanismId } from '../cmap/auth/defaultAuthProviders';
1616
import { Server } from '../sdam/server';
17+
import { WRITE_CONCERN_KEYS } from '../write_concern';
1718

1819
const validOptionNames = [
1920
'poolSize',
@@ -40,9 +41,7 @@ const validOptionNames = [
4041
'acceptableLatencyMS',
4142
'connectWithNoPrimary',
4243
'authSource',
43-
'w',
44-
'wtimeout',
45-
'j',
44+
'writeConcern',
4645
'forceServerObjectId',
4746
'serializeFunctions',
4847
'ignoreUndefined',
@@ -68,7 +67,6 @@ const validOptionNames = [
6867
'password',
6968
'authMechanism',
7069
'compression',
71-
'fsync',
7270
'readPreferenceTags',
7371
'numberOfRetries',
7472
'auto_reconnect',
@@ -216,12 +214,6 @@ export function connect(
216214
delete finalOptions.db_options.auth;
217215
}
218216

219-
// `journal` should be translated to `j` for the driver
220-
if (finalOptions.journal != null) {
221-
finalOptions.j = finalOptions.journal;
222-
finalOptions.journal = undefined;
223-
}
224-
225217
// resolve tls options if needed
226218
resolveTLSOptions(finalOptions);
227219

@@ -412,7 +404,9 @@ function createUnifiedOptions(finalOptions: any, options: any) {
412404
const noMerge = ['readconcern', 'compression', 'autoencryption'];
413405

414406
for (const name in options) {
415-
if (noMerge.indexOf(name.toLowerCase()) !== -1) {
407+
if (name === 'writeConcern') {
408+
finalOptions[name] = { ...finalOptions[name], ...options[name] };
409+
} else if (noMerge.indexOf(name.toLowerCase()) !== -1) {
416410
finalOptions[name] = options[name];
417411
} else if (childOptions.indexOf(name.toLowerCase()) !== -1) {
418412
finalOptions = mergeOptions(finalOptions, options[name], false);
@@ -551,12 +545,23 @@ function transformUrlOptions(connStrOptions: any) {
551545

552546
if (connStrOpts.wTimeoutMS) {
553547
connStrOpts.wtimeout = connStrOpts.wTimeoutMS;
548+
connStrOpts.wTimeoutMS = undefined;
554549
}
555550

556551
if (connStrOptions.srvHost) {
557552
connStrOpts.srvHost = connStrOptions.srvHost;
558553
}
559554

555+
// Any write concern options from the URL will be top-level, so we manually
556+
// move them options under `object.writeConcern`
557+
for (const key of WRITE_CONCERN_KEYS) {
558+
if (connStrOpts[key] !== undefined) {
559+
if (connStrOpts.writeConcern === undefined) connStrOpts.writeConcern = {};
560+
connStrOpts.writeConcern[key] = connStrOpts[key];
561+
connStrOpts[key] = undefined;
562+
}
563+
}
564+
560565
return connStrOpts;
561566
}
562567

src/operations/map_reduce.ts

-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ const exclusionList = [
2424
'readConcern',
2525
'session',
2626
'bypassDocumentValidation',
27-
'w',
28-
'wtimeout',
29-
'j',
3027
'writeConcern',
3128
'raw',
3229
'fieldsAsRaw',

src/write_concern.ts

+16-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ export type W = number | 'majority';
33

44
/** @public */
55
export interface WriteConcernOptions {
6+
/** Write Concern as an object */
7+
writeConcern?: WriteConcern | WriteConcernSettings;
8+
}
9+
10+
/** @public */
11+
export interface WriteConcernSettings {
612
/** The write concern */
713
w?: W;
814
/** The write concern timeout */
@@ -15,10 +21,10 @@ export interface WriteConcernOptions {
1521
journal?: boolean;
1622
/** The file sync write concern */
1723
fsync?: boolean | 1;
18-
/** Write Concern as an object */
19-
writeConcern?: WriteConcernOptions | WriteConcern | W;
2024
}
2125

26+
export const WRITE_CONCERN_KEYS = ['w', 'wtimeout', 'j', 'journal', 'fsync'];
27+
2228
/**
2329
* A MongoDB WriteConcern, which describes the level of acknowledgement
2430
* requested from MongoDB for write operations.
@@ -64,19 +70,17 @@ export class WriteConcern {
6470

6571
/** Construct a WriteConcern given an options object. */
6672
static fromOptions(
67-
options?: WriteConcernOptions | WriteConcern | W,
73+
options?: WriteConcernOptions | WriteConcern,
6874
inherit?: WriteConcernOptions | WriteConcern
6975
): WriteConcern | undefined {
70-
const { fromOptions } = WriteConcern;
7176
if (typeof options === 'undefined') return undefined;
72-
if (typeof options === 'number') return fromOptions({ ...inherit, w: options });
73-
if (typeof options === 'string') return fromOptions({ ...inherit, w: options });
74-
if (options instanceof WriteConcern) return fromOptions({ ...inherit, ...options });
75-
if (options.writeConcern) {
76-
const { writeConcern, ...viable } = { ...inherit, ...options };
77-
return fromOptions(writeConcern, viable);
78-
}
79-
const { w, wtimeout, j, fsync, journal, wtimeoutMS } = { ...inherit, ...options };
77+
inherit = inherit ?? {};
78+
const opts: WriteConcern | WriteConcernSettings | undefined =
79+
options instanceof WriteConcern ? options : options.writeConcern;
80+
const parentOpts: WriteConcern | WriteConcernSettings | undefined =
81+
inherit instanceof WriteConcern ? inherit : inherit.writeConcern;
82+
83+
const { w, wtimeout, j, fsync, journal, wtimeoutMS } = { ...parentOpts, ...opts };
8084
if (
8185
w != null ||
8286
wtimeout != null ||

test/examples/transactions.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,15 @@ describe('examples(transactions):', function () {
234234

235235
// Prereq: Create collections.
236236

237-
await client.db('mydb1').collection('foo').insertOne({ abc: 0 }, { w: 'majority' });
238-
239-
await client.db('mydb2').collection('bar').insertOne({ xyz: 0 }, { w: 'majority' });
237+
await client
238+
.db('mydb1')
239+
.collection('foo')
240+
.insertOne({ abc: 0 }, { writeConcern: { w: 'majority' } });
241+
242+
await client
243+
.db('mydb2')
244+
.collection('bar')
245+
.insertOne({ xyz: 0 }, { writeConcern: { w: 'majority' } });
240246

241247
// Step 1: Start a Client Session
242248
const session = client.startSession();

0 commit comments

Comments
 (0)