Skip to content

Commit ebac1f5

Browse files
authored
feat(NODE-4034)!: make internal bulk result private (#3515)
1 parent 60640e0 commit ebac1f5

File tree

6 files changed

+87
-80
lines changed

6 files changed

+87
-80
lines changed

etc/notes/CHANGES_5.0.0.md

+18
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,21 @@ await collection.insertMany([{ name: 'fido' }, { name: 'luna' }])
191191

192192
The `keepGoing` option was a legacy name for setting `ordered` to `false` for bulk inserts.
193193
It was only supported by the legacy `collection.insert()` method which is now removed as noted above.
194+
195+
### `BulkWriteResult` no longer contains a publicly enumerable `result` property.
196+
197+
To access the raw result, please use `bulkWriteResult.getRawResponse()`.
198+
199+
### `BulkWriteResult` now contains individual ressult properties.
200+
201+
These can be accessed via:
202+
203+
```ts
204+
bulkWriteResult.insertedCount;
205+
bulkWriteResult.matchedCount;
206+
bulkWriteResult.modifiedCount;
207+
bulkWriteResult.deletedCount;
208+
bulkWriteResult.upsertedCount;
209+
bulkWriteResult.upsertedIds;
210+
bulkWriteResult.insertedIds;
211+
```

src/bulk/common.ts

+32-56
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,7 @@ export type AnyBulkWriteOperation<TSchema extends Document = Document> =
123123
| { deleteOne: DeleteOneModel<TSchema> }
124124
| { deleteMany: DeleteManyModel<TSchema> };
125125

126-
/**
127-
* @public
128-
*
129-
* @deprecated Will be made internal in 5.0
130-
*/
126+
/** @internal */
131127
export interface BulkResult {
132128
ok: number;
133129
writeErrors: WriteError[];
@@ -172,54 +168,44 @@ export class Batch<T = Document> {
172168
* The result of a bulk write.
173169
*/
174170
export class BulkWriteResult {
175-
/** @deprecated Will be removed in 5.0 */
176-
result: BulkResult;
177-
178-
/**
179-
* Create a new BulkWriteResult instance
180-
* @internal
181-
*/
182-
constructor(bulkResult: BulkResult) {
183-
this.result = bulkResult;
184-
}
185-
171+
private readonly result: BulkResult;
186172
/** Number of documents inserted. */
187-
get insertedCount(): number {
188-
return this.result.nInserted ?? 0;
189-
}
173+
readonly insertedCount: number;
190174
/** Number of documents matched for update. */
191-
get matchedCount(): number {
192-
return this.result.nMatched ?? 0;
193-
}
175+
readonly matchedCount: number;
194176
/** Number of documents modified. */
195-
get modifiedCount(): number {
196-
return this.result.nModified ?? 0;
197-
}
177+
readonly modifiedCount: number;
198178
/** Number of documents deleted. */
199-
get deletedCount(): number {
200-
return this.result.nRemoved ?? 0;
201-
}
179+
readonly deletedCount: number;
202180
/** Number of documents upserted. */
203-
get upsertedCount(): number {
204-
return this.result.upserted.length ?? 0;
205-
}
206-
181+
readonly upsertedCount: number;
207182
/** Upserted document generated Id's, hash key is the index of the originating operation */
208-
get upsertedIds(): { [key: number]: any } {
209-
const upserted: { [index: number]: any } = {};
210-
for (const doc of this.result.upserted ?? []) {
211-
upserted[doc.index] = doc._id;
183+
readonly upsertedIds: { [key: number]: any };
184+
/** Inserted document generated Id's, hash key is the index of the originating operation */
185+
readonly insertedIds: { [key: number]: any };
186+
187+
private static generateIdMap(ids: Document[]): { [key: number]: any } {
188+
const idMap: { [index: number]: any } = {};
189+
for (const doc of ids) {
190+
idMap[doc.index] = doc._id;
212191
}
213-
return upserted;
192+
return idMap;
214193
}
215194

216-
/** Inserted document generated Id's, hash key is the index of the originating operation */
217-
get insertedIds(): { [key: number]: any } {
218-
const inserted: { [index: number]: any } = {};
219-
for (const doc of this.result.insertedIds ?? []) {
220-
inserted[doc.index] = doc._id;
221-
}
222-
return inserted;
195+
/**
196+
* Create a new BulkWriteResult instance
197+
* @internal
198+
*/
199+
constructor(bulkResult: BulkResult) {
200+
this.result = bulkResult;
201+
this.insertedCount = this.result.nInserted ?? 0;
202+
this.matchedCount = this.result.nMatched ?? 0;
203+
this.modifiedCount = this.result.nModified ?? 0;
204+
this.deletedCount = this.result.nRemoved ?? 0;
205+
this.upsertedCount = this.result.upserted.length ?? 0;
206+
this.upsertedIds = BulkWriteResult.generateIdMap(this.result.upserted);
207+
this.insertedIds = BulkWriteResult.generateIdMap(this.result.insertedIds);
208+
Object.defineProperty(this, 'result', { value: this.result, enumerable: false });
223209
}
224210

225211
/** Evaluates to true if the bulk operation correctly executes */
@@ -314,13 +300,8 @@ export class BulkWriteResult {
314300
}
315301
}
316302

317-
/* @deprecated Will be removed in 5.0 release */
318-
toJSON(): BulkResult {
319-
return this.result;
320-
}
321-
322303
toString(): string {
323-
return `BulkWriteResult(${this.toJSON()})`;
304+
return `BulkWriteResult(${this.result})`;
324305
}
325306

326307
isOk(): boolean {
@@ -550,12 +531,8 @@ function executeCommands(
550531
}
551532

552533
// Merge the results together
534+
mergeBatchResults(batch, bulkOperation.s.bulkResult, err, result);
553535
const writeResult = new BulkWriteResult(bulkOperation.s.bulkResult);
554-
const mergeResult = mergeBatchResults(batch, bulkOperation.s.bulkResult, err, result);
555-
if (mergeResult != null) {
556-
return callback(undefined, writeResult);
557-
}
558-
559536
if (bulkOperation.handleWriteError(callback, writeResult)) return;
560537

561538
// Execute the next command in line
@@ -1246,7 +1223,6 @@ export abstract class BulkOperationBase {
12461223
this.s.executed = true;
12471224
const finalOptions = { ...this.s.options, ...options };
12481225
const operation = new BulkWriteShimOperation(this, finalOptions);
1249-
12501226
return executeOperation(this.s.collection.s.db.s.client, operation);
12511227
}, callback);
12521228
}

test/integration/retryable-writes/retryable_writes.spec.test.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,12 @@ async function executeScenarioTest(test, ctx: RetryableWriteTestContext) {
150150
const result = resultOrError;
151151
const expected = test.outcome.result;
152152

153-
// TODO(NODE-4034): Make CRUD results spec compliant
154-
expect(result.value ?? result).to.deep.include(expected);
153+
const actual = result.value ?? result;
154+
// Some of our result classes contain the optional 'acknowledged' property which is
155+
// not part of the test expectations.
156+
for (const property in expected) {
157+
expect(actual).to.have.deep.property(property, expected[property]);
158+
}
155159
}
156160

157161
if (test.outcome.collection) {

test/spec/client-side-encryption/tests/unified/rewrapManyDataKey.json

+24-6
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,10 @@
321321
"modifiedCount": 4,
322322
"deletedCount": 0,
323323
"upsertedCount": 0,
324-
"upsertedIds": {}
324+
"upsertedIds": {},
325+
"insertedIds": {
326+
"$$unsetOrMatches": {}
327+
}
325328
}
326329
}
327330
}
@@ -503,7 +506,10 @@
503506
"modifiedCount": 4,
504507
"deletedCount": 0,
505508
"upsertedCount": 0,
506-
"upsertedIds": {}
509+
"upsertedIds": {},
510+
"insertedIds": {
511+
"$$unsetOrMatches": {}
512+
}
507513
}
508514
}
509515
}
@@ -687,7 +693,10 @@
687693
"modifiedCount": 4,
688694
"deletedCount": 0,
689695
"upsertedCount": 0,
690-
"upsertedIds": {}
696+
"upsertedIds": {},
697+
"insertedIds": {
698+
"$$unsetOrMatches": {}
699+
}
691700
}
692701
}
693702
}
@@ -873,7 +882,10 @@
873882
"modifiedCount": 4,
874883
"deletedCount": 0,
875884
"upsertedCount": 0,
876-
"upsertedIds": {}
885+
"upsertedIds": {},
886+
"insertedIds": {
887+
"$$unsetOrMatches": {}
888+
}
877889
}
878890
}
879891
}
@@ -1055,7 +1067,10 @@
10551067
"modifiedCount": 4,
10561068
"deletedCount": 0,
10571069
"upsertedCount": 0,
1058-
"upsertedIds": {}
1070+
"upsertedIds": {},
1071+
"insertedIds": {
1072+
"$$unsetOrMatches": {}
1073+
}
10591074
}
10601075
}
10611076
}
@@ -1218,7 +1233,10 @@
12181233
"modifiedCount": 5,
12191234
"deletedCount": 0,
12201235
"upsertedCount": 0,
1221-
"upsertedIds": {}
1236+
"upsertedIds": {},
1237+
"insertedIds": {
1238+
"$$unsetOrMatches": {}
1239+
}
12221240
}
12231241
}
12241242
},

