@@ -7,7 +7,11 @@ import type {
7
7
} from '../baseQueryTypes'
8
8
import type { RootState , QueryKeys , QuerySubstateIdentifier } from './apiState'
9
9
import { QueryStatus } from './apiState'
10
- import type { StartQueryActionCreatorOptions } from './buildInitiate'
10
+ import {
11
+ forceQueryFnSymbol ,
12
+ StartQueryActionCreatorOptions ,
13
+ QueryActionCreatorResult ,
14
+ } from './buildInitiate'
11
15
import type {
12
16
AssertTagTypes ,
13
17
EndpointDefinition ,
@@ -144,6 +148,9 @@ function defaultTransformResponse(baseQueryReturnValue: unknown) {
144
148
145
149
export type MaybeDrafted < T > = T | Draft < T >
146
150
export type Recipe < T > = ( data : MaybeDrafted < T > ) => void | MaybeDrafted < T >
151
+ export type UpsertRecipe < T > = (
152
+ data : MaybeDrafted < T > | undefined
153
+ ) => void | MaybeDrafted < T >
147
154
148
155
export type PatchQueryDataThunk <
149
156
Definitions extends EndpointDefinitions ,
@@ -163,6 +170,24 @@ export type UpdateQueryDataThunk<
163
170
updateRecipe : Recipe < ResultTypeFrom < Definitions [ EndpointName ] > >
164
171
) => ThunkAction < PatchCollection , PartialState , any , AnyAction >
165
172
173
+ export type UpsertQueryDataThunk <
174
+ Definitions extends EndpointDefinitions ,
175
+ PartialState
176
+ > = < EndpointName extends QueryKeys < Definitions > > (
177
+ endpointName : EndpointName ,
178
+ args : QueryArgFrom < Definitions [ EndpointName ] > ,
179
+ value : ResultTypeFrom < Definitions [ EndpointName ] >
180
+ ) => ThunkAction <
181
+ QueryActionCreatorResult <
182
+ Definitions [ EndpointName ] extends QueryDefinition < any , any , any , any >
183
+ ? Definitions [ EndpointName ]
184
+ : never
185
+ > ,
186
+ PartialState ,
187
+ any ,
188
+ AnyAction
189
+ >
190
+
166
191
/**
167
192
* An object returned from dispatching a `api.util.updateQueryData` call.
168
193
*/
@@ -255,6 +280,24 @@ export function buildThunks<
255
280
return ret
256
281
}
257
282
283
+ const upsertQueryData : UpsertQueryDataThunk < Definitions , State > =
284
+ ( endpointName , args , value ) => ( dispatch ) => {
285
+ return dispatch (
286
+ (
287
+ api . endpoints [ endpointName ] as ApiEndpointQuery <
288
+ QueryDefinition < any , any , any , any , any > ,
289
+ Definitions
290
+ >
291
+ ) . initiate ( args , {
292
+ subscribe : false ,
293
+ forceRefetch : true ,
294
+ [ forceQueryFnSymbol ] : ( ) => ( {
295
+ data : value ,
296
+ } ) ,
297
+ } )
298
+ )
299
+ }
300
+
258
301
const executeEndpoint : AsyncThunkPayloadCreator <
259
302
ThunkResult ,
260
303
QueryThunkArg | MutationThunkArg ,
@@ -291,7 +334,12 @@ export function buildThunks<
291
334
forced :
292
335
arg . type === 'query' ? isForcedQuery ( arg , getState ( ) ) : undefined ,
293
336
}
294
- if ( endpointDefinition . query ) {
337
+
338
+ const forceQueryFn =
339
+ arg . type === 'query' ? arg [ forceQueryFnSymbol ] : undefined
340
+ if ( forceQueryFn ) {
341
+ result = forceQueryFn ( )
342
+ } else if ( endpointDefinition . query ) {
295
343
result = await baseQuery (
296
344
endpointDefinition . query ( arg . originalArgs ) ,
297
345
baseQueryApi ,
@@ -431,12 +479,17 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".`
431
479
const requestState = state [ reducerPath ] ?. queries ?. [ arg . queryCacheKey ]
432
480
const fulfilledVal = requestState ?. fulfilledTimeStamp
433
481
434
- // Don't retry a request that's currently in-flight
435
- if ( requestState ?. status === 'pending' ) return false
482
+ // Order of these checks matters.
483
+ // In order for `upsertQueryData` to successfully run while an existing request is
484
+ /// in flight, we have to check `isForcedQuery` before `status === 'pending'`,
485
+ // otherwise `queryThunk` will bail out and not run at all.
436
486
437
487
// if this is forced, continue
438
488
if ( isForcedQuery ( arg , state ) ) return true
439
489
490
+ // Don't retry a request that's currently in-flight
491
+ if ( requestState ?. status === 'pending' ) return false
492
+
440
493
// Pull from the cache unless we explicitly force refetch or qualify based on time
441
494
if ( fulfilledVal )
442
495
// Value is cached and we didn't specify to refresh, skip it.
@@ -527,6 +580,7 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".`
527
580
mutationThunk,
528
581
prefetch,
529
582
updateQueryData,
583
+ upsertQueryData,
530
584
patchQueryData,
531
585
buildMatchThunkActions,
532
586
}
0 commit comments