Skip to content

Commit e884537

Browse files
committed
chore: hook it all up
1 parent 8a129bd commit e884537

File tree

8 files changed

+177
-21
lines changed

8 files changed

+177
-21
lines changed

src/bulk/common.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ export class FindOperators {
705705

706706
/** Add a single update operation to the bulk operation */
707707
updateOne(updateDocument: Document | Document[]): BulkOperationBase {
708-
if (!hasAtomicOperators(updateDocument)) {
708+
if (!hasAtomicOperators(updateDocument, this.bulkOperation.bsonOptions)) {
709709
throw new MongoInvalidArgumentError('Update document requires atomic operators');
710710
}
711711

@@ -1115,7 +1115,7 @@ export abstract class BulkOperationBase {
11151115
...op.updateOne,
11161116
multi: false
11171117
});
1118-
if (!hasAtomicOperators(updateStatement.u)) {
1118+
if (!hasAtomicOperators(updateStatement.u, this.bsonOptions)) {
11191119
throw new MongoInvalidArgumentError('Update document requires atomic operators');
11201120
}
11211121
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
@@ -1129,7 +1129,7 @@ export abstract class BulkOperationBase {
11291129
...op.updateMany,
11301130
multi: true
11311131
});
1132-
if (!hasAtomicOperators(updateStatement.u)) {
1132+
if (!hasAtomicOperators(updateStatement.u, this.bsonOptions)) {
11331133
throw new MongoInvalidArgumentError('Update document requires atomic operators');
11341134
}
11351135
return this.addToOperationsList(BatchType.UPDATE, updateStatement);

src/operations/client_bulk_write/command_builder.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BSON, type Document } from '../../bson';
1+
import { BSON, type BSONSerializeOptions, type Document } from '../../bson';
22
import { DocumentSequence } from '../../cmap/commands';
33
import { MongoAPIError, MongoInvalidArgumentError } from '../../error';
44
import { type PkFactory } from '../../mongo_client';
@@ -128,7 +128,7 @@ export class ClientBulkWriteCommandBuilder {
128128

129129
if (nsIndex != null) {
130130
// Build the operation and serialize it to get the bytes buffer.
131-
const operation = buildOperation(model, nsIndex, this.pkFactory);
131+
const operation = buildOperation(model, nsIndex, this.pkFactory, this.options);
132132
let operationBuffer;
133133
try {
134134
operationBuffer = BSON.serialize(operation);
@@ -159,7 +159,12 @@ export class ClientBulkWriteCommandBuilder {
159159
// construct our nsInfo and ops documents and buffers.
160160
namespaces.set(ns, currentNamespaceIndex);
161161
const nsInfo = { ns: ns };
162-
const operation = buildOperation(model, currentNamespaceIndex, this.pkFactory);
162+
const operation = buildOperation(
163+
model,
164+
currentNamespaceIndex,
165+
this.pkFactory,
166+
this.options
167+
);
163168
let nsInfoBuffer;
164169
let operationBuffer;
165170
try {
@@ -339,9 +344,10 @@ export interface ClientUpdateOperation {
339344
*/
340345
export const buildUpdateOneOperation = (
341346
model: ClientUpdateOneModel<Document>,
342-
index: number
347+
index: number,
348+
options: BSONSerializeOptions
343349
): ClientUpdateOperation => {
344-
return createUpdateOperation(model, index, false);
350+
return createUpdateOperation(model, index, false, options);
345351
};
346352

347353
/**
@@ -352,17 +358,18 @@ export const buildUpdateOneOperation = (
352358
*/
353359
export const buildUpdateManyOperation = (
354360
model: ClientUpdateManyModel<Document>,
355-
index: number
361+
index: number,
362+
options: BSONSerializeOptions
356363
): ClientUpdateOperation => {
357-
return createUpdateOperation(model, index, true);
364+
return createUpdateOperation(model, index, true, options);
358365
};
359366

360367
/**
361368
* Validate the update document.
362369
* @param update - The update document.
363370
*/
364-
function validateUpdate(update: Document) {
365-
if (!hasAtomicOperators(update)) {
371+
function validateUpdate(update: Document, options: BSONSerializeOptions) {
372+
if (!hasAtomicOperators(update, options)) {
366373
throw new MongoAPIError(
367374
'Client bulk write update models must only contain atomic modifiers (start with $) and must not be empty.'
368375
);
@@ -375,13 +382,14 @@ function validateUpdate(update: Document) {
375382
function createUpdateOperation(
376383
model: ClientUpdateOneModel<Document> | ClientUpdateManyModel<Document>,
377384
index: number,
378-
multi: boolean
385+
multi: boolean,
386+
options: BSONSerializeOptions
379387
): ClientUpdateOperation {
380388
// Update documents provided in UpdateOne and UpdateMany write models are
381389
// required only to contain atomic modifiers (i.e. keys that start with "$").
382390
// Drivers MUST throw an error if an update document is empty or if the
383391
// document's first key does not start with "$".
384-
validateUpdate(model.update);
392+
validateUpdate(model.update, options);
385393
const document: ClientUpdateOperation = {
386394
update: index,
387395
multi: multi,
@@ -459,7 +467,8 @@ export const buildReplaceOneOperation = (
459467
export function buildOperation(
460468
model: AnyClientBulkWriteModel<Document>,
461469
index: number,
462-
pkFactory: PkFactory
470+
pkFactory: PkFactory,
471+
options: BSONSerializeOptions
463472
): Document {
464473
switch (model.name) {
465474
case 'insertOne':
@@ -469,9 +478,9 @@ export function buildOperation(
469478
case 'deleteMany':
470479
return buildDeleteManyOperation(model, index);
471480
case 'updateOne':
472-
return buildUpdateOneOperation(model, index);
481+
return buildUpdateOneOperation(model, index, options);
473482
case 'updateMany':
474-
return buildUpdateManyOperation(model, index);
483+
return buildUpdateManyOperation(model, index, options);
475484
case 'replaceOne':
476485
return buildReplaceOneOperation(model, index);
477486
}

src/operations/find_and_modify.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ export class FindOneAndUpdateOperation extends FindAndModifyOperation {
273273
throw new MongoInvalidArgumentError('Argument "update" must be an object');
274274
}
275275

276-
if (!hasAtomicOperators(update)) {
276+
if (!hasAtomicOperators(update, options)) {
277277
throw new MongoInvalidArgumentError('Update document requires atomic operators');
278278
}
279279

src/operations/update.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export class UpdateOneOperation extends UpdateOperation {
144144
options
145145
);
146146

147-
if (!hasAtomicOperators(update)) {
147+
if (!hasAtomicOperators(update, options)) {
148148
throw new MongoInvalidArgumentError('Update document requires atomic operators');
149149
}
150150
}
@@ -179,7 +179,7 @@ export class UpdateManyOperation extends UpdateOperation {
179179
options
180180
);
181181

182-
if (!hasAtomicOperators(update)) {
182+
if (!hasAtomicOperators(update, options)) {
183183
throw new MongoInvalidArgumentError('Update document requires atomic operators');
184184
}
185185
}

test/integration/crud/bulk.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,44 @@ describe('Bulk', function () {
4646
client = null;
4747
});
4848

49+
describe('#bulkWrite', function () {
50+
context('when including an update with all undefined atomic operators', function () {
51+
context('when performing an update many', function () {
52+
it('throws an error', async function () {
53+
const collection = client.db('test').collection('test');
54+
const error = await collection
55+
.bulkWrite([
56+
{
57+
updateMany: {
58+
filter: { age: { $lte: 5 } },
59+
update: { $set: undefined, $unset: undefined }
60+
}
61+
}
62+
])
63+
.catch(error => error);
64+
expect(error.message).to.include('All atomic operators provided have undefined values.');
65+
});
66+
});
67+
68+
context('when performing an update one', function () {
69+
it('throws an error', async function () {
70+
const collection = client.db('test').collection('test');
71+
const error = await collection
72+
.bulkWrite([
73+
{
74+
updateOne: {
75+
filter: { age: { $lte: 5 } },
76+
update: { $set: undefined, $unset: undefined }
77+
}
78+
}
79+
])
80+
.catch(error => error);
81+
expect(error.message).to.include('All atomic operators provided have undefined values.');
82+
});
83+
});
84+
});
85+
});
86+
4987
describe('BulkOperationBase', () => {
5088
describe('#raw()', function () {
5189
context('when called with an undefined operation', function () {

test/integration/crud/client_bulk_write.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,50 @@ describe('Client Bulk Write', function () {
3434
await clearFailPoint(this.configuration);
3535
});
3636

37+
describe('#bulkWrite', function () {
38+
context('when including an update with all undefined atomic operators', function () {
39+
context('when performing an update many', function () {
40+
beforeEach(async function () {
41+
client = this.configuration.newClient();
42+
});
43+
44+
it('throws an error', async function () {
45+
const error = await client
46+
.bulkWrite([
47+
{
48+
name: 'updateMany',
49+
namespace: 'foo.bar',
50+
filter: { age: { $lte: 5 } },
51+
update: { $set: undefined, $unset: undefined }
52+
}
53+
])
54+
.catch(error => error);
55+
expect(error.message).to.include('All atomic operators provided have undefined values.');
56+
});
57+
});
58+
59+
context('when performing an update one', function () {
60+
beforeEach(async function () {
61+
client = this.configuration.newClient();
62+
});
63+
64+
it('throws an error', async function () {
65+
const error = await client
66+
.bulkWrite([
67+
{
68+
name: 'updateOne',
69+
namespace: 'foo.bar',
70+
filter: { age: { $lte: 5 } },
71+
update: { $set: undefined, $unset: undefined }
72+
}
73+
])
74+
.catch(error => error);
75+
expect(error.message).to.include('All atomic operators provided have undefined values.');
76+
});
77+
});
78+
});
79+
});
80+
3781
describe('CSOT enabled', function () {
3882
describe('when timeoutMS is set on the client', function () {
3983
beforeEach(async function () {

test/integration/crud/crud_api.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,58 @@ describe('CRUD API', function () {
896896
});
897897
});
898898

899+
describe('#updateOne', function () {
900+
let collection;
901+
902+
beforeEach(async function () {
903+
await client.connect();
904+
collection = client.db().collection('updateOneTest');
905+
});
906+
907+
afterEach(async function () {
908+
await collection.drop();
909+
});
910+
911+
context('when including an update with all undefined atomic operators', function () {
912+
beforeEach(async function () {
913+
client = this.configuration.newClient();
914+
});
915+
916+
it('throws an error', async function () {
917+
const error = await collection
918+
.updateOne({ a: 1 }, { $set: undefined, $unset: undefined })
919+
.catch(error => error);
920+
expect(error.message).to.include('All atomic operators provided have undefined values.');
921+
});
922+
});
923+
});
924+
925+
describe('#updateMany', function () {
926+
let collection;
927+
928+
beforeEach(async function () {
929+
await client.connect();
930+
collection = client.db().collection('updateManyTest');
931+
});
932+
933+
afterEach(async function () {
934+
await collection.drop();
935+
});
936+
937+
context('when including an update with all undefined atomic operators', function () {
938+
beforeEach(async function () {
939+
client = this.configuration.newClient();
940+
});
941+
942+
it('throws an error', async function () {
943+
const error = await collection
944+
.updateMany({ a: 1 }, { $set: undefined, $unset: undefined })
945+
.catch(error => error);
946+
expect(error.message).to.include('All atomic operators provided have undefined values.');
947+
});
948+
});
949+
});
950+
899951
describe('#findOneAndUpdate', function () {
900952
let collection;
901953

@@ -908,6 +960,19 @@ describe('CRUD API', function () {
908960
await collection.drop();
909961
});
910962

963+
context('when including an update with all undefined atomic operators', function () {
964+
beforeEach(async function () {
965+
client = this.configuration.newClient();
966+
});
967+
968+
it('throws an error', async function () {
969+
const error = await collection
970+
.findOneAndUpdate({ a: 1 }, { $set: undefined, $unset: undefined })
971+
.catch(error => error);
972+
expect(error.message).to.include('All atomic operators provided have undefined values.');
973+
});
974+
});
975+
911976
context('when includeResultMetadata is true', function () {
912977
beforeEach(async function () {
913978
await collection.insertMany([{ a: 1, b: 1 }], { writeConcern: { w: 1 } });

test/unit/utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
import { sleep } from '../tools/utils';
2929

3030
describe('driver utils', function () {
31-
describe.only('.hasAtomicOperators', function () {
31+
describe('.hasAtomicOperators', function () {
3232
context('when ignoreUndefined is true', function () {
3333
const options = { ignoreUndefined: true };
3434

0 commit comments

Comments
 (0)