Skip to content

Commit

Permalink
Add new flag injectOptionsFromRemoteContext
Browse files Browse the repository at this point in the history
Hide the new "options" arguments behind a feature flag
injectOptionsFromRemoteContext that is disabled by default for backwards
compatibility.

Fix construction of sharedCtor remoting metadata to prevent the
situation when we are configuring remoting metadata after
strong-remoting has already picked up data from our parent (base) model.
  • Loading branch information
bajtos committed Jan 5, 2017
1 parent 693d52f commit 74bb1da
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 80 deletions.
105 changes: 58 additions & 47 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,9 @@ module.exports = function(registry) {
var options = this.settings;
var typeName = this.modelName;

var remotingOptions = {};
extend(remotingOptions, options.remoting || {});

// create a sharedClass
var sharedClass = ModelCtor.sharedClass = new SharedClass(
ModelCtor.modelName,
ModelCtor,
remotingOptions
);

// setup a remoting type converter for this model
RemoteObjects.convert(typeName, function(val) {
return val ? new ModelCtor(val) : val;
});

// support remoting prototype methods
// it's important to setup this function *before* calling `new SharedClass`
// otherwise remoting metadata from our base model is picked up
ModelCtor.sharedCtor = function(data, id, options, fn) {
var ModelCtor = this;

Expand Down Expand Up @@ -200,19 +187,34 @@ module.exports = function(registry) {
};

var idDesc = ModelCtor.modelName + ' id';
ModelCtor.sharedCtor.accepts = [
ModelCtor.sharedCtor.accepts = this._removeOptionsArgIfDisabled([
{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 = [
{path: '/:id'}
];

ModelCtor.sharedCtor.returns = {root: true};

var remotingOptions = {};
extend(remotingOptions, options.remoting || {});

// create a sharedClass
var sharedClass = ModelCtor.sharedClass = new SharedClass(
ModelCtor.modelName,
ModelCtor,
remotingOptions
);

// setup a remoting type converter for this model
RemoteObjects.convert(typeName, function(val) {
return val ? new ModelCtor(val) : val;
});

// before remote hook
ModelCtor.beforeRemote = function(name, fn) {
var className = this.modelName;
Expand Down Expand Up @@ -522,10 +524,10 @@ module.exports = function(registry) {
define('__get__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{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 @@ -550,10 +552,10 @@ module.exports = function(registry) {
define('__get__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{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 @@ -563,13 +565,13 @@ module.exports = function(registry) {
define('__create__' + relationName, {
isStatic: false,
http: {verb: 'post', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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 @@ -578,13 +580,13 @@ module.exports = function(registry) {
define('__update__' + relationName, {
isStatic: false,
http: {verb: 'put', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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 @@ -593,9 +595,9 @@ module.exports = function(registry) {
define('__destroy__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
],
]),
description: format('Deletes %s of this model.', relationName),
accessType: 'WRITE',
});
Expand All @@ -609,15 +611,15 @@ module.exports = function(registry) {
define('__findById__' + relationName, {
isStatic: false,
http: {verb: 'get', path: '/' + pathName + '/:fk'},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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 @@ -628,15 +630,15 @@ module.exports = function(registry) {
define('__destroyById__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName + '/:fk'},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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 @@ -646,14 +648,14 @@ module.exports = function(registry) {
define('__updateById__' + relationName, {
isStatic: false,
http: {verb: 'put', path: '/' + pathName + '/:fk'},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{arg: 'fk', type: 'any',
description: format('Foreign key for %s', relationName),
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',
returns: {arg: 'result', type: toModelName, root: true}
Expand All @@ -676,9 +678,9 @@ module.exports = function(registry) {
description: format('Foreign key for %s', relationName),
required: true,
http: {source: 'path'}},
].concat(accepts).concat([
].concat(accepts).concat(this._removeOptionsArgIfDisabled([
{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 @@ -688,15 +690,15 @@ module.exports = function(registry) {
define('__unlink__' + relationName, {
isStatic: false,
http: {verb: 'delete', path: '/' + pathName + '/rel/:fk'},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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 @@ -708,15 +710,15 @@ module.exports = function(registry) {
define('__exists__' + relationName, {
isStatic: false,
http: {verb: 'head', path: '/' + pathName + '/rel/:fk'},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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 @@ -759,10 +761,10 @@ module.exports = function(registry) {
define('__get__' + scopeName, {
isStatic: isStatic,
http: {verb: 'get', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{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 @@ -771,15 +773,15 @@ module.exports = function(registry) {
define('__create__' + scopeName, {
isStatic: isStatic,
http: {verb: 'post', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
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.', scopeName),
accessType: 'WRITE',
returns: {arg: 'data', type: toModelName, root: true}
Expand All @@ -788,7 +790,7 @@ module.exports = function(registry) {
define('__delete__' + scopeName, {
isStatic: isStatic,
http: {verb: 'delete', path: '/' + pathName},
accepts: [
accepts: this._removeOptionsArgIfDisabled([
{
arg: 'where', type: 'object',
// The "where" argument is not exposed in the REST API
Expand All @@ -797,28 +799,37 @@ module.exports = function(registry) {
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: [
accepts: this._removeOptionsArgIfDisabled([
{
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'}
});

};

Model._removeOptionsArgIfDisabled = function(accepts) {
if (this.settings.injectOptionsFromRemoteContext)
return accepts;
var lastArg = accepts[accepts.length - 1];
var hasOptions = lastArg.arg === 'options' && lastArg.type === 'object';
assert(hasOptions, 'last accepts argument is "options" arg');
return accepts.slice(0, -1);
};

/**
* Enabled deeply-nested queries of related models via REST API.
*
Expand Down
Loading

0 comments on commit 74bb1da

Please sign in to comment.