@@ -245,6 +245,80 @@ function get<TKey extends OnyxKey, TValue extends OnyxValue<TKey>>(key: TKey): P
245245 return cache . captureTask ( taskName , promise ) as Promise < TValue > ;
246246}
247247
248+ // multiGet the data first from the cache and then from the storage for the missing keys.
249+ function multiGet < TKey extends OnyxKey > ( keys : CollectionKeyBase [ ] ) : Promise < Map < OnyxKey , OnyxValue < TKey > > > {
250+ // Keys that are not in the cache
251+ const missingKeys : OnyxKey [ ] = [ ] ;
252+
253+ // Tasks that are pending
254+ const pendingTasks : Array < Promise < OnyxValue < TKey > > > = [ ] ;
255+
256+ // Keys for the tasks that are pending
257+ const pendingKeys : OnyxKey [ ] = [ ] ;
258+
259+ // Data to be sent back to the invoker
260+ const dataMap = new Map < OnyxKey , OnyxValue < TKey > > ( ) ;
261+
262+ /**
263+ * We are going to iterate over all the matching keys and check if we have the data in the cache.
264+ * 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
265+ * for the key. If there is such task, then we add the promise to the pendingTasks array and the key to the pendingKeys
266+ * array. If there is no pending task then we add the key to the missingKeys array.
267+ *
268+ * These missingKeys will be later used to multiGet the data from the storage.
269+ */
270+ keys . forEach ( ( key ) => {
271+ const cacheValue = cache . get ( key ) as OnyxValue < TKey > ;
272+ if ( cacheValue ) {
273+ dataMap . set ( key , cacheValue ) ;
274+ return ;
275+ }
276+
277+ const pendingKey = `get:${ key } ` ;
278+ if ( cache . hasPendingTask ( pendingKey ) ) {
279+ pendingTasks . push ( cache . getTaskPromise ( pendingKey ) as Promise < OnyxValue < TKey > > ) ;
280+ pendingKeys . push ( key ) ;
281+ } else {
282+ missingKeys . push ( key ) ;
283+ }
284+ } ) ;
285+
286+ return (
287+ Promise . all ( pendingTasks )
288+ // Wait for all the pending tasks to resolve and then add the data to the data map.
289+ . then ( ( values ) => {
290+ values . forEach ( ( value , index ) => {
291+ dataMap . set ( pendingKeys [ index ] , value ) ;
292+ } ) ;
293+
294+ return Promise . resolve ( ) ;
295+ } )
296+ // Get the missing keys using multiGet from the storage.
297+ . then ( ( ) => {
298+ if ( missingKeys . length === 0 ) {
299+ return Promise . resolve ( undefined ) ;
300+ }
301+
302+ return Storage . multiGet ( missingKeys ) ;
303+ } )
304+ // Add the data from the missing keys to the data map and also merge it to the cache.
305+ . then ( ( values ) => {
306+ if ( ! values || values . length === 0 ) {
307+ return dataMap ;
308+ }
309+
310+ // temp object is used to merge the missing data into the cache
311+ const temp : OnyxCollection < KeyValueMapping [ TKey ] > = { } ;
312+ values . forEach ( ( [ key , value ] ) => {
313+ dataMap . set ( key , value as OnyxValue < TKey > ) ;
314+ temp [ key ] = value as OnyxValue < TKey > ;
315+ } ) ;
316+ cache . merge ( temp ) ;
317+ return dataMap ;
318+ } )
319+ ) ;
320+ }
321+
248322/** Returns current key names stored in persisted storage */
249323function getAllKeys ( ) : Promise < Set < OnyxKey > > {
250324 // When we've already read stored keys, resolve right away
@@ -843,75 +917,10 @@ function addKeyToRecentlyAccessedIfNeeded<TKey extends OnyxKey>(mapping: Mapping
843917 * Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
844918 */
845919function getCollectionDataAndSendAsObject < TKey extends OnyxKey > ( matchingKeys : CollectionKeyBase [ ] , mapping : Mapping < TKey > ) : void {
846- // Keys that are not in the cache
847- const missingKeys : OnyxKey [ ] = [ ] ;
848- // Tasks that are pending
849- const pendingTasks : Array < Promise < OnyxValue < TKey > > > = [ ] ;
850- // Keys for the tasks that are pending
851- const pendingKeys : OnyxKey [ ] = [ ] ;
852-
853- // We are going to combine all the data from the matching keys into a single object
854- const data : OnyxCollection < KeyValueMapping [ TKey ] > = { } ;
855-
856- /**
857- * We are going to iterate over all the matching keys and check if we have the data in the cache.
858- * If we do then we add it to the data object. If we do not then we check if there is a pending task
859- * for the key. If there is then we add the promise to the pendingTasks array and the key to the pendingKeys
860- * array. If there is no pending task then we add the key to the missingKeys array.
861- *
862- * These missingKeys will be later to use to multiGet the data from the storage.
863- */
864- matchingKeys . forEach ( ( key ) => {
865- const cacheValue = cache . get ( key ) as OnyxValue < TKey > ;
866- if ( cacheValue ) {
867- data [ key ] = cacheValue ;
868- return ;
869- }
870-
871- const pendingKey = `get:${ key } ` ;
872- if ( cache . hasPendingTask ( pendingKey ) ) {
873- pendingTasks . push ( cache . getTaskPromise ( pendingKey ) as Promise < OnyxValue < TKey > > ) ;
874- pendingKeys . push ( key ) ;
875- } else {
876- missingKeys . push ( key ) ;
877- }
920+ multiGet ( matchingKeys ) . then ( ( dataMap ) => {
921+ const data = Object . fromEntries ( dataMap . entries ( ) ) as OnyxValue < TKey > ;
922+ sendDataToConnection ( mapping , data , undefined , true ) ;
878923 } ) ;
879-
880- Promise . all ( pendingTasks )
881- // We are going to wait for all the pending tasks to resolve and then add the data to the data object.
882- . then ( ( values ) => {
883- values . forEach ( ( value , index ) => {
884- data [ pendingKeys [ index ] ] = value ;
885- } ) ;
886-
887- return Promise . resolve ( ) ;
888- } )
889- // We are going to get the missing keys using multiGet from the storage.
890- . then ( ( ) => {
891- if ( missingKeys . length === 0 ) {
892- return Promise . resolve ( undefined ) ;
893- }
894- return Storage . multiGet ( missingKeys ) ;
895- } )
896- // We are going to add the data from the missing keys to the data object and also merge it to the cache.
897- . then ( ( values ) => {
898- if ( ! values || values . length === 0 ) {
899- return Promise . resolve ( ) ;
900- }
901-
902- // temp object is used to merge the missing data into the cache
903- const temp : OnyxCollection < KeyValueMapping [ TKey ] > = { } ;
904- values . forEach ( ( [ key , value ] ) => {
905- data [ key ] = value as OnyxValue < TKey > ;
906- temp [ key ] = value as OnyxValue < TKey > ;
907- } ) ;
908- cache . merge ( temp ) ;
909- return Promise . resolve ( ) ;
910- } )
911- // We are going to send the data to the subscriber.
912- . finally ( ( ) => {
913- sendDataToConnection ( mapping , data as OnyxValue < TKey > , undefined , true ) ;
914- } ) ;
915924}
916925
917926/**
@@ -1150,6 +1159,7 @@ const OnyxUtils = {
11501159 applyMerge,
11511160 initializeWithDefaultKeyStates,
11521161 getSnapshotKey,
1162+ multiGet,
11531163} ;
11541164
11551165export default OnyxUtils ;
0 commit comments