Skip to content

Commit

Permalink
Merge pull request #4671 from pierroberto/feat/4644-tags-invalidation…
Browse files Browse the repository at this point in the history
…-improvements

Feat/4644 tags invalidation improvements
  • Loading branch information
markerikson authored Nov 23, 2024
2 parents 4d70f2c + a9def39 commit c87a59a
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 15 deletions.
2 changes: 1 addition & 1 deletion packages/toolkit/src/query/core/buildMiddleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export function buildMiddleware<

const actions = {
invalidateTags: createAction<
Array<TagTypes | FullTagDescription<TagTypes>>
Array<TagTypes | FullTagDescription<TagTypes> | null | undefined>
>(`${reducerPath}/invalidateTags`),
}

Expand Down
6 changes: 3 additions & 3 deletions packages/toolkit/src/query/core/buildSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
TagTypesFrom,
} from '../endpointDefinitions'
import { expandTagDescription } from '../endpointDefinitions'
import { flatten } from '../utils'
import { flatten, isNotNullish } from '../utils'
import type {
MutationSubState,
QueryCacheKey,
Expand Down Expand Up @@ -206,15 +206,15 @@ export function buildSelectors<

function selectInvalidatedBy(
state: RootState,
tags: ReadonlyArray<TagDescription<string>>,
tags: ReadonlyArray<TagDescription<string> | null | undefined>,
): Array<{
endpointName: string
originalArgs: any
queryCacheKey: QueryCacheKey
}> {
const apiState = state[reducerPath]
const toInvalidate = new Set<QueryCacheKey>()
for (const tag of tags.map(expandTagDescription)) {
for (const tag of tags.filter(isNotNullish).map(expandTagDescription)) {
const provided = apiState.provided[tag.type]
if (!provided) {
continue
Expand Down
4 changes: 2 additions & 2 deletions packages/toolkit/src/query/core/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export interface ApiModules<
* ```
*/
invalidateTags: ActionCreatorWithPayload<
Array<TagDescription<TagTypes>>,
Array<TagDescription<TagTypes> | null | undefined>,
string
>

Expand All @@ -361,7 +361,7 @@ export interface ApiModules<
*/
selectInvalidatedBy: (
state: RootState<Definitions, string, ReducerPath>,
tags: ReadonlyArray<TagDescription<TagTypes>>,
tags: ReadonlyArray<TagDescription<TagTypes> | null | undefined>,
) => Array<{
endpointName: string
originalArgs: any
Expand Down
6 changes: 4 additions & 2 deletions packages/toolkit/src/query/endpointDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type {
OmitFromUnion,
UnwrapPromise,
} from './tsHelpers'
import { isNotNullish } from './utils'

const resultType = /* @__PURE__ */ Symbol()
const baseQuery = /* @__PURE__ */ Symbol()
Expand Down Expand Up @@ -224,7 +225,7 @@ export type GetResultDescriptionFn<
error: ErrorType | undefined,
arg: QueryArg,
meta: MetaType,
) => ReadonlyArray<TagDescription<TagTypes>>
) => ReadonlyArray<TagDescription<TagTypes> | undefined | null>

export type FullTagDescription<TagType> = {
type: TagType
Expand All @@ -242,7 +243,7 @@ export type ResultDescription<
ErrorType,
MetaType,
> =
| ReadonlyArray<TagDescription<TagTypes>>
| ReadonlyArray<TagDescription<TagTypes> | undefined | null>
| GetResultDescriptionFn<TagTypes, ResultType, QueryArg, ErrorType, MetaType>

type QueryTypes<
Expand Down Expand Up @@ -778,6 +779,7 @@ export function calculateProvidedBy<ResultType, QueryArg, ErrorType, MetaType>(
queryArg,
meta as MetaType,
)
.filter(isNotNullish)
.map(expandTagDescription)
.map(assertTagTypes)
}
Expand Down
68 changes: 66 additions & 2 deletions packages/toolkit/src/query/tests/buildMiddleware.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createApi } from '@reduxjs/toolkit/query'
import { actionsReducer, setupApiStore } from '../../tests/utils/helpers'
import { delay } from 'msw'
import { actionsReducer, setupApiStore } from '../../tests/utils/helpers'

const baseQuery = (args?: any) => ({ data: args })
const api = createApi({
Expand All @@ -25,9 +25,15 @@ const api = createApi({
},
providesTags: ['Bread'],
}),
invalidateFruit: build.mutation({
query: (fruit?: 'Banana' | 'Bread' | null) => ({ url: `invalidate/fruit/${fruit || ''}` }),
invalidatesTags(result, error, arg) {
return [arg]
}
})
}),
})
const { getBanana, getBread } = api.endpoints
const { getBanana, getBread, invalidateFruit } = api.endpoints

const storeRef = setupApiStore(api, {
...actionsReducer,
Expand Down Expand Up @@ -70,3 +76,61 @@ it('invalidates the specified tags', async () => {
getBread.matchFulfilled,
)
})

it('invalidates tags correctly when null or undefined are provided as tags', async() =>{
await storeRef.store.dispatch(getBanana.initiate(1))
await storeRef.store.dispatch(api.util.invalidateTags([undefined, null, 'Banana']))

// Slight pause to let the middleware run and such
await delay(20)

const apiActions = [
api.internalActions.middlewareRegistered.match,
getBanana.matchPending,
getBanana.matchFulfilled,
api.util.invalidateTags.match,
getBanana.matchPending,
getBanana.matchFulfilled,
]

expect(storeRef.store.getState().actions).toMatchSequence(...apiActions)
})


it.each([
{ tags: [undefined, null, 'Bread'] as Parameters<typeof api.util.invalidateTags>['0'] },
{ tags: [undefined, null], }, { tags: [] }]
)('does not invalidate with tags=$tags if no query matches', async ({ tags }) => {
await storeRef.store.dispatch(getBanana.initiate(1))
await storeRef.store.dispatch(api.util.invalidateTags(tags))

// Slight pause to let the middleware run and such
await delay(20)

const apiActions = [
api.internalActions.middlewareRegistered.match,
getBanana.matchPending,
getBanana.matchFulfilled,
api.util.invalidateTags.match,
]

expect(storeRef.store.getState().actions).toMatchSequence(...apiActions)
})

it.each([{ mutationArg: 'Bread' as "Bread" | null | undefined }, { mutationArg: undefined }, { mutationArg: null }])('does not invalidate queries when a mutation with tags=[$mutationArg] runs and does not match anything', async ({ mutationArg }) => {
await storeRef.store.dispatch(getBanana.initiate(1))
await storeRef.store.dispatch(invalidateFruit.initiate(mutationArg))

// Slight pause to let the middleware run and such
await delay(20)

const apiActions = [
api.internalActions.middlewareRegistered.match,
getBanana.matchPending,
getBanana.matchFulfilled,
invalidateFruit.matchPending,
invalidateFruit.matchFulfilled,
]

expect(storeRef.store.getState().actions).toMatchSequence(...apiActions)
})
2 changes: 1 addition & 1 deletion packages/toolkit/src/query/tests/createApi.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('type tests', () => {

expectTypeOf(api.util.invalidateTags)
.parameter(0)
.toEqualTypeOf<TagDescription<never>[]>()
.toEqualTypeOf<(null | undefined | TagDescription<never>)[]>()
})

describe('endpoint definition typings', () => {
Expand Down
12 changes: 8 additions & 4 deletions packages/toolkit/src/query/tests/invalidation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const tagTypes = [
'giraffe',
] as const
type TagTypes = (typeof tagTypes)[number]
type Tags = TagDescription<TagTypes>[]

type ProvidedTags = TagDescription<TagTypes>[]
type InvalidatesTags = (ProvidedTags[number] | null | undefined)[]
/** providesTags, invalidatesTags, shouldInvalidate */
const caseMatrix: [Tags, Tags, boolean][] = [
const caseMatrix: [ProvidedTags, InvalidatesTags, boolean][] = [
// *****************************
// basic invalidation behavior
// *****************************
Expand All @@ -39,7 +39,11 @@ const caseMatrix: [Tags, Tags, boolean][] = [
// type + id invalidates type + id
[[{ type: 'apple', id: 1 }], [{ type: 'apple', id: 1 }], true],
[[{ type: 'apple', id: 1 }], [{ type: 'apple', id: 2 }], false],

// null and undefined
[['apple'], [null], false],
[['apple'], [undefined], false],
[['apple'], [null, 'apple'], true],
[['apple'], [undefined, 'apple'], true],
// *****************************
// test multiple values in array
// *****************************
Expand Down

0 comments on commit c87a59a

Please sign in to comment.