Skip to content

Commit 2cdbc08

Browse files
authored
refactor(NODE-3337): unwrap WriteConcernError (#2932)
1 parent ead5fa6 commit 2cdbc08

File tree

5 files changed

+87
-52
lines changed

5 files changed

+87
-52
lines changed

src/bulk/common.ts

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ import type { Collection } from '../collection';
2626
import type { Topology } from '../sdam/topology';
2727
import type { CommandOperationOptions, CollationOptions } from '../operations/command';
2828
import type { Hint } from '../operations/operation';
29-
import type { Filter, OptionalId, UpdateFilter } from '../mongo_types';
29+
import type { Filter, OneOrMore, OptionalId, UpdateFilter } from '../mongo_types';
30+
31+
/** @internal */
32+
const kServerError = Symbol('serverError');
3033

3134
/** @public */
3235
export const BatchType = Object.freeze({
@@ -309,9 +312,7 @@ export class BulkWriteResult {
309312
if (i === 0) errmsg = errmsg + ' and ';
310313
}
311314

312-
return new WriteConcernError(
313-
new MongoServerError({ errmsg: errmsg, code: MONGODB_ERROR_CODES.WriteConcernFailed })
314-
);
315+
return new WriteConcernError({ errmsg, code: MONGODB_ERROR_CODES.WriteConcernFailed });
315316
}
316317
}
317318

@@ -328,34 +329,52 @@ export class BulkWriteResult {
328329
}
329330
}
330331

