From affa93a870c74e6e37645bdfbe610157162a3e58 Mon Sep 17 00:00:00 2001 From: regevbr Date: Sat, 30 Nov 2019 15:55:05 +0200 Subject: [PATCH] Fix #1795 - Count issue with related models using though model --- lib/scope.js | 43 +++++++++++++++++++++++++++++++++++++++++- test/relations.test.js | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/lib/scope.js b/lib/scope.js index 17a4b6429..fbcd9c1a2 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -452,10 +452,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.updateAll(filter.where, data, options, cb); + if (!scopeOnRelatedModel) { + return targetModel.updateAll(filter.where, data, 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.updateAll(queryRelated.scope.where, data, options, cb); + }); } function findById(id, filter, options, cb) { diff --git a/test/relations.test.js b/test/relations.test.js index 478325d16..d05d1b06e 100644 --- a/test/relations.test.js +++ b/test/relations.test.js @@ -664,6 +664,44 @@ describe('relations', function() { } }); + it('should update 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.updateAll({ + name: 'a', + }, {age: 5}, function(err, result) { + if (err) return done(err); + should.exist(result); + result.count.should.equal(1); + physician.patients.findOne({ + where: { + name: 'a', + }, + }, function(err, patient) { + if (err) return done(err); + should.exist(patient); + patient.age.should.equal(5); + done(); + }); + }); + } + }); + it('should build record on scope', function(done) { Physician.create(function(err, physician) { const patient = physician.patients.build();