Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -5422,6 +5422,22 @@ Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValue
}));
};

/*!
* Increment this document's version if necessary.
*/

Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
if (!this.$__.version) return;
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);

this.$__.version = undefined;
if (doIncrement) {
const key = this.$__schema.options.versionKey;
const version = this.$__getValue(key) || 0;
this.$__setValue(key, version + 1); // increment version if was successful
}
};

/*!
* Module exports.
*/
Expand Down
13 changes: 5 additions & 8 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,22 +523,17 @@ Model.prototype.$__save = function(options, callback) {
const versionBump = this.$__.version;
// was this an update that required a version bump?
if (versionBump && !this.$__.inserting) {
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
this.$__.version = undefined;
const key = this.$__schema.options.versionKey;
const version = this.$__getValue(key) || 0;
if (numAffected <= 0) {
const key = this.$__schema.options.versionKey;
const version = this.$__getValue(key) || 0;
// the update failed. pass an error back
this.$__undoReset();
const err = this.$__.$versionError ||
new VersionError(this, version, this.$__.modifiedPaths);
return callback(err, this);
}

// increment version if was successful
if (doIncrement) {
this.$__setValue(key, version + 1);
}
this._applyVersionIncrement();
}
if (result != null && numAffected <= 0) {
this.$__undoReset();
Expand Down Expand Up @@ -3666,6 +3661,8 @@ function handleSuccessfulWrite(document) {
}

document.$__reset();
document._applyVersionIncrement();

document.schema.s.hooks.execPost('save', document, [document], {}, (err) => {
if (err) {
reject(err);
Expand Down
47 changes: 47 additions & 0 deletions test/model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7015,6 +7015,53 @@ describe('Model', function() {
);
});

it('increments version key on successful save (gh-15800)', async function() {
// Arrange
const userSchema = new Schema({
name: [String],
email: { type: String, minLength: 3 }
});

const User = db.model('User', userSchema);
const user1 = new User({ name: ['123'], email: '12314' });
await user1.save();

// Act
const user = await User.findOne({ _id: user1._id });
assert.ok(user);

// Before, __v should be 0
assert.equal(user.__v, 0);

// markModified on array field (triggers $set)
user.markModified('name');
await User.bulkSave([user]);

const dbUser1 = await User.findById(user._id);
assert.equal(dbUser1.__v, 1);
assert.equal(user.__v, 1);

// Update another path and markModified
user.email = '1375';
await User.bulkSave([user]);
const dbUser2 = await User.findById(user._id);
assert.equal(dbUser2.__v, 1);
assert.equal(user.__v, 1);

let reloaded = await User.findById(user._id);
assert.equal(reloaded.__v, 1);

user.email = '1';
await assert.rejects(
() => User.bulkSave([user]),
/email.*is shorter than the minimum allowed length/
);
assert.equal(user.__v, 1);

reloaded = await User.findById(user._id);
assert.equal(reloaded.__v, 1);
});

it('saves new documents with ordered: false (gh-15495)', async function() {
const userSchema = new Schema({
name: { type: String }
Expand Down