Skip to content

Commit cefc3e6

Browse files
authored
Merge pull request #43 from DesignByOnyx/42-nested-discriminator-props
fix: allow nested schemas on discriminated models to work
2 parents 5f7065d + d88c67e commit cefc3e6

File tree

3 files changed

+69
-47
lines changed

3 files changed

+69
-47
lines changed

index.js

+13-29
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function applyGettersMiddleware(schema, options) {
3838
};
3939
}
4040

41-
function applyGetters(schema, res, path) {
41+
function applyGetters(schema, res) {
4242
if (res == null) {
4343
return;
4444
}
@@ -49,22 +49,11 @@ function applyGetters(schema, res, path) {
4949
if (Array.isArray(res)) {
5050
const len = res.length;
5151
for (let i = 0; i < len; ++i) {
52-
applyGettersToDoc.call(this, schema, res[i], this._fields, path);
52+
applyGettersToDoc.call(this, schema, res[i]);
5353
}
5454
} else {
55-
applyGettersToDoc.call(this, schema, res, this._fields, path);
55+
applyGettersToDoc.call(this, schema, res);
5656
}
57-
58-
for (let i = 0; i < schema.childSchemas.length; ++i) {
59-
const childPath = path ? path + '.' + schema.childSchemas[i].model.path : schema.childSchemas[i].model.path;
60-
const _schema = schema.childSchemas[i].schema;
61-
const doc = mpath.get(schema.childSchemas[i].model.path, res);
62-
if (doc == null) {
63-
continue;
64-
}
65-
applyGetters.call(this, _schema, doc, childPath);
66-
}
67-
6857
return res;
6958
} else {
7059
return res;
@@ -90,7 +79,7 @@ function getSchemaForDoc(schema, res) {
9079
return childSchema || schema;
9180
}
9281

93-
function applyGettersToDoc(schema, doc, fields, prefix) {
82+
function applyGettersToDoc(schema, doc) {
9483
if (doc == null) {
9584
return;
9685
}
@@ -102,32 +91,23 @@ function applyGettersToDoc(schema, doc, fields, prefix) {
10291
if (currentDoc == null) continue;
10392
// If it is a nested array, apply getters to each subdocument (otherwise it would attempt to apply getters to the array itself)
10493
if (Array.isArray(currentDoc)) {
105-
applyGettersToDoc.call(this, schema, currentDoc, fields, prefix);
94+
applyGettersToDoc.call(this, schema, currentDoc);
10695
continue;
10796
}
10897
const schemaForDoc = getSchemaForDoc(schema, currentDoc);
109-
applyGettersToDoc.call(this, schemaForDoc, currentDoc, fields, prefix);
98+
applyGettersToDoc.call(this, schemaForDoc, currentDoc);
11099
}
111100
return;
112101
}
113102

114103
const schemaForDoc = getSchemaForDoc(schema, doc);
115104

116105
schemaForDoc.eachPath((path, schematype) => {
117-
const pathWithPrefix = prefix ? prefix + '.' + path : path;
118-
if (this.selectedInclusively() &&
119-
fields &&
120-
fields[pathWithPrefix] == null &&
121-
!this.isPathSelectedInclusive(pathWithPrefix)) { // fields[pathWithPrefix] should return false
106+
if (!mpath.has(path, doc)) {
107+
// The path is not present (likely from projection)
122108
return;
123109
}
124-
if (this.selectedExclusively() &&
125-
fields &&
126-
fields[pathWithPrefix] != null &&
127-
!this.isPathSelectedInclusive(pathWithPrefix)) {
128-
return;
129-
}
130-
110+
131111
const pathExists = mpath.has(path, doc);
132112
if (pathExists) {
133113
const val = schematype.applyGetters(mpath.get(path, doc), doc, true);
@@ -139,10 +119,14 @@ function applyGettersToDoc(schema, doc, fields, prefix) {
139119
}),
140120
doc
141121
);
122+
} if (val && schematype.$isSingleNested) {
123+
applyGettersToDoc.call(this, schematype.schema, pathVal);
142124
} else {
143125
mpath.set(path, val, doc);
144126
}
145127
}
128+
129+
mpath.set(path, schematype.applyGetters(pathVal, doc, true), doc);
146130
});
147131
}
148132

package.json

+2-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"mongodb"
2222
],
2323
"dependencies": {
24+
"mongoose": "^8.5.1",
2425
"mpath": "0.9.x"
2526
},
2627
"engines": {
@@ -33,11 +34,7 @@
3334
"co": "4.6.0",
3435
"eslint": "5.16.0",
3536
"istanbul": "0.4.5",
36-
"mocha": "5.2.x",
37-
"mongoose": ">= 7.5.0"
38-
},
39-
"peerDependencies": {
40-
"mongoose": ">= 7.5.0"
37+
"mocha": "5.2.x"
4138
},
4239
"author": "Valeri Karpov <[email protected]>",
4340
"license": "Apache 2.0",

test/index.test.js

