Skip to content

Commit ab9be04

Browse files
committed
Minor fix to mergeObject and add test for mergeCollection
1 parent 7fca303 commit ab9be04

4 files changed

Lines changed: 88 additions & 4 deletions

File tree

lib/storage/providers/IDBKeyValProvider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const provider: StorageProvider = {
5353
shouldRemoveNestedNulls: true,
5454
objectRemovalMode: 'replace',
5555
}).result;
56+
5657
return promisifyRequest(store.put(newValue, key));
5758
});
5859
return Promise.all(upsertMany).then(() => undefined);

lib/storage/providers/MemoryOnlyProvider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,11 @@ const provider: StorageProvider = {
8686
multiMerge(pairs) {
8787
_.forEach(pairs, ([key, value]) => {
8888
const existingValue = store[key] as Record<string, unknown>;
89+
8990
const newValue = utils.fastMerge(existingValue, value as Record<string, unknown>, {
9091
shouldRemoveNestedNulls: true,
9192
objectRemovalMode: 'replace',
92-
}).result as OnyxValue<OnyxKey>;
93+
}).result;
9394

9495
set(key, newValue);
9596
});

lib/utils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,11 @@ function mergeObject<TObject extends Record<string, unknown>>(
135135
// has the internal flag set, we replace the entire destination object with the source one and remove
136136
// the flag.
137137
if (options.objectRemovalMode === 'replace' && sourceProperty[ONYX_INTERNALS__REPLACE_OBJECT_MARK]) {
138-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
139-
delete sourceProperty[ONYX_INTERNALS__REPLACE_OBJECT_MARK];
140-
destination[key] = sourceProperty;
138+
// We do a spread here in order to have a new object reference and allow us to delete the internal flag
139+
// of the merged object only.
140+
const sourcePropertyWithoutMark = {...sourceProperty};
141+
delete sourcePropertyWithoutMark.ONYX_INTERNALS__REPLACE_OBJECT_MARK;
142+
destination[key] = sourcePropertyWithoutMark;
141143
return;
142144
}
143145

tests/unit/onyxTest.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,86 @@ describe('Onyx', () => {
19301930

19311931
expect(result).toEqual({[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`]: entry1ExpectedResult});
19321932
});
1933+
1934+
describe('mergeCollection', () => {
1935+
it('replacing old object after null merge', async () => {
1936+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1937+
const entry1: DeepRecord<string, any> = {
1938+
sub_entry1: {
1939+
id: 'sub_entry1',
1940+
someKey: 'someValue',
1941+
},
1942+
};
1943+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1944+
const entry2: DeepRecord<string, any> = {
1945+
sub_entry2: {
1946+
id: 'sub_entry2',
1947+
someKey: 'someValue',
1948+
},
1949+
};
1950+
await Onyx.multiSet({[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`]: entry1});
1951+
await Onyx.multiSet({[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry2`]: entry2});
1952+
1953+
const entry1ExpectedResult = lodashCloneDeep(entry1);
1954+
const entry2ExpectedResult = lodashCloneDeep(entry2);
1955+
const queuedUpdates: OnyxUpdate[] = [];
1956+
1957+
queuedUpdates.push(
1958+
{
1959+
key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`,
1960+
onyxMethod: 'merge',
1961+
value: {
1962+
// Removing the "sub_entry1" object in this update.
1963+
// Any subsequent changes to this object should completely replace the existing object in store.
1964+
sub_entry1: null,
1965+
},
1966+
},
1967+
{
1968+
key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry2`,
1969+
onyxMethod: 'merge',
1970+
value: {
1971+
// Removing the "sub_entry2" object in this update.
1972+
// Any subsequent changes to this object should completely replace the existing object in store.
1973+
sub_entry2: null,
1974+
},
1975+
},
1976+
);
1977+
delete entry1ExpectedResult.sub_entry1;
1978+
delete entry2ExpectedResult.sub_entry2;
1979+
1980+
queuedUpdates.push(
1981+
{
1982+
key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`,
1983+
onyxMethod: 'merge',
1984+
value: {
1985+
// This change should completely replace "sub_entry1" existing object in store.
1986+
sub_entry1: {
1987+
newKey: 'newValue',
1988+
},
1989+
},
1990+
},
1991+
{
1992+
key: `${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry2`,
1993+
onyxMethod: 'merge',
1994+
value: {
1995+
// This change should completely replace "sub_entry2" existing object in store.
1996+
sub_entry2: {
1997+
newKey: 'newValue',
1998+
},
1999+
},
2000+
},
2001+
);
2002+
entry1ExpectedResult.sub_entry1 = {newKey: 'newValue'};
2003+
entry2ExpectedResult.sub_entry2 = {newKey: 'newValue'};
2004+
2005+
await Onyx.update(queuedUpdates);
2006+
2007+
expect(result).toEqual({
2008+
[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry1`]: entry1ExpectedResult,
2009+
[`${ONYX_KEYS.COLLECTION.TEST_UPDATE}entry2`]: entry2ExpectedResult,
2010+
});
2011+
});
2012+
});
19332013
});
19342014

19352015
describe('merge', () => {

0 commit comments

Comments
 (0)