|
1 | 1 | import { MutationCache, QueryClient } from '@tanstack/react-query'; |
2 | 2 | import { operateOnTags } from './operateOnTags'; |
3 | | -import { resolveTags } from './resolveTags'; |
4 | | -import type { QueryTagContext } from './types'; |
5 | | -import { type UpdateTagsUndoer, undoUpdateTags, updateTags } from './updateTags'; |
| 3 | +import type { QueryTagObject } from './types'; |
6 | 4 |
|
7 | 5 | type BuilderMutationCacheOptions = { |
8 | 6 | getQueryClient: () => QueryClient; |
9 | 7 | syncChannel?: BroadcastChannel; |
10 | 8 | }; |
11 | 9 |
|
12 | 10 | export class BuilderMutationCache extends MutationCache { |
13 | | - constructor(config: MutationCache['config'], { getQueryClient, syncChannel }: BuilderMutationCacheOptions) { |
14 | | - // onMutate does not allow returning a context value in global MutationCache. |
15 | | - // So we store the undos in our own map based on the mutationId. |
16 | | - // See: https://tanstack.com/query/latest/docs/reference/MutationCache#global-callbacks |
17 | | - type MutationContext = { undos?: UpdateTagsUndoer[] }; |
18 | | - |
19 | | - const mutationContexts = new Map<number, MutationContext>(); |
20 | | - |
21 | | - super({ |
22 | | - onMutate: async (...args) => { |
23 | | - await config?.onMutate?.(...args); |
24 | | - |
25 | | - const [vars, mutation] = args; |
26 | | - const queryClient = getQueryClient(); |
27 | | - |
28 | | - const data = !vars || typeof vars !== 'object' ? undefined : Reflect.get(vars, 'body'); |
29 | | - const optUpdates = resolveTags({ client: queryClient, tags: mutation.meta?.optimisticUpdates, vars, data }); |
30 | | - const ctx: QueryTagContext<unknown> = { client: queryClient, vars, data }; |
31 | | - const undos = updateTags({ queryClient, tags: optUpdates, ctx, optimistic: true }); |
32 | | - if (undos.length) mutationContexts.set(mutation.mutationId, { undos }); |
33 | | - |
34 | | - const tags = optUpdates.filter( |
35 | | - (tag) => typeof tag !== 'object' || ['pre', 'both'].includes(tag.invalidate || 'both'), |
36 | | - ); |
37 | | - |
38 | | - operateOnTags({ queryClient, tags }, { refetchType: 'none' }); |
39 | | - }, |
40 | | - onSuccess: async (...args) => { |
41 | | - await config?.onSuccess?.(...args); |
42 | | - |
43 | | - const [data, vars, , mutation] = args; |
44 | | - const queryClient = getQueryClient(); |
45 | | - |
46 | | - const updates = resolveTags({ client: queryClient, tags: mutation.meta?.updates, vars, data }); |
47 | | - updateTags({ queryClient, tags: updates, ctx: { client: queryClient, vars, data } }); |
48 | | - }, |
49 | | - onError: async (...args) => { |
50 | | - await config?.onError?.(...args); |
51 | | - |
52 | | - const [, , , mutation] = args; |
53 | | - const queryClient = getQueryClient(); |
54 | | - |
55 | | - const { undos } = mutationContexts.get(mutation.mutationId) || {}; |
56 | | - if (undos) undoUpdateTags(undos, queryClient); |
57 | | - }, |
58 | | - onSettled: async (...args): Promise<void> => { |
59 | | - await config?.onSettled?.(...args); |
60 | | - |
61 | | - const [data, error, vars, , mutation] = args; |
62 | | - const queryClient = getQueryClient(); |
63 | | - |
64 | | - mutationContexts.delete(mutation.mutationId); |
65 | | - |
66 | | - const optUpdates = resolveTags({ client: queryClient, tags: mutation.meta?.optimisticUpdates, vars, data }); |
67 | | - const optUpdateTags = optUpdates.filter((tag) => ['post', 'both'].includes(tag.invalidate || 'both')); |
68 | | - operateOnTags({ queryClient, tags: optUpdateTags }); |
69 | | - |
70 | | - const pesUpdates = resolveTags({ client: queryClient, tags: mutation.meta?.updates, vars, data }); |
71 | | - const pesUpdateTags = pesUpdates.filter((tag) => ['post', 'both'].includes(tag.invalidate || 'both')); |
72 | | - operateOnTags({ queryClient, tags: pesUpdateTags }); |
73 | | - |
74 | | - const tags = resolveTags({ client: queryClient, tags: mutation.meta?.invalidates, vars, data, error }); |
| 11 | + syncChannel?: BroadcastChannel; |
| 12 | + tagsCache: { hash: string; tag: QueryTagObject }[] = []; |
75 | 13 |
|
76 | | - if (syncChannel) { |
77 | | - const tagsToSync = [...tags, ...optUpdateTags, ...pesUpdateTags].map(({ type, id }) => ({ type, id })); |
78 | | - syncChannel.postMessage({ type: 'invalidate', data: tagsToSync }); |
79 | | - } |
| 14 | + constructor(config: MutationCache['config'], { getQueryClient, syncChannel }: BuilderMutationCacheOptions) { |
| 15 | + super(config); |
80 | 16 |
|
81 | | - return operateOnTags({ queryClient, tags }); |
82 | | - }, |
83 | | - }); |
| 17 | + this.syncChannel = syncChannel; |
84 | 18 |
|
85 | 19 | syncChannel?.addEventListener('message', (event) => { |
86 | 20 | const { type, data } = event.data; |
|
0 commit comments