Skip to content

Commit

Permalink
fix(document): handle virtuals that are stored as objects but getter …
Browse files Browse the repository at this point in the history
…returns string with toJSON

Fix #14446
  • Loading branch information
vkarpov15 committed Mar 26, 2024
1 parent 759f0d4 commit 69a0581
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
7 changes: 6 additions & 1 deletion lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -4113,7 +4113,12 @@ function applyGetters(self, json, options) {
for (let ii = 0; ii < plen; ++ii) {
part = parts[ii];
v = cur[part];
if (ii === last) {
// If we've reached a non-object part of the branch, continuing would
// cause "Cannot create property 'foo' on string 'bar'" error.
// Necessary for mongoose-intl plugin re: gh-14446
if (branch != null && typeof branch !== 'object') {
break;
} else if (ii === last) {
const val = self.$get(path);
branch[part] = clone(val, options);
} else if (v == null) {
Expand Down
32 changes: 32 additions & 0 deletions test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12538,6 +12538,38 @@ describe('document', function() {
assert.equal(purchaseFromDbCart.products[0].product.name, 'Bug');
assert.equal(purchaseFromDbCart.singleProduct.name, 'Bug');
});

it('handles virtuals that are stored as objects but getter returns string with toJSON (gh-14446)', async function() {
const childSchema = new mongoose.Schema();

childSchema.virtual('name')
.set(function(values) {
for (const [lang, val] of Object.entries(values)) {
this.set(`name.${lang}`, val);
}
})
.get(function() {
return this.$__getValue(`name.${this.lang}`);
});

childSchema.add({ name: { en: { type: String }, de: { type: String } } });

const ChildModel = db.model('Child', childSchema);
const ParentModel = db.model('Parent', new mongoose.Schema({
children: [childSchema]
}));

const child = await ChildModel.create({ name: { en: 'Stephen', de: 'Stefan' } });
child.lang = 'en';
assert.equal(child.name, 'Stephen');

const parent = await ParentModel.create({
children: [{ name: { en: 'Stephen', de: 'Stefan' } }]
});
parent.children[0].lang = 'de';
const obj = parent.toJSON({ getters: true });
assert.equal(obj.children[0].name, 'Stefan');
});
});

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

0 comments on commit 69a0581

Please sign in to comment.