diff --git a/lib/Onyx.js b/lib/Onyx.js index 0c49e3270..c7dd4e3f0 100644 --- a/lib/Onyx.js +++ b/lib/Onyx.js @@ -780,6 +780,36 @@ function mergeCollection(collectionKey, collection) { }); } +/** + * Insert API responses and lifecycle data into Onyx + * + * @param {Array} data An array of objects with shape {onyxMethod: oneOf('set', 'merge'), key: string, value: *} + */ +function update(data) { + // First, validate the Onyx object is in the format we expect + _.each(data, ({onyxMethod, key}) => { + if (!_.contains(['set', 'merge'], onyxMethod)) { + throw new Error(`Invalid onyxMethod ${onyxMethod} in Onyx update.`); + } + if (!_.isString(key)) { + throw new Error(`Invalid ${typeof key} key provided in Onyx update. Onyx key must be of type string.`); + } + }); + + _.each(data, ({onyxMethod, key, value}) => { + switch (onyxMethod) { + case 'set': + set(key, value); + break; + case 'merge': + merge(key, value); + break; + default: + break; + } + }); +} + /** * Initialize the store with actions and listening for storage events * @@ -856,6 +886,7 @@ const Onyx = { multiSet, merge, mergeCollection, + update, clear, init, registerLogger, @@ -883,6 +914,7 @@ function applyDecorators() { mergeCollection = decorate.decorateWithMetrics(mergeCollection, 'Onyx:mergeCollection'); getAllKeys = decorate.decorateWithMetrics(getAllKeys, 'Onyx:getAllKeys'); initializeWithDefaultKeyStates = decorate.decorateWithMetrics(initializeWithDefaultKeyStates, 'Onyx:defaults'); + update = decorate.decorateWithMetrics(update, 'Onyx:update'); /* eslint-enable */ // Re-expose decorated methods @@ -891,6 +923,7 @@ function applyDecorators() { Onyx.clear = clear; Onyx.merge = merge; Onyx.mergeCollection = mergeCollection; + Onyx.update = update; // Expose stats methods on Onyx Onyx.getMetrics = decorate.getMetrics; diff --git a/tests/unit/onyxTest.js b/tests/unit/onyxTest.js index d57c066d2..ac7cd4c51 100644 --- a/tests/unit/onyxTest.js +++ b/tests/unit/onyxTest.js @@ -306,4 +306,84 @@ describe('Onyx', () => { }); }); }); + + it('should use update data object to set/merge keys', () => { + let testKeyValue; + connectionID = Onyx.connect({ + key: ONYX_KEYS.TEST_KEY, + initWithStoredValues: false, + callback: (value) => { + testKeyValue = value; + }, + }); + + let anotherTestKeyValue; + connectionID = Onyx.connect({ + key: ONYX_KEYS.ANOTHER_TEST, + initWithStoredValues: false, + callback: (value) => { + anotherTestKeyValue = value; + }, + }); + + return waitForPromisesToResolve() + .then(() => { + // GIVEN the initial Onyx state: {test: true, anotherTest: {test1: 'test1'}} + Onyx.set(ONYX_KEYS.TEST_KEY, true); + Onyx.set(ONYX_KEYS.ANOTHER_TEST, {test1: 'test1'}); + return waitForPromisesToResolve(); + }) + .then(() => { + expect(testKeyValue).toBe(true); + expect(anotherTestKeyValue).toEqual({test1: 'test1'}); + + // WHEN we pass a data object to Onyx.update + Onyx.update([ + { + onyxMethod: 'set', + key: ONYX_KEYS.TEST_KEY, + value: 'one', + }, + { + onyxMethod: 'merge', + key: ONYX_KEYS.ANOTHER_TEST, + value: {test2: 'test2'}, + }, + ]); + return waitForPromisesToResolve(); + }) + .then(() => { + // THEN the final Onyx state should be {test: 'one', anotherTest: {test1: 'test1', test2: 'test2'}} + expect(testKeyValue).toBe('one'); + expect(anotherTestKeyValue).toEqual({test1: 'test1', test2: 'test2'}); + }); + }); + + it('should throw an error when the data object is incorrect in Onyx.update', () => { + // GIVEN the invalid data object with onyxMethod='multiSet' + const data = [ + {onyxMethod: 'set', key: ONYX_KEYS.TEST_KEY, value: 'four'}, + {onyxMethod: 'multiSet', key: ONYX_KEYS.ANOTHER_TEST, value: {test2: 'test2'}} + ]; + + try { + // WHEN we pass it to Onyx.update + Onyx.update(data); + } catch (error) { + // THEN we should expect the error message below + expect(error.message).toEqual('Invalid onyxMethod multiSet in Onyx update.'); + } + + try { + // GIVEN the invalid data object with key=true + data[1] = {onyxMethod: 'merge', key: true, value: {test2: 'test2'}}; + + // WHEN we pass it to Onyx.update + Onyx.update(data); + } catch (error) { + // THEN we should expect the error message below + // eslint-disable-next-line max-len + expect(error.message).toEqual('Invalid boolean key provided in Onyx update. Onyx key must be of type string.'); + } + }); });