@@ -34,6 +34,7 @@ import type {
3434 QuerySubstateIdentifier ,
3535 InfiniteData ,
3636 InfiniteQueryConfigOptions ,
37+ QueryCacheKey ,
3738} from './apiState'
3839import { QueryStatus } from './apiState'
3940import type {
@@ -122,7 +123,6 @@ export type InfiniteQueryThunkArg = QuerySubstateIdentifier &
122123 type : `query`
123124 originalArgs : unknown
124125 endpointName : string
125- data : InfiniteData < unknown >
126126 param : unknown
127127 previous ?: boolean
128128 direction ?: 'forward' | 'backwards'
@@ -379,6 +379,7 @@ export function buildThunks<
379379 )
380380 }
381381
382+ // The generic async payload function for all of our thunks
382383 const executeEndpoint : AsyncThunkPayloadCreator <
383384 ThunkResult ,
384385 QueryThunkArg | MutationThunkArg | InfiniteQueryThunkArg ,
@@ -402,8 +403,11 @@ export function buildThunks<
402403 baseQueryReturnValue : any ,
403404 meta : any ,
404405 arg : any ,
405- ) => any = defaultTransformResponse
406- let result : QueryReturnValue
406+ ) => any =
407+ endpointDefinition . query && endpointDefinition . transformResponse
408+ ? endpointDefinition . transformResponse
409+ : defaultTransformResponse
410+
407411 const baseQueryApi = {
408412 signal,
409413 abort,
@@ -419,158 +423,191 @@ export function buildThunks<
419423
420424 const forceQueryFn =
421425 arg . type === 'query' ? arg [ forceQueryFnSymbol ] : undefined
422- if ( forceQueryFn ) {
423- result = forceQueryFn ( )
424- } else if ( endpointDefinition . query ) {
425- const oldPages : any [ ] = [ ]
426- const oldPageParams : any [ ] = [ ]
427-
428- const fetchPage = async (
429- data : InfiniteData < unknown > ,
430- param : unknown ,
431- previous ?: boolean ,
432- ) : Promise < QueryReturnValue > => {
433- if ( param == null && data . pages . length ) {
434- return Promise . resolve ( { data } )
435- }
436426
437- const page = await baseQuery (
438- endpointDefinition . query ( param ) ,
439- baseQueryApi ,
440- endpointDefinition . extraOptions as any ,
441- )
442-
443- const maxPages = 20
444- const addTo = previous ? addToStart : addToEnd
445-
446- return {
447- data : {
448- pages : addTo ( data . pages , page . data , maxPages ) ,
449- pageParams : addTo ( data . pageParams , param , maxPages ) ,
450- } ,
451- }
427+ let finalQueryReturnValue : QueryReturnValue
428+
429+ // Infinite query wrapper, which executes the request and returns
430+ // the InfiniteData `{pages, pageParams}` structure
431+ const fetchPage = async (
432+ data : InfiniteData < unknown > ,
433+ param : unknown ,
434+ previous ?: boolean ,
435+ ) : Promise < QueryReturnValue > => {
436+ if ( param == null && data . pages . length ) {
437+ return Promise . resolve ( { data } )
452438 }
453439
454- if ( 'infiniteQueryOptions' in endpointDefinition ) {
455- if ( 'direction' in arg && arg . direction && arg . data . pages . length ) {
456- const previous = arg . direction === 'backwards'
457- const pageParamFn = previous
458- ? getPreviousPageParam
459- : getNextPageParam
460- const oldData = arg . data
461- const param = pageParamFn (
462- endpointDefinition . infiniteQueryOptions ,
463- oldData ,
464- )
440+ const pageResponse = await executeRequest ( param )
465441
466- result = await fetchPage ( oldData , param , previous )
467- } else {
468- // Fetch first page
469- result = await fetchPage (
470- { pages : [ ] , pageParams : [ ] } ,
471- oldPageParams [ 0 ] ?? arg . originalArgs ,
472- )
442+ // TODO Get maxPages from endpoint config
443+ const maxPages = 20
444+ const addTo = previous ? addToStart : addToEnd
473445
474- //original
475- // const remainingPages = pages ?? oldPages.length
476- const remainingPages = oldPages . length
477-
478- // Fetch remaining pages
479- for ( let i = 1 ; i < remainingPages ; i ++ ) {
480- // @ts -ignore
481- const param = getNextPageParam (
482- endpointDefinition . infiniteQueryOptions ,
483- result . data as InfiniteData < unknown > ,
484- )
485- result = await fetchPage (
486- result . data as InfiniteData < unknown > ,
487- param ,
488- )
489- }
490- }
491- } else {
446+ return {
447+ data : {
448+ pages : addTo ( data . pages , pageResponse . data , maxPages ) ,
449+ pageParams : addTo ( data . pageParams , param , maxPages ) ,
450+ } ,
451+ }
452+ }
453+
454+ // Wrapper for executing either `query` or `queryFn`,
455+ // and handling any errors
456+ async function executeRequest (
457+ finalQueryArg : unknown ,
458+ ) : Promise < QueryReturnValue > {
459+ let result : QueryReturnValue
460+
461+ if ( forceQueryFn ) {
462+ // upsertQueryData relies on this to pass in the user-provided value
463+ result = forceQueryFn ( )
464+ } else if ( endpointDefinition . query ) {
492465 result = await baseQuery (
493- endpointDefinition . query ( arg . originalArgs ) ,
466+ endpointDefinition . query ( finalQueryArg ) ,
467+ baseQueryApi ,
468+ endpointDefinition . extraOptions as any ,
469+ )
470+ } else {
471+ result = await endpointDefinition . queryFn (
472+ finalQueryArg ,
494473 baseQueryApi ,
495474 endpointDefinition . extraOptions as any ,
475+ ( arg ) =>
476+ baseQuery (
477+ arg ,
478+ baseQueryApi ,
479+ endpointDefinition . extraOptions as any ,
480+ ) ,
496481 )
482+ }
497483
498- if ( endpointDefinition . transformResponse ) {
499- transformResponse = endpointDefinition . transformResponse
484+ if (
485+ typeof process !== 'undefined' &&
486+ process . env . NODE_ENV === 'development'
487+ ) {
488+ const what = endpointDefinition . query ? '`baseQuery`' : '`queryFn`'
489+ let err : undefined | string
490+ if ( ! result ) {
491+ err = `${ what } did not return anything.`
492+ } else if ( typeof result !== 'object' ) {
493+ err = `${ what } did not return an object.`
494+ } else if ( result . error && result . data ) {
495+ err = `${ what } returned an object containing both \`error\` and \`result\`.`
496+ } else if ( result . error === undefined && result . data === undefined ) {
497+ err = `${ what } returned an object containing neither a valid \`error\` and \`result\`. At least one of them should not be \`undefined\``
498+ } else {
499+ for ( const key of Object . keys ( result ) ) {
500+ if ( key !== 'error' && key !== 'data' && key !== 'meta' ) {
501+ err = `The object returned by ${ what } has the unknown property ${ key } .`
502+ break
503+ }
504+ }
505+ }
506+ if ( err ) {
507+ console . error (
508+ `Error encountered handling the endpoint ${ arg . endpointName } .
509+ ${ err }
510+ It needs to return an object with either the shape \`{ data: <value> }\` or \`{ error: <value> }\` that may contain an optional \`meta\` property.
511+ Object returned was:` ,
512+ result ,
513+ )
500514 }
501515 }
502- } else {
503- result = await endpointDefinition . queryFn (
504- arg . originalArgs ,
505- baseQueryApi ,
506- endpointDefinition . extraOptions as any ,
507- ( arg ) =>
508- baseQuery (
509- arg ,
510- baseQueryApi ,
511- endpointDefinition . extraOptions as any ,
512- ) ,
516+
517+ if ( result . error ) throw new HandledError ( result . error , result . meta )
518+
519+ const transformedResponse = await transformResponse (
520+ result . data ,
521+ result . meta ,
522+ finalQueryArg ,
513523 )
524+
525+ return {
526+ ...result ,
527+ data : transformedResponse ,
528+ }
514529 }
515530
516531 if (
517- typeof process !== 'undefined ' &&
518- process . env . NODE_ENV === 'development'
532+ arg . type === 'query ' &&
533+ 'infiniteQueryOptions' in endpointDefinition
519534 ) {
520- const what = endpointDefinition . query ? '`baseQuery`' : '`queryFn`'
521- let err : undefined | string
522- if ( ! result ) {
523- err = `${ what } did not return anything.`
524- } else if ( typeof result !== 'object' ) {
525- err = `${ what } did not return an object.`
526- } else if ( result . error && result . data ) {
527- err = `${ what } returned an object containing both \`error\` and \`result\`.`
528- } else if ( result . error === undefined && result . data === undefined ) {
529- err = `${ what } returned an object containing neither a valid \`error\` and \`result\`. At least one of them should not be \`undefined\``
535+ // This is an infinite query endpoint
536+
537+ let result : QueryReturnValue
538+
539+ // Start by looking up the existing InfiniteData value from state,
540+ // falling back to an empty value if it doesn't exist yet
541+ const existingData = ( getState ( ) [ reducerPath ] . queries [ arg . queryCacheKey ]
542+ ?. data ?? { pages : [ ] , pageParams : [ ] } ) as InfiniteData <
543+ unknown ,
544+ unknown
545+ >
546+
547+ // If the thunk specified a direction and we do have at least one page,
548+ // fetch the next or previous page
549+ if ( 'direction' in arg && arg . direction && existingData . pages . length ) {
550+ const previous = arg . direction === 'backwards'
551+ const pageParamFn = previous ? getPreviousPageParam : getNextPageParam
552+ const param = pageParamFn (
553+ endpointDefinition . infiniteQueryOptions ,
554+ existingData ,
555+ )
556+
557+ result = await fetchPage ( existingData , param , previous )
530558 } else {
531- for ( const key of Object . keys ( result ) ) {
532- if ( key !== 'error' && key !== 'data' && key !== 'meta' ) {
533- err = `The object returned by ${ what } has the unknown property ${ key } .`
534- break
535- }
536- }
537- }
538- if ( err ) {
539- console . error (
540- `Error encountered handling the endpoint ${ arg . endpointName } .
541- ${ err }
542- It needs to return an object with either the shape \`{ data: <value> }\` or \`{ error: <value> }\` that may contain an optional \`meta\` property.
543- Object returned was:` ,
544- result ,
559+ // Otherwise, fetch the first page and then any remaining pages
560+
561+ // Fetch first page
562+ result = await fetchPage (
563+ existingData ,
564+ existingData . pageParams [ 0 ] ?? arg . originalArgs ,
545565 )
566+
567+ //original
568+ // const remainingPages = pages ?? oldPages.length
569+ // const remainingPages = oldPages.length
570+
571+ // TODO This seems pretty wrong
572+ const remainingPages = existingData . pages . length
573+
574+ // Fetch remaining pages
575+ for ( let i = 1 ; i < remainingPages ; i ++ ) {
576+ const param = getNextPageParam (
577+ endpointDefinition . infiniteQueryOptions ,
578+ result . data as InfiniteData < unknown > ,
579+ )
580+ result = await fetchPage (
581+ result . data as InfiniteData < unknown > ,
582+ param ,
583+ )
584+ }
546585 }
547- }
548586
549- if ( result . error ) throw new HandledError ( result . error , result . meta )
587+ finalQueryReturnValue = result
588+ } else {
589+ // Non-infinite endpoint. Just run the one request.
590+ finalQueryReturnValue = await executeRequest ( arg . originalArgs )
591+ }
550592
551- return fulfillWithValue (
552- await transformResponse ( result . data , result . meta , arg . originalArgs ) ,
553- {
554- fulfilledTimeStamp : Date . now ( ) ,
555- baseQueryMeta : result . meta ,
556- [ SHOULD_AUTOBATCH ] : true ,
557- } ,
558- )
593+ // console.log('Final result: ', transformedData)
594+ return fulfillWithValue ( finalQueryReturnValue . data , {
595+ fulfilledTimeStamp : Date . now ( ) ,
596+ baseQueryMeta : finalQueryReturnValue . meta ,
597+ [ SHOULD_AUTOBATCH ] : true ,
598+ } )
559599 } catch ( error ) {
560600 let catchedError = error
561601 if ( catchedError instanceof HandledError ) {
562602 let transformErrorResponse : (
563603 baseQueryReturnValue : any ,
564604 meta : any ,
565605 arg : any ,
566- ) => any = defaultTransformResponse
606+ ) => any =
607+ endpointDefinition . query && endpointDefinition . transformErrorResponse
608+ ? endpointDefinition . transformErrorResponse
609+ : defaultTransformResponse
567610
568- if (
569- endpointDefinition . query &&
570- endpointDefinition . transformErrorResponse
571- ) {
572- transformErrorResponse = endpointDefinition . transformErrorResponse
573- }
574611 try {
575612 return rejectWithValue (
576613 await transformErrorResponse (
@@ -716,7 +753,6 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".`
716753 startedTimeStamp : Date . now ( ) ,
717754 [ SHOULD_AUTOBATCH ] : true ,
718755 direction : queryThunkArgs . arg . direction ,
719- data : queryThunkArgs . arg . data ,
720756 }
721757 } ,
722758 condition ( queryThunkArgs , { getState } ) {
0 commit comments