Skip to content

Commit

Permalink
feat!: remove top-level write concern options (#2642)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
HanaPearlman authored Dec 16, 2020
1 parent 2c03b78 commit 6914e87
Show file tree
Hide file tree
Showing 44 changed files with 1,033 additions and 790 deletions.
2 changes: 1 addition & 1 deletion src/bulk/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ export abstract class BulkOperationBase {
* bulkOp.find({ h: 8 }).delete();
*
* // Add a replaceOne
* bulkOp.find({ i: 9 }).replaceOne({ j: 10 });
* bulkOp.find({ i: 9 }).replaceOne({writeConcern: { j: 10 }});
*
* // Update using a pipeline (requires Mongodb 4.2 or higher)
* bulk.find({ k: 11, y: { $exists: true }, z: { $exists: true } }).updateOne([
Expand Down
39 changes: 25 additions & 14 deletions src/connection_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1199,8 +1199,10 @@ export const OPTIONS = {
target: 'writeConcern',
transform({ name, options, values: [value] }): WriteConcern {
const wc = WriteConcern.fromOptions({
...options.writeConcern,
fsync: getBoolean(name, value)
writeConcern: {
...options.writeConcern,
fsync: getBoolean(name, value)
}
});
if (!wc) throw new TypeError(`Unable to make a writeConcern from fsync=${value}`);
return wc;
Expand All @@ -1216,10 +1218,11 @@ export const OPTIONS = {
j: {
target: 'writeConcern',
transform({ name, options, values: [value] }): WriteConcern {
console.warn('j is deprecated');
const wc = WriteConcern.fromOptions({
...options.writeConcern,
journal: getBoolean(name, value)
writeConcern: {
...options.writeConcern,
journal: getBoolean(name, value)
}
});
if (!wc) throw new TypeError(`Unable to make a writeConcern from journal=${value}`);
return wc;
Expand All @@ -1229,8 +1232,10 @@ export const OPTIONS = {
target: 'writeConcern',
transform({ name, options, values: [value] }): WriteConcern {
const wc = WriteConcern.fromOptions({
...options.writeConcern,
journal: getBoolean(name, value)
writeConcern: {
...options.writeConcern,
journal: getBoolean(name, value)
}
});
if (!wc) throw new TypeError(`Unable to make a writeConcern from journal=${value}`);
return wc;
Expand Down Expand Up @@ -1516,7 +1521,7 @@ export const OPTIONS = {
w: {
target: 'writeConcern',
transform({ values: [value], options }) {
return WriteConcern.fromOptions({ ...options.writeConcern, w: value as W });
return WriteConcern.fromOptions({ writeConcern: { ...options.writeConcern, w: value as W } });
}
},
waitQueueTimeoutMS: {
Expand All @@ -1528,8 +1533,10 @@ export const OPTIONS = {
transform({ values: [value], options }) {
if (isRecord(value) || value instanceof WriteConcern) {
return WriteConcern.fromOptions({
...options.writeConcern,
...value
writeConcern: {
...options.writeConcern,
...value
}
});
}

Expand All @@ -1540,8 +1547,10 @@ export const OPTIONS = {
target: 'writeConcern',
transform({ values: [value], options }) {
const wc = WriteConcern.fromOptions({
...options.writeConcern,
wtimeout: getUint('wtimeout', value)
writeConcern: {
...options.writeConcern,
wtimeout: getUint('wtimeout', value)
}
});
if (wc) return wc;
throw new MongoParseError(`Cannot make WriteConcern from wtimeout`);
Expand All @@ -1551,8 +1560,10 @@ export const OPTIONS = {
target: 'writeConcern',
transform({ values: [value], options }) {
const wc = WriteConcern.fromOptions({
...options.writeConcern,
wtimeoutMS: getUint('wtimeoutMS', value)
writeConcern: {
...options.writeConcern,
wtimeoutMS: getUint('wtimeoutMS', value)
}
});
if (wc) return wc;
throw new MongoParseError(`Cannot make WriteConcern from wtimeout`);
Expand Down
5 changes: 1 addition & 4 deletions src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ import type { Admin } from './admin';

// Allowed parameters
const legalOptionNames = [
'w',
'wtimeout',
'fsync',
'j',
'writeConcern',
'readPreference',
'readPreferenceTags',
'native_parser',
Expand Down
8 changes: 5 additions & 3 deletions src/gridfs-stream/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,11 @@ function doWrite(
function getWriteOptions(stream: GridFSBucketWriteStream): WriteConcernOptions {
const obj: WriteConcernOptions = {};
if (stream.writeConcern) {
obj.w = stream.writeConcern.w;
obj.wtimeout = stream.writeConcern.wtimeout;
obj.j = stream.writeConcern.j;
obj.writeConcern = {
w: stream.writeConcern.w,
wtimeout: stream.writeConcern.wtimeout,
j: stream.writeConcern.j
};
}
return obj;
}
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ export type {
InterruptibleAsyncInterval,
BufferPool
} from './utils';
export type { WriteConcern, W, WriteConcernOptions } from './write_concern';
export type { WriteConcern, W, WriteConcernOptions, WriteConcernSettings } from './write_concern';
export type { ExecutionResult } from './operations/execute_operation';
export type { InternalAbstractCursorOptions } from './cursor/abstract_cursor';
export type {
Expand Down
18 changes: 12 additions & 6 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EventEmitter } from 'events';
import { ChangeStream, ChangeStreamOptions } from './change_stream';
import { ReadPreference, ReadPreferenceModeId } from './read_preference';
import { MongoError, AnyError } from './error';
import { WriteConcern, WriteConcernOptions } from './write_concern';
import { WriteConcern, W, WriteConcernSettings } from './write_concern';
import { maybePromise, MongoDBNamespace, Callback, resolveOptions } from './utils';
import { deprecate } from 'util';
import { connect, validOptions } from './operations/connect';
Expand Down Expand Up @@ -60,7 +60,7 @@ type CleanUpHandlerFunction = (err?: AnyError, result?: any, opts?: any) => Prom
* @public
* @see https://docs.mongodb.com/manual/reference/connection-string
*/
export interface MongoURIOptions extends Pick<WriteConcernOptions, 'journal' | 'w' | 'wtimeoutMS'> {
export interface MongoURIOptions {
/** Specifies the name of the replica set, if the mongod is a member of a replica set. */
replicaSet?: string;
/** Enables or disables TLS/SSL for the connection. */
Expand Down Expand Up @@ -134,13 +134,19 @@ export interface MongoURIOptions extends Pick<WriteConcernOptions, 'journal' | '
// username and password in Authority section not query string.
username?: string;
password?: string;

// remove in NODE-2704
fsync?: boolean;
w?: W;
j?: boolean;
journal?: boolean;
wtimeout?: number;
wtimeoutMS?: number;
writeConcern?: WriteConcern | WriteConcernSettings;
}

/** @public */
export interface MongoClientOptions
extends WriteConcernOptions,
MongoURIOptions,
BSONSerializeOptions {
export interface MongoClientOptions extends MongoURIOptions, BSONSerializeOptions {
/** Validate mongod server certificate against Certificate Authority */
sslValidate?: boolean;
/** SSL Certificate store binary buffer. */
Expand Down
27 changes: 16 additions & 11 deletions src/operations/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { MongoClient } from '../mongo_client';
import { ConnectionOptions, Connection } from '../cmap/connection';
import { AuthMechanism, AuthMechanismId } from '../cmap/auth/defaultAuthProviders';
import { Server } from '../sdam/server';
import { WRITE_CONCERN_KEYS } from '../write_concern';

const validOptionNames = [
'poolSize',
Expand All @@ -40,9 +41,7 @@ const validOptionNames = [
'acceptableLatencyMS',
'connectWithNoPrimary',
'authSource',
'w',
'wtimeout',
'j',
'writeConcern',
'forceServerObjectId',
'serializeFunctions',
'ignoreUndefined',
Expand All @@ -68,7 +67,6 @@ const validOptionNames = [
'password',
'authMechanism',
'compression',
'fsync',
'readPreferenceTags',
'numberOfRetries',
'auto_reconnect',
Expand Down Expand Up @@ -216,12 +214,6 @@ export function connect(
delete finalOptions.db_options.auth;
}

// `journal` should be translated to `j` for the driver
if (finalOptions.journal != null) {
finalOptions.j = finalOptions.journal;
finalOptions.journal = undefined;
}

// resolve tls options if needed
resolveTLSOptions(finalOptions);

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

for (const name in options) {
if (noMerge.indexOf(name.toLowerCase()) !== -1) {
if (name === 'writeConcern') {
finalOptions[name] = { ...finalOptions[name], ...options[name] };
} else if (noMerge.indexOf(name.toLowerCase()) !== -1) {
finalOptions[name] = options[name];
} else if (childOptions.indexOf(name.toLowerCase()) !== -1) {
finalOptions = mergeOptions(finalOptions, options[name], false);
Expand Down Expand Up @@ -551,12 +545,23 @@ function transformUrlOptions(connStrOptions: any) {

if (connStrOpts.wTimeoutMS) {
connStrOpts.wtimeout = connStrOpts.wTimeoutMS;
connStrOpts.wTimeoutMS = undefined;
}

if (connStrOptions.srvHost) {
connStrOpts.srvHost = connStrOptions.srvHost;
}

// Any write concern options from the URL will be top-level, so we manually
// move them options under `object.writeConcern`
for (const key of WRITE_CONCERN_KEYS) {
if (connStrOpts[key] !== undefined) {
if (connStrOpts.writeConcern === undefined) connStrOpts.writeConcern = {};
connStrOpts.writeConcern[key] = connStrOpts[key];
connStrOpts[key] = undefined;
}
}

return connStrOpts;
}

Expand Down
3 changes: 0 additions & 3 deletions src/operations/map_reduce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ const exclusionList = [
'readConcern',
'session',
'bypassDocumentValidation',
'w',
'wtimeout',
'j',
'writeConcern',
'raw',
'fieldsAsRaw',
Expand Down
28 changes: 16 additions & 12 deletions src/write_concern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ export type W = number | 'majority';

/** @public */
export interface WriteConcernOptions {
/** Write Concern as an object */
writeConcern?: WriteConcern | WriteConcernSettings;
}

/** @public */
export interface WriteConcernSettings {
/** The write concern */
w?: W;
/** The write concern timeout */
Expand All @@ -15,10 +21,10 @@ export interface WriteConcernOptions {
journal?: boolean;
/** The file sync write concern */
fsync?: boolean | 1;
/** Write Concern as an object */
writeConcern?: WriteConcernOptions | WriteConcern | W;
}

export const WRITE_CONCERN_KEYS = ['w', 'wtimeout', 'j', 'journal', 'fsync'];

/**
* A MongoDB WriteConcern, which describes the level of acknowledgement
* requested from MongoDB for write operations.
Expand Down Expand Up @@ -64,19 +70,17 @@ export class WriteConcern {

/** Construct a WriteConcern given an options object. */
static fromOptions(
options?: WriteConcernOptions | WriteConcern | W,
options?: WriteConcernOptions | WriteConcern,
inherit?: WriteConcernOptions | WriteConcern
): WriteConcern | undefined {
const { fromOptions } = WriteConcern;
if (typeof options === 'undefined') return undefined;
if (typeof options === 'number') return fromOptions({ ...inherit, w: options });
if (typeof options === 'string') return fromOptions({ ...inherit, w: options });
if (options instanceof WriteConcern) return fromOptions({ ...inherit, ...options });
if (options.writeConcern) {
const { writeConcern, ...viable } = { ...inherit, ...options };
return fromOptions(writeConcern, viable);
}
const { w, wtimeout, j, fsync, journal, wtimeoutMS } = { ...inherit, ...options };
inherit = inherit ?? {};
const opts: WriteConcern | WriteConcernSettings | undefined =
options instanceof WriteConcern ? options : options.writeConcern;
const parentOpts: WriteConcern | WriteConcernSettings | undefined =
inherit instanceof WriteConcern ? inherit : inherit.writeConcern;

const { w, wtimeout, j, fsync, journal, wtimeoutMS } = { ...parentOpts, ...opts };
if (
w != null ||
wtimeout != null ||
Expand Down
12 changes: 9 additions & 3 deletions test/examples/transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,15 @@ describe('examples(transactions):', function () {

// Prereq: Create collections.

await client.db('mydb1').collection('foo').insertOne({ abc: 0 }, { w: 'majority' });

await client.db('mydb2').collection('bar').insertOne({ xyz: 0 }, { w: 'majority' });
await client
.db('mydb1')
.collection('foo')
.insertOne({ abc: 0 }, { writeConcern: { w: 'majority' } });

await client
.db('mydb2')
.collection('bar')
.insertOne({ xyz: 0 }, { writeConcern: { w: 'majority' } });

// Step 1: Start a Client Session
const session = client.startSession();
Expand Down
Loading

0 comments on commit 6914e87

Please sign in to comment.