From b5b7bab0969294028f774fe4849114f5d97d4fef Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 13 May 2015 16:10:07 -0700 Subject: [PATCH] Fix the target id resolution --- lib/include.js | 59 +++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/lib/include.js b/lib/include.js index b1f43930..900d8e2c 100644 --- a/lib/include.js +++ b/lib/include.js @@ -139,19 +139,19 @@ Inclusion.normalizeInclude = normalizeInclude; * `User.include(users, ['posts', 'passports'], function() {});` * * Load all passports owner (users), and all posts of each owner loaded: - *```Passport.include(passports, {owner: 'posts'}, function() {}); - *``` Passport.include(passports, {owner: ['posts', 'passports']}); - *``` Passport.include(passports, {owner: [{posts: 'images'}, 'passports']}); + *```Passport.include(passports, {owner: 'posts'}, function() {}); + *``` Passport.include(passports, {owner: ['posts', 'passports']}); + *``` Passport.include(passports, {owner: [{posts: 'images'}, 'passports']}); * * @param {Array} objects Array of instances * @param {String|Object|Array} include Which relations to load. * @param {Function} cb Callback called when relations are loaded - * + * */ Inclusion.include = function (objects, include, cb) { debug('include', include); var self = this; - + if (!include || (Array.isArray(include) && include.length === 0) || (isPlainObject(include) && Object.keys(include).length === 0)) { // The objects are empty @@ -161,7 +161,7 @@ Inclusion.include = function (objects, include, cb) { } include = normalizeInclude(include); - + async.each(include, function(item, callback) { processIncludeItem(objects, item, callback); }, function(err) { @@ -170,10 +170,10 @@ Inclusion.include = function (objects, include, cb) { function processIncludeItem(objs, include, cb) { var relations = self.relations; - + var relationName; var subInclude = null, scope = null; - + if (isPlainObject(include)) { relationName = Object.keys(include)[0]; if (include[relationName] instanceof IncludeScope) { @@ -191,7 +191,7 @@ Inclusion.include = function (objects, include, cb) { relationName = include; subInclude = null; } - + var relation = relations[relationName]; if (!relation) { cb(new Error('Relation "' + relationName + '" is not defined for ' @@ -283,7 +283,6 @@ Inclusion.include = function (objects, include, cb) { * @param callback */ function includeHasManyThrough(callback) { - var debug = require('debug')('loopback:include:includeHasManyThrough'); var sourceIds = []; //Map for Indexing objects by their id for faster retrieval var objIdMap = {}; @@ -317,7 +316,7 @@ Inclusion.include = function (objects, include, cb) { /** * 1st DB Call of 2 step process. Get through model objects first */ - relation.modelThrough.all(throughFilter, throughFetchHandler); + relation.modelThrough.find(throughFilter, throughFetchHandler); /** * Handle the results of Through model objects and fetch the modelTo items * @param err @@ -362,8 +361,11 @@ Inclusion.include = function (objects, include, cb) { /** * 2nd DB Call of 2 step process. Get modelTo (target) objects */ - relation.modelTo.all(filter, targetsFetchHandler); + relation.modelTo.find(filter, targetsFetchHandler); function targetsFetchHandler(err, targets) { + if (err) { + return callback(err); + } var tasks = []; //simultaneously process subIncludes. Call it first as it is an async //process. @@ -396,7 +398,6 @@ Inclusion.include = function (objects, include, cb) { * @param callback */ function includeReferencesMany(callback) { - var debug = require('debug')('loopback:include:includeReferencesMany'); var allTargetIds = []; //Map for Indexing objects by their id for faster retrieval var targetObjsMap = {}; @@ -406,6 +407,11 @@ Inclusion.include = function (objects, include, cb) { // use modelFrom.keyFrom in where filter later var targetIds = obj[relation.keyFrom]; if (targetIds) { + if (typeof targetIds === 'string') { + // For relational DBs, the array is stored as stringified json + // Please note obj is a plain object at this point + targetIds = JSON.parse(targetIds); + } //referencesMany has multiple targetIds per obj. We need to concat // them into allTargetIds before DB Call allTargetIds = allTargetIds.concat(targetIds); @@ -424,10 +430,11 @@ Inclusion.include = function (objects, include, cb) { filter.where[relation.keyTo] = { inq: allTargetIds }; + /** * Make the DB Call, fetch all target objects */ - relation.modelTo.all(filter, targetFetchHandler); + relation.modelTo.find(filter, targetFetchHandler); /** * Handle the fetched target objects * @param err @@ -468,7 +475,6 @@ Inclusion.include = function (objects, include, cb) { * @param callback */ function includeHasMany(callback) { - var debug = require('debug')('loopback:include:includeHasMany'); var sourceIds = []; //Map for Indexing objects by their id for faster retrieval var objIdMap = {}; @@ -488,7 +494,7 @@ Inclusion.include = function (objects, include, cb) { filter.where[relation.keyTo] = { inq: sourceIds }; - relation.modelTo.all(filter, targetFetchHandler); + relation.modelTo.find(filter, targetFetchHandler); /** * Process fetched related objects * @param err @@ -526,7 +532,6 @@ Inclusion.include = function (objects, include, cb) { * @param callback */ function includePolymorphic(callback) { - var debug = require('debug')('loopback:include:includePolymorphic'); var targetIdsByType = {}; //Map for Indexing objects by their type and targetId for faster retrieval var targetObjMapByType = {}; @@ -562,6 +567,7 @@ Inclusion.include = function (objects, include, cb) { function processPolymorphicType(modelType, callback) { var typeFilter = {where: {}}; utils.mergeQuery(typeFilter, filter); + var targetIds = targetIdsByType[modelType]; typeFilter.where[relation.keyTo] = { inq: targetIds }; @@ -573,7 +579,7 @@ Inclusion.include = function (objects, include, cb) { ' specified but no model exists with such name')); return; } - Model.all(typeFilter, targetFetchHandler); + Model.find(typeFilter, targetFetchHandler); /** * Process fetched related objects * @param err @@ -616,7 +622,6 @@ Inclusion.include = function (objects, include, cb) { * @param callback */ function includeOneToOne(callback) { - var debug = require('debug')('loopback:include:includeOneToOne'); var targetIds = []; var objTargetIdMap = {}; for (var i = 0; i < objs.length; i++) { @@ -642,7 +647,7 @@ Inclusion.include = function (objects, include, cb) { filter.where[relation.keyTo] = { inq: targetIds }; - relation.modelTo.all(filter, targetFetchHandler); + relation.modelTo.find(filter, targetFetchHandler); /** * Process fetched related objects * @param err @@ -741,11 +746,11 @@ Inclusion.include = function (objects, include, cb) { //If related objects are not cached by include Handlers, directly call //related accessor function even though it is not very efficient var related; // relation accessor function - + if ((relation.multiple || relation.type === 'belongsTo') && scope) { var includeScope = {}; var filter = scope.conditions(); - + // make sure not to miss any fields for sub includes if (filter.fields && Array.isArray(subInclude) && relation.modelTo.relations) { includeScope.fields = []; @@ -756,22 +761,22 @@ Inclusion.include = function (objects, include, cb) { } }); } - + utils.mergeQuery(filter, includeScope, {fields: false}); - + related = inst[relationName].bind(inst, filter); } else { related = inst[relationName].bind(inst); } - + related(function (err, result) { if (err) { return callback(err); } else { - + defineCachedRelations(obj); obj.__cachedRelations[relationName] = result; - + return setIncludeData(result, callback); } });