@tanstack/angular-query-experimental 5.103.2 → 5.104.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.
- package/dist/create-base-query.d.mts +168 -0
- package/dist/create-base-query.d.mts.map +1 -0
- package/dist/create-base-query.mjs +91 -0
- package/dist/create-base-query.mjs.map +1 -0
- package/dist/devtools/index.d.mts +3 -0
- package/dist/devtools/index.mjs +2 -0
- package/dist/devtools/production/index.d.mts +4 -0
- package/dist/devtools/production/index.mjs +2 -0
- package/dist/devtools/stub.d.mts +5 -0
- package/dist/devtools/stub.d.mts.map +1 -0
- package/dist/devtools/stub.mjs +9 -0
- package/dist/devtools/stub.mjs.map +1 -0
- package/dist/devtools/types.d.mts +106 -0
- package/dist/devtools/types.d.mts.map +1 -0
- package/dist/devtools/types.mjs +1 -0
- package/{devtools/with-devtools.d.ts → dist/devtools/with-devtools.d.mts} +4 -1
- package/dist/devtools/with-devtools.d.mts.map +1 -0
- package/dist/devtools/with-devtools.mjs +110 -0
- package/dist/devtools/with-devtools.mjs.map +1 -0
- package/dist/devtools-panel/index.d.mts +3 -0
- package/dist/devtools-panel/index.mjs +2 -0
- package/{devtools-panel/inject-devtools-panel.d.ts → dist/devtools-panel/inject-devtools-panel.d.mts} +4 -1
- package/dist/devtools-panel/inject-devtools-panel.d.mts.map +1 -0
- package/dist/devtools-panel/inject-devtools-panel.mjs +67 -0
- package/dist/devtools-panel/inject-devtools-panel.mjs.map +1 -0
- package/dist/devtools-panel/production/index.d.mts +4 -0
- package/dist/devtools-panel/production/index.mjs +2 -0
- package/dist/devtools-panel/stub.d.mts +5 -0
- package/dist/devtools-panel/stub.d.mts.map +1 -0
- package/dist/devtools-panel/stub.mjs +7 -0
- package/dist/devtools-panel/stub.mjs.map +1 -0
- package/dist/devtools-panel/types.d.mts +51 -0
- package/dist/devtools-panel/types.d.mts.map +1 -0
- package/dist/devtools-panel/types.mjs +1 -0
- package/dist/index.d.mts +16 -0
- package/{index.mjs → dist/index.mjs} +8 -21
- package/dist/index.mjs.map +1 -0
- package/{infinite-query-options.d.ts → dist/infinite-query-options.d.mts} +28 -25
- package/dist/infinite-query-options.d.mts.map +1 -0
- package/dist/infinite-query-options.mjs +8 -0
- package/dist/infinite-query-options.mjs.map +1 -0
- package/{inject-infinite-query.d.ts → dist/inject-infinite-query.d.mts} +13 -10
- package/dist/inject-infinite-query.d.mts.map +1 -0
- package/dist/inject-infinite-query.mjs +13 -0
- package/dist/inject-infinite-query.mjs.map +1 -0
- package/{inject-is-fetching.d.ts → dist/inject-is-fetching.d.mts} +11 -8
- package/dist/inject-is-fetching.d.mts.map +1 -0
- package/dist/inject-is-fetching.mjs +69 -0
- package/dist/inject-is-fetching.mjs.map +1 -0
- package/{inject-is-mutating.d.ts → dist/inject-is-mutating.d.mts} +11 -8
- package/dist/inject-is-mutating.d.mts.map +1 -0
- package/dist/inject-is-mutating.mjs +52 -0
- package/dist/inject-is-mutating.mjs.map +1 -0
- package/{inject-is-restoring.d.ts → dist/inject-is-restoring.d.mts} +10 -8
- package/dist/inject-is-restoring.d.mts.map +1 -0
- package/dist/inject-is-restoring.mjs +35 -0
- package/dist/inject-is-restoring.mjs.map +1 -0
- package/{inject-mutation-state.d.ts → dist/inject-mutation-state.d.mts} +13 -11
- package/dist/inject-mutation-state.d.mts.map +1 -0
- package/dist/inject-mutation-state.mjs +103 -0
- package/dist/inject-mutation-state.mjs.map +1 -0
- package/{inject-mutation.d.ts → dist/inject-mutation.d.mts} +12 -9
- package/dist/inject-mutation.d.mts.map +1 -0
- package/dist/inject-mutation.mjs +226 -0
- package/dist/inject-mutation.mjs.map +1 -0
- package/dist/inject-queries-experimental/index.d.mts +2 -0
- package/dist/inject-queries-experimental/index.mjs +2 -0
- package/{inject-queries.d.ts → dist/inject-queries.d.mts} +33 -53
- package/dist/inject-queries.d.mts.map +1 -0
- package/dist/inject-queries.mjs +203 -0
- package/dist/inject-queries.mjs.map +1 -0
- package/{inject-query-client.d.ts → dist/inject-query-client.d.mts} +6 -3
- package/dist/inject-query-client.d.mts.map +1 -0
- package/dist/inject-query-client.mjs +23 -0
- package/dist/inject-query-client.mjs.map +1 -0
- package/{inject-query.d.ts → dist/inject-query.d.mts} +13 -10
- package/dist/inject-query.d.mts.map +1 -0
- package/dist/inject-query.mjs +12 -0
- package/dist/inject-query.mjs.map +1 -0
- package/{mutation-options.d.ts → dist/mutation-options.d.mts} +5 -2
- package/dist/mutation-options.d.mts.map +1 -0
- package/dist/mutation-options.mjs +8 -0
- package/dist/mutation-options.mjs.map +1 -0
- package/dist/pending-tasks-compat.d.mts +9 -0
- package/dist/pending-tasks-compat.d.mts.map +1 -0
- package/dist/pending-tasks-compat.mjs +13 -0
- package/dist/pending-tasks-compat.mjs.map +1 -0
- package/{providers.d.ts → dist/providers.d.mts} +7 -5
- package/dist/providers.d.mts.map +1 -0
- package/dist/providers.mjs +124 -0
- package/dist/providers.mjs.map +1 -0
- package/{query-options.d.ts → dist/query-options.d.mts} +34 -31
- package/dist/query-options.d.mts.map +1 -0
- package/dist/query-options.mjs +8 -0
- package/dist/query-options.mjs.map +1 -0
- package/{signal-proxy.d.ts → dist/signal-proxy.d.mts} +5 -4
- package/dist/signal-proxy.d.mts.map +1 -0
- package/dist/signal-proxy.mjs +35 -0
- package/dist/signal-proxy.mjs.map +1 -0
- package/{types.d.ts → dist/types.d.mts} +24 -26
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +6 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +50 -20
- package/src/__tests__/infinite-query-options.test-d.ts +314 -0
- package/src/__tests__/infinite-query-options.test.ts +19 -0
- package/src/__tests__/inject-devtools-panel.test.ts +196 -0
- package/src/__tests__/inject-infinite-query.test-d.ts +66 -0
- package/src/__tests__/inject-infinite-query.test.ts +227 -0
- package/src/__tests__/inject-is-fetching.test.ts +108 -0
- package/src/__tests__/inject-is-mutating.test.ts +113 -0
- package/src/__tests__/inject-is-restoring.test.ts +93 -0
- package/src/__tests__/inject-mutation-state.test-d.ts +22 -0
- package/src/__tests__/inject-mutation-state.test.ts +198 -0
- package/src/__tests__/inject-mutation.test-d.ts +158 -0
- package/src/__tests__/inject-mutation.test.ts +1161 -0
- package/src/__tests__/inject-queries.test-d.ts +196 -0
- package/src/__tests__/inject-queries.test.ts +240 -0
- package/src/__tests__/inject-query.test-d.ts +357 -0
- package/src/__tests__/inject-query.test.ts +700 -0
- package/src/__tests__/mutation-options.test-d.ts +234 -0
- package/src/__tests__/mutation-options.test.ts +344 -0
- package/src/__tests__/pending-tasks.test.ts +644 -0
- package/src/__tests__/provide-query-client.test.ts +38 -0
- package/src/__tests__/provide-tanstack-query.test.ts +38 -0
- package/src/__tests__/query-options.test-d.ts +262 -0
- package/src/__tests__/query-options.test.ts +14 -0
- package/src/__tests__/signal-proxy.test.ts +27 -0
- package/src/__tests__/test-utils.ts +77 -0
- package/src/__tests__/with-devtools.test.ts +674 -0
- package/src/create-base-query.ts +176 -0
- package/src/devtools/index.ts +8 -0
- package/src/devtools/production/index.ts +1 -0
- package/src/devtools/stub.ts +7 -0
- package/src/devtools/types.ts +116 -0
- package/src/devtools/with-devtools.ts +182 -0
- package/src/devtools-panel/index.ts +8 -0
- package/src/devtools-panel/inject-devtools-panel.ts +110 -0
- package/src/devtools-panel/production/index.ts +1 -0
- package/src/devtools-panel/stub.ts +7 -0
- package/src/devtools-panel/types.ts +57 -0
- package/src/index.ts +60 -0
- package/src/infinite-query-options.ts +354 -0
- package/src/inject-infinite-query.ts +296 -0
- package/src/inject-is-fetching.ts +97 -0
- package/src/inject-is-mutating.ts +80 -0
- package/src/inject-is-restoring.ts +53 -0
- package/src/inject-mutation-state.ts +167 -0
- package/src/inject-mutation.ts +328 -0
- package/src/inject-queries-experimental/index.ts +1 -0
- package/src/inject-queries.ts +480 -0
- package/src/inject-query-client.ts +22 -0
- package/src/inject-query.ts +208 -0
- package/src/mutation-options.ts +121 -0
- package/src/pending-tasks-compat.ts +27 -0
- package/src/providers.ts +170 -0
- package/src/query-options.ts +292 -0
- package/src/signal-proxy.ts +46 -0
- package/src/types.ts +429 -0
- package/create-base-query.d.ts +0 -164
- package/create-base-query.mjs +0 -99
- package/create-base-query.mjs.map +0 -1
- package/devtools/index.d.ts +0 -2
- package/devtools/index.mjs +0 -5
- package/devtools/index.mjs.map +0 -1
- package/devtools/production/index.d.ts +0 -1
- package/devtools/stub.d.ts +0 -2
- package/devtools/stub.mjs +0 -8
- package/devtools/stub.mjs.map +0 -1
- package/devtools/types.d.ts +0 -103
- package/devtools/with-devtools.mjs +0 -106
- package/devtools/with-devtools.mjs.map +0 -1
- package/devtools-panel/index.d.ts +0 -2
- package/devtools-panel/index.mjs +0 -5
- package/devtools-panel/index.mjs.map +0 -1
- package/devtools-panel/inject-devtools-panel.mjs +0 -72
- package/devtools-panel/inject-devtools-panel.mjs.map +0 -1
- package/devtools-panel/production/index.d.ts +0 -1
- package/devtools-panel/stub.d.ts +0 -2
- package/devtools-panel/stub.mjs +0 -8
- package/devtools-panel/stub.mjs.map +0 -1
- package/devtools-panel/types.d.ts +0 -48
- package/index.d.ts +0 -25
- package/index.mjs.map +0 -1
- package/infinite-query-options.mjs +0 -7
- package/infinite-query-options.mjs.map +0 -1
- package/inject-infinite-query.mjs +0 -18
- package/inject-infinite-query.mjs.map +0 -1
- package/inject-is-fetching.mjs +0 -31
- package/inject-is-fetching.mjs.map +0 -1
- package/inject-is-mutating.mjs +0 -31
- package/inject-is-mutating.mjs.map +0 -1
- package/inject-is-restoring.mjs +0 -21
- package/inject-is-restoring.mjs.map +0 -1
- package/inject-mutation-state.mjs +0 -51
- package/inject-mutation-state.mjs.map +0 -1
- package/inject-mutation.mjs +0 -94
- package/inject-mutation.mjs.map +0 -1
- package/inject-queries-experimental/index.d.ts +0 -1
- package/inject-queries-experimental/index.mjs +0 -5
- package/inject-queries-experimental/index.mjs.map +0 -1
- package/inject-queries.mjs +0 -82
- package/inject-queries.mjs.map +0 -1
- package/inject-query-client.mjs +0 -9
- package/inject-query-client.mjs.map +0 -1
- package/inject-query.mjs +0 -14
- package/inject-query.mjs.map +0 -1
- package/mutation-options.mjs +0 -7
- package/mutation-options.mjs.map +0 -1
- package/pending-tasks-compat.d.ts +0 -7
- package/pending-tasks-compat.mjs +0 -19
- package/pending-tasks-compat.mjs.map +0 -1
- package/providers.mjs +0 -32
- package/providers.mjs.map +0 -1
- package/query-options.mjs +0 -7
- package/query-options.mjs.map +0 -1
- package/signal-proxy.mjs +0 -29
- package/signal-proxy.mjs.map +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Injector,
|
|
4
|
+
NgZone,
|
|
5
|
+
assertInInjectionContext,
|
|
6
|
+
inject,
|
|
7
|
+
signal,
|
|
8
|
+
} from '@angular/core'
|
|
9
|
+
import { QueryClient, notifyManager } from '@tanstack/query-core'
|
|
10
|
+
import type { QueryFilters } from '@tanstack/query-core'
|
|
11
|
+
import type { Signal } from '@angular/core'
|
|
12
|
+
|
|
13
|
+
export interface InjectIsFetchingOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The `Injector` in which to create the isFetching signal.
|
|
16
|
+
*
|
|
17
|
+
* If this is not provided, the current injection context will be used instead (via `inject`).
|
|
18
|
+
*/
|
|
19
|
+
injector?: Injector
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Injects a signal that tracks the number of queries that your application is loading or fetching in the
|
|
24
|
+
* background (useful for app-wide loading indicators).
|
|
25
|
+
*
|
|
26
|
+
* @param filters - The {@link QueryFilters} to narrow down the matched queries.
|
|
27
|
+
* @param options - Additional configuration
|
|
28
|
+
* @returns A `Signal` with the number of queries that your application is currently loading or fetching in
|
|
29
|
+
* the background.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```angular-ts
|
|
33
|
+
* @Component({
|
|
34
|
+
* selector: 'posts-fetching-indicator',
|
|
35
|
+
* template: `
|
|
36
|
+
* @if (isFetchingPosts()) {
|
|
37
|
+
* <span>Refreshing posts...</span>
|
|
38
|
+
* }
|
|
39
|
+
* `,
|
|
40
|
+
* })
|
|
41
|
+
* export class PostsFetchingIndicator {
|
|
42
|
+
* // How many queries matching the posts prefix are fetching?
|
|
43
|
+
* readonly isFetchingPosts = injectIsFetching({ queryKey: ['posts'] })
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* A global loading indicator for any query fetching in the background, not just the ones on screen:
|
|
49
|
+
* ```angular-ts
|
|
50
|
+
* @Component({
|
|
51
|
+
* selector: 'global-loading-indicator',
|
|
52
|
+
* template: `
|
|
53
|
+
* @if (isFetching()) {
|
|
54
|
+
* <div>Queries are fetching in the background...</div>
|
|
55
|
+
* }
|
|
56
|
+
* `,
|
|
57
|
+
* })
|
|
58
|
+
* export class GlobalLoadingIndicator {
|
|
59
|
+
* readonly isFetching = injectIsFetching()
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function injectIsFetching(
|
|
64
|
+
filters?: QueryFilters,
|
|
65
|
+
options?: InjectIsFetchingOptions,
|
|
66
|
+
): Signal<number> {
|
|
67
|
+
!options?.injector && assertInInjectionContext(injectIsFetching)
|
|
68
|
+
const injector = options?.injector ?? inject(Injector)
|
|
69
|
+
const destroyRef = injector.get(DestroyRef)
|
|
70
|
+
const ngZone = injector.get(NgZone)
|
|
71
|
+
const queryClient = injector.get(QueryClient)
|
|
72
|
+
|
|
73
|
+
const cache = queryClient.getQueryCache()
|
|
74
|
+
// isFetching is the prev value initialized on mount *
|
|
75
|
+
let isFetching = queryClient.isFetching(filters)
|
|
76
|
+
|
|
77
|
+
const result = signal(isFetching)
|
|
78
|
+
|
|
79
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
80
|
+
cache.subscribe(
|
|
81
|
+
notifyManager.batchCalls(() => {
|
|
82
|
+
const newIsFetching = queryClient.isFetching(filters)
|
|
83
|
+
if (isFetching !== newIsFetching) {
|
|
84
|
+
// * and update with each change
|
|
85
|
+
isFetching = newIsFetching
|
|
86
|
+
ngZone.run(() => {
|
|
87
|
+
result.set(isFetching)
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
destroyRef.onDestroy(unsubscribe)
|
|
95
|
+
|
|
96
|
+
return result
|
|
97
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Injector,
|
|
4
|
+
NgZone,
|
|
5
|
+
assertInInjectionContext,
|
|
6
|
+
inject,
|
|
7
|
+
signal,
|
|
8
|
+
} from '@angular/core'
|
|
9
|
+
import { QueryClient, notifyManager } from '@tanstack/query-core'
|
|
10
|
+
import type { MutationFilters } from '@tanstack/query-core'
|
|
11
|
+
import type { Signal } from '@angular/core'
|
|
12
|
+
|
|
13
|
+
export interface InjectIsMutatingOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The `Injector` in which to create the isMutating signal.
|
|
16
|
+
*
|
|
17
|
+
* If this is not provided, the current injection context will be used instead (via `inject`).
|
|
18
|
+
*/
|
|
19
|
+
injector?: Injector
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Injects a signal that tracks the number of mutations that your application currently has `pending`
|
|
24
|
+
* (useful for app-wide loading indicators).
|
|
25
|
+
*
|
|
26
|
+
* @param filters - The {@link MutationFilters} to narrow down the matched mutations.
|
|
27
|
+
* @param options - Additional configuration
|
|
28
|
+
* @returns A `Signal` with the number of mutations that your application currently has `pending`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```angular-ts
|
|
32
|
+
* @Component({
|
|
33
|
+
* selector: 'posts-mutating-indicator',
|
|
34
|
+
* template: `
|
|
35
|
+
* @if (isMutatingPosts()) {
|
|
36
|
+
* <span>Saving posts...</span>
|
|
37
|
+
* }
|
|
38
|
+
* `,
|
|
39
|
+
* })
|
|
40
|
+
* export class PostsMutatingIndicator {
|
|
41
|
+
* // How many mutations matching the posts prefix are in progress?
|
|
42
|
+
* readonly isMutatingPosts = injectIsMutating({ mutationKey: ['posts'] })
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function injectIsMutating(
|
|
47
|
+
filters?: MutationFilters,
|
|
48
|
+
options?: InjectIsMutatingOptions,
|
|
49
|
+
): Signal<number> {
|
|
50
|
+
!options?.injector && assertInInjectionContext(injectIsMutating)
|
|
51
|
+
const injector = options?.injector ?? inject(Injector)
|
|
52
|
+
const destroyRef = injector.get(DestroyRef)
|
|
53
|
+
const ngZone = injector.get(NgZone)
|
|
54
|
+
const queryClient = injector.get(QueryClient)
|
|
55
|
+
|
|
56
|
+
const cache = queryClient.getMutationCache()
|
|
57
|
+
// isMutating is the prev value initialized on mount *
|
|
58
|
+
let isMutating = queryClient.isMutating(filters)
|
|
59
|
+
|
|
60
|
+
const result = signal(isMutating)
|
|
61
|
+
|
|
62
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
63
|
+
cache.subscribe(
|
|
64
|
+
notifyManager.batchCalls(() => {
|
|
65
|
+
const newIsMutating = queryClient.isMutating(filters)
|
|
66
|
+
if (isMutating !== newIsMutating) {
|
|
67
|
+
// * and update with each change
|
|
68
|
+
isMutating = newIsMutating
|
|
69
|
+
ngZone.run(() => {
|
|
70
|
+
result.set(isMutating)
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
destroyRef.onDestroy(unsubscribe)
|
|
78
|
+
|
|
79
|
+
return result.asReadonly()
|
|
80
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InjectionToken,
|
|
3
|
+
Injector,
|
|
4
|
+
assertInInjectionContext,
|
|
5
|
+
inject,
|
|
6
|
+
signal,
|
|
7
|
+
} from '@angular/core'
|
|
8
|
+
import type { Provider, Signal } from '@angular/core'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Internal token used to track isRestoring state, accessible in public API through `injectIsRestoring` and set via `provideIsRestoring`
|
|
12
|
+
*/
|
|
13
|
+
const IS_RESTORING = new InjectionToken('', {
|
|
14
|
+
// Default value when not provided
|
|
15
|
+
factory: () => signal(false).asReadonly(),
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
interface InjectIsRestoringOptions {
|
|
19
|
+
/**
|
|
20
|
+
* The `Injector` to use to get the isRestoring signal.
|
|
21
|
+
*
|
|
22
|
+
* If this is not provided, the current injection context will be used instead (via `inject`).
|
|
23
|
+
*/
|
|
24
|
+
injector?: Injector
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Injects a signal that tracks whether a restore (e.g. from a persisted client, wired up via
|
|
29
|
+
* `provideIsRestoring`) is currently in progress. `injectQuery` and friends also check this internally to
|
|
30
|
+
* avoid race conditions between the restore and initializing queries.
|
|
31
|
+
* @param options - Additional configuration
|
|
32
|
+
* @returns A readonly `Signal<boolean>` — `true` while a restore is in progress, `false` otherwise (the
|
|
33
|
+
* default when no `provideIsRestoring` provider is registered).
|
|
34
|
+
*/
|
|
35
|
+
export function injectIsRestoring(options?: InjectIsRestoringOptions) {
|
|
36
|
+
!options?.injector && assertInInjectionContext(injectIsRestoring)
|
|
37
|
+
const injector = options?.injector ?? inject(Injector)
|
|
38
|
+
return injector.get(IS_RESTORING)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Registers a provider for the restore state read by `injectIsRestoring`. Wire this up wherever you drive a
|
|
43
|
+
* restore yourself — e.g. a persist-client integration — so `injectQuery` and friends can defer subscribing
|
|
44
|
+
* to their observer (avoiding a race with the restore) until the restore signal flips back to `false`.
|
|
45
|
+
* @param isRestoring - A readonly `Signal<boolean>` that tracks the restore state.
|
|
46
|
+
* @returns A provider for the `isRestoring` signal.
|
|
47
|
+
*/
|
|
48
|
+
export function provideIsRestoring(isRestoring: Signal<boolean>): Provider {
|
|
49
|
+
return {
|
|
50
|
+
provide: IS_RESTORING,
|
|
51
|
+
useValue: isRestoring,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Injector,
|
|
4
|
+
NgZone,
|
|
5
|
+
assertInInjectionContext,
|
|
6
|
+
computed,
|
|
7
|
+
inject,
|
|
8
|
+
signal,
|
|
9
|
+
} from '@angular/core'
|
|
10
|
+
import {
|
|
11
|
+
QueryClient,
|
|
12
|
+
notifyManager,
|
|
13
|
+
replaceEqualDeep,
|
|
14
|
+
} from '@tanstack/query-core'
|
|
15
|
+
import type { Signal } from '@angular/core'
|
|
16
|
+
import type {
|
|
17
|
+
Mutation,
|
|
18
|
+
MutationCache,
|
|
19
|
+
MutationFilters,
|
|
20
|
+
MutationState,
|
|
21
|
+
} from '@tanstack/query-core'
|
|
22
|
+
|
|
23
|
+
type MutationStateOptions<TResult = MutationState> = {
|
|
24
|
+
filters?: MutationFilters
|
|
25
|
+
select?: (mutation: Mutation) => TResult
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getResult<TResult = MutationState>(
|
|
29
|
+
mutationCache: MutationCache,
|
|
30
|
+
options: MutationStateOptions<TResult>,
|
|
31
|
+
): Array<TResult> {
|
|
32
|
+
return mutationCache
|
|
33
|
+
.findAll(options.filters)
|
|
34
|
+
.map(
|
|
35
|
+
(mutation): TResult =>
|
|
36
|
+
(options.select ? options.select(mutation) : mutation.state) as TResult,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface InjectMutationStateOptions {
|
|
41
|
+
/**
|
|
42
|
+
* The `Injector` in which to create the mutation state signal.
|
|
43
|
+
*
|
|
44
|
+
* If this is not provided, the current injection context will be used instead (via `inject`).
|
|
45
|
+
*/
|
|
46
|
+
injector?: Injector
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Injects a signal that gives you access to all mutations in the `MutationCache`. You can pass `filters`
|
|
51
|
+
* ({@link MutationFilters}) to narrow down your mutations, and `select` to transform the mutation state.
|
|
52
|
+
*
|
|
53
|
+
* @param injectMutationStateFn - A function returning the `filters` to narrow down matched mutations, and an
|
|
54
|
+
* optional `select` to transform the mutation state. Similar to `computed` from Angular, this function runs
|
|
55
|
+
* in the reactive context, so signals read inside it re-narrow the matched mutations.
|
|
56
|
+
* @param options - Additional configuration
|
|
57
|
+
* @returns A `Signal` with an Array of whatever `select` returns for each matching mutation.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* Get all variables of all running mutations:
|
|
61
|
+
* ```angular-ts
|
|
62
|
+
* @Component({
|
|
63
|
+
* selector: 'pending-posts',
|
|
64
|
+
* template: `{{ pendingVariables().length }} posts saving...`,
|
|
65
|
+
* })
|
|
66
|
+
* export class PendingPosts {
|
|
67
|
+
* readonly pendingVariables = injectMutationState(() => ({
|
|
68
|
+
* filters: { status: 'pending' },
|
|
69
|
+
* select: (mutation) => mutation.state.variables,
|
|
70
|
+
* }))
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* Get all data for specific mutations via the `mutationKey`:
|
|
76
|
+
* ```angular-ts
|
|
77
|
+
* const mutationKey = ['posts']
|
|
78
|
+
*
|
|
79
|
+
* @Component({
|
|
80
|
+
* selector: 'posts',
|
|
81
|
+
* template: `
|
|
82
|
+
* <button (click)="createPost()">
|
|
83
|
+
* Create post ({{ savedPosts().length }} saved so far)
|
|
84
|
+
* </button>
|
|
85
|
+
* `,
|
|
86
|
+
* })
|
|
87
|
+
* export class Posts {
|
|
88
|
+
* // Some mutation that we want to get the state for
|
|
89
|
+
* readonly createPostMutation = injectMutation(() => ({
|
|
90
|
+
* mutationKey,
|
|
91
|
+
* mutationFn: createPosts,
|
|
92
|
+
* }))
|
|
93
|
+
*
|
|
94
|
+
* readonly savedPosts = injectMutationState(() => ({
|
|
95
|
+
* // this mutation key needs to match the mutation key of the given mutation (see above)
|
|
96
|
+
* filters: { mutationKey, status: 'success' },
|
|
97
|
+
* select: (mutation) => mutation.state.data,
|
|
98
|
+
* }))
|
|
99
|
+
*
|
|
100
|
+
* createPost() {
|
|
101
|
+
* this.createPostMutation.mutate(['New Post'])
|
|
102
|
+
* }
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export function injectMutationState<TResult = MutationState>(
|
|
107
|
+
injectMutationStateFn: () => MutationStateOptions<TResult> = () => ({}),
|
|
108
|
+
options?: InjectMutationStateOptions,
|
|
109
|
+
): Signal<Array<TResult>> {
|
|
110
|
+
!options?.injector && assertInInjectionContext(injectMutationState)
|
|
111
|
+
const injector = options?.injector ?? inject(Injector)
|
|
112
|
+
const destroyRef = injector.get(DestroyRef)
|
|
113
|
+
const ngZone = injector.get(NgZone)
|
|
114
|
+
const queryClient = injector.get(QueryClient)
|
|
115
|
+
const mutationCache = queryClient.getMutationCache()
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Computed signal that gets result from mutation cache based on passed options
|
|
119
|
+
* First element is the result, second element is the time when the result was set
|
|
120
|
+
*/
|
|
121
|
+
const resultFromOptionsSignal = computed(() => {
|
|
122
|
+
return [
|
|
123
|
+
getResult(mutationCache, injectMutationStateFn()),
|
|
124
|
+
performance.now(),
|
|
125
|
+
] as const
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Signal that contains result set by subscriber
|
|
130
|
+
* First element is the result, second element is the time when the result was set
|
|
131
|
+
*/
|
|
132
|
+
const resultFromSubscriberSignal = signal<[Array<TResult>, number] | null>(
|
|
133
|
+
null,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Returns the last result by either subscriber or options
|
|
138
|
+
*/
|
|
139
|
+
const effectiveResultSignal = computed(() => {
|
|
140
|
+
const optionsResult = resultFromOptionsSignal()
|
|
141
|
+
const subscriberResult = resultFromSubscriberSignal()
|
|
142
|
+
return subscriberResult && subscriberResult[1] > optionsResult[1]
|
|
143
|
+
? subscriberResult[0]
|
|
144
|
+
: optionsResult[0]
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const unsubscribe = ngZone.runOutsideAngular(() =>
|
|
148
|
+
mutationCache.subscribe(
|
|
149
|
+
notifyManager.batchCalls(() => {
|
|
150
|
+
const [lastResult] = effectiveResultSignal()
|
|
151
|
+
const nextResult = replaceEqualDeep(
|
|
152
|
+
lastResult,
|
|
153
|
+
getResult(mutationCache, injectMutationStateFn()),
|
|
154
|
+
)
|
|
155
|
+
if (lastResult !== nextResult) {
|
|
156
|
+
ngZone.run(() => {
|
|
157
|
+
resultFromSubscriberSignal.set([nextResult, performance.now()])
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
}),
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
destroyRef.onDestroy(unsubscribe)
|
|
165
|
+
|
|
166
|
+
return effectiveResultSignal
|
|
167
|
+
}
|