Skip to content

Commit

Permalink
Merge branch 'master' into vkarpov15/gh-13372
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed May 23, 2023
2 parents edad51b + 048ec48 commit 2ed05d3
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 7 deletions.
5 changes: 4 additions & 1 deletion lib/helpers/model/castBulkWrite.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use strict';

const MongooseError = require('../../error/mongooseError');
const getDiscriminatorByValue = require('../../helpers/discriminator/getDiscriminatorByValue');
const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
const cast = require('../../cast');
const castUpdate = require('../query/castUpdate');
const { inspect } = require('util');
const setDefaultsOnInsert = require('../setDefaultsOnInsert');

/**
Expand Down Expand Up @@ -212,7 +214,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
};
} else {
return (callback) => {
callback(new Error('Invalid op passed to `bulkWrite()`'), null);
const error = new MongooseError(`Invalid op passed to \`bulkWrite()\`: ${inspect(op)}`);
callback(error, null);
};
}
};
Expand Down
5 changes: 3 additions & 2 deletions lib/helpers/update/applyTimestampsToUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio

if (Array.isArray(updates)) {
// Update with aggregation pipeline
if (updatedAt == null) {
return updates;
}
updates.push({ $set: { [updatedAt]: now } });

return updates;
}

updates.$set = updates.$set || {};
if (!skipUpdatedAt && updatedAt &&
(!currentUpdate.$currentDate || !currentUpdate.$currentDate[updatedAt])) {
Expand Down
10 changes: 6 additions & 4 deletions lib/schematype.js
Original file line number Diff line number Diff line change
Expand Up @@ -822,10 +822,12 @@ SchemaType.prototype.get = function(fn) {
*
* #### Error message templates:
*
* From the examples above, you may have noticed that error messages support
* basic templating. There are a few other template keywords besides `{PATH}`
* and `{VALUE}` too. To find out more, details are available
* [here](./error.html#Error.prototype.name).
* Below is a list of supported template keywords:
*
* - PATH: The schema path where the error is being triggered.
* - VALUE: The value assigned to the PATH that is triggering the error.
* - KIND: The validation property that triggered the error i.e. required.
* - REASON: The error object that caused this error if there was one.
*
* If Mongoose's built-in error message templating isn't enough, Mongoose
* supports setting the `message` property to a function.
Expand Down
7 changes: 7 additions & 0 deletions test/model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3945,7 +3945,14 @@ describe('Model', function() {

const doc = await Parent.findOne();
assert.ok(doc.children[0].updatedAt.valueOf() > end);
});

it('throws readable error if invalid op', async function() {
const Test = db.model('Test', Schema({ name: String }));
await assert.rejects(
() => Test.bulkWrite([Promise.resolve(42)]),
'MongooseError: Invalid op passed to `bulkWrite()`: Promise { 42 }'
);
});

it('with timestamps and replaceOne (gh-5708)', async function() {
Expand Down
33 changes: 33 additions & 0 deletions test/timestamps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,39 @@ describe('timestamps', function() {
assert.deepStrictEqual(keys, ['location', '_id', 'createdAt', 'updatedAt']);
}
});
it('should avoid setting null update when updating document with timestamps gh-13379', async function() {

const subWithTimestampSchema = new Schema({
subName: {
type: String,
default: 'anonymous',
required: true
}
});

subWithTimestampSchema.set('timestamps', true);

const testSchema = new Schema({
name: String,
sub: { type: subWithTimestampSchema }
});

const Test = db.model('gh13379', testSchema);

const doc = new Test({
name: 'Test Testerson',
sub: { subName: 'John' }
});
await doc.save();
await Test.updateMany({}, [{ $set: { updateCounter: 1 } }]);
// oddly enough, the null property is not accessible. Doing check.null doesn't return anything even though
// if you were to console.log() the output of a findOne you would be able to see it. This is the workaround.
const test = await Test.countDocuments({ null: { $exists: true } });
assert.equal(test, 0);
// now we need to make sure that the solution didn't prevent the updateCounter addition
const check = await Test.findOne();
assert(check.toString().includes('updateCounter: 1'));
});
});

async function delay(ms) {
Expand Down

0 comments on commit 2ed05d3

Please sign in to comment.