react-native-onyx 1.0.121 → 1.0.123

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/README.md CHANGED
@@ -410,5 +410,6 @@ To continuously work on Onyx we have to set up a task that copies content to par
410
410
 
411
411
  There are Playwright e2e tests implemented for the web. To run them:
412
412
 
413
+ - in the tests/e2e/app directory, run `npm install`
413
414
  - `npm run e2e` to run the e2e tests
414
415
  - or `npm run e2e-ui` to run the e2e tests in UI mode
@@ -1219,17 +1219,18 @@ function evictStorageAndRetry(error, onyxMethod) {for (var _len = arguments.leng
1219
1219
  *
1220
1220
  * @param {String} key
1221
1221
  * @param {*} value
1222
- * @param {Boolean} hasChanged
1223
1222
  * @param {String} method
1223
+ * @param {Boolean} hasChanged
1224
+ * @param {Boolean} wasRemoved
1224
1225
  * @returns {Promise}
1225
1226
  */
1226
- function broadcastUpdate(key, value, hasChanged, method) {
1227
+ function broadcastUpdate(key, value, method, hasChanged) {let wasRemoved = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
1227
1228
  // Logging properties only since values could be sensitive things we don't want to log
1228
1229
  _Logger__WEBPACK_IMPORTED_MODULE_6__.logInfo(`${method}() called for key: ${key}${underscore__WEBPACK_IMPORTED_MODULE_1___default().isObject(value) ? ` properties: ${underscore__WEBPACK_IMPORTED_MODULE_1___default().keys(value).join(',')}` : ''}`);
1229
1230
 
1230
1231
  // Update subscribers if the cached value has changed, or when the subscriber specifically requires
1231
1232
  // all updates regardless of value changes (indicated by initWithStoredValues set to false).
1232
- if (hasChanged) {
1233
+ if (hasChanged && !wasRemoved) {
1233
1234
  _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].set(key, value);
1234
1235
  } else {
1235
1236
  _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].addToAccessedKeys(key);
@@ -1251,18 +1252,18 @@ function hasPendingMergeForKey(key) {
1251
1252
  * Otherwise removes all nested null values in objects and returns the object
1252
1253
  * @param {String} key
1253
1254
  * @param {Mixed} value
1254
- * @returns {Mixed} `null` if the key got removed completely, otherwise the value without null values
1255
+ * @returns {Mixed} The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
1255
1256
  */
1256
1257
  function removeNullValues(key, value) {
1257
1258
  if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isNull(value)) {
1258
1259
  remove(key);
1259
- return null;
1260
+ return { value, wasRemoved: true };
1260
1261
  }
1261
1262
 
1262
1263
  // We can remove all null values in an object by merging it with itself
1263
1264
  // utils.fastMerge recursively goes through the object and removes all null values
1264
1265
  // Passing two identical objects as source and target to fastMerge will not change it, but only remove the null values
1265
- return _utils__WEBPACK_IMPORTED_MODULE_9__["default"].removeNestedNullValues(value);
1266
+ return { value: _utils__WEBPACK_IMPORTED_MODULE_9__["default"].removeNestedNullValues(value), wasRemoved: false };
1266
1267
  }
1267
1268
 
1268
1269
  /**
@@ -1283,41 +1284,48 @@ function set(key, value) {
1283
1284
  return Promise.resolve();
1284
1285
  }
1285
1286
 
1286
- const valueWithoutNull = removeNullValues(key, value);
1287
-
1288
- if (valueWithoutNull === null) {
1289
- return Promise.resolve();
1290
- }
1287
+ // If the value is null, we remove the key from storage
1288
+ const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value);
1291
1289
 
1292
1290
  if (hasPendingMergeForKey(key)) {
1293
- _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.`);
1291
+ delete mergeQueue[key];
1294
1292
  }
1295
1293
 
1296
- const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, valueWithoutNull);
1294
+ const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, valueAfterRemoving);
1297
1295
 
1298
1296
  // This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
1299
- const updatePromise = broadcastUpdate(key, valueWithoutNull, hasChanged, 'set');
1297
+ const updatePromise = broadcastUpdate(key, valueAfterRemoving, 'set', hasChanged, wasRemoved);
1300
1298
 
1301
- // If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
1302
- if (!hasChanged) {
1299
+ // If the value has not changed or the key got removed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
1300
+ if (!hasChanged || wasRemoved) {
1303
1301
  return updatePromise;
1304
1302
  }
1305
1303
 
1306
- return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].setItem(key, valueWithoutNull).
1307
- catch((error) => evictStorageAndRetry(error, set, key, valueWithoutNull)).
1304
+ return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].setItem(key, valueAfterRemoving).
1305
+ catch((error) => evictStorageAndRetry(error, set, key, valueAfterRemoving)).
1308
1306
  then(() => updatePromise);
1309
1307
  }
1310
1308
 
1311
1309
  /**
1312
1310
  * Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
1313
1311
  * This method transforms an object like {'@MyApp_user': myUserValue, '@MyApp_key': myKeyValue}
1314
- * to an array of key-value pairs in the above format
1312
+ * to an array of key-value pairs in the above format and removes key-value pairs that are being set to null
1315
1313
  * @private
1316
1314
  * @param {Record} data
1317
1315
  * @return {Array} an array of key - value pairs <[key, value]>
1318
1316
  */
1319
1317
  function prepareKeyValuePairsForStorage(data) {
1320
- return underscore__WEBPACK_IMPORTED_MODULE_1___default().map(data, (value, key) => [key, value]);
1318
+ const keyValuePairs = [];
1319
+
1320
+ underscore__WEBPACK_IMPORTED_MODULE_1___default().forEach(data, (value, key) => {
1321
+ const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value);
1322
+
1323
+ if (wasRemoved) return;
1324
+
1325
+ keyValuePairs.push([key, valueAfterRemoving]);
1326
+ });
1327
+
1328
+ return keyValuePairs;
1321
1329
  }
1322
1330
 
1323
1331
  /**
@@ -1340,25 +1348,13 @@ function multiSet(data) {
1340
1348
 
1341
1349
  const keyValuePairs = prepareKeyValuePairsForStorage(data);
1342
1350
 
1343
- const updatePromises = underscore__WEBPACK_IMPORTED_MODULE_1___default().map(data, (val, key) => {
1351
+ const updatePromises = underscore__WEBPACK_IMPORTED_MODULE_1___default().map(keyValuePairs, (_ref2) => {let [key, value] = _ref2;
1344
1352
  // Update cache and optimistically inform subscribers on the next tick
1345
- _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].set(key, val);
1346
- return scheduleSubscriberUpdate(key, val);
1353
+ _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].set(key, value);
1354
+ return scheduleSubscriberUpdate(key, value);
1347
1355
  });
1348
1356
 
1349
- const keyValuePairsWithoutNull = underscore__WEBPACK_IMPORTED_MODULE_1___default().filter(
1350
- underscore__WEBPACK_IMPORTED_MODULE_1___default().map(keyValuePairs, (_ref2) => {let [key, value] = _ref2;
1351
- const valueWithoutNull = removeNullValues(key, value);
1352
-
1353
- if (valueWithoutNull === null) {
1354
- return;
1355
- }
1356
- return [key, valueWithoutNull];
1357
- }),
1358
- Boolean);
1359
-
1360
-
1361
- return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].multiSet(keyValuePairsWithoutNull).
1357
+ return _storage__WEBPACK_IMPORTED_MODULE_5__["default"].multiSet(keyValuePairs).
1362
1358
  catch((error) => evictStorageAndRetry(error, multiSet, data)).
1363
1359
  then(() => Promise.all(updatePromises));
1364
1360
  }
@@ -1434,6 +1430,9 @@ function merge(key, changes) {
1434
1430
  mergeQueue[key] = [changes];
1435
1431
 
1436
1432
  mergeQueuePromise[key] = get(key).then((existingValue) => {
1433
+ // Calls to Onyx.set after a merge will terminate the current merge process and clear the merge queue
1434
+ if (mergeQueue[key] == null) return;
1435
+
1437
1436
  try {
1438
1437
  // 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)
1439
1438
  // We don't want to remove null values from the "batchedChanges", because SQLite uses them to remove keys from storage natively.
@@ -1448,10 +1447,7 @@ function merge(key, changes) {
1448
1447
  delete mergeQueuePromise[key];
1449
1448
 
1450
1449
  // If the batched changes equal null, we want to remove the key from storage, to reduce storage size
1451
- if (underscore__WEBPACK_IMPORTED_MODULE_1___default().isNull(batchedChanges)) {
1452
- remove(key);
1453
- return;
1454
- }
1450
+ const { wasRemoved } = removeNullValues(key, batchedChanges);
1455
1451
 
1456
1452
  // After that we merge the batched changes with the existing value
1457
1453
  // We can remove null values from the "modifiedData", because "null" implicates that the user wants to remove a value from storage.
@@ -1469,10 +1465,10 @@ function merge(key, changes) {
1469
1465
  const hasChanged = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].hasValueChanged(key, modifiedData);
1470
1466
 
1471
1467
  // This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
1472
- const updatePromise = broadcastUpdate(key, modifiedData, hasChanged, 'merge');
1468
+ const updatePromise = broadcastUpdate(key, modifiedData, 'merge', hasChanged, wasRemoved);
1473
1469
 
1474
1470
  // If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
1475
- if (!hasChanged || isClearing) {
1471
+ if (!hasChanged || isClearing || wasRemoved) {
1476
1472
  return updatePromise;
1477
1473
  }
1478
1474