diff --git a/lib/Onyx.js b/lib/Onyx.js index 8af2a87c7..fc28c5662 100644 --- a/lib/Onyx.js +++ b/lib/Onyx.js @@ -1207,20 +1207,27 @@ function set(key, value) { * to an array of key-value pairs in the above format and removes key-value pairs that are being set to null * @private * @param {Record} data + * @param {Boolean} shouldRemoveNullObjectValues * @return {Array} an array of key - value pairs <[key, value]> */ -function prepareKeyValuePairsForStorage(data) { - const keyValuePairs = []; - - _.forEach(data, (value, key) => { - const {value: valueAfterRemoving, wasRemoved} = removeNullValues(key, value); +function prepareKeyValuePairsForStorage(data, shouldRemoveNullObjectValues = true) { + if (!shouldRemoveNullObjectValues) { + return _.map(data, (value, key) => [key, value]); + } - if (wasRemoved) return; + return _.reduce( + data, + (pairs, value, key) => { + const {value: valueAfterRemoving, wasRemoved} = removeNullValues(key, value); - keyValuePairs.push([key, valueAfterRemoving]); - }); + if (!wasRemoved) { + pairs.push([key, valueAfterRemoving]); + } - return keyValuePairs; + return pairs; + }, + [], + ); } /** @@ -1339,7 +1346,7 @@ function merge(key, changes) { // On native platforms we use SQLite which utilises JSON_PATCH to merge changes. // JSON_PATCH generally removes null values from the stored object. // When there is no existing value though, SQLite will just insert the changes as a new value and thus the null values won't be removed. - // Therefore we need to remove null values from the `batchedChanges` which are sent to the SQLite, if no existing value is present. + // Therefore, we need to remove null values from the `batchedChanges` which are sent to the SQLite, if no existing value is present. if (!existingValue) { batchedChanges = applyMerge(undefined, [batchedChanges], true); } @@ -1528,7 +1535,7 @@ function mergeCollection(collectionKey, collection) { const existingKeyCollection = _.pick(collection, existingKeys); const newCollection = _.pick(collection, newKeys); - const keyValuePairsForExistingCollection = prepareKeyValuePairsForStorage(existingKeyCollection); + const keyValuePairsForExistingCollection = prepareKeyValuePairsForStorage(existingKeyCollection, false); const keyValuePairsForNewCollection = prepareKeyValuePairsForStorage(newCollection); const promises = []; diff --git a/tests/unit/onyxTest.js b/tests/unit/onyxTest.js index 5879edcfc..028a67bc6 100644 --- a/tests/unit/onyxTest.js +++ b/tests/unit/onyxTest.js @@ -1,5 +1,6 @@ import _ from 'underscore'; import Onyx from '../../lib'; +import StorageMock from '../../lib/storage'; import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; const ONYX_KEYS = { @@ -10,6 +11,7 @@ const ONYX_KEYS = { TEST_CONNECT_COLLECTION: 'testConnectCollection_', TEST_POLICY: 'testPolicy_', TEST_UPDATE: 'testUpdate_', + ROUTES: 'route_', }, }; @@ -1044,4 +1046,42 @@ describe('Onyx', () => { expect(testKeyValue).toEqual(null); }); }); + + describe('mergeCollection', () => { + it('should call subscriber callback and storage multiMerge with the same data', () => { + const storageSpy = jest.spyOn(StorageMock, 'multiMerge'); + const routineRoute = `${ONYX_KEYS.COLLECTION.ROUTES}routine`; + + let result; + connectionID = Onyx.connect({ + key: routineRoute, + initWithStoredValues: false, + callback: (value) => (result = value), + }); + + const initialValue = { + pendingFields: { + waypoints: 'add', + }, + }; + const updatedValue = { + pendingFields: { + waypoints: null, + }, + }; + + return Onyx.set(routineRoute, initialValue) + .then(() => { + expect(result).toEqual(initialValue); + Onyx.mergeCollection(ONYX_KEYS.COLLECTION.ROUTES, { + [routineRoute]: updatedValue, + }); + return waitForPromisesToResolve(); + }) + .then(() => { + expect(result).toEqual(updatedValue); + expect(storageSpy).toHaveBeenCalledWith([[routineRoute, updatedValue]]); + }); + }); + }); });