Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 28 additions & 10 deletions lib/models/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' ||
Expand Down Expand Up @@ -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'}},
Expand All @@ -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'}},
Expand All @@ -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,
Expand All @@ -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'}},
Expand All @@ -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'}},
Expand All @@ -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'}},
Expand All @@ -446,27 +463,28 @@ 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}
});

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}
});

define('__delete__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + relationName},
http: {verb: 'delete', path: '/' + pathName},
description: 'Deletes all ' + relationName + ' of this model.'
});
}
Expand Down
25 changes: 23 additions & 2 deletions test/relations.integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
});
});
});
Expand All @@ -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);
});
});
});

Expand Down Expand Up @@ -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) {
Expand Down