react-native-onyx 1.0.94 → 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.
@@ -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
- const valueWithNullRemoved = _utils__WEBPACK_IMPORTED_MODULE_9__["default"].removeNullObjectValues(value);
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
- let batchedChanges = applyMerge(undefined, mergeQueue[key]);
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
- const updatedValue = shouldOverwriteExistingValue ? batchedChanges : applyMerge(existingValue, [batchedChanges]);
1259
- const modifiedData = _utils__WEBPACK_IMPORTED_MODULE_9__["default"].removeNullObjectValues(updatedValue);
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 top-level nullish values won't be removed.
1264
- // Therefore we need to remove nullish values from the `batchedChanges` which are sent to the SQLite, if no existing value is present.
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 = _utils__WEBPACK_IMPORTED_MODULE_9__["default"].removeNullObjectValues(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);
@@ -2291,7 +2300,7 @@ const provider = {
2291
2300
  const upsertMany = underscore__WEBPACK_IMPORTED_MODULE_1___default().map(pairs, (_ref2, index) => {let [key, value] = _ref2;
2292
2301
  const prev = values[index];
2293
2302
  const newValue = underscore__WEBPACK_IMPORTED_MODULE_1___default().isObject(prev) ? _utils__WEBPACK_IMPORTED_MODULE_2__["default"].fastMerge(prev, value) : value;
2294
- return (0,idb_keyval__WEBPACK_IMPORTED_MODULE_0__.promisifyRequest)(store.put(_utils__WEBPACK_IMPORTED_MODULE_2__["default"].removeNullObjectValues(newValue), key));
2303
+ return (0,idb_keyval__WEBPACK_IMPORTED_MODULE_0__.promisifyRequest)(store.put(newValue, key));
2295
2304
  });
2296
2305
  return Promise.all(upsertMany);
2297
2306
  });
@@ -2396,8 +2405,8 @@ function areObjectsEmpty(a, b) {
2396
2405
  return (
2397
2406
  typeof a === 'object' &&
2398
2407
  typeof b === 'object' &&
2399
- underscore__WEBPACK_IMPORTED_MODULE_0__.isEmpty(a) &&
2400
- underscore__WEBPACK_IMPORTED_MODULE_0__.isEmpty(b));
2408
+ underscore__WEBPACK_IMPORTED_MODULE_0___default().isEmpty(a) &&
2409
+ underscore__WEBPACK_IMPORTED_MODULE_0___default().isEmpty(b));
2401
2410
 
2402
2411
  }
2403
2412
 
@@ -2417,9 +2426,12 @@ function isMergeableObject(val) {
2417
2426
  /**
2418
2427
  * @param {Object} target
2419
2428
  * @param {Object} source
2429
+ * @param {Boolean} shouldRemoveNullObjectValues
2420
2430
  * @returns {Object}
2421
2431
  */
2422
- 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
+
2423
2435
  const destination = {};
2424
2436
  if (isMergeableObject(target)) {
2425
2437
  // lodash adds a small overhead so we don't use it here
@@ -2427,6 +2439,13 @@ function mergeObject(target, source) {
2427
2439
  const targetKeys = Object.keys(target);
2428
2440
  for (let i = 0; i < targetKeys.length; ++i) {
2429
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
+
2430
2449
  destination[key] = target[key];
2431
2450
  }
2432
2451
  }
@@ -2436,15 +2455,22 @@ function mergeObject(target, source) {
2436
2455
  const sourceKeys = Object.keys(source);
2437
2456
  for (let i = 0; i < sourceKeys.length; ++i) {
2438
2457
  const key = sourceKeys[i];
2439
- if (source[key] === undefined) {
2458
+
2459
+ // If shouldRemoveNullObjectValues is true, we want to remove null values from the merged object
2460
+ if (shouldRemoveNullObjectValues && source[key] === null) {
2440
2461
  // eslint-disable-next-line no-continue
2441
2462
  continue;
2442
2463
  }
2464
+
2443
2465
  if (!isMergeableObject(source[key]) || !target[key]) {
2466
+ if (targetAndSourceIdentical) {
2467
+ // eslint-disable-next-line no-continue
2468
+ continue;
2469
+ }
2444
2470
  destination[key] = source[key];
2445
2471
  } else {
2446
2472
  // eslint-disable-next-line no-use-before-define
2447
- destination[key] = fastMerge(target[key], source[key]);
2473
+ destination[key] = fastMerge(target[key], source[key], shouldRemoveNullObjectValues);
2448
2474
  }
2449
2475
  }
2450
2476
 
@@ -2452,41 +2478,28 @@ function mergeObject(target, source) {
2452
2478
  }
2453
2479
 
2454
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
+ *
2455
2487
  * @param {Object|Array} target
2456
2488
  * @param {Object|Array} source
2489
+ * @param {Boolean} shouldRemoveNullObjectValues
2457
2490
  * @returns {Object|Array}
2458
2491
  */
2459
- function fastMerge(target, source) {
2492
+ function fastMerge(target, source) {let shouldRemoveNullObjectValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
2460
2493
  // We have to ignore arrays and nullish values here,
2461
2494
  // otherwise "mergeObject" will throw an error,
2462
2495
  // because it expects an object as "source"
2463
- if (underscore__WEBPACK_IMPORTED_MODULE_0__.isArray(source) || underscore__WEBPACK_IMPORTED_MODULE_0__.isNull(source) || underscore__WEBPACK_IMPORTED_MODULE_0__.isUndefined(source)) {
2496
+ if (underscore__WEBPACK_IMPORTED_MODULE_0___default().isArray(source) || source === null || source === undefined) {
2464
2497
  return source;
2465
2498
  }
2466
- return mergeObject(target, source);
2467
- }
2468
-
2469
- /**
2470
- * 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.
2471
- * On native, when merging an existing value with new changes, SQLite will use JSON_PATCH, which removes top-level nullish values.
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;
2482
- }
2483
-
2484
- const objectWithoutNullObjectValues = underscore__WEBPACK_IMPORTED_MODULE_0__.omit(value, (objectValue) => underscore__WEBPACK_IMPORTED_MODULE_0__.isNull(objectValue));
2485
-
2486
- return objectWithoutNullObjectValues;
2499
+ return mergeObject(target, source, shouldRemoveNullObjectValues);
2487
2500
  }
2488
2501
 
2489
- /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ removeNullObjectValues, areObjectsEmpty, fastMerge });
2502
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ areObjectsEmpty, fastMerge });
2490
2503
 
2491
2504
  /***/ }),
2492
2505