Skip to content

Commit eaf7d5e

Browse files
committed
Pass additional metadata to merge
1 parent 90ff485 commit eaf7d5e

File tree

3 files changed

+65
-7
lines changed

3 files changed

+65
-7
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ export function buildSlice({
181181

182182
if (merge) {
183183
if (substate.data !== undefined) {
184+
const { fulfilledTimeStamp, arg, baseQueryMeta, requestId } =
185+
meta
184186
// There's existing cache data. Let the user merge it in themselves.
185187
// We're already inside an Immer-powered reducer, and the user could just mutate `substate.data`
186188
// themselves inside of `merge()`. But, they might also want to return a new value.
@@ -189,7 +191,12 @@ export function buildSlice({
189191
substate.data,
190192
(draftSubstateData) => {
191193
// As usual with Immer, you can mutate _or_ return inside here, but not both
192-
return merge(draftSubstateData, payload)
194+
return merge(draftSubstateData, payload, {
195+
arg: arg.originalArgs,
196+
baseQueryMeta,
197+
fulfilledTimeStamp,
198+
requestId,
199+
})
193200
}
194201
)
195202
substate.data = newData

packages/toolkit/src/query/endpointDefinitions.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,13 @@ export interface QueryExtraOptions<
445445
*/
446446
merge?(
447447
currentCacheData: ResultType,
448-
responseData: ResultType
448+
responseData: ResultType,
449+
otherArgs: {
450+
arg: QueryArg
451+
baseQueryMeta: BaseQueryMeta<BaseQuery>
452+
requestId: string
453+
fulfilledTimeStamp: number
454+
}
449455
): ResultType | void
450456

451457
/**

packages/toolkit/src/query/tests/createApi.test.ts

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ afterAll(() => {
3535
spy.mockRestore()
3636
})
3737

38+
function paginate<T>(array: T[], page_size: number, page_number: number) {
39+
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
40+
return array.slice((page_number - 1) * page_size, page_number * page_size)
41+
}
42+
3843
test('sensible defaults', () => {
3944
const api = createApi({
4045
baseQuery: fetchBaseQuery(),
@@ -923,6 +928,22 @@ describe('custom serializeQueryArgs per endpoint', () => {
923928
return currentArg !== previousArg
924929
},
925930
}),
931+
listItems2: build.query<{ items: string[]; meta?: any }, number>({
932+
query: (pageNumber) => `/listItems2?page=${pageNumber}`,
933+
serializeQueryArgs: ({ endpointName }) => {
934+
return endpointName
935+
},
936+
transformResponse(items: string[]) {
937+
return { items }
938+
},
939+
merge: (currentCache, newData, meta) => {
940+
currentCache.items.push(...newData.items)
941+
currentCache.meta = meta
942+
},
943+
forceRefetch({ currentArg, previousArg }) {
944+
return currentArg !== previousArg
945+
},
946+
}),
926947
}),
927948
})
928949

@@ -1010,11 +1031,6 @@ describe('custom serializeQueryArgs per endpoint', () => {
10101031
const allItems = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'i']
10111032
const PAGE_SIZE = 3
10121033

1013-
function paginate<T>(array: T[], page_size: number, page_number: number) {
1014-
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
1015-
return array.slice((page_number - 1) * page_size, page_number * page_size)
1016-
}
1017-
10181034
server.use(
10191035
rest.get('https://example.com/listItems', (req, res, ctx) => {
10201036
const pageString = req.url.searchParams.get('page')
@@ -1038,4 +1054,33 @@ describe('custom serializeQueryArgs per endpoint', () => {
10381054
const updatedEntry = selectListItems(storeRef.store.getState())
10391055
expect(updatedEntry.data).toEqual(['a', 'b', 'c', 'd', 'e', 'f'])
10401056
})
1057+
1058+
test('merge receives a meta object as an argument', async () => {
1059+
const allItems = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'i']
1060+
const PAGE_SIZE = 3
1061+
1062+
server.use(
1063+
rest.get('https://example.com/listItems2', (req, res, ctx) => {
1064+
const pageString = req.url.searchParams.get('page')
1065+
const pageNum = parseInt(pageString || '0')
1066+
1067+
const results = paginate(allItems, PAGE_SIZE, pageNum)
1068+
return res(ctx.json(results))
1069+
})
1070+
)
1071+
1072+
const selectListItems = api.endpoints.listItems2.select(0)
1073+
1074+
await storeRef.store.dispatch(api.endpoints.listItems2.initiate(1))
1075+
await storeRef.store.dispatch(api.endpoints.listItems2.initiate(2))
1076+
const cacheEntry = selectListItems(storeRef.store.getState())
1077+
1078+
// Should have passed along the third arg from `merge` containing these fields
1079+
expect(cacheEntry.data?.meta).toEqual({
1080+
requestId: expect.any(String),
1081+
fulfilledTimeStamp: expect.any(Number),
1082+
arg: 2,
1083+
baseQueryMeta: expect.any(Object),
1084+
})
1085+
})
10411086
})

0 commit comments

Comments
 (0)