+54-13
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('mongoose-lean-getters', function() {
1313
after(() => mongoose.disconnect());
1414

1515
it('with different types', async function() {
16-
const schema = mongoose.Schema({
16+
const schema = new mongoose.Schema({
1717
name: {
1818
type: String,
1919
get: v => v != null ? v.toLowerCase() : v
@@ -62,7 +62,7 @@ describe('mongoose-lean-getters', function() {
6262
});
6363

6464
it('only calls getters once with find() (gh-1)', async function() {
65-
const schema = mongoose.Schema({
65+
const schema = new mongoose.Schema({
6666
name: {
6767
type: String,
6868
get: v => v + '123'
@@ -81,14 +81,14 @@ describe('mongoose-lean-getters', function() {
8181
});
8282

8383
it('avoids running getters on fields that are projected out (gh-9)', async function() {
84-
const childSchema = mongoose.Schema({
84+
const childSchema = new mongoose.Schema({
8585
name: {
8686
type: String,
8787
get: v => v + '456'
8888
}
8989
});
9090

91-
const schema = mongoose.Schema({
91+
const schema = new mongoose.Schema({
9292
name: {
9393
type: String,
9494
get: v => v + '123'
@@ -114,22 +114,22 @@ describe('mongoose-lean-getters', function() {
114114
});
115115

116116
it('should call nested getters', async function() {
117-
const subChildSchema = mongoose.Schema({
117+
const subChildSchema = new mongoose.Schema({
118118
name: {
119119
type: String,
120120
get: v => v + ' nested child'
121121
}
122122
});
123123

124-
const childSchema = mongoose.Schema({
124+
const childSchema = new mongoose.Schema({
125125
name: {
126126
type: String,
127127
get: v => v + ' child'
128128
},
129129
subChilren: [subChildSchema]
130130
});
131131

132-
const schema = mongoose.Schema({
132+
const schema = new mongoose.Schema({
133133
name: {
134134
type: String,
135135
get: v => v + ' root'
@@ -209,12 +209,13 @@ describe('mongoose-lean-getters', function() {
209209
});
210210

211211
it('should work with arrays gh-22', async function() {
212-
const schema = mongoose.Schema({
212+
const schema = new mongoose.Schema({
213213
name: {
214214
type: String
215215
},
216216
items: [{
217-
text: { type: String, default: null, get: v => v.slice(-6) }
217+
text: { type: String, default: null, get: v => v.slice(-6) },
218+
num: Number,
218219
}]
219220
});
220221

@@ -231,18 +232,21 @@ describe('mongoose-lean-getters', function() {
231232
}, {
232233
$push: {
233234
items: {
234-
text: 'Lorem ipsum dolor sit amet'
235+
text: 'Lorem ipsum dolor sit amet',
236+
num: 1234,
235237
}
236238
}
237-
}, { new: true, projection: 'name items'}).lean({ getters: true });
239+
}, { new: true, projection: 'name items.text'}).lean({ getters: true });
238240

239241
const success = await Test.findOneAndUpdate({
240242
name: 'Captain Jean-Luc Picard'
241243
}).lean({ getters: true });
242244

243245
await Test.deleteMany({});
244-
assert.equal(success.items[0].text, 't amet');
245-
assert.equal(res.items[0].text, 't amet');
246+
assert.equal(success.items[0].text, 't amet', 'Success text is wrong');
247+
assert.equal(success.items[0].num, 1234);
248+
assert.equal(res.items[0].text, 't amet', 'Projected result is wrong');
249+
assert.equal(res.items[0].num, undefined, 'num should be undefined');
246250
});
247251

248252
it('should call getters on schemas with discriminator', async function() {
@@ -401,6 +405,43 @@ describe('mongoose-lean-getters', function() {
401405
assert.strictEqual(doc.field, '1337');
402406
});
403407

408+
it('should call getters on nested schemas within discriminated models', async() => {
409+
const nestedSchema = new mongoose.Schema({
410+
num: {
411+
type: mongoose.Types.Decimal128,
412+
get: (val) => `${val}`
413+
}
414+
});
415+
416+
const rootSchema = new mongoose.Schema({
417+
// These properties are here as a control (these always worked as expected)
418+
rootProp: { type: nestedSchema },
419+
rootArray: { type: [nestedSchema] },
420+
});
421+
rootSchema.plugin(mongooseLeanGetters);
422+
423+
const discriminatedSchema = new mongoose.Schema({
424+
// These props on the discriminated schemas were not having getters called
425+
discriminatedProp: { type: nestedSchema },
426+
discriminatedArray: { type: [nestedSchema] },
427+
});
428+
429+
const RootModel = mongoose.model('Root', rootSchema);
430+
const DiscriminatedModel = RootModel.discriminator('Discriminated', discriminatedSchema);
431+
432+
const entry = await DiscriminatedModel.create({
433+
rootProp: { num: -0.1111111111111111111 },
434+
rootArray: [{ num: -0.1111111111111111111 }],
435+
discriminatedProp: { num: -0.222222222222222222 },
436+
discriminatedArray: [{ num: -0.333333333333333333 }],
437+
});
438+
439+
const found = await DiscriminatedModel.findById(entry._id).lean({ getters: true }).exec();
440+
assert.equal(typeof found.rootProp.num, 'string', 'Root prop is not a string');
441+
assert.equal(typeof found.rootArray[0].num, 'string', 'Root array is not a string');
442+
assert.equal(typeof found.discriminatedProp.num, 'string', 'Discriminated prop is not a string');
443+
assert.equal(typeof found.discriminatedArray[0].num, 'string', 'Discriminated array is not a string');
444+
});
404445
it('allows defaultLeanOptions to be set and overridden at call time (#33)', async() => {
405446
const testSchema = new mongoose.Schema({
406447
field: {

0 commit comments

Comments
 (0)