@tanstack/query-core 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/build/cjs/focusManager.js +101 -0
  2. package/build/cjs/focusManager.js.map +1 -0
  3. package/build/cjs/hydration.js +112 -0
  4. package/build/cjs/hydration.js.map +1 -0
  5. package/build/cjs/index.js +51 -0
  6. package/build/cjs/index.js.map +1 -0
  7. package/build/cjs/infiniteQueryBehavior.js +160 -0
  8. package/build/cjs/infiniteQueryBehavior.js.map +1 -0
  9. package/build/cjs/infiniteQueryObserver.js +92 -0
  10. package/build/cjs/infiniteQueryObserver.js.map +1 -0
  11. package/build/cjs/logger.js +18 -0
  12. package/build/cjs/logger.js.map +1 -0
  13. package/build/cjs/mutation.js +258 -0
  14. package/build/cjs/mutation.js.map +1 -0
  15. package/build/cjs/mutationCache.js +99 -0
  16. package/build/cjs/mutationCache.js.map +1 -0
  17. package/build/cjs/mutationObserver.js +130 -0
  18. package/build/cjs/mutationObserver.js.map +1 -0
  19. package/build/cjs/notifyManager.js +114 -0
  20. package/build/cjs/notifyManager.js.map +1 -0
  21. package/build/cjs/onlineManager.js +100 -0
  22. package/build/cjs/onlineManager.js.map +1 -0
  23. package/build/cjs/queriesObserver.js +170 -0
  24. package/build/cjs/queriesObserver.js.map +1 -0
  25. package/build/cjs/query.js +474 -0
  26. package/build/cjs/query.js.map +1 -0
  27. package/build/cjs/queryCache.js +140 -0
  28. package/build/cjs/queryCache.js.map +1 -0
  29. package/build/cjs/queryClient.js +357 -0
  30. package/build/cjs/queryClient.js.map +1 -0
  31. package/build/cjs/queryObserver.js +521 -0
  32. package/build/cjs/queryObserver.js.map +1 -0
  33. package/build/cjs/removable.js +47 -0
  34. package/build/cjs/removable.js.map +1 -0
  35. package/build/cjs/retryer.js +177 -0
  36. package/build/cjs/retryer.js.map +1 -0
  37. package/build/cjs/subscribable.js +43 -0
  38. package/build/cjs/subscribable.js.map +1 -0
  39. package/build/cjs/utils.js +356 -0
  40. package/build/cjs/utils.js.map +1 -0
  41. package/build/esm/index.js +3077 -0
  42. package/build/esm/index.js.map +1 -0
  43. package/build/stats-html.html +2689 -0
  44. package/build/umd/index.development.js +3106 -0
  45. package/build/umd/index.development.js.map +1 -0
  46. package/build/umd/index.production.js +12 -0
  47. package/build/umd/index.production.js.map +1 -0
  48. package/package.json +25 -0
  49. package/src/focusManager.ts +89 -0
  50. package/src/hydration.ts +164 -0
  51. package/src/index.ts +35 -0
  52. package/src/infiniteQueryBehavior.ts +214 -0
  53. package/src/infiniteQueryObserver.ts +159 -0
  54. package/src/logger.native.ts +11 -0
  55. package/src/logger.ts +9 -0
  56. package/src/mutation.ts +349 -0
  57. package/src/mutationCache.ts +157 -0
  58. package/src/mutationObserver.ts +195 -0
  59. package/src/notifyManager.ts +96 -0
  60. package/src/onlineManager.ts +89 -0
  61. package/src/queriesObserver.ts +211 -0
  62. package/src/query.ts +612 -0
  63. package/src/queryCache.ts +206 -0
  64. package/src/queryClient.ts +716 -0
  65. package/src/queryObserver.ts +748 -0
  66. package/src/removable.ts +37 -0
  67. package/src/retryer.ts +215 -0
  68. package/src/subscribable.ts +33 -0
  69. package/src/tests/focusManager.test.tsx +155 -0
  70. package/src/tests/hydration.test.tsx +429 -0
  71. package/src/tests/infiniteQueryBehavior.test.tsx +124 -0
  72. package/src/tests/infiniteQueryObserver.test.tsx +64 -0
  73. package/src/tests/mutationCache.test.tsx +260 -0
  74. package/src/tests/mutationObserver.test.tsx +75 -0
  75. package/src/tests/mutations.test.tsx +363 -0
  76. package/src/tests/notifyManager.test.tsx +51 -0
  77. package/src/tests/onlineManager.test.tsx +148 -0
  78. package/src/tests/queriesObserver.test.tsx +330 -0
  79. package/src/tests/query.test.tsx +888 -0
  80. package/src/tests/queryCache.test.tsx +236 -0
  81. package/src/tests/queryClient.test.tsx +1435 -0
  82. package/src/tests/queryObserver.test.tsx +802 -0
  83. package/src/tests/utils.test.tsx +360 -0
  84. package/src/types.ts +705 -0
  85. package/src/utils.ts +435 -0
