react-native-onyx 1.0.52 → 1.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web.development.js +93 -76
- package/dist/web.development.js.map +1 -1
- package/dist/web.min.js +1 -1
- package/dist/web.min.js.map +1 -1
- package/lib/Onyx.js +70 -64
- package/lib/metrics/index.native.js +1 -0
- package/lib/storage/__mocks__/index.js +5 -3
- package/lib/storage/providers/LocalForage.js +21 -10
- package/lib/storage/providers/SQLiteStorage.js +14 -4
- package/package.json +2 -2
package/dist/web.development.js
CHANGED
|
@@ -102,6 +102,9 @@ const METHOD = {
|
|
|
102
102
|
CLEAR: 'clear'
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
+
// Key/value store of Onyx key and arrays of values to merge
|
|
106
|
+
const mergeQueue = {};
|
|
107
|
+
|
|
105
108
|
// Keeps track of the last connectionID that was used so we can keep incrementing it
|
|
106
109
|
let lastConnectionID = 0;
|
|
107
110
|
|
|
@@ -924,6 +927,24 @@ function evictStorageAndRetry(error, onyxMethod) {for (var _len = arguments.leng
|
|
|
924
927
|
then(() => onyxMethod(...args));
|
|
925
928
|
}
|
|
926
929
|
|
|
930
|
+
/**
|
|
931
|
+
* Notifys subscribers and writes current value to cache
|
|
932
|
+
*
|
|
933
|
+
* @param {String} key
|
|
934
|
+
* @param {*} value
|
|
935
|
+
* @param {String} method
|
|
936
|
+
*/
|
|
937
|
+
function broadcastUpdate(key, value, method) {
|
|
938
|
+
// Logging properties only since values could be sensitive things we don't want to log
|
|
939
|
+
_Logger__WEBPACK_IMPORTED_MODULE_6__.logInfo(`${method}() called for key: ${key}${underscore__WEBPACK_IMPORTED_MODULE_2___default().isObject(value) ? ` properties: ${underscore__WEBPACK_IMPORTED_MODULE_2___default().keys(value).join(',')}` : ''}`);
|
|
940
|
+
|
|
941
|
+
// Update subscribers if the cached value has changed, or when the subscriber specifically requires
|
|
942
|
+
// all updates regardless of value changes (indicated by initWithStoredValues set to false).
|
|
943
|
+
const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, value);
|
|
944
|
+
_OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].set(key, value);
|
|
945
|
+
notifySubscribersOnNextTick(key, value, (subscriber) => hasChanged || subscriber.initWithStoredValues === false);
|
|
946
|
+
}
|
|
947
|
+
|
|
927
948
|
/**
|
|
928
949
|
* Write a value to our store with the given key
|
|
929
950
|
*
|
|
@@ -937,24 +958,9 @@ function set(key, value) {
|
|
|
937
958
|
return remove(key);
|
|
938
959
|
}
|
|
939
960
|
|
|
940
|
-
//
|
|
941
|
-
|
|
942
|
-
_Logger__WEBPACK_IMPORTED_MODULE_6__.logAlert(`Onyx.set() called after Onyx.merge() for key: ${key}. It is recommended to use set() or merge() not both.`);
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
// If the value in the cache is the same as what we have then do not update subscribers unless they
|
|
946
|
-
// have initWithStoredValues: false then they MUST get all updates even if nothing has changed.
|
|
947
|
-
if (!_OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, value)) {
|
|
948
|
-
_OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].addToAccessedKeys(key);
|
|
949
|
-
notifySubscribersOnNextTick(key, value, (subscriber) => subscriber.initWithStoredValues === false);
|
|
950
|
-
return Promise.resolve();
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
// Adds the key to cache when it's not available
|
|
954
|
-
_OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].set(key, value);
|
|
955
|
-
notifySubscribersOnNextTick(key, value);
|
|
961
|
+
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
962
|
+
broadcastUpdate(key, value, 'set');
|
|
956
963
|
|
|
957
|
-
// Write the thing to persistent storage, which will trigger a storage event for any other tabs open on this domain
|
|
958
964
|
return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].setItem(key, value).
|
|
959
965
|
catch((error) => evictStorageAndRetry(error, set, key, value));
|
|
960
966
|
}
|
|
@@ -992,67 +998,43 @@ function multiSet(data) {
|
|
|
992
998
|
catch((error) => evictStorageAndRetry(error, multiSet, data));
|
|
993
999
|
}
|
|
994
1000
|
|
|
995
|
-
// Key/value store of Onyx key and arrays of values to merge
|
|
996
|
-
const mergeQueue = {};
|
|
997
|
-
|
|
998
|
-
/**
|
|
999
|
-
* @private
|
|
1000
|
-
* @param {String} key
|
|
1001
|
-
* @returns {Boolean}
|
|
1002
|
-
*/
|
|
1003
|
-
function hasPendingMergeForKey(key) {
|
|
1004
|
-
return Boolean(mergeQueue[key]);
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
1001
|
/**
|
|
1008
|
-
*
|
|
1009
|
-
* value updates and return a single value. Merge attempts are
|
|
1010
|
-
* batched. They must occur after a single call to get() so we
|
|
1011
|
-
* can avoid race conditions.
|
|
1002
|
+
* Merges an array of changes with an existing value
|
|
1012
1003
|
*
|
|
1013
1004
|
* @private
|
|
1014
|
-
* @param {
|
|
1015
|
-
* @param {*}
|
|
1016
|
-
*
|
|
1005
|
+
* @param {Array<*>} changes Array of changes that should be applied to the existing value
|
|
1006
|
+
* @param {*} existingValue
|
|
1017
1007
|
* @returns {*}
|
|
1018
1008
|
*/
|
|
1019
|
-
function applyMerge(
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
data || []);
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
if (underscore__WEBPACK_IMPORTED_MODULE_2___default().isObject(data) || underscore__WEBPACK_IMPORTED_MODULE_2___default().every(mergeValues, (underscore__WEBPACK_IMPORTED_MODULE_2___default().isObject))) {
|
|
1009
|
+
function applyMerge(changes, existingValue) {
|
|
1010
|
+
const lastChange = underscore__WEBPACK_IMPORTED_MODULE_2___default().last(changes);
|
|
1011
|
+
|
|
1012
|
+
if (underscore__WEBPACK_IMPORTED_MODULE_2___default().isArray(existingValue) || underscore__WEBPACK_IMPORTED_MODULE_2___default().isArray(lastChange)) {
|
|
1013
|
+
return lastChange;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (underscore__WEBPACK_IMPORTED_MODULE_2___default().isObject(existingValue) || underscore__WEBPACK_IMPORTED_MODULE_2___default().every(changes, (underscore__WEBPACK_IMPORTED_MODULE_2___default().isObject))) {
|
|
1031
1017
|
// Object values are merged one after the other
|
|
1032
|
-
return underscore__WEBPACK_IMPORTED_MODULE_2___default().reduce(
|
|
1018
|
+
return underscore__WEBPACK_IMPORTED_MODULE_2___default().reduce(changes, (modifiedData, change) => {
|
|
1033
1019
|
// lodash adds a small overhead so we don't use it here
|
|
1034
1020
|
// eslint-disable-next-line prefer-object-spread, rulesdir/prefer-underscore-method
|
|
1035
|
-
const newData = Object.assign({}, (0,_fastMerge__WEBPACK_IMPORTED_MODULE_9__["default"])(modifiedData,
|
|
1021
|
+
const newData = Object.assign({}, (0,_fastMerge__WEBPACK_IMPORTED_MODULE_9__["default"])(modifiedData, change));
|
|
1036
1022
|
|
|
1037
|
-
// We will also delete any object keys that are undefined or null.
|
|
1038
|
-
// Deleting keys is not supported by AsyncStorage so we do it this way.
|
|
1039
1023
|
// Remove all first level keys that are explicitly set to null.
|
|
1040
|
-
return underscore__WEBPACK_IMPORTED_MODULE_2___default().omit(newData, (value
|
|
1041
|
-
},
|
|
1024
|
+
return underscore__WEBPACK_IMPORTED_MODULE_2___default().omit(newData, (value) => underscore__WEBPACK_IMPORTED_MODULE_2___default().isNull(value));
|
|
1025
|
+
}, existingValue || {});
|
|
1042
1026
|
}
|
|
1043
1027
|
|
|
1044
1028
|
// If we have anything else we can't merge it so we'll
|
|
1045
1029
|
// simply return the last value that was queued
|
|
1046
|
-
return
|
|
1030
|
+
return lastChange;
|
|
1047
1031
|
}
|
|
1048
1032
|
|
|
1049
1033
|
/**
|
|
1050
1034
|
* Merge a new value into an existing value at a key.
|
|
1051
1035
|
*
|
|
1052
|
-
* The types of values that can be merged are `Object` and `Array`. To set another type of value use `Onyx.set()`.
|
|
1053
|
-
*
|
|
1054
|
-
* to note that if you have an array value property on an `Object` that the default behavior of lodash/merge is not to
|
|
1055
|
-
* concatenate. See here: https://github.com/lodash/lodash/issues/2872
|
|
1036
|
+
* The types of values that can be merged are `Object` and `Array`. To set another type of value use `Onyx.set()`.
|
|
1037
|
+
* Values of type `Object` get merged with the old value, whilst for `Array`'s we simply replace the current value with the new one.
|
|
1056
1038
|
*
|
|
1057
1039
|
* Calls to `Onyx.merge()` are batched so that any calls performed in a single tick will stack in a queue and get
|
|
1058
1040
|
* applied in the order they were called. Note: `Onyx.set()` calls do not work this way so use caution when mixing
|
|
@@ -1065,26 +1047,35 @@ function applyMerge(key, data) {
|
|
|
1065
1047
|
* Onyx.merge(ONYXKEYS.POLICY, {name: 'My Workspace'}); // -> {id: 1, name: 'My Workspace'}
|
|
1066
1048
|
*
|
|
1067
1049
|
* @param {String} key ONYXKEYS key
|
|
1068
|
-
* @param {(Object|Array)}
|
|
1050
|
+
* @param {(Object|Array)} changes Object or Array value to merge
|
|
1069
1051
|
* @returns {Promise}
|
|
1070
1052
|
*/
|
|
1071
|
-
function merge(key,
|
|
1053
|
+
function merge(key, changes) {
|
|
1054
|
+
// Merge attempts are batched together. The delta should be applied after a single call to get() to prevent a race condition.
|
|
1055
|
+
// Using the initial value from storage in subsequent merge attempts will lead to an incorrect final merged value.
|
|
1072
1056
|
if (mergeQueue[key]) {
|
|
1073
|
-
mergeQueue[key].push(
|
|
1057
|
+
mergeQueue[key].push(changes);
|
|
1074
1058
|
return Promise.resolve();
|
|
1075
1059
|
}
|
|
1060
|
+
mergeQueue[key] = [changes];
|
|
1076
1061
|
|
|
1077
|
-
mergeQueue[key] = [value];
|
|
1078
1062
|
return get(key).
|
|
1079
|
-
then((
|
|
1063
|
+
then((existingValue) => {
|
|
1080
1064
|
try {
|
|
1081
|
-
|
|
1065
|
+
// We first only merge the changes, so we can provide these to the native implementation (SQLite uses only delta changes in "JSON_PATCH" to merge)
|
|
1066
|
+
const batchedChanges = applyMerge(mergeQueue[key]);
|
|
1082
1067
|
|
|
1083
1068
|
// Clean up the write queue so we
|
|
1084
1069
|
// don't apply these changes again
|
|
1085
1070
|
delete mergeQueue[key];
|
|
1086
1071
|
|
|
1087
|
-
|
|
1072
|
+
// After that we merge the batched changes with the existing value
|
|
1073
|
+
const modifiedData = applyMerge([batchedChanges], existingValue);
|
|
1074
|
+
|
|
1075
|
+
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
1076
|
+
broadcastUpdate(key, modifiedData, 'merge');
|
|
1077
|
+
|
|
1078
|
+
return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].mergeItem(key, batchedChanges, modifiedData);
|
|
1088
1079
|
} catch (error) {
|
|
1089
1080
|
_Logger__WEBPACK_IMPORTED_MODULE_6__.logAlert(`An error occurred while applying merge for key: ${key}, Error: ${error}`);
|
|
1090
1081
|
}
|
|
@@ -1093,6 +1084,15 @@ function merge(key, value) {
|
|
|
1093
1084
|
});
|
|
1094
1085
|
}
|
|
1095
1086
|
|
|
1087
|
+
/**
|
|
1088
|
+
* @private
|
|
1089
|
+
* @param {String} key
|
|
1090
|
+
* @returns {Boolean}
|
|
1091
|
+
*/
|
|
1092
|
+
function hasPendingMergeForKey(key) {
|
|
1093
|
+
return Boolean(mergeQueue[key]);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
1096
|
/**
|
|
1097
1097
|
* Merge user provided default key value pairs.
|
|
1098
1098
|
* @private
|
|
@@ -1218,6 +1218,11 @@ function mergeCollection(collectionKey, collection) {
|
|
|
1218
1218
|
if (isKeyMatch(collectionKey, dataKey)) {
|
|
1219
1219
|
return;
|
|
1220
1220
|
}
|
|
1221
|
+
|
|
1222
|
+
if (true) {
|
|
1223
|
+
throw new Error(`Provided collection doesn't have all its data belonging to the same parent. CollectionKey: ${collectionKey}, DataKey: ${dataKey}`);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1221
1226
|
hasCollectionKeyCheckFailed = true;
|
|
1222
1227
|
_Logger__WEBPACK_IMPORTED_MODULE_6__.logAlert(`Provided collection doesn't have all its data belonging to the same parent. CollectionKey: ${collectionKey}, DataKey: ${dataKey}`);
|
|
1223
1228
|
});
|
|
@@ -1396,6 +1401,7 @@ const Onyx = {
|
|
|
1396
1401
|
multiSet,
|
|
1397
1402
|
merge,
|
|
1398
1403
|
mergeCollection,
|
|
1404
|
+
hasPendingMergeForKey,
|
|
1399
1405
|
update,
|
|
1400
1406
|
clear,
|
|
1401
1407
|
getAllKeys,
|
|
@@ -2203,6 +2209,16 @@ const provider = {
|
|
|
2203
2209
|
return localforage__WEBPACK_IMPORTED_MODULE_0___default().setItem(key, value);
|
|
2204
2210
|
}),
|
|
2205
2211
|
|
|
2212
|
+
/**
|
|
2213
|
+
* Sets the value for a given key. The only requirement is that the value should be serializable to JSON string
|
|
2214
|
+
* @param {String} key
|
|
2215
|
+
* @param {*} value
|
|
2216
|
+
* @return {Promise<void>}
|
|
2217
|
+
*/
|
|
2218
|
+
setItem(key, value) {
|
|
2219
|
+
return this.setItemQueue.push({ key, value });
|
|
2220
|
+
},
|
|
2221
|
+
|
|
2206
2222
|
/**
|
|
2207
2223
|
* Get multiple key-value pairs for the give array of keys in a batch
|
|
2208
2224
|
* @param {String[]} keys
|
|
@@ -2230,6 +2246,17 @@ const provider = {
|
|
|
2230
2246
|
return Promise.all(tasks).then(() => Promise.resolve());
|
|
2231
2247
|
},
|
|
2232
2248
|
|
|
2249
|
+
/**
|
|
2250
|
+
* Merging an existing value with a new one
|
|
2251
|
+
* @param {String} key
|
|
2252
|
+
* @param {any} _changes - not used, as we rely on the pre-merged data from the `modifiedData`
|
|
2253
|
+
* @param {any} modifiedData - the pre-merged data from `Onyx.applyMerge`
|
|
2254
|
+
* @return {Promise<void>}
|
|
2255
|
+
*/
|
|
2256
|
+
mergeItem(key, _changes, modifiedData) {
|
|
2257
|
+
return this.setItem(key, modifiedData);
|
|
2258
|
+
},
|
|
2259
|
+
|
|
2233
2260
|
/**
|
|
2234
2261
|
* Stores multiple key-value pairs in a batch
|
|
2235
2262
|
* @param {Array<[key, value]>} pairs
|
|
@@ -2280,16 +2307,6 @@ const provider = {
|
|
|
2280
2307
|
return localforage__WEBPACK_IMPORTED_MODULE_0___default().removeItems(keys);
|
|
2281
2308
|
},
|
|
2282
2309
|
|
|
2283
|
-
/**
|
|
2284
|
-
* Sets the value for a given key. The only requirement is that the value should be serializable to JSON string
|
|
2285
|
-
* @param {String} key
|
|
2286
|
-
* @param {*} value
|
|
2287
|
-
* @return {Promise<void>}
|
|
2288
|
-
*/
|
|
2289
|
-
setItem(key, value) {
|
|
2290
|
-
return this.setItemQueue.push({ key, value });
|
|
2291
|
-
},
|
|
2292
|
-
|
|
2293
2310
|
/**
|
|
2294
2311
|
* @param {string[]} keyList
|
|
2295
2312
|
*/
|