/** * External dependencies */ import type { Middleware } from 'redux'; /** * Internal dependencies */ import type { DataRegistry } from './types'; /** * Creates a middleware handling resolvers cache invalidation. * * @param registry Registry for which to create the middleware. * @param storeName Name of the store for which to create the middleware. * * @return Middleware function. */ const createResolversCacheMiddleware = ( registry: DataRegistry, storeName: string ): Middleware => () => ( next ) => ( action ) => { const resolvers = registry.select( storeName ).getCachedResolvers(); const resolverEntries = Object.entries< Map< string, { status: 'finished' | 'error' } > >( resolvers ); resolverEntries.forEach( ( [ selectorName, resolversByArgs ] ) => { const resolver = registry.stores[ storeName ]?.resolvers?.[ selectorName ]; if ( ! resolver || ! resolver.shouldInvalidate ) { return; } const { shouldInvalidate } = resolver; resolversByArgs.forEach( ( value, args ) => { // Works around a bug in `EquivalentKeyMap` where `map.delete` merely sets an entry value // to `undefined` and `map.forEach` then iterates also over these orphaned entries. if ( value === undefined ) { return; } // resolversByArgs is the map Map([ args ] => boolean) storing the cache resolution status for a given selector. // If the value is "finished" or "error" it means this resolver has finished its resolution which means we need // to invalidate it, if it's true it means it's inflight and the invalidation is not necessary. if ( value.status !== 'finished' && value.status !== 'error' ) { return; } if ( ! shouldInvalidate( action, ...args ) ) { return; } // Trigger cache invalidation registry .dispatch( storeName ) .invalidateResolution( selectorName, args ); } ); } ); return next( action ); }; export default createResolversCacheMiddleware;