diff --git a/integration/test/ParseObjectTest.js b/integration/test/ParseObjectTest.js index 47df1124f..d4dddc304 100644 --- a/integration/test/ParseObjectTest.js +++ b/integration/test/ParseObjectTest.js @@ -934,6 +934,44 @@ describe('Parse Object', () => { }); }); + it('can skip cascade saving as per request', async(done) => { + const Parent = Parse.Object.extend('Parent'); + const Child = Parse.Object.extend('Child'); + + const parent = new Parent(); + const child1 = new Child(); + const child2 = new Child(); + const child3 = new Child(); + + child1.set('name', 'rob'); + child2.set('name', 'sansa'); + child3.set('name', 'john'); + parent.set('children', [child1, child2]); + parent.set('bastard', child3); + + expect(parent.save).toThrow(); + let results = await new Parse.Query(Child).find(); + assert.equal(results.length, 0); + + await parent.save(null, { cascadeSave: true }); + results = await new Parse.Query(Child).find(); + assert.equal(results.length, 3); + + parent.set('dead', true); + child1.set('dead', true); + await parent.save(null); + const rob = await new Parse.Query(Child).equalTo('name', 'rob').first(); + expect(rob.get('dead')).toBe(true); + + parent.set('lastname', 'stark'); + child3.set('lastname', 'stark'); + await parent.save(null, { cascadeSave: false }); + const john = await new Parse.Query(Child).doesNotExist('lastname').first(); + expect(john.get('lastname')).toBeUndefined(); + + done(); + }); + it('can do two saves at the same time', (done) => { const object = new TestObject(); let firstSave = true; diff --git a/src/ParseObject.js b/src/ParseObject.js index 2f8fa6947..7270227f4 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.js @@ -54,6 +54,10 @@ type SaveParams = { body: AttributeMap; }; +type SaveOptions = FullOptions & { + cascadeSave?: boolean +} + const DEFAULT_BATCH_SIZE = 20; // Mapping of class names to constructors, so we can populate objects from the @@ -1131,6 +1135,7 @@ class ParseObject { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • cascadeSave: If `false`, nested objects will not be saved (default is `true`). * *
  • * @@ -1143,6 +1148,7 @@ class ParseObject { * be used for this request. *
  • sessionToken: A valid session token, used for making a request on * behalf of a specific user. + *
  • cascadeSave: If `false`, nested objects will not be saved (default is `true`). * * * @return {Promise} A promise that is fulfilled when the save @@ -1150,8 +1156,8 @@ class ParseObject { */ save( arg1: ?string | { [attr: string]: mixed }, - arg2: FullOptions | mixed, - arg3?: FullOptions + arg2: SaveOptions | mixed, + arg3?: SaveOptions ): Promise { let attrs; let options; @@ -1200,7 +1206,7 @@ class ParseObject { saveOptions.sessionToken = options.sessionToken; } const controller = CoreManager.getObjectController(); - const unsaved = unsavedChildren(this); + const unsaved = options.cascadeSave !== false ? unsavedChildren(this) : null; return controller.save(unsaved, saveOptions).then(() => { return controller.save(this, saveOptions); });