react-native-onyx 2.0.52 → 2.0.54

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/Onyx.js CHANGED
@@ -146,10 +146,11 @@ function connect(connectOptions) {
146
146
  return;
147
147
  }
148
148
  // We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
149
- // eslint-disable-next-line @typescript-eslint/prefer-for-of
150
- for (let i = 0; i < matchingKeys.length; i++) {
151
- OnyxUtils_1.default.get(matchingKeys[i]).then((val) => OnyxUtils_1.default.sendDataToConnection(mapping, val, matchingKeys[i], true));
152
- }
149
+ OnyxUtils_1.default.multiGet(matchingKeys).then((values) => {
150
+ values.forEach((val, key) => {
151
+ OnyxUtils_1.default.sendDataToConnection(mapping, val, key, true);
152
+ });
153
+ });
153
154
  return;
154
155
  }
155
156
  // If we are not subscribed to a collection key then there's only a single key to send an update for.
@@ -386,7 +387,8 @@ function mergeCollection(collectionKey, collection) {
386
387
  const mergedCollection = collection;
387
388
  // Confirm all the collection keys belong to the same parent
388
389
  let hasCollectionKeyCheckFailed = false;
389
- Object.keys(mergedCollection).forEach((dataKey) => {
390
+ const mergedCollectionKeys = Object.keys(mergedCollection);
391
+ mergedCollectionKeys.forEach((dataKey) => {
390
392
  if (OnyxUtils_1.default.isKeyMatch(collectionKey, dataKey)) {
391
393
  return;
392
394
  }
@@ -403,7 +405,7 @@ function mergeCollection(collectionKey, collection) {
403
405
  return OnyxUtils_1.default.getAllKeys()
404
406
  .then((persistedKeys) => {
405
407
  // Split to keys that exist in storage and keys that don't
406
- const keys = Object.keys(mergedCollection).filter((key) => {
408
+ const keys = mergedCollectionKeys.filter((key) => {
407
409
  if (mergedCollection[key] === null) {
408
410
  OnyxUtils_1.default.remove(key);
409
411
  return false;
@@ -412,7 +414,6 @@ function mergeCollection(collectionKey, collection) {
412
414
  });
413
415
  const existingKeys = keys.filter((key) => persistedKeys.has(key));
414
416
  const cachedCollectionForExistingKeys = OnyxUtils_1.default.getCachedCollection(collectionKey, existingKeys);
415
- const newKeys = keys.filter((key) => !persistedKeys.has(key));
416
417
  const existingKeyCollection = existingKeys.reduce((obj, key) => {
417
418
  const { isCompatible, existingValueType, newValueType } = utils_1.default.checkCompatibilityWithExistingValue(mergedCollection[key], cachedCollectionForExistingKeys[key]);
418
419
  if (!isCompatible) {
@@ -423,11 +424,13 @@ function mergeCollection(collectionKey, collection) {
423
424
  obj[key] = mergedCollection[key];
424
425
  return obj;
425
426
  }, {});
426
- const newCollection = newKeys.reduce((obj, key) => {
427
- // eslint-disable-next-line no-param-reassign
428
- obj[key] = mergedCollection[key];
429
- return obj;
430
- }, {});
427
+ const newCollection = {};
428
+ keys.forEach((key) => {
429
+ if (persistedKeys.has(key)) {
430
+ return;
431
+ }
432
+ newCollection[key] = mergedCollection[key];
433
+ });
431
434
  // When (multi-)merging the values with the existing values in storage,
432
435
  // we don't want to remove nested null values from the data that we pass to the storage layer,
433
436
  // because the storage layer uses them to remove nested keys from storage natively.
@@ -54,6 +54,7 @@ declare function maybeFlushBatchUpdates(): Promise<void>;
54
54
  declare function batchUpdates(updates: () => void): Promise<void>;
55
55
  /** Get some data from the store */
56
56
  declare function get<TKey extends OnyxKey, TValue extends OnyxValue<TKey>>(key: TKey): Promise<TValue>;
57
+ declare function multiGet<TKey extends OnyxKey>(keys: CollectionKeyBase[]): Promise<Map<OnyxKey, OnyxValue<TKey>>>;
57
58
  /** Returns current key names stored in persisted storage */
58
59
  declare function getAllKeys(): Promise<Set<OnyxKey>>;
59
60
  /**
@@ -237,5 +238,6 @@ declare const OnyxUtils: {
237
238
  applyMerge: typeof applyMerge;
238
239
  initializeWithDefaultKeyStates: typeof initializeWithDefaultKeyStates;
239
240
  getSnapshotKey: typeof getSnapshotKey;
241
+ multiGet: typeof multiGet;
240
242
  };
241
243
  export default OnyxUtils;
package/dist/OnyxUtils.js CHANGED
@@ -190,6 +190,69 @@ function get(key) {
190
190
  .catch((err) => Logger.logInfo(`Unable to get item from persistent storage. Key: ${key} Error: ${err}`));
191
191
  return OnyxCache_1.default.captureTask(taskName, promise);
192
192
  }
193
+ // multiGet the data first from the cache and then from the storage for the missing keys.
194
+ function multiGet(keys) {
195
+ // Keys that are not in the cache
196
+ const missingKeys = [];
197
+ // Tasks that are pending
198
+ const pendingTasks = [];
199
+ // Keys for the tasks that are pending
200
+ const pendingKeys = [];
201
+ // Data to be sent back to the invoker
202
+ const dataMap = new Map();
203
+ /**
204
+ * We are going to iterate over all the matching keys and check if we have the data in the cache.
205
+ * If we do then we add it to the data object. If we do not have them, then we check if there is a pending task
206
+ * for the key. If there is such task, then we add the promise to the pendingTasks array and the key to the pendingKeys
207
+ * array. If there is no pending task then we add the key to the missingKeys array.
208
+ *
209
+ * These missingKeys will be later used to multiGet the data from the storage.
210
+ */
211
+ keys.forEach((key) => {
212
+ const cacheValue = OnyxCache_1.default.get(key);
213
+ if (cacheValue) {
214
+ dataMap.set(key, cacheValue);
215
+ return;
216
+ }
217
+ const pendingKey = `get:${key}`;
218
+ if (OnyxCache_1.default.hasPendingTask(pendingKey)) {
219
+ pendingTasks.push(OnyxCache_1.default.getTaskPromise(pendingKey));
220
+ pendingKeys.push(key);
221
+ }
222
+ else {
223
+ missingKeys.push(key);
224
+ }
225
+ });
226
+ return (Promise.all(pendingTasks)
227
+ // Wait for all the pending tasks to resolve and then add the data to the data map.
228
+ .then((values) => {
229
+ values.forEach((value, index) => {
230
+ dataMap.set(pendingKeys[index], value);
231
+ });
232
+ return Promise.resolve();
233
+ })
234
+ // Get the missing keys using multiGet from the storage.
235
+ .then(() => {
236
+ if (missingKeys.length === 0) {
237
+ return Promise.resolve(undefined);
238
+ }
239
+ return storage_1.default.multiGet(missingKeys);
240
+ })
241
+ // Add the data from the missing keys to the data map and also merge it to the cache.
242
+ .then((values) => {
243
+ if (!values || values.length === 0) {
244
+ return dataMap;
245
+ }
246
+ // temp object is used to merge the missing data into the cache
247
+ const temp = {};
248
+ values.forEach(([key, value]) => {
249
+ dataMap.set(key, value);
250
+ temp[key] = value;
251
+ });
252
+ OnyxCache_1.default.merge(temp);
253
+ return dataMap;
254
+ }));
255
+ }
193
256
  /** Returns current key names stored in persisted storage */
194
257
  function getAllKeys() {
195
258
  // When we've already read stored keys, resolve right away
@@ -682,68 +745,8 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
682
745
  * Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
683
746
  */
684
747
  function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
685
- // Keys that are not in the cache
686
- const missingKeys = [];
687
- // Tasks that are pending
688
- const pendingTasks = [];
689
- // Keys for the tasks that are pending
690
- const pendingKeys = [];
691
- // We are going to combine all the data from the matching keys into a single object
692
- const data = {};
693
- /**
694
- * We are going to iterate over all the matching keys and check if we have the data in the cache.
695
- * If we do then we add it to the data object. If we do not then we check if there is a pending task
696
- * for the key. If there is then we add the promise to the pendingTasks array and the key to the pendingKeys
697
- * array. If there is no pending task then we add the key to the missingKeys array.
698
- *
699
- * These missingKeys will be later to use to multiGet the data from the storage.
700
- */
701
- matchingKeys.forEach((key) => {
702
- const cacheValue = OnyxCache_1.default.get(key);
703
- if (cacheValue) {
704
- data[key] = cacheValue;
705
- return;
706
- }
707
- const pendingKey = `get:${key}`;
708
- if (OnyxCache_1.default.hasPendingTask(pendingKey)) {
709
- pendingTasks.push(OnyxCache_1.default.getTaskPromise(pendingKey));
710
- pendingKeys.push(key);
711
- }
712
- else {
713
- missingKeys.push(key);
714
- }
715
- });
716
- Promise.all(pendingTasks)
717
- // We are going to wait for all the pending tasks to resolve and then add the data to the data object.
718
- .then((values) => {
719
- values.forEach((value, index) => {
720
- data[pendingKeys[index]] = value;
721
- });
722
- return Promise.resolve();
723
- })
724
- // We are going to get the missing keys using multiGet from the storage.
725
- .then(() => {
726
- if (missingKeys.length === 0) {
727
- return Promise.resolve(undefined);
728
- }
729
- return storage_1.default.multiGet(missingKeys);
730
- })
731
- // We are going to add the data from the missing keys to the data object and also merge it to the cache.
732
- .then((values) => {
733
- if (!values || values.length === 0) {
734
- return Promise.resolve();
735
- }
736
- // temp object is used to merge the missing data into the cache
737
- const temp = {};
738
- values.forEach(([key, value]) => {
739
- data[key] = value;
740
- temp[key] = value;
741
- });
742
- OnyxCache_1.default.merge(temp);
743
- return Promise.resolve();
744
- })
745
- // We are going to send the data to the subscriber.
746
- .finally(() => {
748
+ multiGet(matchingKeys).then((dataMap) => {
749
+ const data = Object.fromEntries(dataMap.entries());
747
750
  sendDataToConnection(mapping, data, undefined, true);
748
751
  });
749
752
  }
@@ -936,5 +939,6 @@ const OnyxUtils = {
936
939
  applyMerge,
937
940
  initializeWithDefaultKeyStates,
938
941
  getSnapshotKey,
942
+ multiGet,
939
943
  };
940
944
  exports.default = OnyxUtils;
package/dist/useOnyx.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { IsEqual } from 'type-fest';
2
- import type { CollectionKeyBase, OnyxCollection, OnyxKey, OnyxValue, Selector } from './types';
2
+ import type { CollectionKeyBase, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector } from './types';
3
3
  type BaseUseOnyxOptions = {
4
4
  /**
5
5
  * Determines if this key in this subscription is safe to be evicted.
@@ -30,7 +30,8 @@ type UseOnyxSelectorOption<TKey extends OnyxKey, TReturnValue> = {
30
30
  selector?: Selector<TKey, unknown, TReturnValue>;
31
31
  };
32
32
  type FetchStatus = 'loading' | 'loaded';
33
- type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, OnyxValue<TKey>> extends true ? TValue : TKey extends CollectionKeyBase ? NonNullable<OnyxCollection<TValue>> : TValue;
33
+ type SelectedValue<TKey, TValue> = TKey extends CollectionKeyBase ? OnyxCollection<TValue> : OnyxEntry<TValue>;
34
+ type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, OnyxValue<TKey>> extends true ? TValue : SelectedValue<TKey, TValue>;
34
35
  type ResultMetadata = {
35
36
  status: FetchStatus;
36
37
  };
package/dist/utils.js CHANGED
@@ -11,7 +11,7 @@ function isEmptyObject(obj) {
11
11
  */
12
12
  function isMergeableObject(value) {
13
13
  const isNonNullObject = value != null ? typeof value === 'object' : false;
14
- return isNonNullObject && Object.prototype.toString.call(value) !== '[object RegExp]' && Object.prototype.toString.call(value) !== '[object Date]' && !Array.isArray(value);
14
+ return isNonNullObject && !(value instanceof RegExp) && !(value instanceof Date) && !Array.isArray(value);
15
15
  }
16
16
  /**
17
17
  * Merges the source object into the target object.
@@ -28,9 +28,8 @@ function mergeObject(target, source, shouldRemoveNestedNulls = true) {
28
28
  // If "shouldRemoveNestedNulls" is true, we want to remove null values from the merged object
29
29
  // and therefore we need to omit keys where either the source or target value is null.
30
30
  if (targetObject) {
31
- const targetKeys = Object.keys(targetObject);
32
- for (let i = 0; i < targetKeys.length; ++i) {
33
- const key = targetKeys[i];
31
+ // eslint-disable-next-line no-restricted-syntax, guard-for-in
32
+ for (const key in targetObject) {
34
33
  const sourceValue = source === null || source === void 0 ? void 0 : source[key];
35
34
  const targetValue = targetObject === null || targetObject === void 0 ? void 0 : targetObject[key];
36
35
  // If "shouldRemoveNestedNulls" is true, we want to remove null values from the merged object.
@@ -46,9 +45,8 @@ function mergeObject(target, source, shouldRemoveNestedNulls = true) {
46
45
  }
47
46
  }
48
47
  // After copying over all keys from the target object, we want to merge the source object into the destination object.
49
- const sourceKeys = Object.keys(source);
50
- for (let i = 0; i < sourceKeys.length; ++i) {
51
- const key = sourceKeys[i];
48
+ // eslint-disable-next-line no-restricted-syntax, guard-for-in
49
+ for (const key in source) {
52
50
  const sourceValue = source === null || source === void 0 ? void 0 : source[key];
53
51
  const targetValue = targetObject === null || targetObject === void 0 ? void 0 : targetObject[key];
54
52
  // If undefined is passed as the source value for a key, we want to generally ignore it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.52",
3
+ "version": "2.0.54",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",