diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index 1b5cc0c5e9..29a97b2ddb 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -254,6 +254,45 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue(); }); + it('upserts with $setOnInsert', async () => { + const uuid = require('uuid'); + const uuid1 = uuid.v4(); + const uuid2 = uuid.v4(); + const query = { + x: 1, + }; + const update = { + objectId: { + __op: 'SetOnInsert', + amount: uuid1, + }, + x: 1, + count: { + __op: 'Increment', + amount: 1, + }, + }; + await Parse.Server.database.update( + 'MyClass', + query, + update, + { upsert: true }, + ); + update.objectId.amount = uuid2; + await Parse.Server.database.update( + 'MyClass', + query, + update, + { upsert: true }, + ); + const q = new Parse.Query('MyClass'); + const docs = await q.find(); + expect(docs.length).toBe(1); + expect(docs[0].id).toBe(uuid1); + expect(docs[0].get('x')).toBe(1); + expect(docs[0].get('count')).toBe(2); + }); + it('handles updating a single object with array, object date', done => { const adapter = new MongoStorageAdapter({ uri: databaseURI }); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 6f6811cec3..7f66fb32fb 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -986,6 +986,13 @@ function transformUpdateOperator({ __op, amount, objects }, flatten) { return { __op: '$inc', arg: amount }; } + case 'SetOnInsert': + if (flatten) { + return amount; + } else { + return { __op: '$setOnInsert', arg: amount }; + } + case 'Add': case 'AddUnique': if (!(objects instanceof Array)) { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index f9c782db87..defb7976c4 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -279,6 +279,9 @@ const flattenUpdateOperatorsForCreate = object => { } object[key] = object[key].amount; break; + case 'SetOnInsert': + object[key] = object[key].amount; + break; case 'Add': if (!(object[key].objects instanceof Array)) { throw new Parse.Error(Parse.Error.INVALID_JSON, 'objects to add must be an array'); @@ -1817,7 +1820,7 @@ class DatabaseController { keyUpdate && typeof keyUpdate === 'object' && keyUpdate.__op && - ['Add', 'AddUnique', 'Remove', 'Increment'].indexOf(keyUpdate.__op) > -1 + ['Add', 'AddUnique', 'Remove', 'Increment', 'SetOnInsert'].indexOf(keyUpdate.__op) > -1 ) { // only valid ops that produce an actionable result // the op may have happened on a keypath