@@ -0,0 +1,349 @@
1
+ import type { MutationOptions, MutationStatus, MutationMeta } from './types'
2
+ import type { MutationCache } from './mutationCache'
3
+ import type { MutationObserver } from './mutationObserver'
4
+ import { defaultLogger, Logger } from './logger'
5
+ import { notifyManager } from './notifyManager'
6
+ import { Removable } from './removable'
7
+ import { canFetch, Retryer, createRetryer } from './retryer'
8
+
9
+ // TYPES
10
+
11
+ interface MutationConfig<TData, TError, TVariables, TContext> {
12
+ mutationId: number
13
+ mutationCache: MutationCache
14
+ options: MutationOptions<TData, TError, TVariables, TContext>
15
+ logger?: Logger
16
+ defaultOptions?: MutationOptions<TData, TError, TVariables, TContext>
17
+ state?: MutationState<TData, TError, TVariables, TContext>
18
+ meta?: MutationMeta
19
+ }
20
+
21
+ export interface MutationState<
22
+ TData = unknown,
23
+ TError = unknown,
24
+ TVariables = void,
25
+ TContext = unknown,
26
+ > {
27
+ context: TContext | undefined
28
+ data: TData | undefined
29
+ error: TError | null
30
+ failureCount: number
31
+ isPaused: boolean
32
+ status: MutationStatus
33
+ variables: TVariables | undefined
34
+ }
35
+
36
+ interface FailedAction {
37
+ type: 'failed'
38
+ }
39
+
40
+ interface LoadingAction<TVariables, TContext> {
41
+ type: 'loading'
42
+ variables?: TVariables
43
+ context?: TContext
44
+ }
45
+
46
+ interface SuccessAction<TData> {
47
+ type: 'success'
48
+ data: TData
49
+ }
50
+
51
+ interface ErrorAction<TError> {
52
+ type: 'error'
53
+ error: TError
54
+ }
55
+
56
+ interface PauseAction {
57
+ type: 'pause'
58
+ }
59
+
60
+ interface ContinueAction {
61
+ type: 'continue'
62
+ }
63
+
64
+ interface SetStateAction<TData, TError, TVariables, TContext> {
65
+ type: 'setState'
66
+ state: MutationState<TData, TError, TVariables, TContext>
67
+ }
68
+
69
+ export type Action<TData, TError, TVariables, TContext> =
70
+ | ContinueAction
71
+ | ErrorAction<TError>
72
+ | FailedAction
73
+ | LoadingAction<TVariables, TContext>
74
+ | PauseAction
75
+ | SetStateAction<TData, TError, TVariables, TContext>
76
+ | SuccessAction<TData>
77
+
78
+ // CLASS
79
+
80
+ export class Mutation<
81
+ TData = unknown,
82
+ TError = unknown,
83
+ TVariables = void,
84
+ TContext = unknown,
85
+ > extends Removable {
86
+ state: MutationState<TData, TError, TVariables, TContext>
87
+ options: MutationOptions<TData, TError, TVariables, TContext>
88
+ mutationId: number
89
+ meta: MutationMeta | undefined
90
+
91
+ private observers: MutationObserver<TData, TError, TVariables, TContext>[]
92
+ private mutationCache: MutationCache
93
+ private logger: Logger
94
+ private retryer?: Retryer<TData>
95
+
96
+ constructor(config: MutationConfig<TData, TError, TVariables, TContext>) {
97
+ super()
98
+
99
+ this.options = {
100
+ ...config.defaultOptions,
101
+ ...config.options,
102
+ }
103
+ this.mutationId = config.mutationId
104
+ this.mutationCache = config.mutationCache
105
+ this.logger = config.logger || defaultLogger
106
+ this.observers = []
107
+ this.state = config.state || getDefaultState()
108
+ this.meta = config.meta
109
+
110
+ this.updateCacheTime(this.options.cacheTime)
111
+ this.scheduleGc()
112
+ }
113
+
114
+ setState(state: MutationState<TData, TError, TVariables, TContext>): void {
115
+ this.dispatch({ type: 'setState', state })
116
+ }
117
+
118
+ addObserver(observer: MutationObserver<any, any, any, any>): void {
119
+ if (this.observers.indexOf(observer) === -1) {
120
+ this.observers.push(observer)
121
+
122
+ // Stop the mutation from being garbage collected
123
+ this.clearGcTimeout()
124
+
125
+ this.mutationCache.notify({
126
+ type: 'observerAdded',
127
+ mutation: this,
128
+ observer,
129
+ })
130
+ }
131
+ }
132
+
133
+ removeObserver(observer: MutationObserver<any, any, any, any>): void {
134
+ this.observers = this.observers.filter((x) => x !== observer)
135
+
136
+ this.scheduleGc()
137
+
138
+ this.mutationCache.notify({
139
+ type: 'observerRemoved',
140
+ mutation: this,
141
+ observer,
142
+ })
143
+ }
144
+
145
+ protected optionalRemove() {
146
+ if (!this.observers.length) {
147
+ if (this.state.status === 'loading') {
148
+ this.scheduleGc()
149
+ } else {
150
+ this.mutationCache.remove(this)
151
+ }
152
+ }
153
+ }
154
+
155
+ continue(): Promise<TData> {
156
+ if (this.retryer) {
157
+ this.retryer.continue()
158
+ return this.retryer.promise
159
+ }
160
+ return this.execute()
161
+ }
162
+
163
+ async execute(): Promise<TData> {
164
+ const executeMutation = () => {
165
+ this.retryer = createRetryer({
166
+ fn: () => {
167
+ if (!this.options.mutationFn) {
168
+ return Promise.reject('No mutationFn found')
169
+ }
170
+ return this.options.mutationFn(this.state.variables!)
171
+ },
172
+ onFail: () => {
173
+ this.dispatch({ type: 'failed' })
174
+ },
175
+ onPause: () => {
176
+ this.dispatch({ type: 'pause' })
177
+ },
178
+ onContinue: () => {
179
+ this.dispatch({ type: 'continue' })
180
+ },
181
+ retry: this.options.retry ?? 0,
182
+ retryDelay: this.options.retryDelay,
183
+ networkMode: this.options.networkMode,
184
+ })
185
+
186
+ return this.retryer.promise
187
+ }
188
+
189
+ const restored = this.state.status === 'loading'
190
+ try {
191
+ if (!restored) {
192
+ this.dispatch({ type: 'loading', variables: this.options.variables! })
193
+ // Notify cache callback
194
+ this.mutationCache.config.onMutate?.(
195
+ this.state.variables,
196
+ this as Mutation<unknown, unknown, unknown, unknown>,
197
+ )
198
+ const context = await this.options.onMutate?.(this.state.variables!)
199
+ if (context !== this.state.context) {
200
+ this.dispatch({
201
+ type: 'loading',
202
+ context,
203
+ variables: this.state.variables,
204
+ })
205
+ }
206
+ }
207
+ const data = await executeMutation()
208
+
209
+ // Notify cache callback
210
+ this.mutationCache.config.onSuccess?.(
211
+ data,
212
+ this.state.variables,
213
+ this.state.context,
214
+ this as Mutation<unknown, unknown, unknown, unknown>,
215
+ )
216
+
217
+ await this.options.onSuccess?.(
218
+ data,
219
+ this.state.variables!,
220
+ this.state.context!,
221
+ )
222
+
223
+ await this.options.onSettled?.(
224
+ data,
225
+ null,
226
+ this.state.variables!,
227
+ this.state.context,
228
+ )
229
+
230
+ this.dispatch({ type: 'success', data })
231
+ return data
232
+ } catch (error) {
233
+ try {
234
+ // Notify cache callback
235
+ this.mutationCache.config.onError?.(
236
+ error,
237
+ this.state.variables,
238
+ this.state.context,
239
+ this as Mutation<unknown, unknown, unknown, unknown>,
240
+ )
241
+
242
+ if (process.env.NODE_ENV !== 'production') {
243
+ this.logger.error(error)
244
+ }
245
+
246
+ await this.options.onError?.(
247
+ error as TError,
248
+ this.state.variables!,
249
+ this.state.context,
250
+ )
251
+
252
+ await this.options.onSettled?.(
253
+ undefined,
254
+ error as TError,
255
+ this.state.variables!,
256
+ this.state.context,
257
+ )
258
+ throw error
259
+ } finally {
260
+ this.dispatch({ type: 'error', error: error as TError })
261
+ }
262
+ }
263
+ }
264
+
265
+ private dispatch(action: Action<TData, TError, TVariables, TContext>): void {
266
+ const reducer = (
267
+ state: MutationState<TData, TError, TVariables, TContext>,
268
+ ): MutationState<TData, TError, TVariables, TContext> => {
269
+ switch (action.type) {
270
+ case 'failed':
271
+ return {
272
+ ...state,
273
+ failureCount: state.failureCount + 1,
274
+ }
275
+ case 'pause':
276
+ return {
277
+ ...state,
278
+ isPaused: true,
279
+ }
280
+ case 'continue':
281
+ return {
282
+ ...state,
283
+ isPaused: false,
284
+ }
285
+ case 'loading':
286
+ return {
287
+ ...state,
288
+ context: action.context,
289
+ data: undefined,
290
+ error: null,
291
+ isPaused: !canFetch(this.options.networkMode),
292
+ status: 'loading',
293
+ variables: action.variables,
294
+ }
295
+ case 'success':
296
+ return {
297
+ ...state,
298
+ data: action.data,
299
+ error: null,
300
+ status: 'success',
301
+ isPaused: false,
302
+ }
303
+ case 'error':
304
+ return {
305
+ ...state,
306
+ data: undefined,
307
+ error: action.error,
308
+ failureCount: state.failureCount + 1,
309
+ isPaused: false,
310
+ status: 'error',
311
+ }
312
+ case 'setState':
313
+ return {
314
+ ...state,
315
+ ...action.state,
316
+ }
317
+ }
318
+ }
319
+ this.state = reducer(this.state)
320
+
321
+ notifyManager.batch(() => {
322
+ this.observers.forEach((observer) => {
323
+ observer.onMutationUpdate(action)
324
+ })
325
+ this.mutationCache.notify({
326
+ mutation: this,
327
+ type: 'updated',
328
+ action,
329
+ })
330
+ })
331
+ }
332
+ }
333
+
334
+ export function getDefaultState<
335
+ TData,
336
+ TError,
337
+ TVariables,
338
+ TContext,
339
+ >(): MutationState<TData, TError, TVariables, TContext> {
340
+ return {
341
+ context: undefined,
342
+ data: undefined,
343
+ error: null,
344
+ failureCount: 0,
345
+ isPaused: false,
346
+ status: 'idle',
347
+ variables: undefined,
348
+ }
349
+ }
@@ -0,0 +1,157 @@
1
+ import { MutationObserver } from './mutationObserver'
2
+ import type { MutationOptions } from './types'
3
+ import type { QueryClient } from './queryClient'
4
+ import { notifyManager } from './notifyManager'
5
+ import { Action, Mutation, MutationState } from './mutation'
6
+ import { matchMutation, MutationFilters, noop } from './utils'
7
+ import { Subscribable } from './subscribable'
8
+
9
+ // TYPES
10
+
11
+ interface MutationCacheConfig {
12
+ onError?: (
13
+ error: unknown,
14
+ variables: unknown,
15
+ context: unknown,
16
+ mutation: Mutation<unknown, unknown, unknown>,
17
+ ) => void
18
+ onSuccess?: (
19
+ data: unknown,
20
+ variables: unknown,
21
+ context: unknown,
22
+ mutation: Mutation<unknown, unknown, unknown>,
23
+ ) => void
24
+ onMutate?: (
25
+ variables: unknown,
26
+ mutation: Mutation<unknown, unknown, unknown, unknown>,
27
+ ) => void
28
+ }
29
+
30
+ interface NotifyEventMutationAdded {
31
+ type: 'added'
32
+ mutation: Mutation<any, any, any, any>
33
+ }
34
+ interface NotifyEventMutationRemoved {
35
+ type: 'removed'
36
+ mutation: Mutation<any, any, any, any>
37
+ }
38
+
39
+ interface NotifyEventMutationObserverAdded {
40
+ type: 'observerAdded'
41
+ mutation: Mutation<any, any, any, any>
42
+ observer: MutationObserver<any, any, any>
43
+ }
44
+
45
+ interface NotifyEventMutationObserverRemoved {
46
+ type: 'observerRemoved'
47
+ mutation: Mutation<any, any, any, any>
48
+ observer: MutationObserver<any, any, any>
49
+ }
50
+
51
+ interface NotifyEventMutationUpdated {
52
+ type: 'updated'
53
+ mutation: Mutation<any, any, any, any>
54
+ action: Action<any, any, any, any>
55
+ }
56
+
57
+ type MutationCacheNotifyEvent =
58
+ | NotifyEventMutationAdded
59
+ | NotifyEventMutationRemoved
60
+ | NotifyEventMutationObserverAdded
61
+ | NotifyEventMutationObserverRemoved
62
+ | NotifyEventMutationUpdated
63
+
64
+ type MutationCacheListener = (event: MutationCacheNotifyEvent) => void
65
+
66
+ // CLASS
67
+
68
+ export class MutationCache extends Subscribable<MutationCacheListener> {
69
+ config: MutationCacheConfig
70
+
71
+ private mutations: Mutation<any, any, any, any>[]
72
+ private mutationId: number
73
+
74
+ constructor(config?: MutationCacheConfig) {
75
+ super()
76
+ this.config = config || {}
77
+ this.mutations = []
78
+ this.mutationId = 0
79
+ }
80
+
81
+ build<TData, TError, TVariables, TContext>(
82
+ client: QueryClient,
83
+ options: MutationOptions<TData, TError, TVariables, TContext>,
84
+ state?: MutationState<TData, TError, TVariables, TContext>,
85
+ ): Mutation<TData, TError, TVariables, TContext> {
86
+ const mutation = new Mutation({
87
+ mutationCache: this,
88
+ logger: client.getLogger(),
89
+ mutationId: ++this.mutationId,
90
+ options: client.defaultMutationOptions(options),
91
+ state,
92
+ defaultOptions: options.mutationKey
93
+ ? client.getMutationDefaults(options.mutationKey)
94
+ : undefined,
95
+ meta: options.meta,
96
+ })
97
+
98
+ this.add(mutation)
99
+
100
+ return mutation
101
+ }
102
+
103
+ add(mutation: Mutation<any, any, any, any>): void {
104
+ this.mutations.push(mutation)
105
+ this.notify({ type: 'added', mutation })
106
+ }
107
+
108
+ remove(mutation: Mutation<any, any, any, any>): void {
109
+ this.mutations = this.mutations.filter((x) => x !== mutation)
110
+ this.notify({ type: 'removed', mutation })
111
+ }
112
+
113
+ clear(): void {
114
+ notifyManager.batch(() => {
115
+ this.mutations.forEach((mutation) => {
116
+ this.remove(mutation)
117
+ })
118
+ })
119
+ }
120
+
121
+ getAll(): Mutation[] {
122
+ return this.mutations
123
+ }
124
+
125
+ find<TData = unknown, TError = unknown, TVariables = any, TContext = unknown>(
126
+ filters: MutationFilters,
127
+ ): Mutation<TData, TError, TVariables, TContext> | undefined {
128
+ if (typeof filters.exact === 'undefined') {
129
+ filters.exact = true
130
+ }
131
+
132
+ return this.mutations.find((mutation) => matchMutation(filters, mutation))
133
+ }
134
+
135
+ findAll(filters: MutationFilters): Mutation[] {
136
+ return this.mutations.filter((mutation) => matchMutation(filters, mutation))
137
+ }
138
+
139
+ notify(event: MutationCacheNotifyEvent) {
140
+ notifyManager.batch(() => {
141
+ this.listeners.forEach((listener) => {
142
+ listener(event)
143
+ })
144
+ })
145
+ }
146
+
147
+ resumePausedMutations(): Promise<void> {
148
+ const pausedMutations = this.mutations.filter((x) => x.state.isPaused)
149
+ return notifyManager.batch(() =>
150
+ pausedMutations.reduce(
151
+ (promise, mutation) =>
152
+ promise.then(() => mutation.continue().catch(noop)),
153
+ Promise.resolve(),
154
+ ),
155
+ )
156
+ }
157
+ }
@@ -0,0 +1,195 @@
1
+ import { Action, getDefaultState, Mutation } from './mutation'
2
+ import { notifyManager } from './notifyManager'
3
+ import type { QueryClient } from './queryClient'
4
+ import { Subscribable } from './subscribable'
5
+ import type {
6
+ MutateOptions,
7
+ MutationObserverBaseResult,
8
+ MutationObserverResult,
9
+ MutationObserverOptions,
10
+ } from './types'
11
+
12
+ // TYPES
13
+
14
+ type MutationObserverListener<TData, TError, TVariables, TContext> = (
15
+ result: MutationObserverResult<TData, TError, TVariables, TContext>,
16
+ ) => void
17
+
18
+ interface NotifyOptions {
19
+ listeners?: boolean
20
+ onError?: boolean
21
+ onSuccess?: boolean
22
+ }
23
+
24
+ // CLASS
25
+
26
+ export class MutationObserver<
27
+ TData = unknown,
28
+ TError = unknown,
29
+ TVariables = void,
30
+ TContext = unknown,
31
+ > extends Subscribable<
32
+ MutationObserverListener<TData, TError, TVariables, TContext>
33
+ > {
34
+ options!: MutationObserverOptions<TData, TError, TVariables, TContext>
35
+
36
+ private client: QueryClient
37
+ private currentResult!: MutationObserverResult<
38
+ TData,
39
+ TError,
40
+ TVariables,
41
+ TContext
42
+ >
43
+ private currentMutation?: Mutation<TData, TError, TVariables, TContext>
44
+ private mutateOptions?: MutateOptions<TData, TError, TVariables, TContext>
45
+
46
+ constructor(
47
+ client: QueryClient,
48
+ options: MutationObserverOptions<TData, TError, TVariables, TContext>,
49
+ ) {
50
+ super()
51
+
52
+ this.client = client
53
+ this.setOptions(options)
54
+ this.bindMethods()
55
+ this.updateResult()
56
+ }
57
+
58
+ protected bindMethods(): void {
59
+ this.mutate = this.mutate.bind(this)
60
+ this.reset = this.reset.bind(this)
61
+ }
62
+
63
+ setOptions(
64
+ options?: MutationObserverOptions<TData, TError, TVariables, TContext>,
65
+ ) {
66
+ this.options = this.client.defaultMutationOptions(options)
67
+ }
68
+
69
+ protected onUnsubscribe(): void {
70
+ if (!this.listeners.length) {
71
+ this.currentMutation?.removeObserver(this)
72
+ }
73
+ }
74
+
75
+ onMutationUpdate(action: Action<TData, TError, TVariables, TContext>): void {
76
+ this.updateResult()
77
+
78
+ // Determine which callbacks to trigger
79
+ const notifyOptions: NotifyOptions = {
80
+ listeners: true,
81
+ }
82
+
83
+ if (action.type === 'success') {
84
+ notifyOptions.onSuccess = true
85
+ } else if (action.type === 'error') {
86
+ notifyOptions.onError = true
87
+ }
88
+
89
+ this.notify(notifyOptions)
90
+ }
91
+
92
+ getCurrentResult(): MutationObserverResult<
93
+ TData,
94
+ TError,
95
+ TVariables,
96
+ TContext
97
+ > {
98
+ return this.currentResult
99
+ }
100
+
101
+ reset(): void {
102
+ this.currentMutation = undefined
103
+ this.updateResult()
104
+ this.notify({ listeners: true })
105
+ }
106
+
107
+ mutate(
108
+ variables?: TVariables,
109
+ options?: MutateOptions<TData, TError, TVariables, TContext>,
110
+ ): Promise<TData> {
111
+ this.mutateOptions = options
112
+
113
+ if (this.currentMutation) {
114
+ this.currentMutation.removeObserver(this)
115
+ }
116
+
117
+ this.currentMutation = this.client.getMutationCache().build(this.client, {
118
+ ...this.options,
119
+ variables:
120
+ typeof variables !== 'undefined' ? variables : this.options.variables,
121
+ })
122
+
123
+ this.currentMutation.addObserver(this)
124
+
125
+ return this.currentMutation.execute()
126
+ }
127
+
128
+ private updateResult(): void {
129
+ const state = this.currentMutation
130
+ ? this.currentMutation.state
131
+ : getDefaultState<TData, TError, TVariables, TContext>()
132
+
133
+ const result: MutationObserverBaseResult<
134
+ TData,
135
+ TError,
136
+ TVariables,
137
+ TContext
138
+ > = {
139
+ ...state,
140
+ isLoading: state.status === 'loading',
141
+ isSuccess: state.status === 'success',
142
+ isError: state.status === 'error',
143
+ isIdle: state.status === 'idle',
144
+ mutate: this.mutate,
145
+ reset: this.reset,
146
+ }
147
+
148
+ this.currentResult = result as MutationObserverResult<
149
+ TData,
150
+ TError,
151
+ TVariables,
152
+ TContext
153
+ >
154
+ }
155
+
156
+ private notify(options: NotifyOptions) {
157
+ notifyManager.batch(() => {
158
+ // First trigger the mutate callbacks
159
+ if (this.mutateOptions) {
160
+ if (options.onSuccess) {
161
+ this.mutateOptions.onSuccess?.(
162
+ this.currentResult.data!,
163
+ this.currentResult.variables!,
164
+ this.currentResult.context!,
165
+ )
166
+ this.mutateOptions.onSettled?.(
167
+ this.currentResult.data!,
168
+ null,
169
+ this.currentResult.variables!,
170
+ this.currentResult.context,
171
+ )
172
+ } else if (options.onError) {
173
+ this.mutateOptions.onError?.(
174
+ this.currentResult.error!,
175
+ this.currentResult.variables!,
176
+ this.currentResult.context,
177
+ )
178
+ this.mutateOptions.onSettled?.(
179
+ undefined,
180
+ this.currentResult.error,
181
+ this.currentResult.variables!,
182
+ this.currentResult.context,
183
+ )
184
+ }
185
+ }
186
+
187
+ // Then trigger the listeners
188
+ if (options.listeners) {
189
+ this.listeners.forEach((listener) => {
190
+ listener(this.currentResult)
191
+ })
192
+ }
193
+ })
194
+ }
195
+ }