react-native-onyx 1.0.38 → 1.0.39

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/lib/Onyx.js CHANGED
@@ -1047,55 +1047,46 @@ function initializeWithDefaultKeyStates() {
1047
1047
  function clear(keysToPreserve = []) {
1048
1048
  return getAllKeys()
1049
1049
  .then((keys) => {
1050
- const keyValuesToReset = [];
1051
- const defaultKeys = _.keys(defaultKeyStates);
1052
-
1053
- // Get all the values for the keys that need to be preserved. These key/value pairs will be set
1054
- // in Onyx after the database is cleared().
1055
- const keyValuesToPreserve = _.map(keysToPreserve, key => [key, cache.getValue(key)]);
1050
+ const keysToBeClearedFromStorage = [];
1051
+ const keyValuesToResetAsCollection = {};
1052
+ const keyValuesToResetIndividually = {};
1056
1053
 
1057
1054
  // The only keys that should not be cleared are:
1058
1055
  // 1. Anything specifically passed in keysToPreserve (because some keys like language preferences, offline
1059
1056
  // status, or activeClients need to remain in Onyx even when signed out)
1060
1057
  // 2. Any keys with a default state (because they need to remain in Onyx as their default, and setting them
1061
1058
  // to null would cause unknown behavior)
1062
- const keysToClear = _.difference(keys, keysToPreserve, defaultKeys);
1063
- keyValuesToReset.push(..._.map(keysToClear, key => [key, null]));
1064
-
1065
- // Remove any keysToPreserve from the defaultKeyStates because if they are passed in it has been explicitly
1066
- // called out to preserve those values instead of resetting them back
1067
- // to the default.
1068
- const defaultKeyValuePairs = _.pairs(_.omit(defaultKeyStates, ...keysToPreserve));
1069
-
1070
- // Add the default key value pairs to the keyValuesToReset so that they get set back to their default values
1071
- // when we clear Onyx
1072
- keyValuesToReset.push(...defaultKeyValuePairs);
1073
-
1074
- // We now have all the key/values that need to be reset, but we're not done yet!
1075
- // There will be two groups of key/values and they each need to be updated a little bit differently.
1076
- // Collection keys need to be notified differently than non collection keys
1077
- const keyValuesToResetAsCollection = {};
1078
- const keyValuesToResetIndividually = {};
1079
-
1080
- // Make sure that we also reset the cache values before clearing the values from storage.
1081
- // We do this before clearing Storage so that any call to clear() followed by merge() on a key with a
1082
- // default state results in the merged value getting saved, since the update from the merge() call would
1083
- // happen on the tick after the update from this clear()
1084
- _.each(keyValuesToReset, (keyValue) => {
1085
- const key = keyValue[0];
1086
- const value = keyValue[1];
1087
- cache.set(key, value);
1088
-
1089
- const collectionKey = key.substring(0, key.indexOf('_') + 1);
1090
- if (collectionKey) {
1091
- if (!keyValuesToResetAsCollection[collectionKey]) {
1092
- keyValuesToResetAsCollection[collectionKey] = {};
1059
+ _.each(keys, (key) => {
1060
+ const isKeyToPreserve = _.contains(keysToPreserve, key);
1061
+ const isDefaultKey = _.has(defaultKeyStates, key);
1062
+
1063
+ // If the key is being removed or reset to default:
1064
+ // 1. Update it in the cache
1065
+ // 2. Figure out whether it is a collection key or not,
1066
+ // since collection key subscribers need to be updated differently
1067
+ if (!isKeyToPreserve) {
1068
+ const oldValue = cache.getValue(key);
1069
+ const newValue = _.get(defaultKeyStates, key, null);
1070
+ if (newValue !== oldValue) {
1071
+ cache.set(key, newValue);
1072
+ const collectionKey = key.substring(0, key.indexOf('_') + 1);
1073
+ if (collectionKey) {
1074
+ if (!keyValuesToResetAsCollection[collectionKey]) {
1075
+ keyValuesToResetAsCollection[collectionKey] = {};
1076
+ }
1077
+ keyValuesToResetAsCollection[collectionKey][key] = newValue;
1078
+ } else {
1079
+ keyValuesToResetIndividually[key] = newValue;
1080
+ }
1093
1081
  }
1094
- keyValuesToResetAsCollection[collectionKey][key] = value;
1082
+ }
1083
+
1084
+ if (isKeyToPreserve || isDefaultKey) {
1095
1085
  return;
1096
1086
  }
1097
1087
 
1098
- keyValuesToResetIndividually[key] = value;
1088
+ // If it isn't preserved and doesn't have a default, we'll remove it
1089
+ keysToBeClearedFromStorage.push(key);
1099
1090
  });
1100
1091
 
1101
1092
  // Notify the subscribers for each key/value group so they can receive the new values
@@ -1106,11 +1097,10 @@ function clear(keysToPreserve = []) {
1106
1097
  notifyCollectionSubscribersOnNextTick(key, value);
1107
1098
  });
1108
1099
 
1109
- // Call clear() and make sure that the default key/values and the key/values from the parameter
1110
- // are preserved in storage. This makes sure to always leave storage in a state that contains
1111
- // all the default values and any additional values that we want to remain after the database is cleared.
1112
- return Storage.clear()
1113
- .then(() => Storage.multiSet([...defaultKeyValuePairs, ...keyValuesToPreserve]));
1100
+ const defaultKeyValuePairs = _.pairs(_.omit(defaultKeyStates, keysToPreserve));
1101
+
1102
+ // Remove only the items that we want cleared from storage, and reset others to default
1103
+ return Storage.removeItems(keysToBeClearedFromStorage).then(() => Storage.multiSet(defaultKeyValuePairs));
1114
1104
  });
1115
1105
  }
1116
1106
 
@@ -17,6 +17,12 @@ function raiseStorageSyncEvent(onyxKey) {
17
17
  global.localStorage.removeItem(SYNC_ONYX, onyxKey);
18
18
  }
19
19
 
20
+ function raiseStorageSyncManyKeysEvent(onyxKeys) {
21
+ _.each(onyxKeys, (onyxKey) => {
22
+ raiseStorageSyncEvent(onyxKey);
23
+ });
24
+ }
25
+
20
26
  const webStorage = {
21
27
  ...Storage,
22
28
 
@@ -31,6 +37,9 @@ const webStorage = {
31
37
  this.removeItem = key => Storage.removeItem(key)
32
38
  .then(() => raiseStorageSyncEvent(key));
33
39
 
40
+ this.removeItems = keys => Storage.removeItems(keys)
41
+ .then(() => raiseStorageSyncManyKeysEvent(keys));
42
+
34
43
  // If we just call Storage.clear other tabs will have no idea which keys were available previously
35
44
  // so that they can call keysChanged for them. That's why we iterate over every key and raise a storage sync
36
45
  // event for each one
@@ -73,6 +73,13 @@ const provider = {
73
73
  */
74
74
  removeItem: AsyncStorage.removeItem,
75
75
 
76
+ /**
77
+ * Remove given keys and their values from storage
78
+ * @param {Array} keys
79
+ * @returns {Promise}
80
+ */
81
+ removeItems: keys => Promise.all(_.map(keys, key => AsyncStorage.removeItem(key))),
82
+
76
83
  /**
77
84
  * Clear everything from storage
78
85
  * @returns {Promise<void>}
@@ -6,9 +6,12 @@
6
6
 
7
7
  import localforage from 'localforage';
8
8
  import _ from 'underscore';
9
+ import {extendPrototype} from 'localforage-removeitems';
9
10
  import SyncQueue from '../../SyncQueue';
10
11
  import fastMerge from '../../fastMerge';
11
12
 
13
+ extendPrototype(localforage);
14
+
12
15
  localforage.config({
13
16
  name: 'OnyxDB',
14
17
  });
@@ -103,6 +106,16 @@ const provider = {
103
106
  */
104
107
  removeItem: localforage.removeItem,
105
108
 
109
+ /**
110
+ * Remove given keys and their values from storage
111
+ *
112
+ * @param {Array} keys
113
+ * @returns {Promise}
114
+ */
115
+ removeItems(keys) {
116
+ return localforage.removeItems(keys);
117
+ },
118
+
106
119
  /**
107
120
  * Sets the value for a given key. The only requirement is that the value should be serializable to JSON string
108
121
  * @param {String} key
@@ -111,6 +111,18 @@ const provider = {
111
111
  */
112
112
  removeItem: key => db.executeAsync('DELETE FROM keyvaluepairs WHERE record_key = ?;', [key]),
113
113
 
114
+ /**
115
+ * Removes given keys and their values from storage
116
+ *
117
+ * @param {Array<String>} keys
118
+ * @returns {Promise<void>}
119
+ */
120
+ removeItems: (keys) => {
121
+ const placeholders = _.map(keys, () => '?').join(',');
122
+ const query = `DELETE FROM keyvaluepairs WHERE record_key IN (${placeholders});`;
123
+ return db.executeAsync(query, keys);
124
+ },
125
+
114
126
  /**
115
127
  * Clears absolutely everything from storage
116
128
  * @returns {Promise<void>}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",
@@ -79,6 +79,7 @@
79
79
  "@react-native-async-storage/async-storage": "^1.17.11",
80
80
  "expensify-common": ">=1",
81
81
  "localforage": "^1.10.0",
82
+ "localforage-removeitems": "^1.4.0",
82
83
  "react": ">=18.1.0",
83
84
  "react-native-performance": "^4.0.0",
84
85
  "react-native-quick-sqlite": "^8.0.0-beta.2"
@@ -95,6 +96,9 @@
95
96
  },
96
97
  "localforage": {
97
98
  "optional": true
99
+ },
100
+ "localforage-removeitems": {
101
+ "optional": true
98
102
  }
99
103
  },
100
104
  "engines": {