Skip to content
Closed
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
8 changes: 7 additions & 1 deletion common/models/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,13 @@
"permission": "ALLOW",
"property": "resetPassword",
"accessType": "EXECUTE"
}
},
{
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "replaceById"
}
],
"relations": {
"accessTokens": {
Expand Down
67 changes: 65 additions & 2 deletions lib/persisted-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ module.exports = function(registry) {
throwNotAttached(this.modelName, 'upsert');
};

/**
* Replace or insert a model instance
* @param {Object} data The model instance data to insert.
* @callback {Function} callback Callback function called with `cb(err, obj)` signature.
* @param {Error} err Error object; see [Error object](http://docs.strongloop.com/display/LB/Error+object).
* @param {Object} model Replaced model instance.
*/

PersistedModel.replaceOrCreate = function replaceOrCreate(data, cb) {
throwNotAttached(this.modelName, 'replaceOrCreate');
};

/**
* Finds one record matching the optional filter object. If not found, creates
* the object using the data provided as second argument. In this sense it is
Expand Down Expand Up @@ -482,6 +494,19 @@ module.exports = function(registry) {
throwNotAttached(this.modelName, 'updateAttributes');
};

/**
* Replace set of attributes. Performs validation before replacing.
*
* @param {Object} data Data to replace.
* @callback {Function} callback Callback function called with `(err, instance)` arguments. Required.
* @param {Error} err Error object; see [Error object](http://docs.strongloop.com/display/LB/Error+object).
* @param {Object} instance Repalced instance.
*/

PersistedModel.replaceById = function replaceById(data, cb) {
throwNotAttached(this.modelName, 'replaceById');
};

/**
* Reload object from persistence. Requires `id` member of `object` to be able to call `find`.
* @callback {Function} callback Callback function called with `(err, instance)` arguments. Required.
Expand Down Expand Up @@ -549,6 +574,21 @@ module.exports = function(registry) {
var PersistedModel = this;
var typeName = PersistedModel.modelName;
var options = PersistedModel.settings;
// This is the defualt verb used for 2.X
var configurableVerb = {
updateAttributes: 'put',
updateOrCreate: 'put',
replaceOrCreate: 'patch',
replaceById: 'patch',
};

// we check options.newMapping when backporting to `2.x`. Thought?
if (options.newMapping) {
configurableVerb.replaceById = 'put';
configurableVerb.replaceOrCreate = 'put';
configurableVerb.updateAttributes = 'patch';
configurableVerb.updateOrCreate = 'patch';
}

function setRemoting(scope, name, options) {
var fn = scope[name];
Expand All @@ -573,7 +613,16 @@ module.exports = function(registry) {
accepts: { arg: 'data', type: 'object', http: { source: 'body' }, description:
'Model instance data' },
returns: { arg: 'data', type: typeName, root: true },
http: { verb: 'put', path: '/' },
http: { verb: configurableVerb.updateOrCreate, path: '/' },
});

setRemoting(PersistedModel, 'replaceOrCreate', {
description: 'Replace an existing model instance or insert a new one into the data source.',
accessType: 'WRITE',
accepts: { arg: 'data', type: 'object', http: { source: 'body' }, description:
'Model instance data' },
returns: { arg: 'data', type: typeName, root: true },
http: { verb: configurableVerb.replaceOrCreate, path: '/' },
});

setRemoting(PersistedModel, 'exists', {
Expand Down Expand Up @@ -621,6 +670,20 @@ module.exports = function(registry) {
rest: { after: convertNullToNotFoundError },
});

setRemoting(PersistedModel, 'replaceById', {
description: 'Replace attributes for a model instance and persist it into the data source.',
accessType: 'WRITE',
accepts: [
{ arg: 'id', type: 'any', description: 'Model id', required: true,
http: { source: 'put' }},
{ arg: 'data', type: 'object', http: { source: 'body' }, description:
'An object of model property name/value pairs' },
],
returns: { arg: 'data', type: typeName, root: true },
http: { verb: configurableVerb.replaceById, path: '/:id' },
rest: { after: convertNullToNotFoundError },
});

setRemoting(PersistedModel, 'find', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
Expand Down Expand Up @@ -696,7 +759,7 @@ module.exports = function(registry) {
accessType: 'WRITE',
accepts: { arg: 'data', type: 'object', http: { source: 'body' }, description: 'An object of model property name/value pairs' },
returns: { arg: 'data', type: typeName, root: true },
http: { verb: 'put', path: '/' },
http: { verb: configurableVerb.updateAttributes, path: '/' },
});

if (options.trackChanges || options.enableRemoteReplication) {
Expand Down
2 changes: 2 additions & 0 deletions test/model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,8 @@ describe.onServer('Remote Methods', function() {
'upsert', 'updateOrCreate',
'exists',
'findById',
'replaceById',
'replaceOrCreate',
'find',
'findOne',
'updateAll', 'update',
Expand Down
4 changes: 4 additions & 0 deletions test/remoting.integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,15 @@ describe('remoting - integration', function() {
return formatMethod(m);
});

// This is the list of expected default endpoints
// for LB 3.X (They are different for LB 2.X)
var expectedMethods = [
'create(data:object):store POST /stores',
'upsert(data:object):store PUT /stores',
'replaceOrCreate(data:object):store PATCH /stores',
'exists(id:any):boolean GET /stores/:id/exists',
'findById(id:any,filter:object):store GET /stores/:id',
'replaceById(id:any,data:object):store PATCH /stores/:id',
'find(filter:object):store GET /stores',
'findOne(filter:object):store GET /stores/findOne',
'updateAll(where:object,data:object):object POST /stores/update',
Expand Down