diff --git a/lib/scope.js b/lib/scope.js index fbcd9c1a2..98c1ea3dc 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -431,11 +431,51 @@ function defineScope(cls, targetClass, name, params, methods, options) { options = {}; } options = options || {}; - + // If there is a through model + // run another query to apply filter on relatedModel(targetModel) + // see github.com/strongloop/loopback-datasource-juggler/issues/1795 + let scopeOnRelatedModel = false; + let queryRelated; + if (this._scope && this._scope.collect && + where !== null && typeof where === 'object') { + queryRelated = { + relation: this._scope.collect, + scope: { + where: where, + }, + }; + where = {}; + scopeOnRelatedModel = true; + } const targetModel = definition.targetModel(this._receiver); const scoped = (this._scope && this._scope.where) || {}; const filter = mergeQuery({where: scoped}, {where: where || {}}); - return targetModel.destroyAll(filter.where, options, cb); + if (!scopeOnRelatedModel) { + return targetModel.destroyAll(filter.where, options, cb); + } + return targetModel.find(filter, options, function(err, findData) { + const relatedModel = targetModel.relations[queryRelated.relation].modelTo; + const keyFrom = targetModel.relations[queryRelated.relation].keyFrom; + const IdKey = idName(relatedModel); + + // Merge queryRelated filter and targetId filter + const buildWhere = function() { + return { + and: [ + { + [IdKey]: collectTargetIds(findData, keyFrom || IdKey), + }, + queryRelated.scope.where], + }; + }; + if (queryRelated.scope.where !== undefined) { + queryRelated.scope.where = buildWhere(); + } else { + queryRelated.scope.where = {}; + queryRelated.scope.where[IdKey] = collectTargetIds(findData, keyFrom || IdKey); + } + return relatedModel.destroyAll(queryRelated.scope.where, options, cb); + }); } function updateAll(where, data, options, cb) { diff --git a/test/relations.test.js b/test/relations.test.js index d05d1b06e..2133d1d3c 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -702,6 +702,35 @@ describe('relations', function() { } }); + it('should destroyAll all scoped record with promises based on related model properties', function(done) { + let id; + Physician.create() + .then(function(physician) { + return physician.patients.create({name: 'a'}) + .then(function(ch) { + id = ch.id; + return physician.patients.create({name: 'z'}); + }) + .then(function() { + return physician.patients.create({name: 'c'}); + }) + .then(function() { + return verify(physician); + }); + }).catch(done); + + function verify(physician) { + return physician.patients.destroyAll({ + name: 'a', + }, function(err, result) { + if (err) return done(err); + should.exist(result); + result.count.should.equal(1); + done(); + }); + } + }); + it('should build record on scope', function(done) { Physician.create(function(err, physician) { const patient = physician.patients.build();