From 66fe60e6cae6bb69b11c0727a4801c721604b074 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Fri, 1 Aug 2014 11:25:28 +0200 Subject: [PATCH 1/2] Allow custom relation path (http) - enable hasOne remoting access --- lib/models/model.js | 38 ++++++++++++++++++++++++++--------- test/relations.integration.js | 23 +++++++++++++++++++-- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/lib/models/model.js b/lib/models/model.js index 6f61d781..cafa8bd2 100644 --- a/lib/models/model.js +++ b/lib/models/model.js @@ -192,6 +192,8 @@ Model.setup = function () { var relation = relations[relationName]; if (relation.type === 'belongsTo') { ModelCtor.belongsToRemoting(relationName, relation, define) + } else if (relation.type === 'hasOne') { + ModelCtor.hasOneRemoting(relationName, relation, define) } else if ( relation.type === 'hasMany' || relation.type === 'embedsMany' || @@ -343,21 +345,36 @@ Model.remoteMethod = function(name, options) { Model.belongsToRemoting = function(relationName, relation, define) { var fn = this.prototype[relationName]; + var pathName = relation.options.path || relationName; define('__get__' + relationName, { isStatic: false, - http: {verb: 'get', path: '/' + relationName}, + http: {verb: 'get', path: '/' + pathName}, accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}}, description: 'Fetches belongsTo relation ' + relationName, returns: {arg: relationName, type: relation.modelTo.modelName, root: true} }, fn); } +Model.hasOneRemoting = function(relationName, relation, define) { + var fn = this.prototype[relationName]; + var pathName = relation.options.path || relationName; + define('__get__' + relationName, { + isStatic: false, + http: {verb: 'get', path: '/' + pathName}, + accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}}, + description: 'Fetches hasOne relation ' + relationName, + returns: {arg: relationName, type: relation.modelTo.modelName, root: true} + }, fn); +} + Model.hasManyRemoting = function (relationName, relation, define) { + var pathName = relation.options.path || relationName; var toModelName = relation.modelTo.modelName; + var findByIdFunc = this.prototype['__findById__' + relationName]; define('__findById__' + relationName, { isStatic: false, - http: {verb: 'get', path: '/' + relationName + '/:fk'}, + http: {verb: 'get', path: '/' + pathName + '/:fk'}, accepts: {arg: 'fk', type: 'any', description: 'Foreign key for ' + relationName, required: true, http: {source: 'path'}}, @@ -368,7 +385,7 @@ Model.hasManyRemoting = function (relationName, relation, define) { var destroyByIdFunc = this.prototype['__destroyById__' + relationName]; define('__destroyById__' + relationName, { isStatic: false, - http: {verb: 'delete', path: '/' + relationName + '/:fk'}, + http: {verb: 'delete', path: '/' + pathName + '/:fk'}, accepts: {arg: 'fk', type: 'any', description: 'Foreign key for ' + relationName, required: true, http: {source: 'path'}}, @@ -379,7 +396,7 @@ Model.hasManyRemoting = function (relationName, relation, define) { var updateByIdFunc = this.prototype['__updateById__' + relationName]; define('__updateById__' + relationName, { isStatic: false, - http: {verb: 'put', path: '/' + relationName + '/:fk'}, + http: {verb: 'put', path: '/' + pathName + '/:fk'}, accepts: [ {arg: 'fk', type: 'any', description: 'Foreign key for ' + relationName, required: true, @@ -396,7 +413,7 @@ Model.hasManyRemoting = function (relationName, relation, define) { var addFunc = this.prototype['__link__' + relationName]; define('__link__' + relationName, { isStatic: false, - http: {verb: 'put', path: '/' + relationName + '/rel/:fk'}, + http: {verb: 'put', path: '/' + pathName + '/rel/:fk'}, accepts: {arg: 'fk', type: 'any', description: 'Foreign key for ' + relationName, required: true, http: {source: 'path'}}, @@ -407,7 +424,7 @@ Model.hasManyRemoting = function (relationName, relation, define) { var removeFunc = this.prototype['__unlink__' + relationName]; define('__unlink__' + relationName, { isStatic: false, - http: {verb: 'delete', path: '/' + relationName + '/rel/:fk'}, + http: {verb: 'delete', path: '/' + pathName + '/rel/:fk'}, accepts: {arg: 'fk', type: 'any', description: 'Foreign key for ' + relationName, required: true, http: {source: 'path'}}, @@ -420,7 +437,7 @@ Model.hasManyRemoting = function (relationName, relation, define) { var existsFunc = this.prototype['__exists__' + relationName]; define('__exists__' + relationName, { isStatic: false, - http: {verb: 'head', path: '/' + relationName + '/rel/:fk'}, + http: {verb: 'head', path: '/' + pathName + '/rel/:fk'}, accepts: {arg: 'fk', type: 'any', description: 'Foreign key for ' + relationName, required: true, http: {source: 'path'}}, @@ -446,11 +463,12 @@ Model.hasManyRemoting = function (relationName, relation, define) { }; Model.scopeRemoting = function(relationName, relation, define) { + var pathName = relation.options.path || relationName; var toModelName = relation.modelTo.modelName; define('__get__' + relationName, { isStatic: false, - http: {verb: 'get', path: '/' + relationName}, + http: {verb: 'get', path: '/' + pathName}, accepts: {arg: 'filter', type: 'object'}, description: 'Queries ' + relationName + ' of ' + this.modelName + '.', returns: {arg: relationName, type: [toModelName], root: true} @@ -458,7 +476,7 @@ Model.scopeRemoting = function(relationName, relation, define) { define('__create__' + relationName, { isStatic: false, - http: {verb: 'post', path: '/' + relationName}, + http: {verb: 'post', path: '/' + pathName}, accepts: {arg: 'data', type: toModelName, http: {source: 'body'}}, description: 'Creates a new instance in ' + relationName + ' of this model.', returns: {arg: 'data', type: toModelName, root: true} @@ -466,7 +484,7 @@ Model.scopeRemoting = function(relationName, relation, define) { define('__delete__' + relationName, { isStatic: false, - http: {verb: 'delete', path: '/' + relationName}, + http: {verb: 'delete', path: '/' + pathName}, description: 'Deletes all ' + relationName + ' of this model.' }); } diff --git a/test/relations.integration.js b/test/relations.integration.js index 2c27cef9..2ac601f5 100644 --- a/test/relations.integration.js +++ b/test/relations.integration.js @@ -651,7 +651,13 @@ describe('relations - integration', function () { 'ingredient', { properties: { name: 'string' }, dataSource: 'db' } ); + var photo = app.model( + 'photo', + { properties: { name: 'string' }, dataSource: 'db' } + ); recipe.referencesMany(ingredient); + // contrived example for test: + recipe.hasOne(photo, { as: 'picture', options: { path: 'image' } }); }); before(function createRecipe(done) { @@ -664,7 +670,7 @@ describe('relations - integration', function () { name: 'Chocolate' }, function(err, ing) { test.ingredient1 = ing.id; - done(); + recipe.picture.create({ name: 'Photo 1' }, done); }); }); }); @@ -680,7 +686,9 @@ describe('relations - integration', function () { after(function(done) { var app = this.app; app.models.recipe.destroyAll(function() { - app.models.ingredient.destroyAll(done); + app.models.ingredient.destroyAll(function() { + app.models.photo.destroyAll(done); + }); }); }); @@ -902,6 +910,17 @@ describe('relations - integration', function () { }); }); + it('uses a custom relation path', function(done) { + var url = '/api/recipes/' + this.recipe.id + '/image'; + + this.get(url) + .expect(200, function(err, res) { + expect(err).to.not.exist; + expect(res.body.name).to.equal('Photo 1'); + done(); + }); + }); + // TODO - this.head is undefined // it.skip('checks if a referenced model exists - ok', function(done) { From 18c647a9bbfa9a9e5c2edc468e2310ca7aeb3528 Mon Sep 17 00:00:00 2001 From: Fabien Franzen Date: Tue, 5 Aug 2014 09:10:43 +0200 Subject: [PATCH 2/2] Changed options.path to options.http.path --- lib/models/model.js | 8 ++++---- test/relations.integration.js | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/models/model.js b/lib/models/model.js index cafa8bd2..7fad476b 100644 --- a/lib/models/model.js +++ b/lib/models/model.js @@ -345,7 +345,7 @@ Model.remoteMethod = function(name, options) { Model.belongsToRemoting = function(relationName, relation, define) { var fn = this.prototype[relationName]; - var pathName = relation.options.path || relationName; + var pathName = (relation.options.http && relation.options.http.path) || relationName; define('__get__' + relationName, { isStatic: false, http: {verb: 'get', path: '/' + pathName}, @@ -357,7 +357,7 @@ Model.belongsToRemoting = function(relationName, relation, define) { Model.hasOneRemoting = function(relationName, relation, define) { var fn = this.prototype[relationName]; - var pathName = relation.options.path || relationName; + var pathName = (relation.options.http && relation.options.http.path) || relationName; define('__get__' + relationName, { isStatic: false, http: {verb: 'get', path: '/' + pathName}, @@ -368,7 +368,7 @@ Model.hasOneRemoting = function(relationName, relation, define) { } Model.hasManyRemoting = function (relationName, relation, define) { - var pathName = relation.options.path || relationName; + var pathName = (relation.options.http && relation.options.http.path) || relationName; var toModelName = relation.modelTo.modelName; var findByIdFunc = this.prototype['__findById__' + relationName]; @@ -463,7 +463,7 @@ Model.hasManyRemoting = function (relationName, relation, define) { }; Model.scopeRemoting = function(relationName, relation, define) { - var pathName = relation.options.path || relationName; + var pathName = (relation.options.http && relation.options.http.path) || relationName; var toModelName = relation.modelTo.modelName; define('__get__' + relationName, { diff --git a/test/relations.integration.js b/test/relations.integration.js index 2ac601f5..ff7e36ff 100644 --- a/test/relations.integration.js +++ b/test/relations.integration.js @@ -657,7 +657,9 @@ describe('relations - integration', function () { ); recipe.referencesMany(ingredient); // contrived example for test: - recipe.hasOne(photo, { as: 'picture', options: { path: 'image' } }); + recipe.hasOne(photo, { as: 'picture', options: { + http: { path: 'image' } + } }); }); before(function createRecipe(done) {