test/spec/client-side-encryption/tests/unified/rewrapManyDataKey.yml

+6
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ tests:
130130
deletedCount: 0
131131
upsertedCount: 0
132132
upsertedIds: {}
133+
insertedIds: { $$unsetOrMatches: {} }
133134
expectEvents:
134135
- client: *client0
135136
events:
@@ -182,6 +183,7 @@ tests:
182183
deletedCount: 0
183184
upsertedCount: 0
184185
upsertedIds: {}
186+
insertedIds: { $$unsetOrMatches: {} }
185187
expectEvents:
186188
- client: *client0
187189
events:
@@ -236,6 +238,7 @@ tests:
236238
deletedCount: 0
237239
upsertedCount: 0
238240
upsertedIds: {}
241+
insertedIds: { $$unsetOrMatches: {} }
239242
expectEvents:
240243
- client: *client0
241244
events:
@@ -285,6 +288,7 @@ tests:
285288
deletedCount: 0
286289
upsertedCount: 0
287290
upsertedIds: {}
291+
insertedIds: { $$unsetOrMatches: {} }
288292
expectEvents:
289293
- client: *client0
290294
events:
@@ -334,6 +338,7 @@ tests:
334338
deletedCount: 0
335339
upsertedCount: 0
336340
upsertedIds: {}
341+
insertedIds: { $$unsetOrMatches: {} }
337342
expectEvents:
338343
- client: *client0
339344
events:
@@ -381,6 +386,7 @@ tests:
381386
deletedCount: 0
382387
upsertedCount: 0
383388
upsertedIds: {}
389+
insertedIds: { $$unsetOrMatches: {} }
384390
- name: find
385391
object: *collection0
386392
arguments:

