diff --git a/lib/persisted-model.js b/lib/persisted-model.js index 9f4fe37b..be1b2549 100644 --- a/lib/persisted-model.js +++ b/lib/persisted-model.js @@ -142,15 +142,20 @@ module.exports = function(registry) { }; /** - * Find object by ID. + * Find object by ID with an optional filter for include/fields. * * @param {*} id Primary key value + * @options {Object} [filter] Optional Filter JSON object; see below. + * @property {String|Object|Array} fields Identify fields to include in return result. + *
See [Fields filter](http://docs.strongloop.com/display/LB/Fields+filter). + * @property {String|Object|Array} include See PersistedModel.include documentation. + *
See [Include filter](http://docs.strongloop.com/display/LB/Include+filter). * @callback {Function} callback Callback function called with `(err, instance)` arguments. Required. * @param {Error} err Error object; see [Error object](http://docs.strongloop.com/display/LB/Error+object). * @param {Object} instance Model instance matching the specified ID or null if no instance matches. */ - PersistedModel.findById = function find(id, cb) { + PersistedModel.findById = function find(id, filter, cb) { throwNotAttached(this.modelName, 'findById'); }; @@ -180,7 +185,7 @@ module.exports = function(registry) { * @param {Array} models Model instances matching the filter, or null if none found. */ - PersistedModel.find = function find(params, cb) { + PersistedModel.find = function find(filter, cb) { throwNotAttached(this.modelName, 'find'); }; @@ -209,7 +214,7 @@ module.exports = function(registry) { * @param {Array} model First model instance that matches the filter or null if none found. */ - PersistedModel.findOne = function findOne(params, cb) { + PersistedModel.findOne = function findOne(filter, cb) { throwNotAttached(this.modelName, 'findOne'); }; @@ -573,10 +578,12 @@ module.exports = function(registry) { setRemoting(PersistedModel, 'findById', { description: 'Find a model instance by id from the data source.', accessType: 'READ', - accepts: { - arg: 'id', type: 'any', description: 'Model id', required: true, - http: {source: 'path'} - }, + accepts: [ + { arg: 'id', type: 'any', description: 'Model id', required: true, + http: {source: 'path'}}, + { arg: 'filter', type: 'object', + description: 'Filter defining fields and include'} + ], returns: {arg: 'data', type: typeName, root: true}, http: {verb: 'get', path: '/:id'}, rest: {after: convertNullToNotFoundError} @@ -585,7 +592,7 @@ module.exports = function(registry) { setRemoting(PersistedModel, 'find', { description: 'Find all instances of the model matched by filter from the data source.', accessType: 'READ', - accepts: {arg: 'filter', type: 'object', description: 'Filter defining fields, where, order, offset, and limit'}, + accepts: {arg: 'filter', type: 'object', description: 'Filter defining fields, where, include, order, offset, and limit'}, returns: {arg: 'data', type: [typeName], root: true}, http: {verb: 'get', path: '/'} }); @@ -593,7 +600,7 @@ module.exports = function(registry) { setRemoting(PersistedModel, 'findOne', { description: 'Find first instance of the model matched by filter from the data source.', accessType: 'READ', - accepts: {arg: 'filter', type: 'object', description: 'Filter defining fields, where, order, offset, and limit'}, + accepts: {arg: 'filter', type: 'object', description: 'Filter defining fields, where, include, order, offset, and limit'}, returns: {arg: 'data', type: typeName, root: true}, http: {verb: 'get', path: '/findOne'}, rest: {after: convertNullToNotFoundError} diff --git a/test/model.test.js b/test/model.test.js index 7b037adb..abe4f1d5 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -66,7 +66,7 @@ describe('Model / PersistedModel', function() { describe.onServer('Remote Methods', function() { - var User; + var User, Post; var dataSource; var app; @@ -84,11 +84,22 @@ describe.onServer('Remote Methods', function() { trackChanges: true }); + Post = PersistedModel.extend('post', { + id: { id: true, type: String, defaultFn: 'guid' }, + title: String, + content: String + }, { + trackChanges: true + }); + dataSource = loopback.createDataSource({ connector: loopback.Memory }); User.attachTo(dataSource); + Post.attachTo(dataSource); + + User.hasMany(Post); User.login = function(username, password, fn) { if (username === 'foo' && password === 'bar') { @@ -163,6 +174,63 @@ describe.onServer('Remote Methods', function() { done(); }); }); + + it('Call the findById with filter.fields using HTTP / REST', function(done) { + request(app) + .post('/users') + .send({first: 'x', last: 'y'}) + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + if (err) return done(err); + var userId = res.body.id; + assert(userId); + request(app) + .get('/users/' + userId + '?filter[fields]=first') + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + if (err) return done(err); + assert.equal(res.body.first, 'x', 'first should be x'); + assert(res.body.last === undefined, 'last should not be present'); + done(); + }); + }); + }); + + it('Call the findById with filter.include using HTTP / REST', function(done) { + request(app) + .post('/users') + .send({first: 'x', last: 'y'}) + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + if (err) return done(err); + var userId = res.body.id; + assert(userId); + request(app) + .post('/users/' + userId + '/posts') + .send({title: 'T1', content: 'C1'}) + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + if (err) return done(err); + var post = res.body; + request(app) + .get('/users/' + userId + '?filter[include]=posts') + .expect('Content-Type', /json/) + .expect(200) + .end(function(err, res) { + if (err) return done(err); + assert.equal(res.body.first, 'x', 'first should be x'); + assert.equal(res.body.last, 'y', 'last should be y'); + assert.deepEqual(post, res.body.posts[0]); + done(); + }); + }); + }); + }); + }); describe('Model.beforeRemote(name, fn)', function() { diff --git a/test/remoting.integration.js b/test/remoting.integration.js index 76840f69..59a553af 100644 --- a/test/remoting.integration.js +++ b/test/remoting.integration.js @@ -114,7 +114,7 @@ describe('remoting - integration', function() { 'create(data:object):store POST /stores', 'upsert(data:object):store PUT /stores', 'exists(id:any):boolean GET /stores/:id/exists', - 'findById(id:any):store GET /stores/:id', + 'findById(id:any,filter:object):store GET /stores/:id', 'find(filter:object):store GET /stores', 'findOne(filter:object):store GET /stores/findOne', 'updateAll(where:object,data:object) POST /stores/update',