Merge pull request #427 from fabien/feature/relation-paths

Allow custom relation path (http) - enable hasOne remoting access
This commit is contained in:
Raymond Feng 2014-08-07 10:32:13 -07:00
commit 0affc65c67
2 changed files with 51 additions and 12 deletions

View File

@ -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.http && relation.options.http.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.http && relation.options.http.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.http && relation.options.http.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.http && relation.options.http.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.'
});
}

View File

@ -651,7 +651,15 @@ 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: {
http: { path: 'image' }
} });
});
before(function createRecipe(done) {
@ -664,7 +672,7 @@ describe('relations - integration', function () {
name: 'Chocolate' },
function(err, ing) {
test.ingredient1 = ing.id;
done();
recipe.picture.create({ name: 'Photo 1' }, done);
});
});
});
@ -680,7 +688,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 +912,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) {