test/tools/unified-spec-runner/operations.ts

+1-16
Original file line numberDiff line numberDiff line change
@@ -659,22 +659,7 @@ operations.set('rewrapManyDataKey', async ({ entities, operation }) => {
659659
const clientEncryption = entities.getEntity('clientEncryption', operation.object);
660660
const { filter, opts } = operation.arguments!;
661661

662-
const rewrapManyDataKeyResult = await clientEncryption.rewrapManyDataKey(filter, opts);
663-
664-
if (rewrapManyDataKeyResult.bulkWriteResult != null) {
665-
// TODO(NODE-4393): refactor BulkWriteResult to not have a 'result' property
666-
//
667-
// The unified spec runner match function will assert that documents have no extra
668-
// keys. For `rewrapManyDataKey` operations, our unifed tests will fail because
669-
// our BulkWriteResult class has an extra property - "result". We explicitly make it
670-
// non-enumerable for the purposes of testing so that the tests can pass.
671-
const { bulkWriteResult } = rewrapManyDataKeyResult;
672-
Object.defineProperty(bulkWriteResult, 'result', {
673-
value: bulkWriteResult.result,
674-
enumerable: false
675-
});
676-
}
677-
return rewrapManyDataKeyResult;
662+
return await clientEncryption.rewrapManyDataKey(filter, opts);
678663
});
679664

680665
operations.set('deleteKey', async ({ entities, operation }) => {

0 commit comments

Comments
 (0)