diff --git a/spec/MongoStorageAdapter.spec.js b/spec/MongoStorageAdapter.spec.js index f78caa2608..f669196c44 100644 --- a/spec/MongoStorageAdapter.spec.js +++ b/spec/MongoStorageAdapter.spec.js @@ -213,6 +213,61 @@ describe_only_db('mongo')('MongoStorageAdapter', () => { }); }); + it('upserts with $setOnInsert', async () => { + const uuid = require('uuid'); + const uuid1 = uuid.v4(); + const uuid2 = uuid.v4(); + const schema = { + className: 'MyClass', + fields: { + x: { type: 'Number' }, + count: { type: 'Number' }, + }, + classLevelPermissions: {}, + }; + + const myClassSchema = new Parse.Schema(schema.className); + myClassSchema.setCLP(schema.classLevelPermissions); + await myClassSchema.save(); + + const query = { + x: 1, + }; + const update = { + objectId: { + __op: 'SetOnInsert', + amount: uuid1, + }, + 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 res = await Parse.Server.database.find( + schema.className, + {}, + {}, + ); + expect(res.length).toBe(1); + expect(res[0].objectId).toBe(uuid1); + expect(res[0].count).toBe(2); + expect(res[0].x).toBe(1); + }); + 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 91ad23fa4a..ceff4b916b 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -976,6 +976,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 56c37dd33a..9280a474e8 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -272,6 +272,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'); @@ -1813,7 +1816,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