From d40f610d7076e8c165e88fabc4a87366d05dd43b Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Thu, 17 Aug 2023 17:59:07 -0400 Subject: [PATCH 1/4] write test, difficult bug --- index.js | 2 - test/bugs.test.js | 117 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 65ecec5..cde5723 100644 --- a/index.js +++ b/index.js @@ -52,7 +52,6 @@ module.exports = function autopopulatePlugin(schema, options) { const newOptions = { _depth: depth + 1 }; if (options.maxDepth) newOptions.maxDepth = options.maxDepth; Object.assign(pathsToPopulate[i].options.options, newOptions); - const optionsToUse = processOption.call(this, pathsToPopulate[i].autopopulate, pathsToPopulate[i].options); if (optionsToUse) { @@ -65,7 +64,6 @@ module.exports = function autopopulatePlugin(schema, options) { } } } - return finalPaths; }; diff --git a/test/bugs.test.js b/test/bugs.test.js index eea4434..a22ccdb 100644 --- a/test/bugs.test.js +++ b/test/bugs.test.js @@ -360,4 +360,121 @@ describe('bug fixes', function() { section = await Section.findById(section); assert.equal(section.subdoc.subSection.name, 'foo'); }); + it('supports the `refPath` option (gh-96)', async function() { + const AddressSchema = new Schema( + { + name: { + type: String + }, + status: { + type: String, + enum: ["active", "inactive"], + default: "active" + } + }, + { + timestamps: true, + toJSON: { virtuals: true }, + toObject: { virtuals: true } + } + ); + + AddressSchema.virtual("residentials", { + ref: "Citizen", + localField: "_id", + foreignField: "permanentAddress.address", + justOne: false, + autopopulate: true, + match: { + status: "active" + }, + options: { + select: + "name nId" + } + }); + + AddressSchema.plugin(autopopulate); + + + const CitizenSchema = new Schema( + { + nId: { + type: String, + required: [true, "Please add national ID card"] + }, + name: { + type: String, + required: [true, "Please add a name"], + trim: true + }, + permanentAddress: { + name: { + type: String, + trim: true + }, + address: { + type: mongoose.Schema.ObjectId, + ref: "Address" + }, + }, + father: { + type: mongoose.Schema.ObjectId, + refPath: "fatherType", + autopopulate: true + }, + fatherType: { + type: String, + enum: ["Citizen", "Guest"], + required: true + }, + status: { + type: String, + enum: ["active", "inactive"], + default: "active" + } + }, + { + timestamps: true, + toJSON: { virtuals: true }, + toObject: { virtuals: true } + } + ); + + CitizenSchema.plugin(autopopulate); + + + const Address = db.model('Address', AddressSchema); + + const Citizen = db.model('Citizen', CitizenSchema); + const entry = await Address.create({ + name: "Another name for The Address", + status: "active" + }); + + const doc = await Citizen.create({ + nId: 'Hello', + name: 'There', + permanentAddress: { + name: 'The Address', + address: entry._id + }, + fatherType: "Guest" + }); + await Citizen.create({ + nId: 'Yo', + name: 'Test', + permanentAddress: { + name: "The Address", + address: entry._id + }, + father: doc._id, + fatherType: "Citizen", + status: "active" + }); + + const addr = await Address.findOne(); + const testDoc = addr.residentials.find(x => x.father != null); + assert.equal(testDoc.father.fatherType, 'Guest'); // property doesn't matter, just need to ensure its being populated + }); }); From 8d62dea4e9fcd33df96176c05c4cf560043ed760 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 18 Aug 2023 14:23:14 -0400 Subject: [PATCH 2/4] better understanding --- index.js | 3 - test/bugs.test.js | 189 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 155 insertions(+), 37 deletions(-) diff --git a/index.js b/index.js index cde5723..cae440e 100644 --- a/index.js +++ b/index.js @@ -36,7 +36,6 @@ module.exports = function autopopulatePlugin(schema, options) { } const depth = options._depth != null ? options._depth : 0; - if (options.maxDepth > 0 && depth >= options.maxDepth) { return; } @@ -48,7 +47,6 @@ module.exports = function autopopulatePlugin(schema, options) { continue; } pathsToPopulate[i].options.options = pathsToPopulate[i].options.options || {}; - const newOptions = { _depth: depth + 1 }; if (options.maxDepth) newOptions.maxDepth = options.maxDepth; Object.assign(pathsToPopulate[i].options.options, newOptions); @@ -176,7 +174,6 @@ function getPathsToPopulate(schema) { }); } }, null, schemaStack); - return pathsToPopulate; } diff --git a/test/bugs.test.js b/test/bugs.test.js index a22ccdb..10ec4d8 100644 --- a/test/bugs.test.js +++ b/test/bugs.test.js @@ -16,6 +16,10 @@ describe('bug fixes', function() { await db.close(); }); + afterEach(function() { + db.deleteModel(/.+/); + }); + beforeEach(function() { const promises = []; for (const modelName of Object.keys(db.models)) { @@ -368,8 +372,8 @@ describe('bug fixes', function() { }, status: { type: String, - enum: ["active", "inactive"], - default: "active" + enum: ['active', 'inactive'], + default: 'active' } }, { @@ -378,34 +382,34 @@ describe('bug fixes', function() { toObject: { virtuals: true } } ); - - AddressSchema.virtual("residentials", { - ref: "Citizen", - localField: "_id", - foreignField: "permanentAddress.address", + + AddressSchema.virtual('residentials', { + ref: 'Citizen', + localField: '_id', + foreignField: 'permanentAddress.address', justOne: false, autopopulate: true, match: { - status: "active" + status: 'active' }, options: { select: - "name nId" + 'name nId' } }); - + AddressSchema.plugin(autopopulate); - - + + const CitizenSchema = new Schema( { nId: { type: String, - required: [true, "Please add national ID card"] + required: [true, 'Please add national ID card'] }, name: { type: String, - required: [true, "Please add a name"], + required: [true, 'Please add a name'], trim: true }, permanentAddress: { @@ -415,23 +419,23 @@ describe('bug fixes', function() { }, address: { type: mongoose.Schema.ObjectId, - ref: "Address" - }, + ref: 'Address' + } }, father: { type: mongoose.Schema.ObjectId, - refPath: "fatherType", + refPath: 'fatherType', autopopulate: true }, fatherType: { type: String, - enum: ["Citizen", "Guest"], + enum: ['Citizen', 'Guest'], required: true }, status: { type: String, - enum: ["active", "inactive"], - default: "active" + enum: ['active', 'inactive'], + default: 'active' } }, { @@ -440,18 +444,20 @@ describe('bug fixes', function() { toObject: { virtuals: true } } ); - + CitizenSchema.plugin(autopopulate); - - + + const Address = db.model('Address', AddressSchema); - + const Citizen = db.model('Citizen', CitizenSchema); + await Address.deleteMany({}); + await Citizen.deleteMany({}); const entry = await Address.create({ - name: "Another name for The Address", - status: "active" + name: 'Another name for The Address', + status: 'active' }); - + const doc = await Citizen.create({ nId: 'Hello', name: 'There', @@ -459,22 +465,137 @@ describe('bug fixes', function() { name: 'The Address', address: entry._id }, - fatherType: "Guest" + fatherType: 'Guest' }); await Citizen.create({ nId: 'Yo', name: 'Test', permanentAddress: { - name: "The Address", + name: 'The Address', address: entry._id }, father: doc._id, - fatherType: "Citizen", - status: "active" + fatherType: 'Citizen', + status: 'active' + }); + const citizen = await Citizen.find(); + const testDoc = citizen.find(x => x.father != null); + assert.equal(testDoc.father.fatherType, 'Guest'); + }); + it('`refPath` works without autopopulate on the virtual (gh-96)', async function() { + const AddressSchema = new Schema( + { + name: { + type: String + }, + status: { + type: String, + enum: ['active', 'inactive'], + default: 'active' + } + }, + { + timestamps: true, + toJSON: { virtuals: true }, + toObject: { virtuals: true } + } + ); + + AddressSchema.virtual('residentials', { + ref: 'Citizen', + localField: '_id', + foreignField: 'permanentAddress.address', + justOne: false, + autopopulate: true, + match: { + status: 'active' + }, + options: { + select: + 'name nId' + } + }); + + AddressSchema.plugin(autopopulate); + + + const CitizenSchema = new Schema( + { + nId: { + type: String, + required: [true, 'Please add national ID card'] + }, + name: { + type: String, + required: [true, 'Please add a name'], + trim: true + }, + permanentAddress: { + name: { + type: String, + trim: true + }, + address: { + type: mongoose.Schema.ObjectId, + ref: 'Address' + } + }, + father: { + type: mongoose.Schema.ObjectId, + refPath: 'fatherType' + }, + fatherType: { + type: String, + enum: ['Citizen', 'Guest'], + required: true + }, + status: { + type: String, + enum: ['active', 'inactive'], + default: 'active' + } + }, + { + timestamps: true, + toJSON: { virtuals: true }, + toObject: { virtuals: true } + } + ); + + CitizenSchema.plugin(autopopulate); + + + const Address = db.model('Address', AddressSchema); + + const Citizen = db.model('Citizen', CitizenSchema); + await Address.deleteMany({}); + await Citizen.deleteMany({}); + const entry = await Address.create({ + name: 'Another name for The Address', + status: 'active' }); - const addr = await Address.findOne(); - const testDoc = addr.residentials.find(x => x.father != null); - assert.equal(testDoc.father.fatherType, 'Guest'); // property doesn't matter, just need to ensure its being populated + const doc = await Citizen.create({ + nId: 'Hello', + name: 'There', + permanentAddress: { + name: 'The Address', + address: entry._id + }, + fatherType: 'Guest' + }); + await Citizen.create({ + nId: 'Yo', + name: 'Test', + permanentAddress: { + name: 'The Address', + address: entry._id + }, + father: doc._id, + fatherType: 'Citizen', + status: 'active' + }); + const addr = await Address.findOne().populate({ path: 'residentials', populate: { path: 'permanentAddress', populate: 'address'} }); + assert.notEqual(addr.residentials[0].permanentAddress.address.name, undefined); }); }); From 4d1a836babc7a29fa41174b609c4d3d4dc15fabc Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 18 Aug 2023 17:17:15 -0400 Subject: [PATCH 3/4] made requested fixes --- test/bugs.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/bugs.test.js b/test/bugs.test.js index 10ec4d8..dff360e 100644 --- a/test/bugs.test.js +++ b/test/bugs.test.js @@ -506,7 +506,6 @@ describe('bug fixes', function() { localField: '_id', foreignField: 'permanentAddress.address', justOne: false, - autopopulate: true, match: { status: 'active' }, @@ -595,7 +594,7 @@ describe('bug fixes', function() { fatherType: 'Citizen', status: 'active' }); - const addr = await Address.findOne().populate({ path: 'residentials', populate: { path: 'permanentAddress', populate: 'address'} }); + const addr = await Address.findOne().populate({ path: 'residentials', populate: { path: 'permanentAddress.address'} }); assert.notEqual(addr.residentials[0].permanentAddress.address.name, undefined); }); }); From 6189f94015bf25ac52471d0405bcfe3897fb5118 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 18 Aug 2023 17:18:25 -0400 Subject: [PATCH 4/4] fix lint --- test/bugs.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bugs.test.js b/test/bugs.test.js index dff360e..bdb92fc 100644 --- a/test/bugs.test.js +++ b/test/bugs.test.js @@ -594,7 +594,7 @@ describe('bug fixes', function() { fatherType: 'Citizen', status: 'active' }); - const addr = await Address.findOne().populate({ path: 'residentials', populate: { path: 'permanentAddress.address'} }); + const addr = await Address.findOne().populate({ path: 'residentials', populate: { path: 'permanentAddress.address' } }); assert.notEqual(addr.residentials[0].permanentAddress.address.name, undefined); }); });