Fix the target id resolution

This commit is contained in:
Raymond Feng 2015-05-13 16:10:07 -07:00
parent f9bd1544f9
commit b5b7bab096
1 changed files with 32 additions and 27 deletions

View File

@ -139,19 +139,19 @@ Inclusion.normalizeInclude = normalizeInclude;
* `User.include(users, ['posts', 'passports'], function() {});` * `User.include(users, ['posts', 'passports'], function() {});`
* *
* Load all passports owner (users), and all posts of each owner loaded: * Load all passports owner (users), and all posts of each owner loaded:
*```Passport.include(passports, {owner: 'posts'}, function() {}); *```Passport.include(passports, {owner: 'posts'}, function() {});
*``` Passport.include(passports, {owner: ['posts', 'passports']}); *``` Passport.include(passports, {owner: ['posts', 'passports']});
*``` Passport.include(passports, {owner: [{posts: 'images'}, 'passports']}); *``` Passport.include(passports, {owner: [{posts: 'images'}, 'passports']});
* *
* @param {Array} objects Array of instances * @param {Array} objects Array of instances
* @param {String|Object|Array} include Which relations to load. * @param {String|Object|Array} include Which relations to load.
* @param {Function} cb Callback called when relations are loaded * @param {Function} cb Callback called when relations are loaded
* *
*/ */
Inclusion.include = function (objects, include, cb) { Inclusion.include = function (objects, include, cb) {
debug('include', include); debug('include', include);
var self = this; var self = this;
if (!include || (Array.isArray(include) && include.length === 0) || if (!include || (Array.isArray(include) && include.length === 0) ||
(isPlainObject(include) && Object.keys(include).length === 0)) { (isPlainObject(include) && Object.keys(include).length === 0)) {
// The objects are empty // The objects are empty
@ -161,7 +161,7 @@ Inclusion.include = function (objects, include, cb) {
} }
include = normalizeInclude(include); include = normalizeInclude(include);
async.each(include, function(item, callback) { async.each(include, function(item, callback) {
processIncludeItem(objects, item, callback); processIncludeItem(objects, item, callback);
}, function(err) { }, function(err) {
@ -170,10 +170,10 @@ Inclusion.include = function (objects, include, cb) {
function processIncludeItem(objs, include, cb) { function processIncludeItem(objs, include, cb) {
var relations = self.relations; var relations = self.relations;
var relationName; var relationName;
var subInclude = null, scope = null; var subInclude = null, scope = null;
if (isPlainObject(include)) { if (isPlainObject(include)) {
relationName = Object.keys(include)[0]; relationName = Object.keys(include)[0];
if (include[relationName] instanceof IncludeScope) { if (include[relationName] instanceof IncludeScope) {
@ -191,7 +191,7 @@ Inclusion.include = function (objects, include, cb) {
relationName = include; relationName = include;
subInclude = null; subInclude = null;
} }
var relation = relations[relationName]; var relation = relations[relationName];
if (!relation) { if (!relation) {
cb(new Error('Relation "' + relationName + '" is not defined for ' cb(new Error('Relation "' + relationName + '" is not defined for '
@ -283,7 +283,6 @@ Inclusion.include = function (objects, include, cb) {
* @param callback * @param callback
*/ */
function includeHasManyThrough(callback) { function includeHasManyThrough(callback) {
var debug = require('debug')('loopback:include:includeHasManyThrough');
var sourceIds = []; var sourceIds = [];
//Map for Indexing objects by their id for faster retrieval //Map for Indexing objects by their id for faster retrieval
var objIdMap = {}; var objIdMap = {};
@ -317,7 +316,7 @@ Inclusion.include = function (objects, include, cb) {
/** /**
* 1st DB Call of 2 step process. Get through model objects first * 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 * Handle the results of Through model objects and fetch the modelTo items
* @param err * @param err
@ -362,8 +361,11 @@ Inclusion.include = function (objects, include, cb) {
/** /**
* 2nd DB Call of 2 step process. Get modelTo (target) objects * 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) { function targetsFetchHandler(err, targets) {
if (err) {
return callback(err);
}
var tasks = []; var tasks = [];
//simultaneously process subIncludes. Call it first as it is an async //simultaneously process subIncludes. Call it first as it is an async
//process. //process.
@ -396,7 +398,6 @@ Inclusion.include = function (objects, include, cb) {
* @param callback * @param callback
*/ */
function includeReferencesMany(callback) { function includeReferencesMany(callback) {
var debug = require('debug')('loopback:include:includeReferencesMany');
var allTargetIds = []; var allTargetIds = [];
//Map for Indexing objects by their id for faster retrieval //Map for Indexing objects by their id for faster retrieval
var targetObjsMap = {}; var targetObjsMap = {};
@ -406,6 +407,11 @@ Inclusion.include = function (objects, include, cb) {
// use modelFrom.keyFrom in where filter later // use modelFrom.keyFrom in where filter later
var targetIds = obj[relation.keyFrom]; var targetIds = obj[relation.keyFrom];
if (targetIds) { 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 //referencesMany has multiple targetIds per obj. We need to concat
// them into allTargetIds before DB Call // them into allTargetIds before DB Call
allTargetIds = allTargetIds.concat(targetIds); allTargetIds = allTargetIds.concat(targetIds);
@ -424,10 +430,11 @@ Inclusion.include = function (objects, include, cb) {
filter.where[relation.keyTo] = { filter.where[relation.keyTo] = {
inq: allTargetIds inq: allTargetIds
}; };
/** /**
* Make the DB Call, fetch all target objects * Make the DB Call, fetch all target objects
*/ */
relation.modelTo.all(filter, targetFetchHandler); relation.modelTo.find(filter, targetFetchHandler);
/** /**
* Handle the fetched target objects * Handle the fetched target objects
* @param err * @param err
@ -468,7 +475,6 @@ Inclusion.include = function (objects, include, cb) {
* @param callback * @param callback
*/ */
function includeHasMany(callback) { function includeHasMany(callback) {
var debug = require('debug')('loopback:include:includeHasMany');
var sourceIds = []; var sourceIds = [];
//Map for Indexing objects by their id for faster retrieval //Map for Indexing objects by their id for faster retrieval
var objIdMap = {}; var objIdMap = {};
@ -488,7 +494,7 @@ Inclusion.include = function (objects, include, cb) {
filter.where[relation.keyTo] = { filter.where[relation.keyTo] = {
inq: sourceIds inq: sourceIds
}; };
relation.modelTo.all(filter, targetFetchHandler); relation.modelTo.find(filter, targetFetchHandler);
/** /**
* Process fetched related objects * Process fetched related objects
* @param err * @param err
@ -526,7 +532,6 @@ Inclusion.include = function (objects, include, cb) {
* @param callback * @param callback
*/ */
function includePolymorphic(callback) { function includePolymorphic(callback) {
var debug = require('debug')('loopback:include:includePolymorphic');
var targetIdsByType = {}; var targetIdsByType = {};
//Map for Indexing objects by their type and targetId for faster retrieval //Map for Indexing objects by their type and targetId for faster retrieval
var targetObjMapByType = {}; var targetObjMapByType = {};
@ -562,6 +567,7 @@ Inclusion.include = function (objects, include, cb) {
function processPolymorphicType(modelType, callback) { function processPolymorphicType(modelType, callback) {
var typeFilter = {where: {}}; var typeFilter = {where: {}};
utils.mergeQuery(typeFilter, filter); utils.mergeQuery(typeFilter, filter);
var targetIds = targetIdsByType[modelType];
typeFilter.where[relation.keyTo] = { typeFilter.where[relation.keyTo] = {
inq: targetIds inq: targetIds
}; };
@ -573,7 +579,7 @@ Inclusion.include = function (objects, include, cb) {
' specified but no model exists with such name')); ' specified but no model exists with such name'));
return; return;
} }
Model.all(typeFilter, targetFetchHandler); Model.find(typeFilter, targetFetchHandler);
/** /**
* Process fetched related objects * Process fetched related objects
* @param err * @param err
@ -616,7 +622,6 @@ Inclusion.include = function (objects, include, cb) {
* @param callback * @param callback
*/ */
function includeOneToOne(callback) { function includeOneToOne(callback) {
var debug = require('debug')('loopback:include:includeOneToOne');
var targetIds = []; var targetIds = [];
var objTargetIdMap = {}; var objTargetIdMap = {};
for (var i = 0; i < objs.length; i++) { for (var i = 0; i < objs.length; i++) {
@ -642,7 +647,7 @@ Inclusion.include = function (objects, include, cb) {
filter.where[relation.keyTo] = { filter.where[relation.keyTo] = {
inq: targetIds inq: targetIds
}; };
relation.modelTo.all(filter, targetFetchHandler); relation.modelTo.find(filter, targetFetchHandler);
/** /**
* Process fetched related objects * Process fetched related objects
* @param err * @param err
@ -741,11 +746,11 @@ Inclusion.include = function (objects, include, cb) {
//If related objects are not cached by include Handlers, directly call //If related objects are not cached by include Handlers, directly call
//related accessor function even though it is not very efficient //related accessor function even though it is not very efficient
var related; // relation accessor function var related; // relation accessor function
if ((relation.multiple || relation.type === 'belongsTo') && scope) { if ((relation.multiple || relation.type === 'belongsTo') && scope) {
var includeScope = {}; var includeScope = {};
var filter = scope.conditions(); var filter = scope.conditions();
// make sure not to miss any fields for sub includes // make sure not to miss any fields for sub includes
if (filter.fields && Array.isArray(subInclude) && relation.modelTo.relations) { if (filter.fields && Array.isArray(subInclude) && relation.modelTo.relations) {
includeScope.fields = []; includeScope.fields = [];
@ -756,22 +761,22 @@ Inclusion.include = function (objects, include, cb) {
} }
}); });
} }
utils.mergeQuery(filter, includeScope, {fields: false}); utils.mergeQuery(filter, includeScope, {fields: false});
related = inst[relationName].bind(inst, filter); related = inst[relationName].bind(inst, filter);
} else { } else {
related = inst[relationName].bind(inst); related = inst[relationName].bind(inst);
} }
related(function (err, result) { related(function (err, result) {
if (err) { if (err) {
return callback(err); return callback(err);
} else { } else {
defineCachedRelations(obj); defineCachedRelations(obj);
obj.__cachedRelations[relationName] = result; obj.__cachedRelations[relationName] = result;
return setIncludeData(result, callback); return setIncludeData(result, callback);
} }
}); });