11import type { QueryDefinition } from '../../endpointDefinitions'
2- import type { ConfigState , QueryCacheKey } from '../apiState'
2+ import type { ConfigState , QueryCacheKey , QuerySubState } from '../apiState'
33import { isAnyOf } from '../rtkImports'
44import type {
55 ApiMiddlewareInternalHandler ,
@@ -11,16 +11,6 @@ import type {
1111
1212export type ReferenceCacheCollection = never
1313
14- function isObjectEmpty ( obj : Record < any , any > ) {
15- // Apparently a for..in loop is faster than `Object.keys()` here:
16- // https://stackoverflow.com/a/59787784/62937
17- for ( const k in obj ) {
18- // If there is at least one key, it's not empty
19- return false
20- }
21- return true
22- }
23-
2414export type CacheCollectionQueryExtraOptions = {
2515 /**
2616 * Overrides the api-wide definition of `keepUnusedDataFor` for this endpoint only. _(This value is in seconds.)_
@@ -44,6 +34,7 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
4434 context,
4535 internalState,
4636 selectors : { selectQueryEntry, selectConfig } ,
37+ getRunningQueryThunk,
4738} ) => {
4839 const { removeQueryResult, unsubscribeQueryResult, cacheEntriesUpserted } =
4940 api . internalActions
@@ -57,7 +48,16 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
5748
5849 function anySubscriptionsRemainingForKey ( queryCacheKey : string ) {
5950 const subscriptions = internalState . currentSubscriptions [ queryCacheKey ]
60- return ! ! subscriptions && ! isObjectEmpty ( subscriptions )
51+ if ( ! subscriptions ) return false
52+
53+ // Check if there are any keys that are NOT _running subscriptions
54+ for ( const key in subscriptions ) {
55+ if ( ! key . endsWith ( '_running' ) ) {
56+ return true
57+ }
58+ }
59+ // Only _running subscriptions remain (or empty)
60+ return false
6161 }
6262
6363 const currentRemovalTimeouts : QueryStateMeta < TimeoutId > = { }
@@ -69,6 +69,7 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
6969 ) => {
7070 const state = mwApi . getState ( )
7171 const config = selectConfig ( state )
72+
7273 if ( canTriggerUnsubscribe ( action ) ) {
7374 let queryCacheKeys : QueryCacheKey [ ]
7475
@@ -114,18 +115,20 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
114115 const state = api . getState ( )
115116 for ( const queryCacheKey of cacheKeys ) {
116117 const entry = selectQueryEntry ( state , queryCacheKey )
117- handleUnsubscribe ( queryCacheKey , entry ?. endpointName , api , config )
118+ if ( entry ?. endpointName ) {
119+ handleUnsubscribe ( queryCacheKey , entry . endpointName , api , config )
120+ }
118121 }
119122 }
120123
121124 function handleUnsubscribe (
122125 queryCacheKey : QueryCacheKey ,
123- endpointName : string | undefined ,
126+ endpointName : string ,
124127 api : SubMiddlewareApi ,
125128 config : ConfigState < string > ,
126129 ) {
127130 const endpointDefinition = context . endpointDefinitions [
128- endpointName !
131+ endpointName
129132 ] as QueryDefinition < any , any , any , any >
130133 const keepUnusedDataFor =
131134 endpointDefinition ?. keepUnusedDataFor ?? config . keepUnusedDataFor
@@ -150,7 +153,17 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
150153 }
151154
152155 currentRemovalTimeouts [ queryCacheKey ] = setTimeout ( ( ) => {
156+ // console.log(new Date(), 'Timeout fired: ', queryCacheKey)
153157 if ( ! anySubscriptionsRemainingForKey ( queryCacheKey ) ) {
158+ // Try to abort any running query for this cache key
159+ const entry = selectQueryEntry ( api . getState ( ) , queryCacheKey )
160+
161+ if ( entry ?. endpointName ) {
162+ const runningQuery = api . dispatch (
163+ getRunningQueryThunk ( entry . endpointName , entry . originalArgs ) ,
164+ )
165+ runningQuery ?. abort ( )
166+ }
154167 api . dispatch ( removeQueryResult ( { queryCacheKey } ) )
155168 }
156169 delete currentRemovalTimeouts ! [ queryCacheKey ]
0 commit comments