@@ -6,7 +6,6 @@ import type {
66 ThunkDispatch ,
77 UnknownAction ,
88} from '@reduxjs/toolkit'
9- import util from 'util'
109import type { Patch } from 'immer'
1110import { isDraftable , produceWithPatches } from 'immer'
1211import type { Api , ApiContext } from '../apiTypes'
@@ -297,6 +296,21 @@ export type PatchCollection = {
297296 undo : ( ) => void
298297}
299298
299+ type TransformCallback = (
300+ baseQueryReturnValue : unknown ,
301+ meta : unknown ,
302+ arg : unknown ,
303+ ) => any
304+
305+ export const addShouldAutoBatch = < T extends Record < string , any > > (
306+ arg : T = { } as T ,
307+ ) : T & { [ SHOULD_AUTOBATCH ] : true } => {
308+ return {
309+ ...arg ,
310+ [ SHOULD_AUTOBATCH ] : true ,
311+ }
312+ }
313+
300314export function buildThunks <
301315 BaseQuery extends BaseQueryFn ,
302316 ReducerPath extends string ,
@@ -446,6 +460,15 @@ export function buildThunks<
446460 return res
447461 }
448462
463+ const getTransformCallbackForEndpoint = (
464+ endpointDefinition : EndpointDefinition < any , any , any , any > ,
465+ transformFieldName : 'transformResponse' | 'transformErrorResponse' ,
466+ ) => {
467+ return endpointDefinition . query && endpointDefinition [ transformFieldName ]
468+ ? endpointDefinition [ transformFieldName ]
469+ : defaultTransformResponse
470+ }
471+
449472 // The generic async payload function for all of our thunks
450473 const executeEndpoint : AsyncThunkPayloadCreator <
451474 ThunkResult ,
@@ -466,14 +489,8 @@ export function buildThunks<
466489 const endpointDefinition = endpointDefinitions [ arg . endpointName ]
467490
468491 try {
469- let transformResponse : (
470- baseQueryReturnValue : any ,
471- meta : any ,
472- arg : any ,
473- ) => any =
474- endpointDefinition . query && endpointDefinition . transformResponse
475- ? endpointDefinition . transformResponse
476- : defaultTransformResponse
492+ let transformResponse : TransformCallback =
493+ getTransformCallbackForEndpoint ( endpointDefinition , 'transformResponse' )
477494
478495 const baseQueryApi = {
479496 signal,
@@ -509,7 +526,6 @@ export function buildThunks<
509526
510527 const pageResponse = await executeRequest ( param )
511528
512- // TODO Get maxPages from endpoint config
513529 const addTo = previous ? addToStart : addToEnd
514530
515531 return {
@@ -526,6 +542,7 @@ export function buildThunks<
526542 finalQueryArg : unknown ,
527543 ) : Promise < QueryReturnValue > {
528544 let result : QueryReturnValue
545+ const { extraOptions } = endpointDefinition
529546
530547 if ( forceQueryFn ) {
531548 // upsertQueryData relies on this to pass in the user-provided value
@@ -534,19 +551,14 @@ export function buildThunks<
534551 result = await baseQuery (
535552 endpointDefinition . query ( finalQueryArg ) ,
536553 baseQueryApi ,
537- endpointDefinition . extraOptions as any ,
554+ extraOptions as any ,
538555 )
539556 } else {
540557 result = await endpointDefinition . queryFn (
541558 finalQueryArg ,
542559 baseQueryApi ,
543- endpointDefinition . extraOptions as any ,
544- ( arg ) =>
545- baseQuery (
546- arg ,
547- baseQueryApi ,
548- endpointDefinition . extraOptions as any ,
549- ) ,
560+ extraOptions as any ,
561+ ( arg ) => baseQuery ( arg , baseQueryApi , extraOptions as any ) ,
550562 )
551563 }
552564
@@ -657,7 +669,7 @@ export function buildThunks<
657669 // Fetch remaining pages
658670 for ( let i = 1 ; i < totalPages ; i ++ ) {
659671 const param = getNextPageParam (
660- endpointDefinition . infiniteQueryOptions ,
672+ infiniteQueryOptions ,
661673 result . data as InfiniteData < unknown , unknown > ,
662674 )
663675 result = await fetchPage (
@@ -675,22 +687,21 @@ export function buildThunks<
675687 }
676688
677689 // console.log('Final result: ', transformedData)
678- return fulfillWithValue ( finalQueryReturnValue . data , {
679- fulfilledTimeStamp : Date . now ( ) ,
680- baseQueryMeta : finalQueryReturnValue . meta ,
681- [ SHOULD_AUTOBATCH ] : true ,
682- } )
690+ return fulfillWithValue (
691+ finalQueryReturnValue . data ,
692+ addShouldAutoBatch ( {
693+ fulfilledTimeStamp : Date . now ( ) ,
694+ baseQueryMeta : finalQueryReturnValue . meta ,
695+ } ) ,
696+ )
683697 } catch ( error ) {
684698 let catchedError = error
685699 if ( catchedError instanceof HandledError ) {
686- let transformErrorResponse : (
687- baseQueryReturnValue : any ,
688- meta : any ,
689- arg : any ,
690- ) => any =
691- endpointDefinition . query && endpointDefinition . transformErrorResponse
692- ? endpointDefinition . transformErrorResponse
693- : defaultTransformResponse
700+ let transformErrorResponse : TransformCallback =
701+ getTransformCallbackForEndpoint (
702+ endpointDefinition ,
703+ 'transformErrorResponse' ,
704+ )
694705
695706 try {
696707 return rejectWithValue (
@@ -699,7 +710,7 @@ export function buildThunks<
699710 catchedError . meta ,
700711 arg . originalArgs ,
701712 ) ,
702- { baseQueryMeta : catchedError . meta , [ SHOULD_AUTOBATCH ] : true } ,
713+ addShouldAutoBatch ( { baseQueryMeta : catchedError . meta } ) ,
703714 )
704715 } catch ( e ) {
705716 catchedError = e
@@ -743,124 +754,92 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".`
743754 return false
744755 }
745756
746- const queryThunk = createAsyncThunk <
747- ThunkResult ,
748- QueryThunkArg ,
749- ThunkApiMetaConfig & { state : RootState < any , string , ReducerPath > }
750- > ( `${ reducerPath } /executeQuery` , executeEndpoint , {
751- getPendingMeta ( ) {
752- return { startedTimeStamp : Date . now ( ) , [ SHOULD_AUTOBATCH ] : true }
753- } ,
754- condition ( queryThunkArgs , { getState } ) {
755- const state = getState ( )
756-
757- const requestState =
758- state [ reducerPath ] ?. queries ?. [ queryThunkArgs . queryCacheKey ]
759- const fulfilledVal = requestState ?. fulfilledTimeStamp
760- const currentArg = queryThunkArgs . originalArgs
761- const previousArg = requestState ?. originalArgs
762- const endpointDefinition =
763- endpointDefinitions [ queryThunkArgs . endpointName ]
764-
765- // Order of these checks matters.
766- // In order for `upsertQueryData` to successfully run while an existing request is in flight,
767- /// we have to check for that first, otherwise `queryThunk` will bail out and not run at all.
768- if ( isUpsertQuery ( queryThunkArgs ) ) {
769- return true
770- }
771-
772- // Don't retry a request that's currently in-flight
773- if ( requestState ?. status === 'pending' ) {
774- return false
775- }
776-
777- // if this is forced, continue
778- if ( isForcedQuery ( queryThunkArgs , state ) ) {
779- return true
780- }
757+ const createQueryThunk = <
758+ ThunkArgType extends QueryThunkArg | InfiniteQueryThunkArg < any > ,
759+ > ( ) => {
760+ const generatedQueryThunk = createAsyncThunk <
761+ ThunkResult ,
762+ ThunkArgType ,
763+ ThunkApiMetaConfig & { state : RootState < any , string , ReducerPath > }
764+ > ( `${ reducerPath } /executeQuery` , executeEndpoint , {
765+ getPendingMeta ( { arg } ) {
766+ const endpointDefinition = endpointDefinitions [ arg . endpointName ]
767+ return addShouldAutoBatch ( {
768+ startedTimeStamp : Date . now ( ) ,
769+ ...( isInfiniteQueryDefinition ( endpointDefinition )
770+ ? {
771+ direction : ( arg as InfiniteQueryThunkArg < any > ) . direction ,
772+ }
773+ : { } ) ,
774+ } )
775+ } ,
776+ condition ( queryThunkArg , { getState } ) {
777+ const state = getState ( )
781778
782- if (
783- isQueryDefinition ( endpointDefinition ) &&
784- endpointDefinition ?. forceRefetch ?.( {
785- currentArg,
786- previousArg,
787- endpointState : requestState ,
779+ const requestState = selectors . selectQueryEntry (
788780 state ,
789- } )
790- ) {
791- return true
792- }
781+ queryThunkArg . queryCacheKey ,
782+ )
783+ const fulfilledVal = requestState ?. fulfilledTimeStamp
784+ const currentArg = queryThunkArg . originalArgs
785+ const previousArg = requestState ?. originalArgs
786+ const endpointDefinition =
787+ endpointDefinitions [ queryThunkArg . endpointName ]
788+ const direction = ( queryThunkArg as InfiniteQueryThunkArg < any > )
789+ . direction
790+
791+ // Order of these checks matters.
792+ // In order for `upsertQueryData` to successfully run while an existing request is in flight,
793+ /// we have to check for that first, otherwise `queryThunk` will bail out and not run at all.
794+ if ( isUpsertQuery ( queryThunkArg ) ) {
795+ return true
796+ }
793797
794- // Pull from the cache unless we explicitly force refetch or qualify based on time
795- if ( fulfilledVal ) {
796- // Value is cached and we didn't specify to refresh, skip it.
797- return false
798- }
798+ // Don't retry a request that's currently in-flight
799+ if ( requestState ?. status === 'pending' ) {
800+ return false
801+ }
799802
800- return true
801- } ,
802- dispatchConditionRejection : true ,
803- } )
803+ // if this is forced, continue
804+ if ( isForcedQuery ( queryThunkArg , state ) ) {
805+ return true
806+ }
804807
805- const infiniteQueryThunk = createAsyncThunk <
806- ThunkResult ,
807- InfiniteQueryThunkArg < any > ,
808- ThunkApiMetaConfig & { state : RootState < any , string , ReducerPath > }
809- > ( `${ reducerPath } /executeQuery` , executeEndpoint , {
810- getPendingMeta ( queryThunkArgs ) {
811- return {
812- startedTimeStamp : Date . now ( ) ,
813- [ SHOULD_AUTOBATCH ] : true ,
814- direction : queryThunkArgs . arg . direction ,
815- }
816- } ,
817- condition ( queryThunkArgs , { getState } ) {
818- const state = getState ( )
819-
820- const requestState =
821- state [ reducerPath ] ?. queries ?. [ queryThunkArgs . queryCacheKey ]
822- const fulfilledVal = requestState ?. fulfilledTimeStamp
823- const currentArg = queryThunkArgs . originalArgs
824- const previousArg = requestState ?. originalArgs
825- const endpointDefinition =
826- endpointDefinitions [ queryThunkArgs . endpointName ]
827- const direction = queryThunkArgs . direction
828-
829- // Order of these checks matters.
830- // In order for `upsertQueryData` to successfully run while an existing request is in flight,
831- /// we have to check for that first, otherwise `queryThunk` will bail out and not run at all.
832- // if (isUpsertQuery(queryThunkArgs)) {
833- // return true
834- // }
835-
836- // Don't retry a request that's currently in-flight
837- if ( requestState ?. status === 'pending' ) {
838- return false
839- }
808+ if (
809+ isQueryDefinition ( endpointDefinition ) &&
810+ endpointDefinition ?. forceRefetch ?.( {
811+ currentArg,
812+ previousArg,
813+ endpointState : requestState ,
814+ state,
815+ } )
816+ ) {
817+ return true
818+ }
840819
841- // if this is forced, continue
842- if ( isForcedQuery ( queryThunkArgs , state ) ) {
843- return true
844- }
820+ // Pull from the cache unless we explicitly force refetch or qualify based on time
821+ if ( fulfilledVal && ! direction ) {
822+ // Value is cached and we didn't specify to refresh, skip it.
823+ return false
824+ }
845825
846- // Pull from the cache unless we explicitly force refetch or qualify based on time
847- if ( fulfilledVal && ! direction ) {
848- // Value is cached and we didn't specify to refresh, skip it.
849- return false
850- }
826+ return true
827+ } ,
828+ dispatchConditionRejection : true ,
829+ } )
830+ return generatedQueryThunk
831+ }
851832
852- return true
853- } ,
854- dispatchConditionRejection : true ,
855- } )
833+ const queryThunk = createQueryThunk < QueryThunkArg > ( )
834+ const infiniteQueryThunk = createQueryThunk < InfiniteQueryThunkArg < any > > ( )
856835
857836 const mutationThunk = createAsyncThunk <
858837 ThunkResult ,
859838 MutationThunkArg ,
860839 ThunkApiMetaConfig & { state : RootState < any , string , ReducerPath > }
861840 > ( `${ reducerPath } /executeMutation` , executeEndpoint , {
862841 getPendingMeta ( ) {
863- return { startedTimeStamp : Date . now ( ) , [ SHOULD_AUTOBATCH ] : true }
842+ return addShouldAutoBatch ( { startedTimeStamp : Date . now ( ) } )
864843 } ,
865844 } )
866845
0 commit comments