Merge pull request #2539 from mountain1234585/upsertWithWhere
Add upsertWithWhere
This commit is contained in:
commit
a6f8ec672d
|
@ -364,6 +364,8 @@ module.exports = function(registry) {
|
|||
return ACL.WRITE;
|
||||
case 'updateOrCreate':
|
||||
return ACL.WRITE;
|
||||
case 'upsertWithWhere':
|
||||
return ACL.WRITE;
|
||||
case 'upsert':
|
||||
return ACL.WRITE;
|
||||
case 'exists':
|
||||
|
|
|
@ -118,6 +118,28 @@ module.exports = function(registry) {
|
|||
throwNotAttached(this.modelName, 'upsert');
|
||||
};
|
||||
|
||||
/**
|
||||
* Update or insert a model instance based on the search criteria.
|
||||
* If there is a single instance retrieved, update the retrieved model.
|
||||
* Creates a new model if no model instances were found.
|
||||
* Returns an error if multiple instances are found.
|
||||
* * @param {Object} [where] `where` filter, like
|
||||
* ```
|
||||
* { key: val, key2: {gt: 'val2'}, ...}
|
||||
* ```
|
||||
* <br/>see
|
||||
* [Where filter](https://docs.strongloop.com/display/LB/Where+filter#Wherefilter-Whereclauseforothermethods).
|
||||
* @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 Updated model instance.
|
||||
*/
|
||||
|
||||
PersistedModel.upsertWithWhere =
|
||||
PersistedModel.patchOrCreateWithWhere = function upsertWithWhere(where, data, callback) {
|
||||
throwNotAttached(this.modelName, 'upsertWithWhere');
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace or insert a model instance; replace existing record if one is found,
|
||||
* such that parameter `data.id` matches `id` of model instance; otherwise,
|
||||
|
@ -654,6 +676,21 @@ module.exports = function(registry) {
|
|||
|
||||
setRemoting(PersistedModel, 'replaceOrCreate', replaceOrCreateOptions);
|
||||
|
||||
setRemoting(PersistedModel, 'upsertWithWhere', {
|
||||
aliases: ['patchOrCreateWithWhere'],
|
||||
description: 'Update an existing model instance or insert a new one into ' +
|
||||
'the data source based on the where criteria.',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{ arg: 'where', type: 'object', http: { source: 'query' },
|
||||
description: 'Criteria to match model instances' },
|
||||
{ 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: 'post', path: '/upsertWithWhere' },
|
||||
});
|
||||
|
||||
setRemoting(PersistedModel, 'exists', {
|
||||
description: 'Check whether a model instance exists in the data source.',
|
||||
accessType: 'READ',
|
||||
|
|
|
@ -122,6 +122,10 @@ describe('access control - integration', function() {
|
|||
});
|
||||
});
|
||||
|
||||
lt.it.shouldBeDeniedWhenCalledAnonymously('POST', '/api/users/upsertWithWhere');
|
||||
lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', '/api/users/upsertWithWhere');
|
||||
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', '/api/users/upsertWithWhere');
|
||||
|
||||
lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForUser);
|
||||
lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForUser);
|
||||
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForUser);
|
||||
|
@ -193,6 +197,10 @@ describe('access control - integration', function() {
|
|||
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForBank);
|
||||
lt.it.shouldBeAllowedWhenCalledByUser(SPECIAL_USER, 'DELETE', urlForBank);
|
||||
|
||||
lt.it.shouldBeDeniedWhenCalledAnonymously('POST', '/api/banks/upsertWithWhere');
|
||||
lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', '/api/banks/upsertWithWhere');
|
||||
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', '/api/banks/upsertWithWhere');
|
||||
|
||||
function urlForBank() {
|
||||
return '/api/banks/' + this.bank.id;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ describe('DataSource', function() {
|
|||
assert.isFunc(Color, 'findOne');
|
||||
assert.isFunc(Color, 'create');
|
||||
assert.isFunc(Color, 'updateOrCreate');
|
||||
assert.isFunc(Color, 'upsertWithWhere');
|
||||
assert.isFunc(Color, 'upsert');
|
||||
assert.isFunc(Color, 'findOrCreate');
|
||||
assert.isFunc(Color, 'exists');
|
||||
|
@ -82,6 +83,7 @@ describe('DataSource', function() {
|
|||
existsAndShared('_forDB', false);
|
||||
existsAndShared('create', true);
|
||||
existsAndShared('updateOrCreate', true);
|
||||
existsAndShared('upsertWithWhere', true);
|
||||
existsAndShared('upsert', true);
|
||||
existsAndShared('findOrCreate', false);
|
||||
existsAndShared('exists', true);
|
||||
|
|
|
@ -146,6 +146,43 @@ describe.onServer('Remote Methods', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Model.upsertWithWhere(where, data, callback)', function() {
|
||||
it('Updates when a Model instance is retreived from data source', function(done) {
|
||||
var taskEmitter = new TaskEmitter();
|
||||
taskEmitter
|
||||
.task(User, 'create', { first: 'jill', second: 'pill' })
|
||||
.task(User, 'create', { first: 'bob', second: 'sob' })
|
||||
.on('done', function() {
|
||||
User.upsertWithWhere({ second: 'pill' }, { second: 'jones' }, function(err, user) {
|
||||
if (err) return done(err);
|
||||
var id = user.id;
|
||||
User.findById(id, function(err, user) {
|
||||
if (err) return done(err);
|
||||
assert.equal(user.second, 'jones');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Creates when no Model instance is retreived from data source', function(done) {
|
||||
var taskEmitter = new TaskEmitter();
|
||||
taskEmitter
|
||||
.task(User, 'create', { first: 'simon', second: 'somers' })
|
||||
.on('done', function() {
|
||||
User.upsertWithWhere({ first: 'somers' }, { first: 'Simon' }, function(err, user) {
|
||||
if (err) return done(err);
|
||||
var id = user.id;
|
||||
User.findById(id, function(err, user) {
|
||||
if (err) return done(err);
|
||||
assert.equal(user.first, 'Simon');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Example Remote Method', function() {
|
||||
it('Call the method using HTTP / REST', function(done) {
|
||||
request(app)
|
||||
|
@ -515,6 +552,7 @@ describe.onServer('Remote Methods', function() {
|
|||
describe('Model.checkAccessTypeForMethod(remoteMethod)', function() {
|
||||
shouldReturn('create', ACL.WRITE);
|
||||
shouldReturn('updateOrCreate', ACL.WRITE);
|
||||
shouldReturn('upsertWithWhere', ACL.WRITE);
|
||||
shouldReturn('upsert', ACL.WRITE);
|
||||
shouldReturn('exists', ACL.READ);
|
||||
shouldReturn('findById', ACL.READ);
|
||||
|
@ -634,6 +672,7 @@ describe.onServer('Remote Methods', function() {
|
|||
// 'destroyAll', 'deleteAll', 'remove',
|
||||
'create',
|
||||
'upsert', 'updateOrCreate', 'patchOrCreate',
|
||||
'upsertWithWhere', 'patchOrCreateWithWhere',
|
||||
'exists',
|
||||
'findById',
|
||||
'replaceById',
|
||||
|
|
|
@ -183,6 +183,15 @@ describe('remoting - integration', function() {
|
|||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
});
|
||||
|
||||
it('has upsertWithWhere remote method', function() {
|
||||
var storeClass = findClass('store');
|
||||
var methods = getFormattedMethodsExcludingRelations(storeClass.methods);
|
||||
var expectedMethods = [
|
||||
'upsertWithWhere(where:object,data:object):store POST /stores/upsertWithWhere',
|
||||
];
|
||||
expect(methods).to.include.members(expectedMethods);
|
||||
});
|
||||
});
|
||||
|
||||
describe('With model.settings.replaceOnPUT false', function() {
|
||||
|
@ -202,6 +211,7 @@ describe('With model.settings.replaceOnPUT false', function() {
|
|||
'patchOrCreate(data:object):storeWithReplaceOnPUTfalse PUT /stores-updating',
|
||||
'patchOrCreate(data:object):storeWithReplaceOnPUTfalse PATCH /stores-updating',
|
||||
'replaceOrCreate(data:object):storeWithReplaceOnPUTfalse POST /stores-updating/replaceOrCreate',
|
||||
'upsertWithWhere(where:object,data:object):storeWithReplaceOnPUTfalse POST /stores-updating/upsertWithWhere',
|
||||
'exists(id:any):boolean GET /stores-updating/:id/exists',
|
||||
'exists(id:any):boolean HEAD /stores-updating/:id',
|
||||
'findById(id:any,filter:object):storeWithReplaceOnPUTfalse GET /stores-updating/:id',
|
||||
|
|
|
@ -1010,6 +1010,19 @@ describe('Replication / Change APIs', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('detects "upsertWithWhere"', function(done) {
|
||||
givenReplicatedInstance(function(err, inst) {
|
||||
if (err) return done(err);
|
||||
SourceModel.upsertWithWhere(
|
||||
{ name: inst.name },
|
||||
{ name: 'updated' },
|
||||
function(err) {
|
||||
if (err) return done(err);
|
||||
assertChangeRecordedForId(inst.id, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('detects "findOrCreate"', function(done) {
|
||||
// make sure we bypass find+create and call the connector directly
|
||||
SourceModel.dataSource.connector.findOrCreate =
|
||||
|
|
Loading…
Reference in New Issue