From 65c40b5c468ca3862de5dcd64f836987c0b790c7 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 17 May 2024 16:29:19 -0400 Subject: [PATCH] fix(document): fire pre validate hooks on 5 level deep single nested subdoc when modifying after save() Fix #14591 --- lib/document.js | 4 ++++ lib/types/subdocument.js | 2 +- test/document.test.js | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/document.js b/lib/document.js index 264a94a6684..f76af16cc16 100644 --- a/lib/document.js +++ b/lib/document.js @@ -1716,6 +1716,9 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa } else { obj._doc[parts[i]] = val; } + if (shouldModify) { + obj.markModified(parts[i]); + } } else { obj[parts[i]] = val; } @@ -2698,6 +2701,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) { !doc.isDirectModified(fullPathToSubdoc) && !doc.$isDefault(fullPathToSubdoc)) { paths.add(fullPathToSubdoc); + if (doc.$__.pathsToScopes == null) { doc.$__.pathsToScopes = {}; } diff --git a/lib/types/subdocument.js b/lib/types/subdocument.js index 8ea50d03ecc..014babe6caf 100644 --- a/lib/types/subdocument.js +++ b/lib/types/subdocument.js @@ -113,7 +113,7 @@ Subdocument.prototype.$__fullPath = function(path) { /** * Given a path relative to this document, return the path relative - * to the top-level document. + * to the parent document. * @param {String} p * @returns {String} * @method $__pathRelativeToParent diff --git a/test/document.test.js b/test/document.test.js index 3ce45f384d4..69cedd4979f 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -12627,6 +12627,41 @@ describe('document', function() { doc.set('branding.logo.attachment', { name: 'coolLogo' }); await doc.save(); assert.strictEqual(attachmentSchemaPreValidateCalls, 1); + + instance.set('branding.logo.attachment', { name: 'coolOtherLogo' }); + await instance.save(); + assert.strictEqual(attachmentSchemaPreValidateCalls, 2); + }); + + it('fires pre validate hooks on 5 level deep single nested subdoc when modifying after save() (gh-14591)', async function() { + let preValidate = []; + + const createSchema = (path, subSchema) => { + const schema = new Schema({ [path]: subSchema }); + schema.pre('validate', function() { + preValidate.push(path); + }); + return schema; + }; + + const e = createSchema('e', { type: String }); + const d = createSchema('d', { type: e }); + const c = createSchema('c', { type: d }); + const b = createSchema('b', { type: c }); + const a = createSchema('a', { type: b }); + b.add({ otherProp: String }); + const NestedModelHooksTestModel = db.model('Test', a); + + const newData = { a: { b: { c: { d: { e: new Date().toString() } } } } }; + newData.a.otherProp = 'test'; + const doc = await new NestedModelHooksTestModel(newData).save(); + preValidate = []; + doc.set({ 'a.b.c.d.e': 'updated nested value' }); + await doc.save(); + assert.deepStrictEqual(preValidate, ['a', 'b', 'c', 'd', 'e']); + + const fromDb = await NestedModelHooksTestModel.findById(doc._id); + assert.strictEqual(fromDb.a.otherProp, 'test'); }); it('returns constructor if using $model() with no args (gh-13878)', async function() {