11import type {
2+ AsyncThunkAction ,
23 SafePromise ,
34 SerializedError ,
45 ThunkAction ,
5- ThunkDispatch ,
66 UnknownAction ,
77} from '@reduxjs/toolkit'
88import type { Dispatch } from 'redux'
99import { asSafePromise } from '../../tsHelpers'
1010import type { Api , ApiContext } from '../apiTypes'
1111import type { BaseQueryError , QueryReturnValue } from '../baseQueryTypes'
1212import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
13- import type {
14- EndpointDefinitions ,
15- InfiniteQueryArgFrom ,
16- InfiniteQueryDefinition ,
17- MutationDefinition ,
18- PageParamFrom ,
19- QueryArgFrom ,
20- QueryDefinition ,
21- ResultTypeFrom ,
13+ import {
14+ isQueryDefinition ,
15+ type EndpointDefinition ,
16+ type EndpointDefinitions ,
17+ type InfiniteQueryArgFrom ,
18+ type InfiniteQueryDefinition ,
19+ type MutationDefinition ,
20+ type PageParamFrom ,
21+ type QueryArgFrom ,
22+ type QueryDefinition ,
23+ type ResultTypeFrom ,
2224} from '../endpointDefinitions'
2325import { countObjectKeys , getOrInsert , isNotNullish } from '../utils'
2426import type {
@@ -33,11 +35,13 @@ import type {
3335} from './buildSelectors'
3436import type {
3537 InfiniteQueryThunk ,
38+ InfiniteQueryThunkArg ,
3639 MutationThunk ,
3740 QueryThunk ,
3841 QueryThunkArg ,
42+ ThunkApiMetaConfig ,
3943} from './buildThunks'
40- import type { ApiEndpointInfiniteQuery , ApiEndpointQuery } from './module'
44+ import type { ApiEndpointQuery } from './module'
4145
4246export type BuildInitiateApiEndpointQuery <
4347 Definition extends QueryDefinition < any , any , any , any , any > ,
@@ -70,20 +74,20 @@ export type StartQueryActionCreatorOptions = {
7074
7175export type StartInfiniteQueryActionCreatorOptions <
7276 D extends InfiniteQueryDefinition < any , any , any , any , any > ,
73- > = {
74- subscribe ?: boolean
75- forceRefetch ?: boolean | number
76- subscriptionOptions ?: SubscriptionOptions
77+ > = StartQueryActionCreatorOptions & {
7778 direction ?: InfiniteQueryDirection
78- [ forceQueryFnSymbol ] ?: ( ) => QueryReturnValue
7979 param ?: unknown
80- previous ?: boolean
8180} & Partial <
82- Pick <
83- Partial < InfiniteQueryConfigOptions < ResultTypeFrom < D > , PageParamFrom < D > > > ,
84- 'initialPageParam'
81+ Pick <
82+ Partial < InfiniteQueryConfigOptions < ResultTypeFrom < D > , PageParamFrom < D > > > ,
83+ 'initialPageParam'
84+ >
8585 >
86- >
86+
87+ type AnyQueryActionCreator < D extends EndpointDefinition < any , any , any , any > > = (
88+ arg : any ,
89+ options ?: StartQueryActionCreatorOptions ,
90+ ) => ThunkAction < AnyActionCreatorResult , any , any , UnknownAction >
8791
8892type StartQueryActionCreator <
8993 D extends QueryDefinition < any , any , any , any , any > ,
@@ -99,38 +103,41 @@ type StartInfiniteQueryActionCreator<
99103> = (
100104 arg : InfiniteQueryArgFrom < D > ,
101105 options ?: StartInfiniteQueryActionCreatorOptions < D > ,
102- ) => (
103- dispatch : ThunkDispatch < any , any , UnknownAction > ,
104- getState : ( ) => any ,
105- ) => InfiniteQueryActionCreatorResult < D >
106+ ) => ThunkAction < InfiniteQueryActionCreatorResult < D > , any , any , UnknownAction >
106107
107- export type QueryActionCreatorResult <
108- D extends QueryDefinition < any , any , any , any > ,
109- > = SafePromise < QueryResultSelectorResult < D > > & {
110- arg : QueryArgFrom < D >
108+ type QueryActionCreatorFields = {
111109 requestId : string
112110 subscriptionOptions : SubscriptionOptions | undefined
113111 abort ( ) : void
114- unwrap ( ) : Promise < ResultTypeFrom < D > >
115112 unsubscribe ( ) : void
116- refetch ( ) : QueryActionCreatorResult < D >
117113 updateSubscriptionOptions ( options : SubscriptionOptions ) : void
118114 queryCacheKey : string
119115}
120116
117+ type AnyActionCreatorResult = SafePromise < any > &
118+ QueryActionCreatorFields & {
119+ arg : any
120+ unwrap ( ) : Promise < any >
121+ refetch ( ) : AnyActionCreatorResult
122+ }
123+
124+ export type QueryActionCreatorResult <
125+ D extends QueryDefinition < any , any , any , any > ,
126+ > = SafePromise < QueryResultSelectorResult < D > > &
127+ QueryActionCreatorFields & {
128+ arg : QueryArgFrom < D >
129+ unwrap ( ) : Promise < ResultTypeFrom < D > >
130+ refetch ( ) : QueryActionCreatorResult < D >
131+ }
132+
121133export type InfiniteQueryActionCreatorResult <
122134 D extends InfiniteQueryDefinition < any , any , any , any , any > ,
123- > = Promise < InfiniteQueryResultSelectorResult < D > > & {
124- arg : InfiniteQueryArgFrom < D >
125- requestId : string
126- subscriptionOptions : SubscriptionOptions | undefined
127- abort ( ) : void
128- unwrap ( ) : Promise < ResultTypeFrom < D > >
129- unsubscribe ( ) : void
130- refetch ( ) : InfiniteQueryActionCreatorResult < D >
131- updateSubscriptionOptions ( options : SubscriptionOptions ) : void
132- queryCacheKey : string
133- }
135+ > = SafePromise < InfiniteQueryResultSelectorResult < D > > &
136+ QueryActionCreatorFields & {
137+ arg : InfiniteQueryArgFrom < D >
138+ unwrap ( ) : Promise < InfiniteData < ResultTypeFrom < D > , PageParamFrom < D > > >
139+ refetch ( ) : InfiniteQueryActionCreatorResult < D >
140+ }
134141
135142type StartMutationActionCreator <
136143 D extends MutationDefinition < any , any , any , any > ,
@@ -360,11 +367,13 @@ You must add the middleware for RTK-Query to function correctly!`,
360367 }
361368 }
362369
363- function buildInitiateQuery (
370+ function buildInitiateAnyQuery < T extends 'query' | 'infiniteQuery' > (
364371 endpointName : string ,
365- endpointDefinition : QueryDefinition < any , any , any , any > ,
372+ endpointDefinition :
373+ | QueryDefinition < any , any , any , any >
374+ | InfiniteQueryDefinition < any , any , any , any , any > ,
366375 ) {
367- const queryAction : StartQueryActionCreator < any > =
376+ const queryAction : AnyQueryActionCreator < any > =
368377 (
369378 arg ,
370379 {
@@ -382,17 +391,36 @@ You must add the middleware for RTK-Query to function correctly!`,
382391 endpointName,
383392 } )
384393
385- const thunk = queryThunk ( {
394+ let thunk : AsyncThunkAction < unknown , QueryThunkArg , ThunkApiMetaConfig >
395+
396+ const commonThunkArgs = {
386397 ...rest ,
387- type : 'query' ,
398+ type : 'query' as const ,
388399 subscribe,
389400 forceRefetch : forceRefetch ,
390401 subscriptionOptions,
391402 endpointName,
392403 originalArgs : arg ,
393404 queryCacheKey,
394405 [ forceQueryFnSymbol ] : forceQueryFn ,
395- } )
406+ }
407+
408+ if ( isQueryDefinition ( endpointDefinition ) ) {
409+ thunk = queryThunk ( commonThunkArgs )
410+ } else {
411+ const { direction, initialPageParam } = rest as Pick <
412+ InfiniteQueryThunkArg < any > ,
413+ 'direction' | 'initialPageParam'
414+ >
415+ thunk = infiniteQueryThunk ( {
416+ ...( commonThunkArgs as InfiniteQueryThunkArg < any > ) ,
417+ // Supply these even if undefined. This helps with a field existence
418+ // check over in `buildSlice.ts`
419+ direction,
420+ initialPageParam,
421+ } )
422+ }
423+
396424 const selector = (
397425 api . endpoints [ endpointName ] as ApiEndpointQuery < any , any >
398426 ) . select ( arg )
@@ -409,7 +437,7 @@ You must add the middleware for RTK-Query to function correctly!`,
409437 const runningQuery = runningQueries . get ( dispatch ) ?. [ queryCacheKey ]
410438 const selectFromState = ( ) => selector ( getState ( ) )
411439
412- const statePromise : QueryActionCreatorResult < any > = Object . assign (
440+ const statePromise : AnyActionCreatorResult = Object . assign (
413441 ( forceQueryFn
414442 ? // a query has been forced (upsertQueryData)
415443 // -> we want to resolve it once data has been written with the data that will be written
@@ -482,138 +510,25 @@ You must add the middleware for RTK-Query to function correctly!`,
482510 return queryAction
483511 }
484512
485- // Concept for the pagination thunk which queries for each page
513+ function buildInitiateQuery (
514+ endpointName : string ,
515+ endpointDefinition : QueryDefinition < any , any , any , any > ,
516+ ) {
517+ const queryAction : StartQueryActionCreator < any > = buildInitiateAnyQuery (
518+ endpointName ,
519+ endpointDefinition ,
520+ )
521+
522+ return queryAction
523+ }
486524
487525 function buildInitiateInfiniteQuery (
488526 endpointName : string ,
489527 endpointDefinition : InfiniteQueryDefinition < any , any , any , any , any > ,
490- pages ?: number ,
491528 ) {
492529 const infiniteQueryAction : StartInfiniteQueryActionCreator < any > =
493- (
494- arg ,
495- {
496- subscribe = true ,
497- forceRefetch,
498- subscriptionOptions,
499- initialPageParam,
500- [ forceQueryFnSymbol ] : forceQueryFn ,
501- direction,
502- param = arg ,
503- previous,
504- } = { } ,
505- ) =>
506- ( dispatch , getState ) => {
507- const queryCacheKey = serializeQueryArgs ( {
508- queryArgs : param ,
509- endpointDefinition,
510- endpointName,
511- } )
512-
513- const thunk = infiniteQueryThunk ( {
514- type : 'query' ,
515- subscribe,
516- forceRefetch : forceRefetch ,
517- subscriptionOptions,
518- endpointName,
519- originalArgs : arg ,
520- queryCacheKey,
521- [ forceQueryFnSymbol ] : forceQueryFn ,
522- param,
523- previous,
524- direction,
525- initialPageParam,
526- } )
527- const selector = (
528- api . endpoints [ endpointName ] as ApiEndpointInfiniteQuery < any , any >
529- ) . select ( arg )
530+ buildInitiateAnyQuery ( endpointName , endpointDefinition )
530531
531- const thunkResult = dispatch ( thunk )
532- const stateAfter = selector ( getState ( ) )
533-
534- middlewareWarning ( dispatch )
535-
536- const { requestId, abort } = thunkResult
537-
538- const skippedSynchronously = stateAfter . requestId !== requestId
539-
540- const runningQuery = runningQueries . get ( dispatch ) ?. [ queryCacheKey ]
541- const selectFromState = ( ) => selector ( getState ( ) )
542-
543- const statePromise : InfiniteQueryActionCreatorResult < any > =
544- Object . assign (
545- ( forceQueryFn
546- ? // a query has been forced (upsertQueryData)
547- // -> we want to resolve it once data has been written with the data that will be written
548- thunkResult . then ( selectFromState )
549- : skippedSynchronously && ! runningQuery
550- ? // a query has been skipped due to a condition and we do not have any currently running query
551- // -> we want to resolve it immediately with the current data
552- Promise . resolve ( stateAfter )
553- : // query just started or one is already in flight
554- // -> wait for the running query, then resolve with data from after that
555- Promise . all ( [ runningQuery , thunkResult ] ) . then (
556- selectFromState ,
557- ) ) as SafePromise < any > ,
558- {
559- arg,
560- requestId,
561- subscriptionOptions,
562- queryCacheKey,
563- abort,
564- async unwrap ( ) {
565- const result = await statePromise
566-
567- if ( result . isError ) {
568- throw result . error
569- }
570-
571- return result . data
572- } ,
573- refetch : ( ) =>
574- dispatch (
575- infiniteQueryAction ( arg , {
576- subscribe : false ,
577- forceRefetch : true ,
578- } ) ,
579- ) ,
580- unsubscribe ( ) {
581- if ( subscribe )
582- dispatch (
583- unsubscribeQueryResult ( {
584- queryCacheKey,
585- requestId,
586- } ) ,
587- )
588- } ,
589- updateSubscriptionOptions ( options : SubscriptionOptions ) {
590- statePromise . subscriptionOptions = options
591- dispatch (
592- updateSubscriptionOptions ( {
593- endpointName,
594- requestId,
595- queryCacheKey,
596- options,
597- } ) ,
598- )
599- } ,
600- } ,
601- )
602-
603- if ( ! runningQuery && ! skippedSynchronously && ! forceQueryFn ) {
604- const running = runningQueries . get ( dispatch ) || { }
605- running [ queryCacheKey ] = statePromise
606- runningQueries . set ( dispatch , running )
607-
608- statePromise . then ( ( ) => {
609- delete running [ queryCacheKey ]
610- if ( ! countObjectKeys ( running ) ) {
611- runningQueries . delete ( dispatch )
612- }
613- } )
614- }
615- return statePromise
616- }
617532 return infiniteQueryAction
618533 }
619534
0 commit comments