Refactored inclusion

The syntax is now consistent, regardless of using [] or {} for the
include param.
This commit is contained in:
Fabien Franzen 2014-10-10 14:24:25 +02:00
parent ca0b3399c8
commit 0c28ccedac
3 changed files with 71 additions and 11 deletions

View File

@ -803,19 +803,19 @@ DataAccessObject.find = function find(query, cb) {
// This handles the case to return parent items including the related
// models. For example, Article.find({include: 'tags'}, ...);
// Try to normalize the include
var includes = query.include || [];
if (typeof includes === 'string') {
includes = [includes];
} else if (!Array.isArray(includes) && typeof includes === 'object') {
includes = Object.keys(includes);
}
var includes = Inclusion.normalizeInclude(query.include || []);
includes.forEach(function (inc) {
var relationName = inc;
if (utils.isPlainObject(inc)) {
relationName = Object.keys(inc)[0];
}
// Promote the included model as a direct property
var data = obj.__cachedRelations[inc];
var data = obj.__cachedRelations[relationName];
if(Array.isArray(data)) {
data = new List(data, null, obj);
}
obj.__data[inc] = data;
if (data) obj.__data[relationName] = data;
});
delete obj.__data.__cachedRelations;
}

View File

@ -63,6 +63,13 @@ module.exports = Inclusion;
function Inclusion() {
}
/**
* Normalize includes - used in DataAccessObject
*
*/
Inclusion.normalizeInclude = normalizeInclude;
/**
* Enables you to load relations of several objects and optimize numbers of requests.
*
@ -98,7 +105,7 @@ Inclusion.include = function (objects, include, cb) {
}
include = normalizeInclude(include);
async.each(include, function(item, callback) {
processIncludeItem(objects, item, callback);
}, function(err) {
@ -107,9 +114,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) {
@ -122,8 +130,8 @@ Inclusion.include = function (objects, include, cb) {
relationName = include;
subInclude = null;
}
var relation = relations[relationName];
var relation = relations[relationName];
if (!relation) {
cb(new Error('Relation "' + relationName + '" is not defined for '
+ self.modelName + ' model'));
@ -183,6 +191,7 @@ Inclusion.include = function (objects, include, cb) {
if (err) {
return callback(err);
} else {
defineCachedRelations(obj);
obj.__cachedRelations[relationName] = result;

View File

@ -144,6 +144,57 @@ describe('include', function () {
done();
});
});
it('should fetch Users with include scope on Posts', function (done) {
User.find({
include: {relation: 'posts', scope:{
order: 'title DESC'
}}
}, function (err, users) {
should.not.exist(err);
should.exist(users);
users.length.should.equal(5);
users[0].name.should.equal('User A');
users[1].name.should.equal('User B');
var posts = users[0].posts();
posts.should.be.an.array;
posts.should.have.length(3);
posts[0].title.should.equal('Post C');
posts[1].title.should.equal('Post B');
posts[2].title.should.equal('Post A');
var posts = users[1].posts();
posts.should.be.an.array;
posts.should.have.length(1);
posts[0].title.should.equal('Post D');
done();
});
});
it('should fetch Users with include scope on Passports', function (done) {
User.find({
include: {relation: 'passports', scope:{
where: { number: '2' }
}}
}, function (err, users) {
should.not.exist(err);
should.exist(users);
users.length.should.equal(5);
users[0].name.should.equal('User A');
users[0].passports().should.be.empty;
users[1].name.should.equal('User B');
var passports = users[1].passports();
passports[0].number.should.equal('2');
done();
});
});
it('should fetch User - Posts AND Passports', function (done) {
User.find({include: ['posts', 'passports']}, function (err, users) {