Skip to content

Commit

Permalink
added support for inclusion of compound documents at multiple depths
Browse files Browse the repository at this point in the history
  • Loading branch information
mjtodd committed Mar 6, 2014
1 parent 42641c9 commit 92c80f3
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 24 deletions.
81 changes: 58 additions & 23 deletions lib/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,32 +544,67 @@ function route(name, model, inflect) {
return adapter.findMany(model, ids);
}

function appendLinked(body, resources, schema, inclusions, req, res) {
var promises = [],
_this = this;
function getLinked(fetchedIds, resources, schema, key, req, res) {
var ids = linkedIds(resources, key);
if (ids.length > 0) {
var type = _.isArray(schema[key]) ? schema[key][0] : schema[key];
type = _.isPlainObject(type) ? type.ref : type;

inclusions = _.sortBy(inclusions, function(path) { return path.length; });
fetchedIds[type] = fetchedIds[type] || [];
ids = _.without(ids, fetchedIds[type]);
fetchedIds[type] = fetchedIds[type].concat(ids);

_.each(inclusions, function(path) {
return findResources.call(this,type,ids).then(function(resources) {
return RSVP.all(resources.map(function(resource) {
return afterTransform(inflect.singularize(type), resource, req, res);
})).then(function() {
return {type: inflect.pluralize(type), resources: resources};
});
});
}

var ids = linkedIds(resources, path);
if (ids.length > 0) {
var type = _.isArray(schema[path]) ? schema[path][0] : schema[path];
type = _.isPlainObject(type) ? type.ref : type;
promises.push(findResources.call(_this,type,ids).then(function(resources) {
body.linked = body.linked || {};
body.linked[inflect.pluralize(type)] = resources;
return RSVP.all(resources.map(function(resource) {
return afterTransform(inflect.singularize(type), resource, req, res);
}));
}));
}
});
var deferred = RSVP.defer();
deferred.resolve();
return deferred.promise;
}

return RSVP.all(promises)
.then(function() {
return body;
function appendLinked(body, resources, schema, inclusions, req, res) {
// build of tree of paths to fetch and maybe include
var includePaths = {},
_this = this;
_.each(inclusions, function(include) {
include = include.split('.');
var location = includePaths;
_.each(include, function(part) {
if (!location[part]) {
location[part] = {__includeInBody: false};
}
location = location[part];
});
location.__includeInBody = true;
});
var fetchedIds = {};
body.linked = {};

function fetchChildren(config, resources, schema, req, res) {
return RSVP.all(_.map(_.keys(config), function(key) {
if (key !== "__includeInBody") {
return getLinked.call(_this,fetchedIds, resources, schema, key, req, res)
.then(function(result) {
if (result) {
if (config[key].__includeInBody) {
body.linked[result.type] = body.linked[result.type] || [];
body.linked[result.type] = body.linked[result.type].concat(result.resources);
}
return fetchChildren(config[key], result.resources, _this._schema[inflect.singularize(result.type)], req, res);
}
});
}
}));
}
return fetchChildren(includePaths, resources, schema, req, res).then(function() {
return body;
});
}

/*
Expand All @@ -582,7 +617,6 @@ function route(name, model, inflect) {
function appendLinks(body, req, res) {
var schemas = this._schema,
_this = this;

var promises = [];

_.each(body, function(value, key) {
Expand All @@ -591,8 +625,9 @@ function route(name, model, inflect) {
, schema = schemas[modelName];
if (schema) {
addLinksToBody.call(_this, body, schema, key);
if (req.query.include)
if (req.query.include) {
promises.push(appendLinked.call(_this,body, body[key], schema, req.query.include.split(','), req, res));
}
}
});

Expand Down
80 changes: 79 additions & 1 deletion test/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ _.each(global.adapters, function(port, adapter) {
});
});

it("should return immediate child documents of people by default", function(done) {
it("should return immediate child documents of people when requested", function(done) {
new RSVP.Promise(function(resolve) {
request(baseUrl)
.put('/people/' + ids.people[0])
Expand Down Expand Up @@ -397,6 +397,84 @@ _.each(global.adapters, function(port, adapter) {
});
});
});

it("should return grandchild plus child documents of people when requested", function(done) {
new RSVP.Promise(function(resolve) {
request(baseUrl)
.put('/people/' + ids.people[1])
.send({people: [{
links: {
pets: [ids.pets[1]]
}
}]})
.expect('Content-Type', /json/)
.expect(200)
.end(function(error, response) {
should.not.exist(error);
var body = JSON.parse(response.text);
(body.people[0].links.pets).should.includeEql(ids.pets[1]);
resolve();
});
})
.then(function() {
request(baseUrl)
.get('/people/' + ids.people[0] + '?include=pets,soulmate,soulmate.pets')
.expect('Content-Type', /json/)
.expect(200)
.end(function(error, response) {
should.not.exist(error);
var body = JSON.parse(response.text);
body.linked.pets.length.should.equal(2);
body.linked.pets[0].id.should.equal(ids.pets[0]);
body.linked.pets[0].name.should.equal(fixtures.pets[0].name);
body.linked.pets[1].id.should.equal(ids.pets[1]);
body.linked.pets[1].name.should.equal(fixtures.pets[1].name);
body.linked.people.length.should.equal(1);
body.linked.people[0].name.should.equal(fixtures.people[1].name);
body.people[0].nickname.should.equal('Super ' + fixtures.people[0].name);
body.linked.people[0].nickname.should.equal('Super ' + fixtures.people[1].name);
done();
});
});
});

it("should return grandchild without child documents of people when requested", function(done) {
new RSVP.Promise(function(resolve) {
request(baseUrl)
.put('/people/' + ids.people[1])
.send({people: [{
links: {
pets: [ids.pets[1]]
}
}]})
.expect('Content-Type', /json/)
.expect(200)
.end(function(error, response) {
should.not.exist(error);
var body = JSON.parse(response.text);
(body.people[0].links.pets).should.includeEql(ids.pets[1]);
resolve();
});
})
.then(function() {
request(baseUrl)
.get('/people/' + ids.people[0] + '?include=pets,soulmate.pets')
.expect('Content-Type', /json/)
.expect(200)
.end(function(error, response) {
should.not.exist(error);
var body = JSON.parse(response.text);
body.linked.pets.length.should.equal(2);
body.linked.pets[0].id.should.equal(ids.pets[0]);
body.linked.pets[0].name.should.equal(fixtures.pets[0].name);
body.linked.pets[1].id.should.equal(ids.pets[1]);
body.linked.pets[1].name.should.equal(fixtures.pets[1].name);
should.not.exist(body.linked.people);
done();
});
});
});

});

after(function(done) {
Expand Down

0 comments on commit 92c80f3

Please sign in to comment.