react-native-onyx 1.0.98 → 1.0.100
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 +111 -57
- 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 +58 -19
- package/lib/storage/__mocks__/index.js +1 -2
- package/lib/storage/providers/IDBKeyVal.js +3 -2
- package/lib/utils.js +48 -35
- package/package.json +1 -1
package/dist/web.development.js
CHANGED
|
@@ -1107,6 +1107,25 @@ function hasPendingMergeForKey(key) {
|
|
|
1107
1107
|
return Boolean(mergeQueue[key]);
|
|
1108
1108
|
}
|
|
1109
1109
|
|
|
1110
|
+
/**
|
|
1111
|
+
* Removes a key from storage if the value is null.
|
|
1112
|
+
* Otherwise removes all nested null values in objects and returns the object
|
|
1113
|
+
* @param {String} key
|
|
1114
|
+
* @param {Mixed} value
|
|
1115
|
+
* @returns {Mixed} `null` if the key got removed completely, otherwise the value without null values
|
|
1116
|
+
*/
|
|
1117
|
+
function removeNullValues(key, value) {
|
|
1118
|
+
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isNull(value)) {
|
|
1119
|
+
remove(key);
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// We can remove all null values in an object by merging it with itself
|
|
1124
|
+
// utils.fastMerge recursively goes through the object and removes all null values
|
|
1125
|
+
// Passing two identical objects as source and target to fastMerge will not change it, but only remove the null values
|
|
1126
|
+
return _utils__WEBPACK_IMPORTED_MODULE_9__["default"].removeNestedNullValues(value);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1110
1129
|
/**
|
|
1111
1130
|
* Write a value to our store with the given key
|
|
1112
1131
|
*
|
|
@@ -1116,28 +1135,28 @@ function hasPendingMergeForKey(key) {
|
|
|
1116
1135
|
* @returns {Promise}
|
|
1117
1136
|
*/
|
|
1118
1137
|
function set(key, value) {
|
|
1119
|
-
|
|
1120
|
-
|
|
1138
|
+
const valueWithoutNull = removeNullValues(key, value);
|
|
1139
|
+
|
|
1140
|
+
if (valueWithoutNull === null) {
|
|
1141
|
+
return Promise.resolve();
|
|
1121
1142
|
}
|
|
1122
1143
|
|
|
1123
1144
|
if (hasPendingMergeForKey(key)) {
|
|
1124
1145
|
_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.`);
|
|
1125
1146
|
}
|
|
1126
1147
|
|
|
1127
|
-
const
|
|
1128
|
-
|
|
1129
|
-
const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, valueWithNullRemoved);
|
|
1148
|
+
const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, valueWithoutNull);
|
|
1130
1149
|
|
|
1131
1150
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
1132
|
-
const updatePromise = broadcastUpdate(key,
|
|
1151
|
+
const updatePromise = broadcastUpdate(key, valueWithoutNull, hasChanged, 'set');
|
|
1133
1152
|
|
|
1134
1153
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
1135
1154
|
if (!hasChanged) {
|
|
1136
1155
|
return updatePromise;
|
|
1137
1156
|
}
|
|
1138
1157
|
|
|
1139
|
-
return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].setItem(key,
|
|
1140
|
-
catch((error) => evictStorageAndRetry(error, set, key,
|
|
1158
|
+
return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].setItem(key, valueWithoutNull).
|
|
1159
|
+
catch((error) => evictStorageAndRetry(error, set, key, valueWithoutNull)).
|
|
1141
1160
|
then(() => updatePromise);
|
|
1142
1161
|
}
|
|
1143
1162
|
|
|
@@ -1170,7 +1189,16 @@ function multiSet(data) {
|
|
|
1170
1189
|
return scheduleSubscriberUpdate(key, val);
|
|
1171
1190
|
});
|
|
1172
1191
|
|
|
1173
|
-
|
|
1192
|
+
const keyValuePairsWithoutNull = underscore__WEBPACK_IMPORTED_MODULE_1___default().filter(underscore__WEBPACK_IMPORTED_MODULE_1___default().map(keyValuePairs, (_ref2) => {let [key, value] = _ref2;
|
|
1193
|
+
const valueWithoutNull = removeNullValues(key, value);
|
|
1194
|
+
|
|
1195
|
+
if (valueWithoutNull === null) {
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
return [key, valueWithoutNull];
|
|
1199
|
+
}), Boolean);
|
|
1200
|
+
|
|
1201
|
+
return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].multiSet(keyValuePairsWithoutNull).
|
|
1174
1202
|
catch((error) => evictStorageAndRetry(error, multiSet, data)).
|
|
1175
1203
|
then(() => Promise.all(updatePromises));
|
|
1176
1204
|
}
|
|
@@ -1181,9 +1209,10 @@ function multiSet(data) {
|
|
|
1181
1209
|
* @private
|
|
1182
1210
|
* @param {*} existingValue
|
|
1183
1211
|
* @param {Array<*>} changes Array of changes that should be applied to the existing value
|
|
1212
|
+
* @param {Boolean} shouldRemoveNullObjectValues
|
|
1184
1213
|
* @returns {*}
|
|
1185
1214
|
*/
|
|
1186
|
-
function applyMerge(existingValue, changes) {
|
|
1215
|
+
function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
|
|
1187
1216
|
const lastChange = underscore__WEBPACK_IMPORTED_MODULE_1___default().last(changes);
|
|
1188
1217
|
|
|
1189
1218
|
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isArray(lastChange)) {
|
|
@@ -1192,7 +1221,7 @@ function applyMerge(existingValue, changes) {
|
|
|
1192
1221
|
|
|
1193
1222
|
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().some(changes, (underscore__WEBPACK_IMPORTED_MODULE_1___default().isObject))) {
|
|
1194
1223
|
// Object values are then merged one after the other
|
|
1195
|
-
return underscore__WEBPACK_IMPORTED_MODULE_1___default().reduce(changes, (modifiedData, change) => _utils__WEBPACK_IMPORTED_MODULE_9__["default"].fastMerge(modifiedData, change),
|
|
1224
|
+
return underscore__WEBPACK_IMPORTED_MODULE_1___default().reduce(changes, (modifiedData, change) => _utils__WEBPACK_IMPORTED_MODULE_9__["default"].fastMerge(modifiedData, change, shouldRemoveNullObjectValues),
|
|
1196
1225
|
existingValue || {});
|
|
1197
1226
|
}
|
|
1198
1227
|
|
|
@@ -1240,10 +1269,12 @@ function merge(key, changes) {
|
|
|
1240
1269
|
then((existingValue) => {
|
|
1241
1270
|
try {
|
|
1242
1271
|
// 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)
|
|
1243
|
-
|
|
1272
|
+
// We don't want to remove null values from the "batchedChanges", because SQLite uses them to remove keys from storage natively.
|
|
1273
|
+
let batchedChanges = applyMerge(undefined, mergeQueue[key], false);
|
|
1244
1274
|
|
|
1245
1275
|
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isNull(batchedChanges)) {
|
|
1246
|
-
|
|
1276
|
+
remove(key);
|
|
1277
|
+
return;
|
|
1247
1278
|
}
|
|
1248
1279
|
|
|
1249
1280
|
// The presence of a `null` in the merge queue instructs us to drop the existing value.
|
|
@@ -1255,15 +1286,16 @@ function merge(key, changes) {
|
|
|
1255
1286
|
delete mergeQueuePromise[key];
|
|
1256
1287
|
|
|
1257
1288
|
// After that we merge the batched changes with the existing value
|
|
1258
|
-
|
|
1259
|
-
|
|
1289
|
+
// We can remove null values from the "modifiedData", because "null" implicates that the user wants to remove a value from storage.
|
|
1290
|
+
// The "modifiedData" will be directly "set" in storage instead of being merged
|
|
1291
|
+
const modifiedData = shouldOverwriteExistingValue ? batchedChanges : applyMerge(existingValue, [batchedChanges], true);
|
|
1260
1292
|
|
|
1261
1293
|
// On native platforms we use SQLite which utilises JSON_PATCH to merge changes.
|
|
1262
|
-
// JSON_PATCH generally removes
|
|
1263
|
-
// When there is no existing value though, SQLite will just insert the changes as a new value and thus the
|
|
1264
|
-
// Therefore we need to remove
|
|
1294
|
+
// JSON_PATCH generally removes null values from the stored object.
|
|
1295
|
+
// 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.
|
|
1296
|
+
// Therefore we need to remove null values from the `batchedChanges` which are sent to the SQLite, if no existing value is present.
|
|
1265
1297
|
if (!existingValue) {
|
|
1266
|
-
batchedChanges =
|
|
1298
|
+
batchedChanges = applyMerge(undefined, [batchedChanges], true);
|
|
1267
1299
|
}
|
|
1268
1300
|
|
|
1269
1301
|
const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, modifiedData);
|
|
@@ -1432,6 +1464,13 @@ function mergeCollection(collectionKey, collection) {
|
|
|
1432
1464
|
then((persistedKeys) => {
|
|
1433
1465
|
// Split to keys that exist in storage and keys that don't
|
|
1434
1466
|
const [existingKeys, newKeys] = underscore__WEBPACK_IMPORTED_MODULE_1___default().chain(collection).
|
|
1467
|
+
pick((value, key) => {
|
|
1468
|
+
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isNull(value)) {
|
|
1469
|
+
remove(key);
|
|
1470
|
+
return false;
|
|
1471
|
+
}
|
|
1472
|
+
return true;
|
|
1473
|
+
}).
|
|
1435
1474
|
keys().
|
|
1436
1475
|
partition((key) => persistedKeys.includes(key)).
|
|
1437
1476
|
value();
|
|
@@ -1474,7 +1513,7 @@ function mergeCollection(collectionKey, collection) {
|
|
|
1474
1513
|
*/
|
|
1475
1514
|
function update(data) {
|
|
1476
1515
|
// First, validate the Onyx object is in the format we expect
|
|
1477
|
-
underscore__WEBPACK_IMPORTED_MODULE_1___default().each(data, (
|
|
1516
|
+
underscore__WEBPACK_IMPORTED_MODULE_1___default().each(data, (_ref3) => {let { onyxMethod, key, value } = _ref3;
|
|
1478
1517
|
if (!underscore__WEBPACK_IMPORTED_MODULE_1___default().contains([METHOD.CLEAR, METHOD.SET, METHOD.MERGE, METHOD.MERGE_COLLECTION, METHOD.MULTI_SET], onyxMethod)) {
|
|
1479
1518
|
throw new Error(`Invalid onyxMethod ${onyxMethod} in Onyx update.`);
|
|
1480
1519
|
}
|
|
@@ -1491,7 +1530,7 @@ function update(data) {
|
|
|
1491
1530
|
const promises = [];
|
|
1492
1531
|
let clearPromise = Promise.resolve();
|
|
1493
1532
|
|
|
1494
|
-
underscore__WEBPACK_IMPORTED_MODULE_1___default().each(data, (
|
|
1533
|
+
underscore__WEBPACK_IMPORTED_MODULE_1___default().each(data, (_ref4) => {let { onyxMethod, key, value } = _ref4;
|
|
1495
1534
|
switch (onyxMethod) {
|
|
1496
1535
|
case METHOD.SET:
|
|
1497
1536
|
promises.push(() => set(key, value));
|
|
@@ -2279,6 +2318,7 @@ const provider = {
|
|
|
2279
2318
|
/**
|
|
2280
2319
|
* Multiple merging of existing and new values in a batch
|
|
2281
2320
|
* @param {Array<[key, value]>} pairs
|
|
2321
|
+
* This function also removes all nested null values from an object.
|
|
2282
2322
|
* @return {Promise<void>}
|
|
2283
2323
|
*/
|
|
2284
2324
|
multiMerge: (pairs) => getCustomStore()('readwrite', (store) => {
|
|
@@ -2290,8 +2330,8 @@ const provider = {
|
|
|
2290
2330
|
return getValues.then((values) => {
|
|
2291
2331
|
const upsertMany = underscore__WEBPACK_IMPORTED_MODULE_1___default().map(pairs, (_ref2, index) => {let [key, value] = _ref2;
|
|
2292
2332
|
const prev = values[index];
|
|
2293
|
-
const newValue =
|
|
2294
|
-
return (0,idb_keyval__WEBPACK_IMPORTED_MODULE_0__.promisifyRequest)(store.put(
|
|
2333
|
+
const newValue = _utils__WEBPACK_IMPORTED_MODULE_2__["default"].fastMerge(prev, value);
|
|
2334
|
+
return (0,idb_keyval__WEBPACK_IMPORTED_MODULE_0__.promisifyRequest)(store.put(newValue, key));
|
|
2295
2335
|
});
|
|
2296
2336
|
return Promise.all(upsertMany);
|
|
2297
2337
|
});
|
|
@@ -2396,8 +2436,8 @@ function areObjectsEmpty(a, b) {
|
|
|
2396
2436
|
return (
|
|
2397
2437
|
typeof a === 'object' &&
|
|
2398
2438
|
typeof b === 'object' &&
|
|
2399
|
-
|
|
2400
|
-
|
|
2439
|
+
underscore__WEBPACK_IMPORTED_MODULE_0___default().isEmpty(a) &&
|
|
2440
|
+
underscore__WEBPACK_IMPORTED_MODULE_0___default().isEmpty(b));
|
|
2401
2441
|
|
|
2402
2442
|
}
|
|
2403
2443
|
|
|
@@ -2411,15 +2451,18 @@ function isMergeableObject(val) {
|
|
|
2411
2451
|
const nonNullObject = val != null ? typeof val === 'object' : false;
|
|
2412
2452
|
return nonNullObject &&
|
|
2413
2453
|
Object.prototype.toString.call(val) !== '[object RegExp]' &&
|
|
2414
|
-
Object.prototype.toString.call(val) !== '[object Date]'
|
|
2454
|
+
Object.prototype.toString.call(val) !== '[object Date]'
|
|
2455
|
+
// eslint-disable-next-line rulesdir/prefer-underscore-method
|
|
2456
|
+
&& !Array.isArray(val);
|
|
2415
2457
|
}
|
|
2416
2458
|
|
|
2417
2459
|
/**
|
|
2418
2460
|
* @param {Object} target
|
|
2419
2461
|
* @param {Object} source
|
|
2462
|
+
* @param {Boolean} shouldRemoveNullObjectValues
|
|
2420
2463
|
* @returns {Object}
|
|
2421
2464
|
*/
|
|
2422
|
-
function mergeObject(target, source) {
|
|
2465
|
+
function mergeObject(target, source) {let shouldRemoveNullObjectValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
2423
2466
|
const destination = {};
|
|
2424
2467
|
if (isMergeableObject(target)) {
|
|
2425
2468
|
// lodash adds a small overhead so we don't use it here
|
|
@@ -2427,7 +2470,14 @@ function mergeObject(target, source) {
|
|
|
2427
2470
|
const targetKeys = Object.keys(target);
|
|
2428
2471
|
for (let i = 0; i < targetKeys.length; ++i) {
|
|
2429
2472
|
const key = targetKeys[i];
|
|
2430
|
-
|
|
2473
|
+
|
|
2474
|
+
// If shouldRemoveNullObjectValues is true, we want to remove null values from the merged object
|
|
2475
|
+
const isSourceOrTargetNull = target[key] === null || source[key] === null;
|
|
2476
|
+
const shouldOmitSourceKey = shouldRemoveNullObjectValues && isSourceOrTargetNull;
|
|
2477
|
+
|
|
2478
|
+
if (!shouldOmitSourceKey) {
|
|
2479
|
+
destination[key] = target[key];
|
|
2480
|
+
}
|
|
2431
2481
|
}
|
|
2432
2482
|
}
|
|
2433
2483
|
|
|
@@ -2436,15 +2486,24 @@ function mergeObject(target, source) {
|
|
|
2436
2486
|
const sourceKeys = Object.keys(source);
|
|
2437
2487
|
for (let i = 0; i < sourceKeys.length; ++i) {
|
|
2438
2488
|
const key = sourceKeys[i];
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2489
|
+
|
|
2490
|
+
// If shouldRemoveNullObjectValues is true, we want to remove null values from the merged object
|
|
2491
|
+
const shouldOmitSourceKey = shouldRemoveNullObjectValues && source[key] === null;
|
|
2492
|
+
|
|
2493
|
+
// If we pass undefined as the updated value for a key, we want to generally ignore it
|
|
2494
|
+
const isSourceKeyUndefined = source[key] === undefined;
|
|
2495
|
+
|
|
2496
|
+
if (!isSourceKeyUndefined && !shouldOmitSourceKey) {
|
|
2497
|
+
const isSourceKeyMergable = isMergeableObject(source[key]);
|
|
2498
|
+
|
|
2499
|
+
if (isSourceKeyMergable && target[key]) {
|
|
2500
|
+
if (!shouldRemoveNullObjectValues || isSourceKeyMergable) {
|
|
2501
|
+
// eslint-disable-next-line no-use-before-define
|
|
2502
|
+
destination[key] = fastMerge(target[key], source[key], shouldRemoveNullObjectValues);
|
|
2503
|
+
}
|
|
2504
|
+
} else if (!shouldRemoveNullObjectValues || source[key] !== null) {
|
|
2505
|
+
destination[key] = source[key];
|
|
2506
|
+
}
|
|
2448
2507
|
}
|
|
2449
2508
|
}
|
|
2450
2509
|
|
|
@@ -2452,41 +2511,36 @@ function mergeObject(target, source) {
|
|
|
2452
2511
|
}
|
|
2453
2512
|
|
|
2454
2513
|
/**
|
|
2514
|
+
* Merges two objects and removes null values if "shouldRemoveNullObjectValues" is set to true
|
|
2515
|
+
*
|
|
2516
|
+
* We generally want to remove null values from objects written to disk and cache, because it decreases the amount of data stored in memory and on disk.
|
|
2517
|
+
* On native, when merging an existing value with new changes, SQLite will use JSON_PATCH, which removes top-level nullish values.
|
|
2518
|
+
* To be consistent with the behaviour for merge, we'll also want to remove null values for "set" operations.
|
|
2519
|
+
*
|
|
2455
2520
|
* @param {Object|Array} target
|
|
2456
2521
|
* @param {Object|Array} source
|
|
2522
|
+
* @param {Boolean} shouldRemoveNullObjectValues
|
|
2457
2523
|
* @returns {Object|Array}
|
|
2458
2524
|
*/
|
|
2459
|
-
function fastMerge(target, source) {
|
|
2525
|
+
function fastMerge(target, source) {let shouldRemoveNullObjectValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
2460
2526
|
// We have to ignore arrays and nullish values here,
|
|
2461
2527
|
// otherwise "mergeObject" will throw an error,
|
|
2462
2528
|
// because it expects an object as "source"
|
|
2463
|
-
if (
|
|
2529
|
+
if (underscore__WEBPACK_IMPORTED_MODULE_0___default().isArray(source) || source === null || source === undefined) {
|
|
2464
2530
|
return source;
|
|
2465
2531
|
}
|
|
2466
|
-
return mergeObject(target, source);
|
|
2532
|
+
return mergeObject(target, source, shouldRemoveNullObjectValues);
|
|
2467
2533
|
}
|
|
2468
2534
|
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
* To be consistent with the behaviour for merge, we'll also want to remove nullish values for "set" operations.
|
|
2473
|
-
* On web, IndexedDB will keep the top-level keys along with a null value and this uses up storage and memory.
|
|
2474
|
-
* This method will ensure that keys for null values are removed before an object is written to disk and cache so that all platforms are storing the data in the same efficient way.
|
|
2475
|
-
* @private
|
|
2476
|
-
* @param {*} value
|
|
2477
|
-
* @returns {*}
|
|
2478
|
-
*/
|
|
2479
|
-
function removeNullObjectValues(value) {
|
|
2480
|
-
if (underscore__WEBPACK_IMPORTED_MODULE_0__.isArray(value) || !underscore__WEBPACK_IMPORTED_MODULE_0__.isObject(value)) {
|
|
2481
|
-
return value;
|
|
2535
|
+
function removeNestedNullValues(value) {
|
|
2536
|
+
if (typeof value === 'object' && !underscore__WEBPACK_IMPORTED_MODULE_0___default().isArray(value)) {
|
|
2537
|
+
return fastMerge(value, value);
|
|
2482
2538
|
}
|
|
2483
2539
|
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
return objectWithoutNullObjectValues;
|
|
2540
|
+
return value;
|
|
2487
2541
|
}
|
|
2488
2542
|
|
|
2489
|
-
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
|
|
2543
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ areObjectsEmpty, fastMerge, removeNestedNullValues });
|
|
2490
2544
|
|
|
2491
2545
|
/***/ }),
|
|
2492
2546
|
|