@tanstack/angular-query-experimental 5.73.3 → 5.74.1
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.d.ts +48 -15
- package/build/index.mjs +276 -222
- package/build/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/create-base-query.ts +31 -29
- package/src/index.ts +1 -0
- package/src/inject-infinite-query.ts +9 -7
- package/src/inject-is-fetching.ts +34 -28
- package/src/inject-is-mutating.ts +34 -28
- package/src/inject-is-restoring.ts +50 -0
- package/src/inject-mutation-state.ts +61 -55
- package/src/inject-mutation.ts +108 -114
- package/src/inject-queries.ts +19 -8
- package/src/inject-query.ts +8 -3
- package/src/providers.ts +10 -3
- package/src/util/assert-injector/assert-injector.test.ts +0 -78
- package/src/util/assert-injector/assert-injector.ts +0 -83
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Injector,
|
|
4
|
+
NgZone,
|
|
5
|
+
assertInInjectionContext,
|
|
6
|
+
inject,
|
|
7
|
+
signal,
|
|
8
|
+
} from '@angular/core'
|
|
2
9
|
import { QueryClient, notifyManager } from '@tanstack/query-core'
|
|
3
|
-
import { assertInjector } from './util/assert-injector/assert-injector'
|
|
4
10
|
import type { MutationFilters } from '@tanstack/query-core'
|
|
5
|
-
import type {
|
|
11
|
+
import type { Signal } from '@angular/core'
|
|
6
12
|
|
|
7
13
|
export interface InjectIsMutatingOptions {
|
|
8
14
|
/**
|
|
@@ -26,34 +32,34 @@ export function injectIsMutating(
|
|
|
26
32
|
filters?: MutationFilters,
|
|
27
33
|
options?: InjectIsMutatingOptions,
|
|
28
34
|
): Signal<number> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
!options?.injector && assertInInjectionContext(injectIsMutating)
|
|
36
|
+
const injector = options?.injector ?? inject(Injector)
|
|
37
|
+
const destroyRef = injector.get(DestroyRef)
|
|
38
|
+
const ngZone = injector.get(NgZone)
|
|
39
|
+
const queryClient = injector.get(QueryClient)
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
const cache = queryClient.getMutationCache()
|
|
42
|
+
// isMutating is the prev value initialized on mount *
|
|
43
|
+
let isMutating = queryClient.isMutating(filters)
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
const result = signal(isMutating)
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
48
|
+
cache.subscribe(
|
|
49
|
+
notifyManager.batchCalls(() => {
|
|
50
|
+
const newIsMutating = queryClient.isMutating(filters)
|
|
51
|
+
if (isMutating !== newIsMutating) {
|
|
52
|
+
// * and update with each change
|
|
53
|
+
isMutating = newIsMutating
|
|
54
|
+
ngZone.run(() => {
|
|
55
|
+
result.set(isMutating)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}),
|
|
59
|
+
),
|
|
60
|
+
)
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
destroyRef.onDestroy(unsubscribe)
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
})
|
|
64
|
+
return result
|
|
59
65
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InjectionToken,
|
|
3
|
+
Injector,
|
|
4
|
+
assertInInjectionContext,
|
|
5
|
+
computed,
|
|
6
|
+
inject,
|
|
7
|
+
} from '@angular/core'
|
|
8
|
+
import type { Provider, Signal } from '@angular/core'
|
|
9
|
+
|
|
10
|
+
const IS_RESTORING = new InjectionToken<Signal<boolean>>('')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The `Injector` in which to create the isRestoring signal.
|
|
14
|
+
*
|
|
15
|
+
* If this is not provided, the current injection context will be used instead (via `inject`).
|
|
16
|
+
*/
|
|
17
|
+
interface InjectIsRestoringOptions {
|
|
18
|
+
injector?: Injector
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Injects a signal that tracks whether a restore is currently in progress. {@link injectQuery} and friends also check this internally to avoid race conditions between the restore and mounting queries.
|
|
23
|
+
* @param options - Options for injectIsRestoring.
|
|
24
|
+
* @returns signal with boolean that indicates whether a restore is in progress.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export function injectIsRestoring(
|
|
28
|
+
options?: InjectIsRestoringOptions,
|
|
29
|
+
): Signal<boolean> {
|
|
30
|
+
!options?.injector && assertInInjectionContext(injectIsRestoring)
|
|
31
|
+
const injector = options?.injector ?? inject(Injector)
|
|
32
|
+
return injector.get(
|
|
33
|
+
IS_RESTORING,
|
|
34
|
+
computed(() => false),
|
|
35
|
+
{ optional: true },
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Used by TanStack Query Angular persist client plugin to provide the signal that tracks the restore state
|
|
41
|
+
* @param isRestoring - a readonly signal that returns a boolean
|
|
42
|
+
* @returns Provider for the `isRestoring` signal
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export function provideIsRestoring(isRestoring: Signal<boolean>): Provider {
|
|
46
|
+
return {
|
|
47
|
+
provide: IS_RESTORING,
|
|
48
|
+
useValue: isRestoring,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Injector,
|
|
4
|
+
NgZone,
|
|
5
|
+
assertInInjectionContext,
|
|
6
|
+
computed,
|
|
7
|
+
inject,
|
|
8
|
+
signal,
|
|
9
|
+
} from '@angular/core'
|
|
2
10
|
import {
|
|
3
11
|
QueryClient,
|
|
4
12
|
notifyManager,
|
|
5
13
|
replaceEqualDeep,
|
|
6
14
|
} from '@tanstack/query-core'
|
|
7
|
-
import {
|
|
8
|
-
import type { Injector, Signal } from '@angular/core'
|
|
15
|
+
import type { Signal } from '@angular/core'
|
|
9
16
|
import type {
|
|
10
17
|
Mutation,
|
|
11
18
|
MutationCache,
|
|
@@ -58,62 +65,61 @@ export function injectMutationState<TResult = MutationState>(
|
|
|
58
65
|
injectMutationStateFn: () => MutationStateOptions<TResult> = () => ({}),
|
|
59
66
|
options?: InjectMutationStateOptions,
|
|
60
67
|
): Signal<Array<TResult>> {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
!options?.injector && assertInInjectionContext(injectMutationState)
|
|
69
|
+
const injector = options?.injector ?? inject(Injector)
|
|
70
|
+
const destroyRef = injector.get(DestroyRef)
|
|
71
|
+
const ngZone = injector.get(NgZone)
|
|
72
|
+
const queryClient = injector.get(QueryClient)
|
|
73
|
+
const mutationCache = queryClient.getMutationCache()
|
|
67
74
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Computed signal that gets result from mutation cache based on passed options
|
|
77
|
+
* First element is the result, second element is the time when the result was set
|
|
78
|
+
*/
|
|
79
|
+
const resultFromOptionsSignal = computed(() => {
|
|
80
|
+
return [
|
|
81
|
+
getResult(mutationCache, injectMutationStateFn()),
|
|
82
|
+
performance.now(),
|
|
83
|
+
] as const
|
|
84
|
+
})
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Signal that contains result set by subscriber
|
|
88
|
+
* First element is the result, second element is the time when the result was set
|
|
89
|
+
*/
|
|
90
|
+
const resultFromSubscriberSignal = signal<[Array<TResult>, number] | null>(
|
|
91
|
+
null,
|
|
92
|
+
)
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Returns the last result by either subscriber or options
|
|
96
|
+
*/
|
|
97
|
+
const effectiveResultSignal = computed(() => {
|
|
98
|
+
const optionsResult = resultFromOptionsSignal()
|
|
99
|
+
const subscriberResult = resultFromSubscriberSignal()
|
|
100
|
+
return subscriberResult && subscriberResult[1] > optionsResult[1]
|
|
101
|
+
? subscriberResult[0]
|
|
102
|
+
: optionsResult[0]
|
|
103
|
+
})
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
106
|
+
mutationCache.subscribe(
|
|
107
|
+
notifyManager.batchCalls(() => {
|
|
108
|
+
const [lastResult] = effectiveResultSignal()
|
|
109
|
+
const nextResult = replaceEqualDeep(
|
|
110
|
+
lastResult,
|
|
111
|
+
getResult(mutationCache, injectMutationStateFn()),
|
|
112
|
+
)
|
|
113
|
+
if (lastResult !== nextResult) {
|
|
114
|
+
ngZone.run(() => {
|
|
115
|
+
resultFromSubscriberSignal.set([nextResult, performance.now()])
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
}),
|
|
119
|
+
),
|
|
120
|
+
)
|
|
114
121
|
|
|
115
|
-
|
|
122
|
+
destroyRef.onDestroy(unsubscribe)
|
|
116
123
|
|
|
117
|
-
|
|
118
|
-
})
|
|
124
|
+
return effectiveResultSignal
|
|
119
125
|
}
|
package/src/inject-mutation.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DestroyRef,
|
|
3
|
+
Injector,
|
|
3
4
|
NgZone,
|
|
5
|
+
assertInInjectionContext,
|
|
4
6
|
computed,
|
|
5
7
|
effect,
|
|
6
8
|
inject,
|
|
@@ -12,10 +14,8 @@ import {
|
|
|
12
14
|
QueryClient,
|
|
13
15
|
notifyManager,
|
|
14
16
|
} from '@tanstack/query-core'
|
|
15
|
-
import { assertInjector } from './util/assert-injector/assert-injector'
|
|
16
17
|
import { signalProxy } from './signal-proxy'
|
|
17
18
|
import { noop, shouldThrowError } from './util'
|
|
18
|
-
import type { Injector } from '@angular/core'
|
|
19
19
|
import type { DefaultError, MutationObserverResult } from '@tanstack/query-core'
|
|
20
20
|
import type { CreateMutateFunction, CreateMutationResult } from './types'
|
|
21
21
|
import type { CreateMutationOptions } from './mutation-options'
|
|
@@ -52,123 +52,117 @@ export function injectMutation<
|
|
|
52
52
|
>,
|
|
53
53
|
options?: InjectMutationOptions,
|
|
54
54
|
): CreateMutationResult<TData, TError, TVariables, TContext> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* computed() is used so signals can be inserted into the options
|
|
62
|
-
* making it reactive. Wrapping options in a function ensures embedded expressions
|
|
63
|
-
* are preserved and can keep being applied after signal changes
|
|
64
|
-
*/
|
|
65
|
-
const optionsSignal = computed(injectMutationFn)
|
|
66
|
-
|
|
67
|
-
const observerSignal = (() => {
|
|
68
|
-
let instance: MutationObserver<
|
|
69
|
-
TData,
|
|
70
|
-
TError,
|
|
71
|
-
TVariables,
|
|
72
|
-
TContext
|
|
73
|
-
> | null = null
|
|
74
|
-
|
|
75
|
-
return computed(() => {
|
|
76
|
-
return (instance ||= new MutationObserver(queryClient, optionsSignal()))
|
|
77
|
-
})
|
|
78
|
-
})()
|
|
55
|
+
!options?.injector && assertInInjectionContext(injectMutation)
|
|
56
|
+
const injector = options?.injector ?? inject(Injector)
|
|
57
|
+
const destroyRef = injector.get(DestroyRef)
|
|
58
|
+
const ngZone = injector.get(NgZone)
|
|
59
|
+
const queryClient = injector.get(QueryClient)
|
|
79
60
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
61
|
+
/**
|
|
62
|
+
* computed() is used so signals can be inserted into the options
|
|
63
|
+
* making it reactive. Wrapping options in a function ensures embedded expressions
|
|
64
|
+
* are preserved and can keep being applied after signal changes
|
|
65
|
+
*/
|
|
66
|
+
const optionsSignal = computed(injectMutationFn)
|
|
67
|
+
|
|
68
|
+
const observerSignal = (() => {
|
|
69
|
+
let instance: MutationObserver<TData, TError, TVariables, TContext> | null =
|
|
70
|
+
null
|
|
71
|
+
|
|
72
|
+
return computed(() => {
|
|
73
|
+
return (instance ||= new MutationObserver(queryClient, optionsSignal()))
|
|
87
74
|
})
|
|
75
|
+
})()
|
|
76
|
+
|
|
77
|
+
const mutateFnSignal = computed<
|
|
78
|
+
CreateMutateFunction<TData, TError, TVariables, TContext>
|
|
79
|
+
>(() => {
|
|
80
|
+
const observer = observerSignal()
|
|
81
|
+
return (variables, mutateOptions) => {
|
|
82
|
+
observer.mutate(variables, mutateOptions).catch(noop)
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Computed signal that gets result from mutation cache based on passed options
|
|
88
|
+
*/
|
|
89
|
+
const resultFromInitialOptionsSignal = computed(() => {
|
|
90
|
+
const observer = observerSignal()
|
|
91
|
+
return observer.getCurrentResult()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Signal that contains result set by subscriber
|
|
96
|
+
*/
|
|
97
|
+
const resultFromSubscriberSignal = signal<MutationObserverResult<
|
|
98
|
+
TData,
|
|
99
|
+
TError,
|
|
100
|
+
TVariables,
|
|
101
|
+
TContext
|
|
102
|
+
> | null>(null)
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*/
|
|
92
|
-
const resultFromInitialOptionsSignal = computed(() => {
|
|
104
|
+
effect(
|
|
105
|
+
() => {
|
|
93
106
|
const observer = observerSignal()
|
|
94
|
-
|
|
95
|
-
})
|
|
107
|
+
const observerOptions = optionsSignal()
|
|
96
108
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const observerOptions = optionsSignal()
|
|
111
|
-
|
|
112
|
-
untracked(() => {
|
|
113
|
-
observer.setOptions(observerOptions)
|
|
114
|
-
})
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
injector: options?.injector,
|
|
118
|
-
},
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
effect(
|
|
122
|
-
() => {
|
|
123
|
-
// observer.trackResult is not used as this optimization is not needed for Angular
|
|
124
|
-
const observer = observerSignal()
|
|
125
|
-
|
|
126
|
-
untracked(() => {
|
|
127
|
-
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
128
|
-
observer.subscribe(
|
|
129
|
-
notifyManager.batchCalls((state) => {
|
|
130
|
-
ngZone.run(() => {
|
|
131
|
-
if (
|
|
132
|
-
state.isError &&
|
|
133
|
-
shouldThrowError(observer.options.throwOnError, [
|
|
134
|
-
state.error,
|
|
135
|
-
])
|
|
136
|
-
) {
|
|
137
|
-
ngZone.onError.emit(state.error)
|
|
138
|
-
throw state.error
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
resultFromSubscriberSignal.set(state)
|
|
142
|
-
})
|
|
143
|
-
}),
|
|
144
|
-
),
|
|
145
|
-
)
|
|
146
|
-
destroyRef.onDestroy(unsubscribe)
|
|
147
|
-
})
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
injector: options?.injector,
|
|
151
|
-
},
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
const resultSignal = computed(() => {
|
|
155
|
-
const resultFromSubscriber = resultFromSubscriberSignal()
|
|
156
|
-
const resultFromInitialOptions = resultFromInitialOptionsSignal()
|
|
157
|
-
|
|
158
|
-
const result = resultFromSubscriber ?? resultFromInitialOptions
|
|
159
|
-
|
|
160
|
-
return {
|
|
161
|
-
...result,
|
|
162
|
-
mutate: mutateFnSignal(),
|
|
163
|
-
mutateAsync: result.mutate,
|
|
164
|
-
}
|
|
165
|
-
})
|
|
109
|
+
untracked(() => {
|
|
110
|
+
observer.setOptions(observerOptions)
|
|
111
|
+
})
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
injector,
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
effect(
|
|
119
|
+
() => {
|
|
120
|
+
// observer.trackResult is not used as this optimization is not needed for Angular
|
|
121
|
+
const observer = observerSignal()
|
|
166
122
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
123
|
+
untracked(() => {
|
|
124
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
125
|
+
observer.subscribe(
|
|
126
|
+
notifyManager.batchCalls((state) => {
|
|
127
|
+
ngZone.run(() => {
|
|
128
|
+
if (
|
|
129
|
+
state.isError &&
|
|
130
|
+
shouldThrowError(observer.options.throwOnError, [state.error])
|
|
131
|
+
) {
|
|
132
|
+
ngZone.onError.emit(state.error)
|
|
133
|
+
throw state.error
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
resultFromSubscriberSignal.set(state)
|
|
137
|
+
})
|
|
138
|
+
}),
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
destroyRef.onDestroy(unsubscribe)
|
|
142
|
+
})
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
injector,
|
|
146
|
+
},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
const resultSignal = computed(() => {
|
|
150
|
+
const resultFromSubscriber = resultFromSubscriberSignal()
|
|
151
|
+
const resultFromInitialOptions = resultFromInitialOptionsSignal()
|
|
152
|
+
|
|
153
|
+
const result = resultFromSubscriber ?? resultFromInitialOptions
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
...result,
|
|
157
|
+
mutate: mutateFnSignal(),
|
|
158
|
+
mutateAsync: result.mutate,
|
|
159
|
+
}
|
|
173
160
|
})
|
|
161
|
+
|
|
162
|
+
return signalProxy(resultSignal) as CreateMutationResult<
|
|
163
|
+
TData,
|
|
164
|
+
TError,
|
|
165
|
+
TVariables,
|
|
166
|
+
TContext
|
|
167
|
+
>
|
|
174
168
|
}
|
package/src/inject-queries.ts
CHANGED
|
@@ -5,14 +5,17 @@ import {
|
|
|
5
5
|
} from '@tanstack/query-core'
|
|
6
6
|
import {
|
|
7
7
|
DestroyRef,
|
|
8
|
+
Injector,
|
|
8
9
|
NgZone,
|
|
10
|
+
assertInInjectionContext,
|
|
9
11
|
computed,
|
|
10
12
|
effect,
|
|
11
13
|
inject,
|
|
14
|
+
runInInjectionContext,
|
|
12
15
|
signal,
|
|
13
16
|
} from '@angular/core'
|
|
14
|
-
import {
|
|
15
|
-
import type {
|
|
17
|
+
import { injectIsRestoring } from './inject-is-restoring'
|
|
18
|
+
import type { Signal } from '@angular/core'
|
|
16
19
|
import type {
|
|
17
20
|
DefaultError,
|
|
18
21
|
OmitKeyof,
|
|
@@ -213,16 +216,20 @@ export function injectQueries<
|
|
|
213
216
|
},
|
|
214
217
|
injector?: Injector,
|
|
215
218
|
): Signal<TCombinedResult> {
|
|
216
|
-
|
|
219
|
+
!injector && assertInInjectionContext(injectQueries)
|
|
220
|
+
return runInInjectionContext(injector ?? inject(Injector), () => {
|
|
217
221
|
const destroyRef = inject(DestroyRef)
|
|
218
222
|
const ngZone = inject(NgZone)
|
|
219
223
|
const queryClient = inject(QueryClient)
|
|
224
|
+
const isRestoring = injectIsRestoring()
|
|
220
225
|
|
|
221
226
|
const defaultedQueries = computed(() => {
|
|
222
227
|
return queries().map((opts) => {
|
|
223
228
|
const defaultedOptions = queryClient.defaultQueryOptions(opts)
|
|
224
229
|
// Make sure the results are already in fetching state before subscribing or updating options
|
|
225
|
-
defaultedOptions._optimisticResults =
|
|
230
|
+
defaultedOptions._optimisticResults = isRestoring()
|
|
231
|
+
? 'isRestoring'
|
|
232
|
+
: 'optimistic'
|
|
226
233
|
|
|
227
234
|
return defaultedOptions as QueryObserverOptions
|
|
228
235
|
})
|
|
@@ -250,10 +257,14 @@ export function injectQueries<
|
|
|
250
257
|
|
|
251
258
|
const result = signal(getCombinedResult() as any)
|
|
252
259
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
effect(() => {
|
|
261
|
+
const unsubscribe = isRestoring()
|
|
262
|
+
? () => undefined
|
|
263
|
+
: ngZone.runOutsideAngular(() =>
|
|
264
|
+
observer.subscribe(notifyManager.batchCalls(result.set)),
|
|
265
|
+
)
|
|
266
|
+
destroyRef.onDestroy(unsubscribe)
|
|
267
|
+
})
|
|
257
268
|
|
|
258
269
|
return result
|
|
259
270
|
})
|
package/src/inject-query.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { QueryObserver } from '@tanstack/query-core'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Injector,
|
|
4
|
+
assertInInjectionContext,
|
|
5
|
+
inject,
|
|
6
|
+
runInInjectionContext,
|
|
7
|
+
} from '@angular/core'
|
|
3
8
|
import { createBaseQuery } from './create-base-query'
|
|
4
|
-
import type { Injector } from '@angular/core'
|
|
5
9
|
import type { DefaultError, QueryKey } from '@tanstack/query-core'
|
|
6
10
|
import type {
|
|
7
11
|
CreateQueryOptions,
|
|
@@ -219,7 +223,8 @@ export function injectQuery(
|
|
|
219
223
|
injectQueryFn: () => CreateQueryOptions,
|
|
220
224
|
options?: InjectQueryOptions,
|
|
221
225
|
) {
|
|
222
|
-
|
|
226
|
+
!options?.injector && assertInInjectionContext(injectQuery)
|
|
227
|
+
return runInInjectionContext(options?.injector ?? inject(Injector), () =>
|
|
223
228
|
createBaseQuery(injectQueryFn, QueryObserver),
|
|
224
229
|
) as unknown as CreateQueryResult
|
|
225
230
|
}
|
package/src/providers.ts
CHANGED
|
@@ -140,7 +140,7 @@ export interface QueryFeature<TFeatureKind extends QueryFeatureKind> {
|
|
|
140
140
|
* @param providers -
|
|
141
141
|
* @returns A Query feature.
|
|
142
142
|
*/
|
|
143
|
-
function queryFeature<TFeatureKind extends QueryFeatureKind>(
|
|
143
|
+
export function queryFeature<TFeatureKind extends QueryFeatureKind>(
|
|
144
144
|
kind: TFeatureKind,
|
|
145
145
|
providers: Array<Provider>,
|
|
146
146
|
): QueryFeature<TFeatureKind> {
|
|
@@ -155,6 +155,13 @@ function queryFeature<TFeatureKind extends QueryFeatureKind>(
|
|
|
155
155
|
*/
|
|
156
156
|
export type DeveloperToolsFeature = QueryFeature<'DeveloperTools'>
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* A type alias that represents a feature which enables persistence.
|
|
160
|
+
* The type is used to describe the return value of the `withPersistQueryClient` function.
|
|
161
|
+
* @public
|
|
162
|
+
*/
|
|
163
|
+
export type PersistQueryClientFeature = QueryFeature<'PersistQueryClient'>
|
|
164
|
+
|
|
158
165
|
/**
|
|
159
166
|
* Options for configuring the TanStack Query devtools.
|
|
160
167
|
* @public
|
|
@@ -342,8 +349,8 @@ export function withDevtools(
|
|
|
342
349
|
* @public
|
|
343
350
|
* @see {@link provideTanStackQuery}
|
|
344
351
|
*/
|
|
345
|
-
export type QueryFeatures = DeveloperToolsFeature
|
|
352
|
+
export type QueryFeatures = DeveloperToolsFeature | PersistQueryClientFeature
|
|
346
353
|
|
|
347
|
-
export const queryFeatures = ['DeveloperTools'] as const
|
|
354
|
+
export const queryFeatures = ['DeveloperTools', 'PersistQueryClient'] as const
|
|
348
355
|
|
|
349
356
|
export type QueryFeatureKind = (typeof queryFeatures)[number]
|