From 87f93ebcee4756efe007130198d8353f876b5145 Mon Sep 17 00:00:00 2001 From: Amir Jafarian Date: Tue, 10 May 2016 16:47:33 -0400 Subject: [PATCH] Initial implementtaion --- lib/persisted-model.js | 67 ++++++++++++++++++++++++++++++++++-- test/model.test.js | 2 ++ test/remoting.integration.js | 4 +++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/lib/persisted-model.js b/lib/persisted-model.js index c27cd279..844f68b9 100644 --- a/lib/persisted-model.js +++ b/lib/persisted-model.js @@ -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 @@ -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. @@ -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]; @@ -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', { @@ -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', @@ -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) { diff --git a/test/model.test.js b/test/model.test.js index 4399a7fb..88fdaded 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -636,6 +636,8 @@ describe.onServer('Remote Methods', function() { 'upsert', 'updateOrCreate', 'exists', 'findById', + 'replaceById', + 'replaceOrCreate', 'find', 'findOne', 'updateAll', 'update', diff --git a/test/remoting.integration.js b/test/remoting.integration.js index be0f928a..82c617c7 100644 --- a/test/remoting.integration.js +++ b/test/remoting.integration.js @@ -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',