Skip to content

Commit

Permalink
Merge pull request #14587 from Automattic/vkarpov15/gh-14572
Browse files Browse the repository at this point in the history
fix(model): make `bulkWrite()` and `insertMany()` throw if `throwOnValidationError` set and all ops invalid
  • Loading branch information
vkarpov15 authored May 17, 2024
2 parents 40805aa + 55d9d7e commit cdedde6
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
16 changes: 16 additions & 0 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -3233,6 +3233,14 @@ Model.$__insertMany = function(arr, options, callback) {

// Quickly escape while there aren't any valid docAttributes
if (docAttributes.length === 0) {
if (throwOnValidationError) {
return callback(new MongooseBulkWriteError(
validationErrors,
results,
null,
'insertMany'
));
}
if (rawResult) {
const res = {
acknowledged: true,
Expand Down Expand Up @@ -3588,6 +3596,14 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
validOps = validOps.sort().map(index => ops[index]);

if (validOps.length === 0) {
if (options.throwOnValidationError && validationErrors.length) {
throw new MongooseBulkWriteError(
validationErrors,
results,
res,
'bulkWrite'
);
}
return getDefaultBulkwriteResult();
}

Expand Down
44 changes: 41 additions & 3 deletions test/model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4062,7 +4062,32 @@ describe('Model', function() {
assert.ok(doc.createdAt.valueOf() >= now.valueOf());
assert.ok(doc.updatedAt);
assert.ok(doc.updatedAt.valueOf() >= now.valueOf());
});

it('throwOnValidationError (gh-14572)', async function() {
const schema = new Schema({
num: Number
});

const M = db.model('Test', schema);

const ops = [
{
insertOne: {
document: {
num: 'not a number'
}
}
}
];

const err = await M.bulkWrite(
ops,
{ ordered: false, throwOnValidationError: true }
).then(() => null, err => err);
assert.ok(err);
assert.equal(err.name, 'MongooseBulkWriteError');
assert.equal(err.validationErrors[0].errors['num'].name, 'CastError');
});

it('with child timestamps and array filters (gh-7032)', async function() {
Expand Down Expand Up @@ -6602,14 +6627,14 @@ describe('Model', function() {
});

it('insertMany should throw an error if there were operations that failed validation, ' +
'but all operations that passed validation succeeded (gh-13256)', async function() {
'but all operations that passed validation succeeded (gh-14572) (gh-13256)', async function() {
const userSchema = new Schema({
age: { type: Number }
});

const User = db.model('User', userSchema);

const err = await User.insertMany([
let err = await User.insertMany([
new User({ age: 12 }),
new User({ age: 12 }),
new User({ age: 'NaN' })
Expand All @@ -6623,7 +6648,20 @@ describe('Model', function() {
assert.ok(err.results[2] instanceof Error);
assert.equal(err.results[2].errors['age'].name, 'CastError');

const docs = await User.find();
let docs = await User.find();
assert.deepStrictEqual(docs.map(doc => doc.age), [12, 12]);

err = await User.insertMany([
new User({ age: 'NaN' })
], { ordered: false, throwOnValidationError: true })
.then(() => null)
.catch(err => err);

assert.ok(err);
assert.equal(err.name, 'MongooseBulkWriteError');
assert.equal(err.validationErrors[0].errors['age'].name, 'CastError');

docs = await User.find();
assert.deepStrictEqual(docs.map(doc => doc.age), [12, 12]);
});

Expand Down

0 comments on commit cdedde6

Please sign in to comment.