From fa4341a8c0ce5a9c478435250b4af6ea020a45bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kartal=20Kaan=20Bozdo=C4=9Fan?= Date: Wed, 1 May 2024 23:05:46 +0200 Subject: [PATCH] fix: Multiple object updates of nested keys overwrite each other (#1451) --- src/ObjectStateMutations.js | 6 +-- src/__tests__/ParseObject-test.js | 63 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/ObjectStateMutations.js b/src/ObjectStateMutations.js index 271e4f6b5..dfcbcff87 100644 --- a/src/ObjectStateMutations.js +++ b/src/ObjectStateMutations.js @@ -120,14 +120,14 @@ export function estimateAttributes( if (attr.includes('.')) { // convert a.b.c into { a: { b: { c: value } } } const fields = attr.split('.'); - const first = fields[0]; const last = fields[fields.length - 1]; - data[first] = { ...serverData[first] }; - let object = { ...data }; + let object = data; for (let i = 0; i < fields.length - 1; i++) { const key = fields[i]; if (!(key in object)) { object[key] = {}; + } else { + object[key] = { ...object[key] }; } object = object[key]; } diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index 06a7f3c2f..bd6643ff2 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -669,6 +669,69 @@ describe('ParseObject', () => { }); }); + it('can set multiple nested fields (regression test for #1450)', () => { + const o = new ParseObject('Person'); + o._finishFetch({ + objectId: 'setNested2_1450', + objectField: { + number: 5, + letter: 'a', + nested: { + number: 0, + letter: 'b', + }, + }, + }); + + expect(o.attributes).toEqual({ + objectField: { number: 5, letter: 'a', nested: { number: 0, letter: 'b' } }, + }); + o.set('objectField.number', 20); + o.set('objectField.letter', 'b'); + o.set('objectField.nested.number', 1); + o.set('objectField.nested.letter', 'c'); + + expect(o.attributes).toEqual({ + objectField: { number: 20, letter: 'b', nested: { number: 1, letter: 'c' } }, + }); + expect(o.op('objectField.number') instanceof SetOp).toBe(true); + expect(o.dirtyKeys()).toEqual([ + 'objectField.number', + 'objectField.letter', + 'objectField.nested.number', + 'objectField.nested.letter', + 'objectField', + ]); + expect(o._getSaveJSON()).toEqual({ + 'objectField.number': 20, + 'objectField.letter': 'b', + 'objectField.nested.number': 1, + 'objectField.nested.letter': 'c', + }); + + o.revert('objectField.nested.number'); + o.revert('objectField.nested.letter'); + expect(o._getSaveJSON()).toEqual({ + 'objectField.number': 20, + 'objectField.letter': 'b', + }); + expect(o.attributes).toEqual({ + objectField: { number: 20, letter: 'b', nested: { number: 0, letter: 'b' } }, + }); + + // Also test setting new root fields using the dot notation + o.set('objectField2.number', 0); + expect(o._getSaveJSON()).toEqual({ + 'objectField.number': 20, + 'objectField.letter': 'b', + 'objectField2.number': 0, + }); + expect(o.attributes).toEqual({ + objectField: { number: 20, letter: 'b', nested: { number: 0, letter: 'b' } }, + objectField2: { number: 0 }, + }); + }); + it('can increment a nested field', () => { const o = new ParseObject('Person'); o._finishFetch({