react-native-onyx 1.0.93 → 1.0.95
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 +63 -46
- 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.d.ts +5 -9
- package/lib/Onyx.js +18 -9
- package/lib/OnyxCache.js +11 -7
- package/lib/storage/providers/IDBKeyVal.js +1 -1
- package/lib/types.d.ts +38 -19
- package/lib/utils.js +32 -28
- package/package.json +1 -1
package/dist/web.development.js
CHANGED
|
@@ -1124,7 +1124,13 @@ function set(key, value) {
|
|
|
1124
1124
|
_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
1125
|
}
|
|
1126
1126
|
|
|
1127
|
-
|
|
1127
|
+
// We can remove all null values in an object by merging it with itself
|
|
1128
|
+
// utils.fastMerge recursively goes through the object and removes all null values
|
|
1129
|
+
// Passing two identical objects as source and target to fastMerge will not change it, but only remove the null values
|
|
1130
|
+
let valueWithNullRemoved = value;
|
|
1131
|
+
if (typeof value === 'object' && !underscore__WEBPACK_IMPORTED_MODULE_1___default().isArray(value)) {
|
|
1132
|
+
valueWithNullRemoved = _utils__WEBPACK_IMPORTED_MODULE_9__["default"].fastMerge(value, value);
|
|
1133
|
+
}
|
|
1128
1134
|
|
|
1129
1135
|
const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, valueWithNullRemoved);
|
|
1130
1136
|
|
|
@@ -1181,9 +1187,10 @@ function multiSet(data) {
|
|
|
1181
1187
|
* @private
|
|
1182
1188
|
* @param {*} existingValue
|
|
1183
1189
|
* @param {Array<*>} changes Array of changes that should be applied to the existing value
|
|
1190
|
+
* @param {Boolean} shouldRemoveNullObjectValues
|
|
1184
1191
|
* @returns {*}
|
|
1185
1192
|
*/
|
|
1186
|
-
function applyMerge(existingValue, changes) {
|
|
1193
|
+
function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
|
|
1187
1194
|
const lastChange = underscore__WEBPACK_IMPORTED_MODULE_1___default().last(changes);
|
|
1188
1195
|
|
|
1189
1196
|
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isArray(lastChange)) {
|
|
@@ -1192,7 +1199,7 @@ function applyMerge(existingValue, changes) {
|
|
|
1192
1199
|
|
|
1193
1200
|
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().some(changes, (underscore__WEBPACK_IMPORTED_MODULE_1___default().isObject))) {
|
|
1194
1201
|
// 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),
|
|
1202
|
+
return underscore__WEBPACK_IMPORTED_MODULE_1___default().reduce(changes, (modifiedData, change) => _utils__WEBPACK_IMPORTED_MODULE_9__["default"].fastMerge(modifiedData, change, shouldRemoveNullObjectValues),
|
|
1196
1203
|
existingValue || {});
|
|
1197
1204
|
}
|
|
1198
1205
|
|
|
@@ -1240,7 +1247,8 @@ function merge(key, changes) {
|
|
|
1240
1247
|
then((existingValue) => {
|
|
1241
1248
|
try {
|
|
1242
1249
|
// 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
|
-
|
|
1250
|
+
// We don't want to remove null values from the "batchedChanges", because SQLite uses them to remove keys from storage natively.
|
|
1251
|
+
let batchedChanges = applyMerge(undefined, mergeQueue[key], false);
|
|
1244
1252
|
|
|
1245
1253
|
if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isNull(batchedChanges)) {
|
|
1246
1254
|
return remove(key);
|
|
@@ -1255,15 +1263,16 @@ function merge(key, changes) {
|
|
|
1255
1263
|
delete mergeQueuePromise[key];
|
|
1256
1264
|
|
|
1257
1265
|
// After that we merge the batched changes with the existing value
|
|
1258
|
-
|
|
1259
|
-
|
|
1266
|
+
// We can remove null values from the "modifiedData", because "null" implicates that the user wants to remove a value from storage.
|
|
1267
|
+
// The "modifiedData" will be directly "set" in storage instead of being merged
|
|
1268
|
+
const modifiedData = shouldOverwriteExistingValue ? batchedChanges : applyMerge(existingValue, [batchedChanges], true);
|
|
1260
1269
|
|
|
1261
1270
|
// On native platforms we use SQLite which utilises JSON_PATCH to merge changes.
|
|
1262
1271
|
// JSON_PATCH generally removes top-level nullish values from the stored object.
|
|
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
|
|
1272
|
+
// 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.
|
|
1273
|
+
// Therefore we need to remove null values from the `batchedChanges` which are sent to the SQLite, if no existing value is present.
|
|
1265
1274
|
if (!existingValue) {
|
|
1266
|
-
batchedChanges =
|
|
1275
|
+
batchedChanges = applyMerge(undefined, mergeQueue[key], true);
|
|
1267
1276
|
}
|
|
1268
1277
|
|
|
1269
1278
|
const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, modifiedData);
|
|
@@ -1719,9 +1728,11 @@ class OnyxCache {
|
|
|
1719
1728
|
/**
|
|
1720
1729
|
* @private
|
|
1721
1730
|
* Captured pending tasks for already running storage methods
|
|
1722
|
-
*
|
|
1731
|
+
* Using a map yields better performance on operations such a delete
|
|
1732
|
+
* https://www.zhenghao.io/posts/object-vs-map
|
|
1733
|
+
* @type {Map<string, Promise>}
|
|
1723
1734
|
*/
|
|
1724
|
-
this.pendingPromises =
|
|
1735
|
+
this.pendingPromises = new Map();
|
|
1725
1736
|
|
|
1726
1737
|
// bind all public methods to prevent problems with `this`
|
|
1727
1738
|
underscore__WEBPACK_IMPORTED_MODULE_0___default().bindAll(
|
|
@@ -1818,7 +1829,7 @@ class OnyxCache {
|
|
|
1818
1829
|
* @returns {*}
|
|
1819
1830
|
*/
|
|
1820
1831
|
hasPendingTask(taskName) {
|
|
1821
|
-
return isDefined(this.pendingPromises
|
|
1832
|
+
return isDefined(this.pendingPromises.get(taskName));
|
|
1822
1833
|
}
|
|
1823
1834
|
|
|
1824
1835
|
/**
|
|
@@ -1830,7 +1841,7 @@ class OnyxCache {
|
|
|
1830
1841
|
* @returns {Promise<T>}
|
|
1831
1842
|
*/
|
|
1832
1843
|
getTaskPromise(taskName) {
|
|
1833
|
-
return this.pendingPromises
|
|
1844
|
+
return this.pendingPromises.get(taskName);
|
|
1834
1845
|
}
|
|
1835
1846
|
|
|
1836
1847
|
/**
|
|
@@ -1842,11 +1853,13 @@ class OnyxCache {
|
|
|
1842
1853
|
* @returns {Promise<T>}
|
|
1843
1854
|
*/
|
|
1844
1855
|
captureTask(taskName, promise) {
|
|
1845
|
-
|
|
1846
|
-
|
|
1856
|
+
const returnPromise = promise.finally(() => {
|
|
1857
|
+
this.pendingPromises.delete(taskName);
|
|
1847
1858
|
});
|
|
1848
1859
|
|
|
1849
|
-
|
|
1860
|
+
this.pendingPromises.set(taskName, returnPromise);
|
|
1861
|
+
|
|
1862
|
+
return returnPromise;
|
|
1850
1863
|
}
|
|
1851
1864
|
|
|
1852
1865
|
/**
|
|
@@ -2287,7 +2300,7 @@ const provider = {
|
|
|
2287
2300
|
const upsertMany = underscore__WEBPACK_IMPORTED_MODULE_1___default().map(pairs, (_ref2, index) => {let [key, value] = _ref2;
|
|
2288
2301
|
const prev = values[index];
|
|
2289
2302
|
const newValue = underscore__WEBPACK_IMPORTED_MODULE_1___default().isObject(prev) ? _utils__WEBPACK_IMPORTED_MODULE_2__["default"].fastMerge(prev, value) : value;
|
|
2290
|
-
return (0,idb_keyval__WEBPACK_IMPORTED_MODULE_0__.promisifyRequest)(store.put(
|
|
2303
|
+
return (0,idb_keyval__WEBPACK_IMPORTED_MODULE_0__.promisifyRequest)(store.put(newValue, key));
|
|
2291
2304
|
});
|
|
2292
2305
|
return Promise.all(upsertMany);
|
|
2293
2306
|
});
|
|
@@ -2392,8 +2405,8 @@ function areObjectsEmpty(a, b) {
|
|
|
2392
2405
|
return (
|
|
2393
2406
|
typeof a === 'object' &&
|
|
2394
2407
|
typeof b === 'object' &&
|
|
2395
|
-
|
|
2396
|
-
|
|
2408
|
+
underscore__WEBPACK_IMPORTED_MODULE_0___default().isEmpty(a) &&
|
|
2409
|
+
underscore__WEBPACK_IMPORTED_MODULE_0___default().isEmpty(b));
|
|
2397
2410
|
|
|
2398
2411
|
}
|
|
2399
2412
|
|
|
@@ -2413,9 +2426,12 @@ function isMergeableObject(val) {
|
|
|
2413
2426
|
/**
|
|
2414
2427
|
* @param {Object} target
|
|
2415
2428
|
* @param {Object} source
|
|
2429
|
+
* @param {Boolean} shouldRemoveNullObjectValues
|
|
2416
2430
|
* @returns {Object}
|
|
2417
2431
|
*/
|
|
2418
|
-
function mergeObject(target, source) {
|
|
2432
|
+
function mergeObject(target, source) {let shouldRemoveNullObjectValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
2433
|
+
const targetAndSourceIdentical = target === source;
|
|
2434
|
+
|
|
2419
2435
|
const destination = {};
|
|
2420
2436
|
if (isMergeableObject(target)) {
|
|
2421
2437
|
// lodash adds a small overhead so we don't use it here
|
|
@@ -2423,6 +2439,13 @@ function mergeObject(target, source) {
|
|
|
2423
2439
|
const targetKeys = Object.keys(target);
|
|
2424
2440
|
for (let i = 0; i < targetKeys.length; ++i) {
|
|
2425
2441
|
const key = targetKeys[i];
|
|
2442
|
+
|
|
2443
|
+
// If shouldRemoveNullObjectValues is true, we want to remove null values from the merged object
|
|
2444
|
+
if (shouldRemoveNullObjectValues && (target[key] === null || source[key] === null)) {
|
|
2445
|
+
// eslint-disable-next-line no-continue
|
|
2446
|
+
continue;
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2426
2449
|
destination[key] = target[key];
|
|
2427
2450
|
}
|
|
2428
2451
|
}
|
|
@@ -2432,15 +2455,22 @@ function mergeObject(target, source) {
|
|
|
2432
2455
|
const sourceKeys = Object.keys(source);
|
|
2433
2456
|
for (let i = 0; i < sourceKeys.length; ++i) {
|
|
2434
2457
|
const key = sourceKeys[i];
|
|
2435
|
-
|
|
2458
|
+
|
|
2459
|
+
// If shouldRemoveNullObjectValues is true, we want to remove null values from the merged object
|
|
2460
|
+
if (shouldRemoveNullObjectValues && source[key] === null) {
|
|
2436
2461
|
// eslint-disable-next-line no-continue
|
|
2437
2462
|
continue;
|
|
2438
2463
|
}
|
|
2464
|
+
|
|
2439
2465
|
if (!isMergeableObject(source[key]) || !target[key]) {
|
|
2466
|
+
if (targetAndSourceIdentical) {
|
|
2467
|
+
// eslint-disable-next-line no-continue
|
|
2468
|
+
continue;
|
|
2469
|
+
}
|
|
2440
2470
|
destination[key] = source[key];
|
|
2441
2471
|
} else {
|
|
2442
2472
|
// eslint-disable-next-line no-use-before-define
|
|
2443
|
-
destination[key] = fastMerge(target[key], source[key]);
|
|
2473
|
+
destination[key] = fastMerge(target[key], source[key], shouldRemoveNullObjectValues);
|
|
2444
2474
|
}
|
|
2445
2475
|
}
|
|
2446
2476
|
|
|
@@ -2448,41 +2478,28 @@ function mergeObject(target, source) {
|
|
|
2448
2478
|
}
|
|
2449
2479
|
|
|
2450
2480
|
/**
|
|
2481
|
+
* Merges two objects and removes null values if "shouldRemoveNullObjectValues" is set to true
|
|
2482
|
+
*
|
|
2483
|
+
* 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.
|
|
2484
|
+
* On native, when merging an existing value with new changes, SQLite will use JSON_PATCH, which removes top-level nullish values.
|
|
2485
|
+
* To be consistent with the behaviour for merge, we'll also want to remove null values for "set" operations.
|
|
2486
|
+
*
|
|
2451
2487
|
* @param {Object|Array} target
|
|
2452
2488
|
* @param {Object|Array} source
|
|
2489
|
+
* @param {Boolean} shouldRemoveNullObjectValues
|
|
2453
2490
|
* @returns {Object|Array}
|
|
2454
2491
|
*/
|
|
2455
|
-
function fastMerge(target, source) {
|
|
2492
|
+
function fastMerge(target, source) {let shouldRemoveNullObjectValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
2456
2493
|
// We have to ignore arrays and nullish values here,
|
|
2457
2494
|
// otherwise "mergeObject" will throw an error,
|
|
2458
2495
|
// because it expects an object as "source"
|
|
2459
|
-
if (
|
|
2496
|
+
if (underscore__WEBPACK_IMPORTED_MODULE_0___default().isArray(source) || source === null || source === undefined) {
|
|
2460
2497
|
return source;
|
|
2461
2498
|
}
|
|
2462
|
-
return mergeObject(target, source);
|
|
2463
|
-
}
|
|
2464
|
-
|
|
2465
|
-
/**
|
|
2466
|
-
* We generally want to remove top-level nullish values from objects written to disk and cache, because it decreases the amount of data stored in memory and on disk.
|
|
2467
|
-
* On native, when merging an existing value with new changes, SQLite will use JSON_PATCH, which removes top-level nullish values.
|
|
2468
|
-
* To be consistent with the behaviour for merge, we'll also want to remove nullish values for "set" operations.
|
|
2469
|
-
* On web, IndexedDB will keep the top-level keys along with a null value and this uses up storage and memory.
|
|
2470
|
-
* 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.
|
|
2471
|
-
* @private
|
|
2472
|
-
* @param {*} value
|
|
2473
|
-
* @returns {*}
|
|
2474
|
-
*/
|
|
2475
|
-
function removeNullObjectValues(value) {
|
|
2476
|
-
if (underscore__WEBPACK_IMPORTED_MODULE_0__.isArray(value) || !underscore__WEBPACK_IMPORTED_MODULE_0__.isObject(value)) {
|
|
2477
|
-
return value;
|
|
2478
|
-
}
|
|
2479
|
-
|
|
2480
|
-
const objectWithoutNullObjectValues = underscore__WEBPACK_IMPORTED_MODULE_0__.omit(value, (objectValue) => underscore__WEBPACK_IMPORTED_MODULE_0__.isNull(objectValue));
|
|
2481
|
-
|
|
2482
|
-
return objectWithoutNullObjectValues;
|
|
2499
|
+
return mergeObject(target, source, shouldRemoveNullObjectValues);
|
|
2483
2500
|
}
|
|
2484
2501
|
|
|
2485
|
-
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
|
|
2502
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ areObjectsEmpty, fastMerge });
|
|
2486
2503
|
|
|
2487
2504
|
/***/ }),
|
|
2488
2505
|
|