react-native-onyx 2.0.27 → 2.0.29
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/API.md +85 -327
- package/dist/DevTools.d.ts +1 -1
- package/dist/Onyx.d.ts +7 -7
- package/dist/Onyx.js +21 -14
- package/dist/OnyxUtils.d.ts +107 -189
- package/dist/OnyxUtils.js +102 -264
- package/dist/PerformanceUtils.js +1 -1
- package/dist/storage/providers/NoopProvider.js +1 -3
- package/dist/storage/providers/types.d.ts +2 -2
- package/dist/types.d.ts +29 -17
- package/dist/useOnyx.js +1 -1
- package/package.json +8 -2
package/dist/OnyxUtils.js
CHANGED
|
@@ -26,9 +26,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
/* eslint-disable @typescript-eslint/prefer-for-of */
|
|
29
30
|
/* eslint-disable no-continue */
|
|
30
31
|
const fast_equals_1 = require("fast-equals");
|
|
31
|
-
const
|
|
32
|
+
const clone_1 = __importDefault(require("lodash/clone"));
|
|
32
33
|
const Logger = __importStar(require("./Logger"));
|
|
33
34
|
const OnyxCache_1 = __importDefault(require("./OnyxCache"));
|
|
34
35
|
const Str = __importStar(require("./Str"));
|
|
@@ -66,32 +67,24 @@ let batchUpdatesPromise = null;
|
|
|
66
67
|
let batchUpdatesQueue = [];
|
|
67
68
|
/**
|
|
68
69
|
* Getter - returns the merge queue.
|
|
69
|
-
*
|
|
70
|
-
* @returns {Object} The callback to state mapping.
|
|
71
70
|
*/
|
|
72
71
|
function getMergeQueue() {
|
|
73
72
|
return mergeQueue;
|
|
74
73
|
}
|
|
75
74
|
/**
|
|
76
75
|
* Getter - returns the merge queue promise.
|
|
77
|
-
*
|
|
78
|
-
* @returns {Object} The callback to state mapping.
|
|
79
76
|
*/
|
|
80
77
|
function getMergeQueuePromise() {
|
|
81
78
|
return mergeQueuePromise;
|
|
82
79
|
}
|
|
83
80
|
/**
|
|
84
81
|
* Getter - returns the callback to state mapping.
|
|
85
|
-
*
|
|
86
|
-
* @returns {Object} The callback to state mapping.
|
|
87
82
|
*/
|
|
88
83
|
function getCallbackToStateMapping() {
|
|
89
84
|
return callbackToStateMapping;
|
|
90
85
|
}
|
|
91
86
|
/**
|
|
92
87
|
* Getter - returns the default key states.
|
|
93
|
-
*
|
|
94
|
-
* @returns {Object} The callback to state mapping.
|
|
95
88
|
*/
|
|
96
89
|
function getDefaultKeyStates() {
|
|
97
90
|
return defaultKeyStates;
|
|
@@ -99,15 +92,16 @@ function getDefaultKeyStates() {
|
|
|
99
92
|
/**
|
|
100
93
|
* Sets the initial values for the Onyx store
|
|
101
94
|
*
|
|
102
|
-
* @param
|
|
103
|
-
* @param
|
|
104
|
-
* @param
|
|
95
|
+
* @param keys - `ONYXKEYS` constants object from Onyx.init()
|
|
96
|
+
* @param initialKeyStates - initial data to set when `init()` and `clear()` are called
|
|
97
|
+
* @param safeEvictionKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
|
|
105
98
|
*/
|
|
106
99
|
function initStoreValues(keys, initialKeyStates, safeEvictionKeys) {
|
|
100
|
+
var _a;
|
|
107
101
|
// We need the value of the collection keys later for checking if a
|
|
108
102
|
// key is a collection. We store it in a map for faster lookup.
|
|
109
|
-
const collectionValues =
|
|
110
|
-
onyxCollectionKeyMap =
|
|
103
|
+
const collectionValues = Object.values((_a = keys.COLLECTION) !== null && _a !== void 0 ? _a : {});
|
|
104
|
+
onyxCollectionKeyMap = collectionValues.reduce((acc, val) => {
|
|
111
105
|
acc.set(val, true);
|
|
112
106
|
return acc;
|
|
113
107
|
}, new Map());
|
|
@@ -117,14 +111,6 @@ function initStoreValues(keys, initialKeyStates, safeEvictionKeys) {
|
|
|
117
111
|
// Let Onyx know about which keys are safe to evict
|
|
118
112
|
evictionAllowList = safeEvictionKeys;
|
|
119
113
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Sends an action to DevTools extension
|
|
122
|
-
*
|
|
123
|
-
* @param {string} method - Onyx method from METHOD
|
|
124
|
-
* @param {string} key - Onyx key that was changed
|
|
125
|
-
* @param {any} value - contains the change that was made by the method
|
|
126
|
-
* @param {any} mergedValue - (optional) value that was written in the storage after a merge method was executed.
|
|
127
|
-
*/
|
|
128
114
|
function sendActionToDevTools(method, key, value, mergedValue = undefined) {
|
|
129
115
|
DevTools_1.default.registerAction(utils_1.default.formatActionName(method, key), value, key ? { [key]: mergedValue || value } : value);
|
|
130
116
|
}
|
|
@@ -133,7 +119,6 @@ function sendActionToDevTools(method, key, value, mergedValue = undefined) {
|
|
|
133
119
|
* This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
|
|
134
120
|
* update operations. Instead of calling the subscribers for each update operation, we batch them together which will
|
|
135
121
|
* cause react to schedule the updates at once instead of after each other. This is mainly a performance optimization.
|
|
136
|
-
* @returns {Promise}
|
|
137
122
|
*/
|
|
138
123
|
function maybeFlushBatchUpdates() {
|
|
139
124
|
if (batchUpdatesPromise) {
|
|
@@ -162,35 +147,19 @@ function batchUpdates(updates) {
|
|
|
162
147
|
batchUpdatesQueue.push(updates);
|
|
163
148
|
return maybeFlushBatchUpdates();
|
|
164
149
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Uses a selector function to return a simplified version of sourceData
|
|
167
|
-
* @param {Mixed} sourceData
|
|
168
|
-
* @param {Function} selector Function that takes sourceData and returns a simplified version of it
|
|
169
|
-
* @param {Object} [withOnyxInstanceState]
|
|
170
|
-
* @returns {Mixed}
|
|
171
|
-
*/
|
|
172
|
-
const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => selector(sourceData, withOnyxInstanceState);
|
|
173
150
|
/**
|
|
174
151
|
* Takes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}})
|
|
175
152
|
* and runs it through a reducer function to return a subset of the data according to a selector.
|
|
176
153
|
* The resulting collection will only contain items that are returned by the selector.
|
|
177
|
-
* @param {Object} collection
|
|
178
|
-
* @param {String|Function} selector (see method docs for getSubsetOfData() for full details)
|
|
179
|
-
* @param {Object} [withOnyxInstanceState]
|
|
180
|
-
* @returns {Object}
|
|
181
|
-
*/
|
|
182
|
-
const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceState) => underscore_1.default.reduce(collection, (finalCollection, item, key) => {
|
|
183
|
-
// eslint-disable-next-line no-param-reassign
|
|
184
|
-
finalCollection[key] = getSubsetOfData(item, selector, withOnyxInstanceState);
|
|
185
|
-
return finalCollection;
|
|
186
|
-
}, {});
|
|
187
|
-
/**
|
|
188
|
-
* Get some data from the store
|
|
189
|
-
*
|
|
190
|
-
* @private
|
|
191
|
-
* @param {string} key
|
|
192
|
-
* @returns {Promise<*>}
|
|
193
154
|
*/
|
|
155
|
+
function reduceCollectionWithSelector(collection, selector, withOnyxInstanceState) {
|
|
156
|
+
return Object.entries(collection !== null && collection !== void 0 ? collection : {}).reduce((finalCollection, [key, item]) => {
|
|
157
|
+
// eslint-disable-next-line no-param-reassign
|
|
158
|
+
finalCollection[key] = selector(item, withOnyxInstanceState);
|
|
159
|
+
return finalCollection;
|
|
160
|
+
}, {});
|
|
161
|
+
}
|
|
162
|
+
/** Get some data from the store */
|
|
194
163
|
function get(key) {
|
|
195
164
|
// When we already have the value in cache - resolve right away
|
|
196
165
|
if (OnyxCache_1.default.hasCacheForKey(key)) {
|
|
@@ -210,11 +179,7 @@ function get(key) {
|
|
|
210
179
|
.catch((err) => Logger.logInfo(`Unable to get item from persistent storage. Key: ${key} Error: ${err}`));
|
|
211
180
|
return OnyxCache_1.default.captureTask(taskName, promise);
|
|
212
181
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Returns current key names stored in persisted storage
|
|
215
|
-
* @private
|
|
216
|
-
* @returns {Promise<Set<Key>>}
|
|
217
|
-
*/
|
|
182
|
+
/** Returns current key names stored in persisted storage */
|
|
218
183
|
function getAllKeys() {
|
|
219
184
|
// When we've already read stored keys, resolve right away
|
|
220
185
|
const storedKeys = OnyxCache_1.default.getAllKeys();
|
|
@@ -237,25 +202,17 @@ function getAllKeys() {
|
|
|
237
202
|
/**
|
|
238
203
|
* Checks to see if the a subscriber's supplied key
|
|
239
204
|
* is associated with a collection of keys.
|
|
240
|
-
*
|
|
241
|
-
* @param {String} key
|
|
242
|
-
* @returns {Boolean}
|
|
243
205
|
*/
|
|
244
206
|
function isCollectionKey(key) {
|
|
245
207
|
return onyxCollectionKeyMap.has(key);
|
|
246
208
|
}
|
|
247
|
-
/**
|
|
248
|
-
* @param {String} collectionKey
|
|
249
|
-
* @param {String} key
|
|
250
|
-
* @returns {Boolean}
|
|
251
|
-
*/
|
|
252
209
|
function isCollectionMemberKey(collectionKey, key) {
|
|
253
210
|
return Str.startsWith(key, collectionKey) && key.length > collectionKey.length;
|
|
254
211
|
}
|
|
255
212
|
/**
|
|
256
213
|
* Splits a collection member key into the collection key part and the ID part.
|
|
257
|
-
* @param
|
|
258
|
-
* @returns
|
|
214
|
+
* @param key - The collection member key to split.
|
|
215
|
+
* @returns A tuple where the first element is the collection part and the second element is the ID part.
|
|
259
216
|
*/
|
|
260
217
|
function splitCollectionMemberKey(key) {
|
|
261
218
|
const underscoreIndex = key.indexOf('_');
|
|
@@ -267,35 +224,19 @@ function splitCollectionMemberKey(key) {
|
|
|
267
224
|
/**
|
|
268
225
|
* Checks to see if a provided key is the exact configured key of our connected subscriber
|
|
269
226
|
* or if the provided key is a collection member key (in case our configured key is a "collection key")
|
|
270
|
-
*
|
|
271
|
-
* @private
|
|
272
|
-
* @param {String} configKey
|
|
273
|
-
* @param {String} key
|
|
274
|
-
* @return {Boolean}
|
|
275
227
|
*/
|
|
276
228
|
function isKeyMatch(configKey, key) {
|
|
277
229
|
return isCollectionKey(configKey) ? Str.startsWith(key, configKey) : configKey === key;
|
|
278
230
|
}
|
|
279
|
-
/**
|
|
280
|
-
* Checks to see if this key has been flagged as
|
|
281
|
-
* safe for removal.
|
|
282
|
-
*
|
|
283
|
-
* @private
|
|
284
|
-
* @param {String} testKey
|
|
285
|
-
* @returns {Boolean}
|
|
286
|
-
*/
|
|
231
|
+
/** Checks to see if this key has been flagged as safe for removal. */
|
|
287
232
|
function isSafeEvictionKey(testKey) {
|
|
288
|
-
return
|
|
233
|
+
return evictionAllowList.some((key) => isKeyMatch(key, testKey));
|
|
289
234
|
}
|
|
290
235
|
/**
|
|
291
236
|
* Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
|
|
292
237
|
* If the requested key is a collection, it will return an object with all the collection members.
|
|
293
|
-
*
|
|
294
|
-
* @param {String} key
|
|
295
|
-
* @param {Object} mapping
|
|
296
|
-
* @returns {Mixed}
|
|
297
238
|
*/
|
|
298
|
-
function tryGetCachedValue(key, mapping
|
|
239
|
+
function tryGetCachedValue(key, mapping) {
|
|
299
240
|
let val = OnyxCache_1.default.getValue(key);
|
|
300
241
|
if (isCollectionKey(key)) {
|
|
301
242
|
const allCacheKeys = OnyxCache_1.default.getAllKeys();
|
|
@@ -304,14 +245,8 @@ function tryGetCachedValue(key, mapping = {}) {
|
|
|
304
245
|
if (allCacheKeys.size === 0) {
|
|
305
246
|
return;
|
|
306
247
|
}
|
|
307
|
-
const matchingKeys =
|
|
308
|
-
|
|
309
|
-
if (!k.startsWith(key)) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
matchingKeys.push(k);
|
|
313
|
-
});
|
|
314
|
-
const values = underscore_1.default.reduce(matchingKeys, (finalObject, matchedKey) => {
|
|
248
|
+
const matchingKeys = Array.from(allCacheKeys).filter((k) => k.startsWith(key));
|
|
249
|
+
const values = matchingKeys.reduce((finalObject, matchedKey) => {
|
|
315
250
|
const cachedValue = OnyxCache_1.default.getValue(matchedKey);
|
|
316
251
|
if (cachedValue) {
|
|
317
252
|
// This is permissible because we're in the process of constructing the final object in a reduce function.
|
|
@@ -322,31 +257,25 @@ function tryGetCachedValue(key, mapping = {}) {
|
|
|
322
257
|
}, {});
|
|
323
258
|
val = values;
|
|
324
259
|
}
|
|
325
|
-
if (mapping.selector) {
|
|
260
|
+
if (mapping === null || mapping === void 0 ? void 0 : mapping.selector) {
|
|
326
261
|
const state = mapping.withOnyxInstance ? mapping.withOnyxInstance.state : undefined;
|
|
327
262
|
if (isCollectionKey(key)) {
|
|
328
263
|
return reduceCollectionWithSelector(val, mapping.selector, state);
|
|
329
264
|
}
|
|
330
|
-
return
|
|
265
|
+
return mapping.selector(val, state);
|
|
331
266
|
}
|
|
332
267
|
return val;
|
|
333
268
|
}
|
|
334
269
|
/**
|
|
335
270
|
* Remove a key from the recently accessed key list.
|
|
336
|
-
*
|
|
337
|
-
* @private
|
|
338
|
-
* @param {String} key
|
|
339
271
|
*/
|
|
340
272
|
function removeLastAccessedKey(key) {
|
|
341
|
-
recentlyAccessedKeys =
|
|
273
|
+
recentlyAccessedKeys = recentlyAccessedKeys.filter((recentlyAccessedKey) => recentlyAccessedKey !== key);
|
|
342
274
|
}
|
|
343
275
|
/**
|
|
344
276
|
* Add a key to the list of recently accessed keys. The least
|
|
345
277
|
* recently accessed key should be at the head and the most
|
|
346
278
|
* recently accessed key at the tail.
|
|
347
|
-
*
|
|
348
|
-
* @private
|
|
349
|
-
* @param {String} key
|
|
350
279
|
*/
|
|
351
280
|
function addLastAccessedKey(key) {
|
|
352
281
|
// Only specific keys belong in this list since we cannot remove an entire collection.
|
|
@@ -359,25 +288,16 @@ function addLastAccessedKey(key) {
|
|
|
359
288
|
/**
|
|
360
289
|
* Removes a key previously added to this list
|
|
361
290
|
* which will enable it to be deleted again.
|
|
362
|
-
*
|
|
363
|
-
* @private
|
|
364
|
-
* @param {String} key
|
|
365
|
-
* @param {Number} connectionID
|
|
366
291
|
*/
|
|
367
292
|
function removeFromEvictionBlockList(key, connectionID) {
|
|
368
|
-
|
|
293
|
+
var _a, _b, _c;
|
|
294
|
+
evictionBlocklist[key] = (_b = (_a = evictionBlocklist[key]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== connectionID)) !== null && _b !== void 0 ? _b : [];
|
|
369
295
|
// Remove the key if there are no more subscribers
|
|
370
|
-
if (evictionBlocklist[key].length === 0) {
|
|
296
|
+
if (((_c = evictionBlocklist[key]) === null || _c === void 0 ? void 0 : _c.length) === 0) {
|
|
371
297
|
delete evictionBlocklist[key];
|
|
372
298
|
}
|
|
373
299
|
}
|
|
374
|
-
/**
|
|
375
|
-
* Keys added to this list can never be deleted.
|
|
376
|
-
*
|
|
377
|
-
* @private
|
|
378
|
-
* @param {String} key
|
|
379
|
-
* @param {Number} connectionID
|
|
380
|
-
*/
|
|
300
|
+
/** Keys added to this list can never be deleted. */
|
|
381
301
|
function addToEvictionBlockList(key, connectionID) {
|
|
382
302
|
removeFromEvictionBlockList(key, connectionID);
|
|
383
303
|
if (!evictionBlocklist[key]) {
|
|
@@ -390,13 +310,10 @@ function addToEvictionBlockList(key, connectionID) {
|
|
|
390
310
|
* the recently accessed list when initializing the app. This
|
|
391
311
|
* enables keys that have not recently been accessed to be
|
|
392
312
|
* removed.
|
|
393
|
-
*
|
|
394
|
-
* @private
|
|
395
|
-
* @returns {Promise}
|
|
396
313
|
*/
|
|
397
314
|
function addAllSafeEvictionKeysToRecentlyAccessedList() {
|
|
398
315
|
return getAllKeys().then((keys) => {
|
|
399
|
-
|
|
316
|
+
evictionAllowList.forEach((safeEvictionKey) => {
|
|
400
317
|
keys.forEach((key) => {
|
|
401
318
|
if (!isKeyMatch(safeEvictionKey, key)) {
|
|
402
319
|
return;
|
|
@@ -406,43 +323,26 @@ function addAllSafeEvictionKeysToRecentlyAccessedList() {
|
|
|
406
323
|
});
|
|
407
324
|
});
|
|
408
325
|
}
|
|
409
|
-
/**
|
|
410
|
-
* @private
|
|
411
|
-
* @param {String} collectionKey
|
|
412
|
-
* @returns {Object}
|
|
413
|
-
*/
|
|
414
326
|
function getCachedCollection(collectionKey) {
|
|
415
|
-
const collectionMemberKeys =
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
collectionMemberKeys.push(storedKey);
|
|
421
|
-
});
|
|
422
|
-
return underscore_1.default.reduce(collectionMemberKeys, (prev, curr) => {
|
|
423
|
-
const cachedValue = OnyxCache_1.default.getValue(curr);
|
|
327
|
+
const collectionMemberKeys = Array.from(OnyxCache_1.default.getAllKeys()).filter((storedKey) => isCollectionMemberKey(collectionKey, storedKey));
|
|
328
|
+
return collectionMemberKeys.reduce((prev, key) => {
|
|
329
|
+
const cachedValue = OnyxCache_1.default.getValue(key);
|
|
424
330
|
if (!cachedValue) {
|
|
425
331
|
return prev;
|
|
426
332
|
}
|
|
427
333
|
// eslint-disable-next-line no-param-reassign
|
|
428
|
-
prev[
|
|
334
|
+
prev[key] = cachedValue;
|
|
429
335
|
return prev;
|
|
430
336
|
}, {});
|
|
431
337
|
}
|
|
432
338
|
/**
|
|
433
339
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
434
|
-
*
|
|
435
|
-
* @private
|
|
436
|
-
* @param {String} collectionKey
|
|
437
|
-
* @param {Object} partialCollection - a partial collection of grouped member keys
|
|
438
|
-
* @param {boolean} [notifyRegularSubscibers=true]
|
|
439
|
-
* @param {boolean} [notifyWithOnyxSubscibers=true]
|
|
440
340
|
*/
|
|
441
341
|
function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
|
|
442
342
|
// We are iterating over all subscribers similar to keyChanged(). However, we are looking for subscribers who are subscribing to either a collection key or
|
|
443
343
|
// individual collection key member for the collection that is being updated. It is important to note that the collection parameter cane be a PARTIAL collection
|
|
444
344
|
// and does not represent all of the combined keys and values for a collection key. It is just the "new" data that was merged in via mergeCollection().
|
|
445
|
-
const stateMappingKeys =
|
|
345
|
+
const stateMappingKeys = Object.keys(callbackToStateMapping);
|
|
446
346
|
for (let i = 0; i < stateMappingKeys.length; i++) {
|
|
447
347
|
const subscriber = callbackToStateMapping[stateMappingKeys[i]];
|
|
448
348
|
if (!subscriber) {
|
|
@@ -464,7 +364,7 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
464
364
|
// was merged in via mergeCollection().
|
|
465
365
|
const cachedCollection = getCachedCollection(collectionKey);
|
|
466
366
|
// Regular Onyx.connect() subscriber found.
|
|
467
|
-
if (
|
|
367
|
+
if (typeof subscriber.callback === 'function') {
|
|
468
368
|
if (!notifyRegularSubscibers) {
|
|
469
369
|
continue;
|
|
470
370
|
}
|
|
@@ -477,7 +377,7 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
477
377
|
}
|
|
478
378
|
// If they are not using waitForCollectionCallback then we notify the subscriber with
|
|
479
379
|
// the new merged data but only for any keys in the partial collection.
|
|
480
|
-
const dataKeys =
|
|
380
|
+
const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
|
|
481
381
|
for (let j = 0; j < dataKeys.length; j++) {
|
|
482
382
|
const dataKey = dataKeys[j];
|
|
483
383
|
subscriber.callback(cachedCollection[dataKey], dataKey);
|
|
@@ -487,13 +387,14 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
487
387
|
// And if the subscriber is specifically only tracking a particular collection member key then we will
|
|
488
388
|
// notify them with the cached data for that key only.
|
|
489
389
|
if (isSubscribedToCollectionMemberKey) {
|
|
490
|
-
subscriber.callback
|
|
390
|
+
const subscriberCallback = subscriber.callback;
|
|
391
|
+
subscriberCallback(cachedCollection[subscriber.key], subscriber.key);
|
|
491
392
|
continue;
|
|
492
393
|
}
|
|
493
394
|
continue;
|
|
494
395
|
}
|
|
495
396
|
// React component subscriber found.
|
|
496
|
-
if (subscriber.withOnyxInstance) {
|
|
397
|
+
if ('withOnyxInstance' in subscriber && subscriber.withOnyxInstance) {
|
|
497
398
|
if (!notifyWithOnyxSubscibers) {
|
|
498
399
|
continue;
|
|
499
400
|
}
|
|
@@ -502,10 +403,11 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
502
403
|
if (isSubscribedToCollectionKey) {
|
|
503
404
|
// If the subscriber has a selector, then the component's state must only be updated with the data
|
|
504
405
|
// returned by the selector.
|
|
505
|
-
|
|
406
|
+
const collectionSelector = subscriber.selector;
|
|
407
|
+
if (collectionSelector) {
|
|
506
408
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
507
409
|
const previousData = prevState[subscriber.statePropertyName];
|
|
508
|
-
const newData = reduceCollectionWithSelector(cachedCollection,
|
|
410
|
+
const newData = reduceCollectionWithSelector(cachedCollection, collectionSelector, subscriber.withOnyxInstance.state);
|
|
509
411
|
if (!(0, fast_equals_1.deepEqual)(previousData, newData)) {
|
|
510
412
|
return {
|
|
511
413
|
[subscriber.statePropertyName]: newData,
|
|
@@ -516,13 +418,14 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
516
418
|
continue;
|
|
517
419
|
}
|
|
518
420
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
519
|
-
|
|
520
|
-
const
|
|
421
|
+
var _a;
|
|
422
|
+
const finalCollection = (0, clone_1.default)((_a = prevState === null || prevState === void 0 ? void 0 : prevState[subscriber.statePropertyName]) !== null && _a !== void 0 ? _a : {});
|
|
423
|
+
const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
|
|
521
424
|
for (let j = 0; j < dataKeys.length; j++) {
|
|
522
425
|
const dataKey = dataKeys[j];
|
|
523
426
|
finalCollection[dataKey] = cachedCollection[dataKey];
|
|
524
427
|
}
|
|
525
|
-
PerformanceUtils.logSetStateCall(subscriber, prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
|
|
428
|
+
PerformanceUtils.logSetStateCall(subscriber, prevState === null || prevState === void 0 ? void 0 : prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
|
|
526
429
|
return {
|
|
527
430
|
[subscriber.statePropertyName]: finalCollection,
|
|
528
431
|
};
|
|
@@ -533,17 +436,18 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
533
436
|
if (isSubscribedToCollectionMemberKey) {
|
|
534
437
|
// However, we only want to update this subscriber if the partial data contains a change.
|
|
535
438
|
// Otherwise, we would update them with a value they already have and trigger an unnecessary re-render.
|
|
536
|
-
const dataFromCollection = partialCollection[subscriber.key];
|
|
537
|
-
if (
|
|
439
|
+
const dataFromCollection = partialCollection === null || partialCollection === void 0 ? void 0 : partialCollection[subscriber.key];
|
|
440
|
+
if (dataFromCollection === undefined) {
|
|
538
441
|
continue;
|
|
539
442
|
}
|
|
540
443
|
// If the subscriber has a selector, then the component's state must only be updated with the data
|
|
541
444
|
// returned by the selector and the state should only change when the subset of data changes from what
|
|
542
445
|
// it was previously.
|
|
543
|
-
|
|
446
|
+
const selector = subscriber.selector;
|
|
447
|
+
if (selector) {
|
|
544
448
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
545
449
|
const prevData = prevState[subscriber.statePropertyName];
|
|
546
|
-
const newData =
|
|
450
|
+
const newData = selector(cachedCollection[subscriber.key], subscriber.withOnyxInstance.state);
|
|
547
451
|
if (!(0, fast_equals_1.deepEqual)(prevData, newData)) {
|
|
548
452
|
PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keysChanged', collectionKey);
|
|
549
453
|
return {
|
|
@@ -578,18 +482,10 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
578
482
|
*
|
|
579
483
|
* @example
|
|
580
484
|
* keyChanged(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
581
|
-
*
|
|
582
|
-
* @private
|
|
583
|
-
* @param {String} key
|
|
584
|
-
* @param {*} data
|
|
585
|
-
* @param {*} prevData
|
|
586
|
-
* @param {Function} [canUpdateSubscriber] only subscribers that pass this truth test will be updated
|
|
587
|
-
* @param {boolean} [notifyRegularSubscibers=true]
|
|
588
|
-
* @param {boolean} [notifyWithOnyxSubscibers=true]
|
|
589
485
|
*/
|
|
590
486
|
function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
|
|
591
487
|
// Add or remove this key from the recentlyAccessedKeys lists
|
|
592
|
-
if (
|
|
488
|
+
if (data !== null) {
|
|
593
489
|
addLastAccessedKey(key);
|
|
594
490
|
}
|
|
595
491
|
else {
|
|
@@ -598,14 +494,14 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
598
494
|
// We are iterating over all subscribers to see if they are interested in the key that has just changed. If the subscriber's key is a collection key then we will
|
|
599
495
|
// notify them if the key that changed is a collection member. Or if it is a regular key notify them when there is an exact match. Depending on whether the subscriber
|
|
600
496
|
// was connected via withOnyx we will call setState() directly on the withOnyx instance. If it is a regular connection we will pass the data to the provided callback.
|
|
601
|
-
const stateMappingKeys =
|
|
497
|
+
const stateMappingKeys = Object.keys(callbackToStateMapping);
|
|
602
498
|
for (let i = 0; i < stateMappingKeys.length; i++) {
|
|
603
499
|
const subscriber = callbackToStateMapping[stateMappingKeys[i]];
|
|
604
500
|
if (!subscriber || !isKeyMatch(subscriber.key, key) || !canUpdateSubscriber(subscriber)) {
|
|
605
501
|
continue;
|
|
606
502
|
}
|
|
607
503
|
// Subscriber is a regular call to connect() and provided a callback
|
|
608
|
-
if (
|
|
504
|
+
if (typeof subscriber.callback === 'function') {
|
|
609
505
|
if (!notifyRegularSubscibers) {
|
|
610
506
|
continue;
|
|
611
507
|
}
|
|
@@ -615,23 +511,25 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
615
511
|
subscriber.callback(cachedCollection);
|
|
616
512
|
continue;
|
|
617
513
|
}
|
|
618
|
-
subscriber.callback
|
|
514
|
+
const subscriberCallback = subscriber.callback;
|
|
515
|
+
subscriberCallback(data, key);
|
|
619
516
|
continue;
|
|
620
517
|
}
|
|
621
518
|
// Subscriber connected via withOnyx() HOC
|
|
622
|
-
if (subscriber.withOnyxInstance) {
|
|
519
|
+
if ('withOnyxInstance' in subscriber && subscriber.withOnyxInstance) {
|
|
623
520
|
if (!notifyWithOnyxSubscibers) {
|
|
624
521
|
continue;
|
|
625
522
|
}
|
|
523
|
+
const selector = subscriber.selector;
|
|
626
524
|
// Check if we are subscribing to a collection key and overwrite the collection member key value in state
|
|
627
525
|
if (isCollectionKey(subscriber.key)) {
|
|
628
526
|
// If the subscriber has a selector, then the consumer of this data must only be given the data
|
|
629
527
|
// returned by the selector and only when the selected data has changed.
|
|
630
|
-
if (
|
|
528
|
+
if (selector) {
|
|
631
529
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
632
530
|
const prevWithOnyxData = prevState[subscriber.statePropertyName];
|
|
633
531
|
const newWithOnyxData = {
|
|
634
|
-
[key]:
|
|
532
|
+
[key]: selector(data, subscriber.withOnyxInstance.state),
|
|
635
533
|
};
|
|
636
534
|
const prevDataWithNewData = Object.assign(Object.assign({}, prevWithOnyxData), newWithOnyxData);
|
|
637
535
|
if (!(0, fast_equals_1.deepEqual)(prevWithOnyxData, prevDataWithNewData)) {
|
|
@@ -656,10 +554,10 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
656
554
|
}
|
|
657
555
|
// If the subscriber has a selector, then the component's state must only be updated with the data
|
|
658
556
|
// returned by the selector and only if the selected data has changed.
|
|
659
|
-
if (
|
|
557
|
+
if (selector) {
|
|
660
558
|
subscriber.withOnyxInstance.setStateProxy(() => {
|
|
661
|
-
const previousValue =
|
|
662
|
-
const newValue =
|
|
559
|
+
const previousValue = selector(prevData, subscriber.withOnyxInstance.state);
|
|
560
|
+
const newValue = selector(data, subscriber.withOnyxInstance.state);
|
|
663
561
|
if (!(0, fast_equals_1.deepEqual)(previousValue, newValue)) {
|
|
664
562
|
return {
|
|
665
563
|
[subscriber.statePropertyName]: newValue,
|
|
@@ -693,24 +591,15 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
693
591
|
* Sends the data obtained from the keys to the connection. It either:
|
|
694
592
|
* - sets state on the withOnyxInstances
|
|
695
593
|
* - triggers the callback function
|
|
696
|
-
*
|
|
697
|
-
* @private
|
|
698
|
-
* @param {Object} mapping
|
|
699
|
-
* @param {Object} [mapping.withOnyxInstance]
|
|
700
|
-
* @param {String} [mapping.statePropertyName]
|
|
701
|
-
* @param {Function} [mapping.callback]
|
|
702
|
-
* @param {String} [mapping.selector]
|
|
703
|
-
* @param {*|null} val
|
|
704
|
-
* @param {String|undefined} matchedKey
|
|
705
|
-
* @param {Boolean} isBatched
|
|
706
594
|
*/
|
|
707
595
|
function sendDataToConnection(mapping, val, matchedKey, isBatched) {
|
|
596
|
+
var _a, _b;
|
|
708
597
|
// If the mapping no longer exists then we should not send any data.
|
|
709
598
|
// This means our subscriber disconnected or withOnyx wrapped component unmounted.
|
|
710
599
|
if (!callbackToStateMapping[mapping.connectionID]) {
|
|
711
600
|
return;
|
|
712
601
|
}
|
|
713
|
-
if (mapping.withOnyxInstance) {
|
|
602
|
+
if ('withOnyxInstance' in mapping && mapping.withOnyxInstance) {
|
|
714
603
|
let newData = val;
|
|
715
604
|
// If the mapping has a selector, then the component's state must only be updated with the data
|
|
716
605
|
// returned by the selector.
|
|
@@ -719,30 +608,23 @@ function sendDataToConnection(mapping, val, matchedKey, isBatched) {
|
|
|
719
608
|
newData = reduceCollectionWithSelector(val, mapping.selector, mapping.withOnyxInstance.state);
|
|
720
609
|
}
|
|
721
610
|
else {
|
|
722
|
-
newData =
|
|
611
|
+
newData = mapping.selector(val, mapping.withOnyxInstance.state);
|
|
723
612
|
}
|
|
724
613
|
}
|
|
725
614
|
PerformanceUtils.logSetStateCall(mapping, null, newData, 'sendDataToConnection');
|
|
726
615
|
if (isBatched) {
|
|
727
|
-
batchUpdates(() =>
|
|
728
|
-
mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData);
|
|
729
|
-
});
|
|
616
|
+
batchUpdates(() => mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData));
|
|
730
617
|
}
|
|
731
618
|
else {
|
|
732
619
|
mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData);
|
|
733
620
|
}
|
|
734
621
|
return;
|
|
735
622
|
}
|
|
736
|
-
|
|
737
|
-
mapping.callback(val, matchedKey);
|
|
738
|
-
}
|
|
623
|
+
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, val, matchedKey);
|
|
739
624
|
}
|
|
740
625
|
/**
|
|
741
626
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
742
627
|
* run out of storage the least recently accessed key can be removed.
|
|
743
|
-
*
|
|
744
|
-
* @private
|
|
745
|
-
* @param {Object} mapping
|
|
746
628
|
*/
|
|
747
629
|
function addKeyToRecentlyAccessedIfNeeded(mapping) {
|
|
748
630
|
if (!isSafeEvictionKey(mapping.key)) {
|
|
@@ -750,9 +632,9 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
|
|
|
750
632
|
}
|
|
751
633
|
// Try to free some cache whenever we connect to a safe eviction key
|
|
752
634
|
OnyxCache_1.default.removeLeastRecentlyUsedKeys();
|
|
753
|
-
if (mapping.withOnyxInstance && !isCollectionKey(mapping.key)) {
|
|
635
|
+
if ('withOnyxInstance' in mapping && mapping.withOnyxInstance && !isCollectionKey(mapping.key)) {
|
|
754
636
|
// All React components subscribing to a key flagged as a safe eviction key must implement the canEvict property.
|
|
755
|
-
if (
|
|
637
|
+
if (mapping.canEvict === undefined) {
|
|
756
638
|
throw new Error(`Cannot subscribe to safe eviction key '${mapping.key}' without providing a canEvict value.`);
|
|
757
639
|
}
|
|
758
640
|
addLastAccessedKey(mapping.key);
|
|
@@ -760,10 +642,6 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
|
|
|
760
642
|
}
|
|
761
643
|
/**
|
|
762
644
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
763
|
-
*
|
|
764
|
-
* @private
|
|
765
|
-
* @param {Array} matchingKeys
|
|
766
|
-
* @param {Object} mapping
|
|
767
645
|
*/
|
|
768
646
|
function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
769
647
|
// Keys that are not in the cache
|
|
@@ -808,7 +686,7 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
808
686
|
// We are going to get the missing keys using multiGet from the storage.
|
|
809
687
|
.then(() => {
|
|
810
688
|
if (missingKeys.length === 0) {
|
|
811
|
-
return Promise.resolve();
|
|
689
|
+
return Promise.resolve(undefined);
|
|
812
690
|
}
|
|
813
691
|
return storage_1.default.multiGet(missingKeys);
|
|
814
692
|
})
|
|
@@ -819,9 +697,9 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
819
697
|
}
|
|
820
698
|
// temp object is used to merge the missing data into the cache
|
|
821
699
|
const temp = {};
|
|
822
|
-
values.forEach((value) => {
|
|
823
|
-
data[
|
|
824
|
-
temp[
|
|
700
|
+
values.forEach(([key, value]) => {
|
|
701
|
+
data[key] = value;
|
|
702
|
+
temp[key] = value;
|
|
825
703
|
});
|
|
826
704
|
OnyxCache_1.default.merge(temp);
|
|
827
705
|
return Promise.resolve();
|
|
@@ -836,49 +714,31 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
836
714
|
*
|
|
837
715
|
* @example
|
|
838
716
|
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
839
|
-
*
|
|
840
|
-
* @param {String} key
|
|
841
|
-
* @param {*} value
|
|
842
|
-
* @param {*} prevValue
|
|
843
|
-
* @param {Function} [canUpdateSubscriber] only subscribers that pass this truth test will be updated
|
|
844
|
-
* @returns {Promise}
|
|
845
717
|
*/
|
|
846
718
|
function scheduleSubscriberUpdate(key, value, prevValue, canUpdateSubscriber = () => true) {
|
|
847
719
|
const promise = Promise.resolve().then(() => keyChanged(key, value, prevValue, canUpdateSubscriber, true, false));
|
|
848
720
|
batchUpdates(() => keyChanged(key, value, prevValue, canUpdateSubscriber, false, true));
|
|
849
|
-
return Promise.all([maybeFlushBatchUpdates(), promise]);
|
|
721
|
+
return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
|
|
850
722
|
}
|
|
851
723
|
/**
|
|
852
724
|
* This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
|
|
853
725
|
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
854
726
|
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
855
|
-
*
|
|
856
|
-
* @param {String} key
|
|
857
|
-
* @param {*} value
|
|
858
|
-
* @returns {Promise}
|
|
859
727
|
*/
|
|
860
728
|
function scheduleNotifyCollectionSubscribers(key, value) {
|
|
861
729
|
const promise = Promise.resolve().then(() => keysChanged(key, value, true, false));
|
|
862
730
|
batchUpdates(() => keysChanged(key, value, false, true));
|
|
863
|
-
return Promise.all([maybeFlushBatchUpdates(), promise]);
|
|
731
|
+
return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
|
|
864
732
|
}
|
|
865
733
|
/**
|
|
866
734
|
* Remove a key from Onyx and update the subscribers
|
|
867
|
-
*
|
|
868
|
-
* @private
|
|
869
|
-
* @param {String} key
|
|
870
|
-
* @return {Promise}
|
|
871
735
|
*/
|
|
872
736
|
function remove(key) {
|
|
873
737
|
const prevValue = OnyxCache_1.default.getValue(key, false);
|
|
874
738
|
OnyxCache_1.default.drop(key);
|
|
875
739
|
scheduleSubscriberUpdate(key, null, prevValue);
|
|
876
|
-
return storage_1.default.removeItem(key);
|
|
740
|
+
return storage_1.default.removeItem(key).then(() => undefined);
|
|
877
741
|
}
|
|
878
|
-
/**
|
|
879
|
-
* @private
|
|
880
|
-
* @returns {Promise<void>}
|
|
881
|
-
*/
|
|
882
742
|
function reportStorageQuota() {
|
|
883
743
|
return storage_1.default.getDatabaseSize()
|
|
884
744
|
.then(({ bytesUsed, bytesRemaining }) => {
|
|
@@ -892,12 +752,6 @@ function reportStorageQuota() {
|
|
|
892
752
|
* If we fail to set or merge we must handle this by
|
|
893
753
|
* evicting some data from Onyx and then retrying to do
|
|
894
754
|
* whatever it is we attempted to do.
|
|
895
|
-
*
|
|
896
|
-
* @private
|
|
897
|
-
* @param {Error} error
|
|
898
|
-
* @param {Function} onyxMethod
|
|
899
|
-
* @param {...any} args
|
|
900
|
-
* @return {Promise}
|
|
901
755
|
*/
|
|
902
756
|
function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
903
757
|
Logger.logInfo(`Failed to save to storage. Error: ${error}. onyxMethod: ${onyxMethod.name}`);
|
|
@@ -906,7 +760,7 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
906
760
|
throw error;
|
|
907
761
|
}
|
|
908
762
|
// Find the first key that we can remove that has no subscribers in our blocklist
|
|
909
|
-
const keyForRemoval =
|
|
763
|
+
const keyForRemoval = recentlyAccessedKeys.find((key) => !evictionBlocklist[key]);
|
|
910
764
|
if (!keyForRemoval) {
|
|
911
765
|
// If we have no acceptable keys to remove then we are possibly trying to save mission critical data. If this is the case,
|
|
912
766
|
// then we should stop retrying as there is not much the user can do to fix this. Instead of getting them stuck in an infinite loop we
|
|
@@ -917,16 +771,11 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
917
771
|
// Remove the least recently viewed key that is not currently being accessed and retry.
|
|
918
772
|
Logger.logInfo(`Out of storage. Evicting least recently accessed key (${keyForRemoval}) and retrying.`);
|
|
919
773
|
reportStorageQuota();
|
|
774
|
+
// @ts-expect-error No overload matches this call.
|
|
920
775
|
return remove(keyForRemoval).then(() => onyxMethod(...args));
|
|
921
776
|
}
|
|
922
777
|
/**
|
|
923
|
-
*
|
|
924
|
-
*
|
|
925
|
-
* @param {String} key
|
|
926
|
-
* @param {*} value
|
|
927
|
-
* @param {Boolean} hasChanged
|
|
928
|
-
* @param {Boolean} wasRemoved
|
|
929
|
-
* @returns {Promise}
|
|
778
|
+
* Notifies subscribers and writes current value to cache
|
|
930
779
|
*/
|
|
931
780
|
function broadcastUpdate(key, value, hasChanged, wasRemoved = false) {
|
|
932
781
|
const prevValue = OnyxCache_1.default.getValue(key, false);
|
|
@@ -938,24 +787,19 @@ function broadcastUpdate(key, value, hasChanged, wasRemoved = false) {
|
|
|
938
787
|
else {
|
|
939
788
|
OnyxCache_1.default.addToAccessedKeys(key);
|
|
940
789
|
}
|
|
941
|
-
return scheduleSubscriberUpdate(key, value, prevValue, (subscriber) => hasChanged || subscriber.initWithStoredValues === false);
|
|
790
|
+
return scheduleSubscriberUpdate(key, value, prevValue, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false).then(() => undefined);
|
|
942
791
|
}
|
|
943
|
-
/**
|
|
944
|
-
* @param {String} key
|
|
945
|
-
* @returns {Boolean}
|
|
946
|
-
*/
|
|
947
792
|
function hasPendingMergeForKey(key) {
|
|
948
|
-
return
|
|
793
|
+
return !!mergeQueue[key];
|
|
949
794
|
}
|
|
950
795
|
/**
|
|
951
796
|
* Removes a key from storage if the value is null.
|
|
952
797
|
* Otherwise removes all nested null values in objects and returns the object
|
|
953
|
-
*
|
|
954
|
-
* @
|
|
955
|
-
* @returns {Mixed} The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
|
|
798
|
+
*
|
|
799
|
+
* @returns The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
|
|
956
800
|
*/
|
|
957
801
|
function removeNullValues(key, value) {
|
|
958
|
-
if (
|
|
802
|
+
if (value === null) {
|
|
959
803
|
remove(key);
|
|
960
804
|
return { value, wasRemoved: true };
|
|
961
805
|
}
|
|
@@ -968,16 +812,16 @@ function removeNullValues(key, value) {
|
|
|
968
812
|
* Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
|
|
969
813
|
* This method transforms an object like {'@MyApp_user': myUserValue, '@MyApp_key': myKeyValue}
|
|
970
814
|
* to an array of key-value pairs in the above format and removes key-value pairs that are being set to null
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
* @return {Array} an array of key - value pairs <[key, value]>
|
|
815
|
+
|
|
816
|
+
* @return an array of key - value pairs <[key, value]>
|
|
974
817
|
*/
|
|
975
818
|
function prepareKeyValuePairsForStorage(data) {
|
|
976
819
|
const keyValuePairs = [];
|
|
977
|
-
|
|
820
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
978
821
|
const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value);
|
|
979
|
-
if (wasRemoved)
|
|
822
|
+
if (wasRemoved) {
|
|
980
823
|
return;
|
|
824
|
+
}
|
|
981
825
|
keyValuePairs.push([key, valueAfterRemoving]);
|
|
982
826
|
});
|
|
983
827
|
return keyValuePairs;
|
|
@@ -985,20 +829,16 @@ function prepareKeyValuePairsForStorage(data) {
|
|
|
985
829
|
/**
|
|
986
830
|
* Merges an array of changes with an existing value
|
|
987
831
|
*
|
|
988
|
-
* @
|
|
989
|
-
* @param {*} existingValue
|
|
990
|
-
* @param {Array<*>} changes Array of changes that should be applied to the existing value
|
|
991
|
-
* @param {Boolean} shouldRemoveNullObjectValues
|
|
992
|
-
* @returns {*}
|
|
832
|
+
* @param changes Array of changes that should be applied to the existing value
|
|
993
833
|
*/
|
|
994
834
|
function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
|
|
995
|
-
const lastChange =
|
|
996
|
-
if (
|
|
835
|
+
const lastChange = changes === null || changes === void 0 ? void 0 : changes.at(-1);
|
|
836
|
+
if (Array.isArray(lastChange)) {
|
|
997
837
|
return lastChange;
|
|
998
838
|
}
|
|
999
|
-
if (
|
|
839
|
+
if (changes.some((change) => typeof change === 'object')) {
|
|
1000
840
|
// Object values are then merged one after the other
|
|
1001
|
-
return
|
|
841
|
+
return changes.reduce((modifiedData, change) => utils_1.default.fastMerge(modifiedData, change, shouldRemoveNullObjectValues), existingValue || {});
|
|
1002
842
|
}
|
|
1003
843
|
// If we have anything else we can't merge it so we'll
|
|
1004
844
|
// simply return the last value that was queued
|
|
@@ -1006,15 +846,13 @@ function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
|
|
|
1006
846
|
}
|
|
1007
847
|
/**
|
|
1008
848
|
* Merge user provided default key value pairs.
|
|
1009
|
-
* @private
|
|
1010
|
-
* @returns {Promise}
|
|
1011
849
|
*/
|
|
1012
850
|
function initializeWithDefaultKeyStates() {
|
|
1013
|
-
return storage_1.default.multiGet(
|
|
1014
|
-
const existingDataAsObject =
|
|
851
|
+
return storage_1.default.multiGet(Object.keys(defaultKeyStates)).then((pairs) => {
|
|
852
|
+
const existingDataAsObject = Object.fromEntries(pairs);
|
|
1015
853
|
const merged = utils_1.default.fastMerge(existingDataAsObject, defaultKeyStates);
|
|
1016
|
-
OnyxCache_1.default.merge(merged);
|
|
1017
|
-
|
|
854
|
+
OnyxCache_1.default.merge(merged !== null && merged !== void 0 ? merged : {});
|
|
855
|
+
Object.entries(merged !== null && merged !== void 0 ? merged : {}).forEach(([key, value]) => keyChanged(key, value, existingDataAsObject));
|
|
1018
856
|
});
|
|
1019
857
|
}
|
|
1020
858
|
const OnyxUtils = {
|