332+
/** @public */
333+
export interface WriteConcernErrorData {
334+
code: number;
335+
errmsg: string;
336+
errInfo?: Document;
337+
}
338+
331339
/**
332340
* An error representing a failure by the server to apply the requested write concern to the bulk operation.
333341
* @public
334342
* @category Error
335343
*/
336344
export class WriteConcernError {
337-
err: MongoServerError;
345+
/** @internal */
346+
[kServerError]: WriteConcernErrorData;
338347

339-
constructor(err: MongoServerError) {
340-
this.err = err;
348+
constructor(error: WriteConcernErrorData) {
349+
this[kServerError] = error;
341350
}
342351

343352
/** Write concern error code. */
344353
get code(): number | undefined {
345-
return this.err.code;
354+
return this[kServerError].code;
346355
}
347356

348357
/** Write concern error message. */
349-
get errmsg(): string {
350-
return this.err.errmsg;
358+
get errmsg(): string | undefined {
359+
return this[kServerError].errmsg;
360+
}
361+
362+
/** Write concern error info. */
363+
get errInfo(): Document | undefined {
364+
return this[kServerError].errInfo;
365+
}
366+
367+
/** @deprecated The `err` prop that contained a MongoServerError has been deprecated. */
368+
get err(): WriteConcernErrorData {
369+
return this[kServerError];
351370
}
352371

353-
toJSON(): { code?: number; errmsg: string } {
354-
return { code: this.err.code, errmsg: this.err.errmsg };
372+
toJSON(): WriteConcernErrorData {
373+
return this[kServerError];
355374
}
356375

357376
toString(): string {
358-
return `WriteConcernError(${this.err.errmsg})`;
377+
return `WriteConcernError(${this.errmsg})`;
359378
}
360379
}
361380

@@ -656,17 +675,12 @@ function handleMongoWriteConcernError(
656675
) {
657676
mergeBatchResults(batch, bulkResult, undefined, err.result);
658677

659-
// TODO: Remove multiple levels of wrapping (NODE-3337)
660-
const wrappedWriteConcernError = new WriteConcernError(
661-
new MongoServerError({
662-
errmsg: err.result?.writeConcernError.errmsg,
663-
code: err.result?.writeConcernError.result
664-
})
665-
);
666-
667678
callback(
668679
new MongoBulkWriteError(
669-
new MongoServerError(wrappedWriteConcernError),
680+
{
681+
message: err.result?.writeConcernError.errmsg,
682+
code: err.result?.writeConcernError.result
683+
},
670684
new BulkWriteResult(bulkResult)
671685
)
672686
);
@@ -679,13 +693,28 @@ function handleMongoWriteConcernError(
679693
*/
680694
export class MongoBulkWriteError extends MongoServerError {
681695
result: BulkWriteResult;
696+
writeErrors: OneOrMore<WriteError> = [];
697+
err?: WriteConcernError;
682698

683699
/** Creates a new MongoBulkWriteError */
684-
constructor(error: AnyError, result: BulkWriteResult) {
685-
super(error as Error);
686-
Object.assign(this, error);
700+
constructor(
701+
error:
702+
| { message: string; code: number; writeErrors?: WriteError[] }
703+
| WriteConcernError
704+
| AnyError,
705+
result: BulkWriteResult
706+
) {
707+
super(error);
708+
709+
if (error instanceof WriteConcernError) this.err = error;
710+
else if (!(error instanceof Error)) {
711+
this.message = error.message;
712+
this.code = error.code;
713+
this.writeErrors = error.writeErrors ?? [];
714+
}
687715

688716
this.result = result;
717+
Object.assign(this, error);
689718
}
690719

691720
get name(): string {
@@ -1225,11 +1254,11 @@ export abstract class BulkOperationBase {
12251254

12261255
callback(
12271256
new MongoBulkWriteError(
1228-
new MongoServerError({
1257+
{
12291258
message: msg,
12301259
code: this.s.bulkResult.writeErrors[0].code,
12311260
writeErrors: this.s.bulkResult.writeErrors
1232-
}),
1261+
},
12331262
writeResult
12341263
)
12351264
);
@@ -1239,7 +1268,7 @@ export abstract class BulkOperationBase {
12391268

12401269
const writeConcernError = writeResult.getWriteConcernError();
12411270
if (writeConcernError) {
1242-
callback(new MongoBulkWriteError(new MongoServerError(writeConcernError), writeResult));
1271+
callback(new MongoBulkWriteError(writeConcernError, writeResult));
12431272
return true;
12441273
}
12451274
}

src/error.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ export const GET_MORE_RESUMABLE_CODES = new Set<number>([
6060
]);
6161

6262
/** @public */
63-
export interface ErrorDescription {
63+
export interface ErrorDescription extends Document {
6464
message?: string;
6565
errmsg?: string;
6666
$err?: string;
6767
errorLabels?: string[];
68-
[key: string]: any;
68+
errInfo?: Document;
6969
}
7070

7171
/**
@@ -84,7 +84,6 @@ export class MongoError extends Error {
8484
constructor(message: string | Error) {
8585
if (message instanceof Error) {
8686
super(message.message);
87-
this.stack = message.stack;
8887
} else {
8988
super(message);
9089
}
@@ -136,23 +135,20 @@ export class MongoServerError extends MongoError {
136135
code?: number;
137136
codeName?: string;
138137
writeConcernError?: Document;
138+
errInfo?: Document;
139+
ok?: number;
140+
topologyVersion?: TopologyVersion;
141+
[key: string]: any;
139142

140-
constructor(message: Error | ErrorDescription) {
141-
if (message instanceof Error) {
142-
super(message);
143-
} else {
144-
super(message.message || message.errmsg || message.$err || 'n/a');
145-
if (message.errorLabels) {
146-
this[kErrorLabels] = new Set(message.errorLabels);
147-
}
148-
149-
for (const name in message) {
150-
if (name === 'errorLabels' || name === 'errmsg' || name === 'message') {
151-
continue;
152-
}
153-
154-
(this as any)[name] = message[name];
155-
}
143+
constructor(message: ErrorDescription) {
144+
super(message.message || message.errmsg || message.$err || 'n/a');
145+
if (message.errorLabels) {
146+
this[kErrorLabels] = new Set(message.errorLabels);
147+
}
148+
149+
for (const name in message) {
150+
if (name !== 'errorLabels' && name !== 'errmsg' && name !== 'message')
151+
this[name] = message[name];
156152
}
157153
}
158154

@@ -649,13 +645,15 @@ function makeWriteConcernResultObject(input: any) {
649645
export class MongoWriteConcernError extends MongoServerError {
650646
/** The result document (provided if ok: 1) */
651647
result?: Document;
648+
errInfo?: Document;
652649

653-
constructor(message: ErrorDescription, result: Document) {
650+
constructor(message: ErrorDescription, result?: Document) {
654651
if (result && Array.isArray(result.errorLabels)) {
655652
message.errorLabels = result.errorLabels;
656653
}
657654

658655
super(message);
656+
this.errInfo = message.errInfo;
659657

660658
if (result != null) {
661659
this.result = makeWriteConcernResultObject(result);

src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,13 @@ export type {
374374
export type { W, WriteConcernOptions, WriteConcernSettings } from './write_concern';
375375
export type { ExecutionResult } from './operations/execute_operation';
376376
export type { InternalAbstractCursorOptions } from './cursor/abstract_cursor';
377-
export type { BulkOperationBase, BulkOperationPrivate, FindOperators, Batch } from './bulk/common';
377+
export type {
378+
BulkOperationBase,
379+
BulkOperationPrivate,
380+
FindOperators,
381+
Batch,
382+
WriteConcernErrorData
383+
} from './bulk/common';
378384
export type { OrderedBulkOperation } from './bulk/ordered';
379385
export type { UnorderedBulkOperation } from './bulk/unordered';
380386
export type { Encrypter, EncrypterOptions } from './encrypter';

src/operations/insert.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ export class InsertOneOperation extends InsertOperation {
7070
super.execute(server, session, (err, res) => {
7171
if (err || res == null) return callback(err);
7272
if (res.code) return callback(new MongoServerError(res));
73-
if (res.writeErrors) return callback(new MongoServerError(res.writeErrors[0]));
73+
if (res.writeErrors) {
74+
// This should be a WriteError but we can't change it now because of error hierarchy
75+
return callback(new MongoServerError(res.writeErrors[0]));
76+
}
7477

7578
callback(undefined, {
7679
acknowledged: this.writeConcern?.w !== 0 ?? true,

test/unit/core/write_concern_error.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
const { Topology } = require('../../../src/sdam/topology');
33
const mock = require('../../tools/mock');
44
const { ReplSetFixture } = require('./common');
5-
const { MongoWriteConcernError } = require('../../../src/error');
5+
const { MongoServerError, MongoWriteConcernError } = require('../../../src/error');
66
const { expect } = require('chai');
77
const { ns } = require('../../../src/utils');
88
const { once } = require('events');
9-
const { MongoServerError } = require('../../../src');
109

1110
describe('WriteConcernError', function () {
1211
let test;

0 commit comments

Comments
 (0)