Skip to content

Commit 337e06f

Browse files
committed
Deduplicate buildInitiate
1 parent 2de5170 commit 337e06f

File tree

2 files changed

+89
-175
lines changed

2 files changed

+89
-175
lines changed

packages/toolkit/src/query/core/buildInitiate.ts

Lines changed: 89 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
import type {
2+
AsyncThunkAction,
23
SafePromise,
34
SerializedError,
45
ThunkAction,
5-
ThunkDispatch,
66
UnknownAction,
77
} from '@reduxjs/toolkit'
88
import type { Dispatch } from 'redux'
99
import { asSafePromise } from '../../tsHelpers'
1010
import type { Api, ApiContext } from '../apiTypes'
1111
import type { BaseQueryError, QueryReturnValue } from '../baseQueryTypes'
1212
import 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'
2325
import { countObjectKeys, getOrInsert, isNotNullish } from '../utils'
2426
import type {
@@ -33,11 +35,13 @@ import type {
3335
} from './buildSelectors'
3436
import 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

4246
export type BuildInitiateApiEndpointQuery<
4347
Definition extends QueryDefinition<any, any, any, any, any>,
@@ -70,20 +74,20 @@ export type StartQueryActionCreatorOptions = {
7074

7175
export 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

8892
type 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+
121133
export 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

135142
type 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

packages/toolkit/src/query/core/buildThunks.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ export type InfiniteQueryThunkArg<
136136
originalArgs: unknown
137137
endpointName: string
138138
param: unknown
139-
previous?: boolean
140139
direction?: InfiniteQueryDirection
141140
}
142141

0 commit comments

Comments
 (0)