Skip to content

Commit

Permalink
Contextify DAO and relation methods
Browse files Browse the repository at this point in the history
Modify remoting metadata of data-access methods in PersistedModel
and relation method in Model and add an "options" argument to "accepts"
list.
  • Loading branch information
bajtos committed Dec 22, 2016
1 parent a1a5fb9 commit 2e419f8
Show file tree
Hide file tree
Showing 6 changed files with 607 additions and 67 deletions.
162 changes: 127 additions & 35 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
'use strict';
var g = require('./globalize');
var assert = require('assert');
var debug = require('debug')('loopback:model');
var RemoteObjects = require('strong-remoting');
var SharedClass = require('strong-remoting').SharedClass;
var extend = require('util')._extend;
Expand Down Expand Up @@ -136,15 +137,29 @@ module.exports = function(registry) {
);

// support remoting prototype methods
ModelCtor.sharedCtor = function(data, id, fn) {
ModelCtor.sharedCtor = function(data, id, options, fn) {
var ModelCtor = this;

if (typeof data === 'function') {
var isRemoteInvocationWithOptions = typeof data !== 'object' &&
typeof id === 'object' &&
typeof options === 'function';
if (isRemoteInvocationWithOptions) {
// sharedCtor(id, options, fn)
fn = options;
options = id;
id = data;
data = null;
} else if (typeof data === 'function') {
// sharedCtor(fn)
fn = data;
data = null;
id = null;
options = null;
} else if (typeof id === 'function') {
// sharedCtor(data, fn)
// sharedCtor(id, fn)
fn = id;
options = null;

if (typeof data !== 'object') {
id = data;
Expand All @@ -161,7 +176,8 @@ module.exports = function(registry) {
} else if (data) {
fn(null, new ModelCtor(data));
} else if (id) {
ModelCtor.findById(id, function(err, model) {
var filter = {};
ModelCtor.findById(id, filter, options, function(err, model) {
if (err) {
fn(err);
} else if (model) {
Expand All @@ -183,6 +199,7 @@ module.exports = function(registry) {
{arg: 'id', type: 'any', required: true, http: {source: 'path'},
description: idDesc},
// {arg: 'instance', type: 'object', http: {source: 'body'}}
{arg: 'options', type: 'object', http: createOptionsViaModelMethod},
];

ModelCtor.sharedCtor.http = [
Expand Down Expand Up @@ -232,6 +249,14 @@ module.exports = function(registry) {
// resolve relation functions
sharedClass.resolve(function resolver(define) {
var relations = ModelCtor.relations || {};
var defineRaw = define;
define = function(name, options, fn) {
if (options.accepts) {
options = extend({}, options);
options.accepts = setupOptionsArgs(options.accepts);
}
defineRaw(name, options, fn);
};

// get the relations
for (var relationName in relations) {
Expand Down Expand Up @@ -439,7 +464,7 @@ module.exports = function(registry) {

return accepts.map(function(arg) {
if (arg.http && arg.http === 'optionsFromRequest') {
// deep clone to preserve the input value
// clone to preserve the input value
arg = extend({}, arg);
arg.http = createOptionsViaModelMethod;
}
Expand All @@ -454,6 +479,7 @@ module.exports = function(registry) {
return EMPTY_OPTIONS;
if (typeof ModelCtor.createOptionsFromRemotingContext !== 'function')
return EMPTY_OPTIONS;
debug('createOptionsFromRemotingContext for %s', ctx.method.stringName);
return ModelCtor.createOptionsFromRemotingContext(ctx);
}

Expand Down Expand Up @@ -494,7 +520,10 @@ module.exports = function(registry) {
define('__get__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName},
accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}},
accepts: [
{arg: 'refresh', type: 'boolean', http: {source: 'query'}},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
accessType: 'READ',
description: format('Fetches belongsTo relation %s.', relationName),
returns: {arg: relationName, type: modelName, root: true},
Expand All @@ -519,7 +548,10 @@ module.exports = function(registry) {
define('__get__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName},
accepts: {arg: 'refresh', type: 'boolean', http: {source: 'query'}},
accepts: [
{arg: 'refresh', type: 'boolean', http: {source: 'query'}},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Fetches hasOne relation %s.', relationName),
accessType: 'READ',
returns: {arg: relationName, type: relation.modelTo.modelName, root: true},
Expand All @@ -529,7 +561,13 @@ module.exports = function(registry) {
define('__create__' + relationName, {
isStatic: false,
http: {verb: 'post', path: '/' + pathName},
accepts: {arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
accepts: [
{
arg: 'data', type: 'object', model: toModelName,
http: {source: 'body'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Creates a new instance in %s of this model.', relationName),
accessType: 'WRITE',
returns: {arg: 'data', type: toModelName, root: true},
Expand All @@ -538,7 +576,13 @@ module.exports = function(registry) {
define('__update__' + relationName, {
isStatic: false,
http: {verb: 'put', path: '/' + pathName},
accepts: {arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
accepts: [
{
arg: 'data', type: 'object', model: toModelName,
http: {source: 'body'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Update %s of this model.', relationName),
accessType: 'WRITE',
returns: {arg: 'data', type: toModelName, root: true},
Expand All @@ -547,6 +591,9 @@ module.exports = function(registry) {
define('__destroy__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName},
accepts: [
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Deletes %s of this model.', relationName),
accessType: 'WRITE',
});
Expand All @@ -560,10 +607,15 @@ module.exports = function(registry) {
define('__findById__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName + '/:fk'},
accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'}},
accepts: [
{
arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Find a related item by id for %s.', relationName),
accessType: 'READ',
returns: {arg: 'result', type: toModelName, root: true},
Expand All @@ -574,10 +626,15 @@ module.exports = function(registry) {
define('__destroyById__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName + '/:fk'},
accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'}},
accepts: [
{
arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Delete a related item by id for %s.', relationName),
accessType: 'WRITE',
returns: [],
Expand All @@ -593,6 +650,7 @@ module.exports = function(registry) {
required: true,
http: {source: 'path'}},
{arg: 'data', type: 'object', model: toModelName, http: {source: 'body'}},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Update a related item by id for %s.', relationName),
accessType: 'WRITE',
Expand All @@ -618,7 +676,10 @@ module.exports = function(registry) {
accepts: [{arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'}}].concat(accepts),
http: {source: 'path'}},
].concat(accepts).concat([
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
]),
description: format('Add a related item by id for %s.', relationName),
accessType: 'WRITE',
returns: {arg: relationName, type: modelThrough.modelName, root: true},
Expand All @@ -628,10 +689,15 @@ module.exports = function(registry) {
define('__unlink__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName + '/rel/:fk'},
accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'}},
accepts: [
{
arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Remove the %s relation to an item by id.', relationName),
accessType: 'WRITE',
returns: [],
Expand All @@ -643,10 +709,15 @@ module.exports = function(registry) {
define('__exists__' + relationName, {
isStatic: false,
http: {verb: 'head', path: '/' + pathName + '/rel/:fk'},
accepts: {arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'}},
accepts: [
{
arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Check the existence of %s relation to an item by id.', relationName),
accessType: 'READ',
returns: {arg: 'exists', type: 'boolean', root: true},
Expand Down Expand Up @@ -689,7 +760,10 @@ module.exports = function(registry) {
define('__get__' + scopeName, {
isStatic: isStatic,
http: {verb: 'get', path: '/' + pathName},
accepts: {arg: 'filter', type: 'object'},
accepts: [
{arg: 'filter', type: 'object'},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Queries %s of %s.', scopeName, this.modelName),
accessType: 'READ',
returns: {arg: scopeName, type: [toModelName], root: true},
Expand All @@ -698,13 +772,16 @@ module.exports = function(registry) {
define('__create__' + scopeName, {
isStatic: isStatic,
http: {verb: 'post', path: '/' + pathName},
accepts: {
arg: 'data',
type: 'object',
allowArray: true,
model: toModelName,
http: {source: 'body'},
},
accepts: [
{
arg: 'data',
type: 'object',
allowArray: true,
model: toModelName,
http: {source: 'body'},
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Creates a new instance in %s of this model.', scopeName),
accessType: 'WRITE',
returns: {arg: 'data', type: toModelName, root: true},
Expand All @@ -713,15 +790,30 @@ module.exports = function(registry) {
define('__delete__' + scopeName, {
isStatic: isStatic,
http: {verb: 'delete', path: '/' + pathName},
accepts: [
{
arg: 'where', type: 'object',
// The "where" argument is not exposed in the REST API
// but we need to provide a value so that we can pass "options"
// as the third argument.
http: function(ctx) { return undefined; },
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Deletes all %s of this model.', scopeName),
accessType: 'WRITE',
});

define('__count__' + scopeName, {
isStatic: isStatic,
http: {verb: 'get', path: '/' + pathName + '/count'},
accepts: {arg: 'where', type: 'object',
description: 'Criteria to match model instances'},
accepts: [
{
arg: 'where', type: 'object',
description: 'Criteria to match model instances',
},
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
description: format('Counts %s of %s.', scopeName, this.modelName),
accessType: 'READ',
returns: {arg: 'count', type: 'number'},
Expand Down
Loading

0 comments on commit 2e419f8

Please sign in to comment.