Skip to content

Commit

Permalink
Merge pull request #14801 from Automattic/vkarpov15/gh-14788
Browse files Browse the repository at this point in the history
fix(document): call required functions on subdocuments underneath nested paths with correct context
  • Loading branch information
vkarpov15 committed Aug 13, 2024
2 parents f98b463 + 1472719 commit 9742d5a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 10 deletions.
14 changes: 4 additions & 10 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -2770,15 +2770,6 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
}
}

for (const path of paths) {
// Single nested paths (paths embedded under single nested subdocs) will
// be validated on their own when we call `validate()` on the subdoc itself.
// Re: gh-8468
if (doc.$__schema.singleNestedPaths.hasOwnProperty(path)) {
paths.delete(path);
continue;
}
}

if (Array.isArray(pathsToValidate)) {
paths = _handlePathsToValidate(paths, pathsToValidate);
Expand All @@ -2800,7 +2791,10 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
_v = _v.toObject({ transform: false });
}
const flat = flatten(_v, pathToCheck, flattenOptions, doc.$__schema);
Object.keys(flat).forEach(addToPaths);
// Single nested paths (paths embedded under single nested subdocs) will
// be validated on their own when we call `validate()` on the subdoc itself.
// Re: gh-8468
Object.keys(flat).filter(path => !doc.$__schema.singleNestedPaths.hasOwnProperty(path)).forEach(addToPaths);
}
}

Expand Down
58 changes: 58 additions & 0 deletions test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13782,6 +13782,64 @@ describe('document', function() {
assert.strictEqual(doc.toObject().labPlots[0].lab.capacityLevelCeil, 4);
assert.strictEqual(doc.toJSON().labPlots[0].lab.capacityLevelCeil, 4);
});

it('calls required with correct context on single nested properties (gh-14788)', async function() {
const requiredCalls = [];
function createCustomSchema() {
return new mongoose.Schema({
prop1: {
type: String,
required() {
requiredCalls.push(this);
return this.prop1 === undefined;
},
validate: {
validator(prop1) {
if (this.prop2 !== null && prop1 != null) {
throw new Error('cannot use prop1 if prop2 is defined!');
}
return true;
}
}
},
prop2: {
type: String,
required() {
requiredCalls.push(this);
return this.prop2 === undefined;
},
validate: {
validator(prop2) {
if (this.prop1 === null && prop2 === null) {
throw new Error('cannot be null if prop1 is missing!');
}
return true;
}
}
}
}, { _id: false });
}

const schema = new mongoose.Schema({
config: {
prop: {
type: createCustomSchema(),
required: true
}
}
});

const TestModel = db.model('Test', schema);
const doc = new TestModel({
config: {
prop: { prop1: null, prop2: 'test-value' }
}
});
await doc.validate();
assert.equal(requiredCalls.length, 2);
assert.strictEqual(requiredCalls[0], doc.config.prop);
assert.strictEqual(requiredCalls[1], doc.config.prop);
});
});

describe('Check if instance function that is supplied in schema option is available', function() {
Expand Down

0 comments on commit 9742d5a

Please sign in to comment.