@tanstack/angular-query-experimental 5.62.2 → 5.62.4
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.
- package/build/index.mjs +163 -169
- package/build/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/create-base-query.ts +66 -44
- package/src/inject-mutation-state.ts +46 -41
- package/src/inject-mutation.ts +101 -56
- package/src/providers.ts +1 -0
- package/src/util/lazy-init/lazy-init.ts +0 -34
- package/src/util/lazy-signal-initializer/lazy-signal-initializer.ts +0 -23
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DestroyRef,
|
|
3
|
-
NgZone,
|
|
4
|
-
effect,
|
|
5
|
-
inject,
|
|
6
|
-
signal,
|
|
7
|
-
untracked,
|
|
8
|
-
} from '@angular/core'
|
|
1
|
+
import { DestroyRef, NgZone, computed, inject, signal } from '@angular/core'
|
|
9
2
|
import {
|
|
10
3
|
QueryClient,
|
|
11
4
|
notifyManager,
|
|
12
5
|
replaceEqualDeep,
|
|
13
6
|
} from '@tanstack/query-core'
|
|
14
7
|
import { assertInjector } from './util/assert-injector/assert-injector'
|
|
15
|
-
import { lazySignalInitializer } from './util/lazy-signal-initializer/lazy-signal-initializer'
|
|
16
8
|
import type { Injector, Signal } from '@angular/core'
|
|
17
9
|
import type {
|
|
18
10
|
Mutation,
|
|
@@ -63,42 +55,55 @@ export function injectMutationState<TResult = MutationState>(
|
|
|
63
55
|
|
|
64
56
|
const mutationCache = queryClient.getMutationCache()
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Computed signal that gets result from mutation cache based on passed options
|
|
60
|
+
* First element is the result, second element is the time when the result was set
|
|
61
|
+
*/
|
|
62
|
+
const resultFromOptionsSignal = computed(() => {
|
|
63
|
+
return [
|
|
68
64
|
getResult(mutationCache, mutationStateOptionsFn()),
|
|
69
|
-
|
|
65
|
+
performance.now(),
|
|
66
|
+
] as const
|
|
67
|
+
})
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
})
|
|
79
|
-
},
|
|
80
|
-
{ injector },
|
|
81
|
-
)
|
|
69
|
+
/**
|
|
70
|
+
* Signal that contains result set by subscriber
|
|
71
|
+
* First element is the result, second element is the time when the result was set
|
|
72
|
+
*/
|
|
73
|
+
const resultFromSubscriberSignal = signal<[Array<TResult>, number] | null>(
|
|
74
|
+
null,
|
|
75
|
+
)
|
|
82
76
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
})
|
|
94
|
-
}
|
|
95
|
-
}),
|
|
96
|
-
),
|
|
97
|
-
)
|
|
77
|
+
/**
|
|
78
|
+
* Returns the last result by either subscriber or options
|
|
79
|
+
*/
|
|
80
|
+
const effectiveResultSignal = computed(() => {
|
|
81
|
+
const optionsResult = resultFromOptionsSignal()
|
|
82
|
+
const subscriberResult = resultFromSubscriberSignal()
|
|
83
|
+
return subscriberResult && subscriberResult[1] > optionsResult[1]
|
|
84
|
+
? subscriberResult[0]
|
|
85
|
+
: optionsResult[0]
|
|
86
|
+
})
|
|
98
87
|
|
|
99
|
-
|
|
88
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
89
|
+
mutationCache.subscribe(
|
|
90
|
+
notifyManager.batchCalls(() => {
|
|
91
|
+
const [lastResult] = effectiveResultSignal()
|
|
92
|
+
const nextResult = replaceEqualDeep(
|
|
93
|
+
lastResult,
|
|
94
|
+
getResult(mutationCache, mutationStateOptionsFn()),
|
|
95
|
+
)
|
|
96
|
+
if (lastResult !== nextResult) {
|
|
97
|
+
ngZone.run(() => {
|
|
98
|
+
resultFromSubscriberSignal.set([nextResult, performance.now()])
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
}),
|
|
102
|
+
),
|
|
103
|
+
)
|
|
100
104
|
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
destroyRef.onDestroy(unsubscribe)
|
|
106
|
+
|
|
107
|
+
return effectiveResultSignal
|
|
103
108
|
})
|
|
104
109
|
}
|
package/src/inject-mutation.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
inject,
|
|
8
8
|
runInInjectionContext,
|
|
9
9
|
signal,
|
|
10
|
+
untracked,
|
|
10
11
|
} from '@angular/core'
|
|
11
12
|
import {
|
|
12
13
|
MutationObserver,
|
|
@@ -16,8 +17,6 @@ import {
|
|
|
16
17
|
import { assertInjector } from './util/assert-injector/assert-injector'
|
|
17
18
|
import { signalProxy } from './signal-proxy'
|
|
18
19
|
import { noop, shouldThrowError } from './util'
|
|
19
|
-
|
|
20
|
-
import { lazyInit } from './util/lazy-init/lazy-init'
|
|
21
20
|
import type { DefaultError, MutationObserverResult } from '@tanstack/query-core'
|
|
22
21
|
import type { CreateMutateFunction, CreateMutationResult } from './types'
|
|
23
22
|
import type { CreateMutationOptions } from './mutation-options'
|
|
@@ -46,42 +45,78 @@ export function injectMutation<
|
|
|
46
45
|
const ngZone = inject(NgZone)
|
|
47
46
|
const queryClient = inject(QueryClient)
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
48
|
+
/**
|
|
49
|
+
* computed() is used so signals can be inserted into the options
|
|
50
|
+
* making it reactive. Wrapping options in a function ensures embedded expressions
|
|
51
|
+
* are preserved and can keep being applied after signal changes
|
|
52
|
+
*/
|
|
53
|
+
const optionsSignal = computed(() =>
|
|
54
|
+
runInInjectionContext(currentInjector, () => optionsFn()),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const observerSignal = (() => {
|
|
58
|
+
let instance: MutationObserver<
|
|
59
|
+
TData,
|
|
60
|
+
TError,
|
|
61
|
+
TVariables,
|
|
62
|
+
TContext
|
|
63
|
+
> | null = null
|
|
64
|
+
|
|
65
|
+
return computed(() => {
|
|
66
|
+
return (instance ||= new MutationObserver(queryClient, optionsSignal()))
|
|
67
|
+
})
|
|
68
|
+
})()
|
|
69
|
+
|
|
70
|
+
const mutateFnSignal = computed<
|
|
71
|
+
CreateMutateFunction<TData, TError, TVariables, TContext>
|
|
72
|
+
>(() => {
|
|
73
|
+
const observer = observerSignal()
|
|
74
|
+
return (variables, mutateOptions) => {
|
|
75
|
+
observer.mutate(variables, mutateOptions).catch(noop)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Computed signal that gets result from mutation cache based on passed options
|
|
81
|
+
*/
|
|
82
|
+
const resultFromInitialOptionsSignal = computed(() => {
|
|
83
|
+
const observer = observerSignal()
|
|
84
|
+
return observer.getCurrentResult()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Signal that contains result set by subscriber
|
|
89
|
+
*/
|
|
90
|
+
const resultFromSubscriberSignal = signal<MutationObserverResult<
|
|
91
|
+
TData,
|
|
92
|
+
TError,
|
|
93
|
+
TVariables,
|
|
94
|
+
TContext
|
|
95
|
+
> | null>(null)
|
|
96
|
+
|
|
97
|
+
effect(
|
|
98
|
+
() => {
|
|
99
|
+
const observer = observerSignal()
|
|
100
|
+
const options = optionsSignal()
|
|
101
|
+
|
|
102
|
+
untracked(() => {
|
|
103
|
+
observer.setOptions(options)
|
|
70
104
|
})
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
injector,
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
effect(
|
|
112
|
+
() => {
|
|
113
|
+
// observer.trackResult is not used as this optimization is not needed for Angular
|
|
114
|
+
const observer = observerSignal()
|
|
71
115
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
notifyManager.batchCalls(
|
|
77
|
-
(
|
|
78
|
-
state: MutationObserverResult<
|
|
79
|
-
TData,
|
|
80
|
-
TError,
|
|
81
|
-
TVariables,
|
|
82
|
-
TContext
|
|
83
|
-
>,
|
|
84
|
-
) => {
|
|
116
|
+
untracked(() => {
|
|
117
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
118
|
+
observer.subscribe(
|
|
119
|
+
notifyManager.batchCalls((state) => {
|
|
85
120
|
ngZone.run(() => {
|
|
86
121
|
if (
|
|
87
122
|
state.isError &&
|
|
@@ -91,28 +126,38 @@ export function injectMutation<
|
|
|
91
126
|
) {
|
|
92
127
|
throw state.error
|
|
93
128
|
}
|
|
94
|
-
|
|
129
|
+
|
|
130
|
+
resultFromSubscriberSignal.set(state)
|
|
95
131
|
})
|
|
96
|
-
},
|
|
132
|
+
}),
|
|
97
133
|
),
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
mutate,
|
|
106
|
-
mutateAsync: result().mutate,
|
|
107
|
-
}))
|
|
108
|
-
|
|
109
|
-
return signalProxy(resultSignal) as unknown as CreateMutationResult<
|
|
110
|
-
TData,
|
|
111
|
-
TError,
|
|
112
|
-
TVariables,
|
|
113
|
-
TContext
|
|
114
|
-
>
|
|
115
|
-
}),
|
|
134
|
+
)
|
|
135
|
+
destroyRef.onDestroy(unsubscribe)
|
|
136
|
+
})
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
injector,
|
|
140
|
+
},
|
|
116
141
|
)
|
|
142
|
+
|
|
143
|
+
const resultSignal = computed(() => {
|
|
144
|
+
const resultFromSubscriber = resultFromSubscriberSignal()
|
|
145
|
+
const resultFromInitialOptions = resultFromInitialOptionsSignal()
|
|
146
|
+
|
|
147
|
+
const result = resultFromSubscriber ?? resultFromInitialOptions
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
...result,
|
|
151
|
+
mutate: mutateFnSignal(),
|
|
152
|
+
mutateAsync: result.mutate,
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
return signalProxy(resultSignal) as CreateMutationResult<
|
|
157
|
+
TData,
|
|
158
|
+
TError,
|
|
159
|
+
TVariables,
|
|
160
|
+
TContext
|
|
161
|
+
>
|
|
117
162
|
})
|
|
118
163
|
}
|
package/src/providers.ts
CHANGED
|
@@ -99,6 +99,7 @@ export function provideTanStackQuery(
|
|
|
99
99
|
return makeEnvironmentProviders([
|
|
100
100
|
provideQueryClient(queryClient),
|
|
101
101
|
{
|
|
102
|
+
// Do not use provideEnvironmentInitializer to support Angular < v19
|
|
102
103
|
provide: ENVIRONMENT_INITIALIZER,
|
|
103
104
|
multi: true,
|
|
104
105
|
useValue: () => {
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { untracked } from '@angular/core'
|
|
2
|
-
|
|
3
|
-
export function lazyInit<T extends object>(initializer: () => T): T {
|
|
4
|
-
let object: T | null = null
|
|
5
|
-
|
|
6
|
-
const initializeObject = () => {
|
|
7
|
-
if (!object) {
|
|
8
|
-
object = untracked(() => initializer())
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
queueMicrotask(() => initializeObject())
|
|
13
|
-
|
|
14
|
-
return new Proxy<T>({} as T, {
|
|
15
|
-
get(_, prop, receiver) {
|
|
16
|
-
initializeObject()
|
|
17
|
-
return Reflect.get(object as T, prop, receiver)
|
|
18
|
-
},
|
|
19
|
-
has(_, prop) {
|
|
20
|
-
initializeObject()
|
|
21
|
-
return Reflect.has(object as T, prop)
|
|
22
|
-
},
|
|
23
|
-
ownKeys() {
|
|
24
|
-
initializeObject()
|
|
25
|
-
return Reflect.ownKeys(object as T)
|
|
26
|
-
},
|
|
27
|
-
getOwnPropertyDescriptor() {
|
|
28
|
-
return {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
configurable: true,
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
})
|
|
34
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Injector, computed, inject, untracked } from '@angular/core'
|
|
2
|
-
import type { Signal } from '@angular/core'
|
|
3
|
-
|
|
4
|
-
type SignalInitializerFn<T> = (injector: Injector) => Signal<T>
|
|
5
|
-
|
|
6
|
-
export function lazySignalInitializer<T>(
|
|
7
|
-
initializerFn: SignalInitializerFn<T>,
|
|
8
|
-
) {
|
|
9
|
-
const injector = inject(Injector)
|
|
10
|
-
|
|
11
|
-
let source: Signal<T> | null = null
|
|
12
|
-
|
|
13
|
-
const unwrapSignal = () => {
|
|
14
|
-
if (!source) {
|
|
15
|
-
source = untracked(() => initializerFn(injector))
|
|
16
|
-
}
|
|
17
|
-
return source()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
queueMicrotask(() => unwrapSignal())
|
|
21
|
-
|
|
22
|
-
return computed(unwrapSignal)
|
|
23
|
-
}
|