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(NODE-5274): deprecate write concern options #3752

Merged
merged 17 commits into from
Jul 6, 2023
2 changes: 1 addition & 1 deletion src/operations/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export abstract class CommandOperation<T> extends AbstractCallbackOperation<T> {
}

if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION) && !inTransaction) {
Object.assign(cmd, { writeConcern: this.writeConcern });
WriteConcern.apply(cmd, this.writeConcern);
}

if (
Expand Down
78 changes: 62 additions & 16 deletions src/write_concern.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { type Document } from 'bson';
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved

/** @public */
export type W = number | 'majority';

Expand All @@ -17,16 +19,35 @@ export interface WriteConcernSettings {
journal?: boolean;

// legacy options
/** The journal write concern */
/**
* The journal write concern.
* @deprecated Will be removed in the next major version. Please use the journal option.
*/
j?: boolean;
/** The write concern timeout */
/**
* The write concern timeout.
* @deprecated Will be removed in the next major version. Please use the wtimeoutMS option.
*/
wtimeout?: number;
/** The file sync write concern */
/**
* The file sync write concern.
* @deprecated Will be removed in the next major version. Please use the journal option.
*/
fsync?: boolean | 1;
}

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

/** The write concern options that decorate the server command. */
interface CommandWriteConcernOptions {
/** The write concern */
w?: W;
/** The journal write concern. */
j?: boolean;
/** The write concern timeout. */
wtimeout?: number;
}

/**
* A MongoDB WriteConcern, which describes the level of acknowledgement
* requested from MongoDB for write operations.
Expand All @@ -35,41 +56,66 @@ export const WRITE_CONCERN_KEYS = ['w', 'wtimeout', 'j', 'journal', 'fsync'];
* @see https://www.mongodb.com/docs/manual/reference/write-concern/
*/
export class WriteConcern {
/** request acknowledgment that the write operation has propagated to a specified number of mongod instances or to mongod instances with specified tags. */
w?: W;
/** specify a time limit to prevent write operations from blocking indefinitely */
/** Request acknowledgment that the write operation has propagated to a specified number of mongod instances or to mongod instances with specified tags. */
readonly w?: W;
/** Request acknowledgment that the write operation has been written to the on-disk journal */
readonly journal?: boolean;
/** Specify a time limit to prevent write operations from blocking indefinitely */
readonly wtimeoutMS?: number;
/**
* Specify a time limit to prevent write operations from blocking indefinitely.
* @deprecated Will be removed in the next major version. Please use wtimeoutMS.
*/
wtimeout?: number;
/** request acknowledgment that the write operation has been written to the on-disk journal */
/**
* Request acknowledgment that the write operation has been written to the on-disk journal.
* @deprecated Will be removed in the next major version. Please use journal.
*/
j?: boolean;
/** equivalent to the j option */
/**
* Equivalent to the j option.
* @deprecated Will be removed in the next major version. Please use journal.
*/
fsync?: boolean | 1;

/**
* Constructs a WriteConcern from the write concern properties.
* @param w - request acknowledgment that the write operation has propagated to a specified number of mongod instances or to mongod instances with specified tags.
* @param wtimeout - specify a time limit to prevent write operations from blocking indefinitely
* @param j - request acknowledgment that the write operation has been written to the on-disk journal
* @param wtimeoutMS - specify a time limit to prevent write operations from blocking indefinitely
* @param journal - request acknowledgment that the write operation has been written to the on-disk journal
* @param fsync - equivalent to the j option
*/
constructor(w?: W, wtimeout?: number, j?: boolean, fsync?: boolean | 1) {
constructor(w?: W, wtimeoutMS?: number, journal?: boolean, fsync?: boolean | 1) {
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
if (w != null) {
if (!Number.isNaN(Number(w))) {
this.w = Number(w);
} else {
this.w = w;
}
}
if (wtimeout != null) {
this.wtimeout = wtimeout;
if (wtimeoutMS != null) {
this.wtimeoutMS = this.wtimeout = wtimeoutMS;
}
if (j != null) {
this.j = j;
if (journal != null) {
this.journal = this.j = journal;
}
if (fsync != null) {
this.fsync = fsync;
this.journal = this.j = fsync ? true : false;
}
}

/**
* Apply a write concern to a command document.
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
*/
static apply(command: Document, writeConcern: WriteConcern): Document {
const wc: CommandWriteConcernOptions = {};
// The write concern document sent to the server has w/wtimeout/j fields.
if (writeConcern.w != null) wc.w = writeConcern.w;
if (writeConcern.wtimeoutMS != null) wc.wtimeout = writeConcern.wtimeoutMS;
if (writeConcern.journal != null) wc.j = writeConcern.j;
return Object.assign(command, { writeConcern: wc });
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
}

/** Construct a WriteConcern given an options object. */
static fromOptions(
options?: WriteConcernOptions | WriteConcern | W,
Expand Down
106 changes: 106 additions & 0 deletions test/unit/write_concern.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { expect } from 'chai';

import { WriteConcern } from '../mongodb';

describe('WriteConcern', function () {
describe('#constructor', function () {
context('when w is provided', function () {
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
const writeConcern = new WriteConcern(1);

it('sets the w property', function () {
expect(writeConcern.w).to.equal(1);
});
});

context('when wtimeoutMS is provided', function () {
const writeConcern = new WriteConcern(1, 50);

it('sets the wtimeoutMS property', function () {
expect(writeConcern.wtimeoutMS).to.equal(50);
});

it('sets the wtimeout property', function () {
expect(writeConcern.wtimeout).to.equal(50);
});
});

context('when journal is provided', function () {
const writeConcern = new WriteConcern(1, 50, true);

it('sets the journal property', function () {
expect(writeConcern.journal).to.be.true;
});

it('sets the j property', function () {
expect(writeConcern.j).to.be.true;
});
});

context('when fsync is provided', function () {
const writeConcern = new WriteConcern(1, 50, false, true);

it('sets the journal property', function () {
expect(writeConcern.journal).to.be.true;
});

it('sets the j property', function () {
expect(writeConcern.j).to.be.true;
});
});
});

describe('.apply', function () {
context('when no options are set', function () {
const document = {};
const writeConcern = new WriteConcern();

it('returns an empty write concern', function () {
expect(WriteConcern.apply(document, writeConcern)).to.deep.equal({ writeConcern: {} });
});
});

context('when w is in the write concern', function () {
const document = {};
const writeConcern = new WriteConcern(2);

it('adds w to the write concern document', function () {
expect(WriteConcern.apply(document, writeConcern)).to.deep.equal({
writeConcern: { w: 2 }
});
});
});

context('when wtimeoutMS is in the write concern', function () {
const document = {};
const writeConcern = new WriteConcern(2, 30);

it('adds wtimeout to the write concern document', function () {
expect(WriteConcern.apply(document, writeConcern)).to.deep.equal({
writeConcern: { w: 2, wtimeout: 30 }
});
});
});

context('when journal is in the write concern', function () {
const document = {};
const writeConcern = new WriteConcern(2, 30, true);

it('adds j to the write concern document', function () {
expect(WriteConcern.apply(document, writeConcern)).to.deep.equal({
writeConcern: { w: 2, wtimeout: 30, j: true }
});
});
});

context('when fsync is in the write concern', function () {
const document = {};
const writeConcern = new WriteConcern(2, 30, true, false);

it('overrites j to the write concern document', function () {
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
expect(WriteConcern.apply(document, writeConcern)).to.deep.equal({
writeConcern: { w: 2, wtimeout: 30, j: false }
});
});
});
});
});