Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove top-level write concern options #2642

Merged
merged 10 commits into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)) {
return WriteConcern.fromOptions({
...options.writeConcern,
...value
writeConcern: {
...options.writeConcern,
...value
}
});
}
throw new MongoParseError(`WriteConcern must be an object, got ${JSON.stringify(value)}`);
Expand All @@ -1539,8 +1546,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 @@ -1550,8 +1559,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 @@ -295,7 +295,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