@veams/status-quo-query 0.2.0 → 0.4.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/.turbo/turbo-build.log +14 -12
- package/README.md +13 -13
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/mutation.d.ts +15 -0
- package/dist/mutation.js +18 -1
- package/dist/mutation.js.map +1 -1
- package/dist/provider.d.ts +8 -2
- package/dist/provider.js +16 -1
- package/dist/provider.js.map +1 -1
- package/dist/query.d.ts +27 -0
- package/dist/query.js +32 -1
- package/dist/query.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/provider.spec.ts +12 -12
- package/src/index.ts +3 -0
- package/src/mutation.ts +50 -0
- package/src/provider.ts +31 -2
- package/src/query.ts +75 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
>
|
|
12
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @veams/status-quo-query@0.3.0 build
|
|
4
|
+
> npm-run-all compile
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
> @veams/status-quo-query@0.3.0 compile
|
|
8
|
+
> npm-run-all bundle:ts
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
> @veams/status-quo-query@0.3.0 bundle:ts
|
|
12
|
+
> tsc --project tsconfig.json
|
|
13
|
+
|
|
14
|
+
⠙[1G[0K⠙[1G[0K⠙[1G[0K
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install @veams/status-quo-query @tanstack/query-core
|
|
|
12
12
|
|
|
13
13
|
Root exports:
|
|
14
14
|
|
|
15
|
-
- `
|
|
15
|
+
- `setupQueryManager`
|
|
16
16
|
- `setupQuery`
|
|
17
17
|
- `setupMutation`
|
|
18
18
|
- `isQueryLoading`
|
|
@@ -20,7 +20,7 @@ Root exports:
|
|
|
20
20
|
- `QueryFetchStatus`
|
|
21
21
|
- `QueryStatus`
|
|
22
22
|
- `MutationStatus`
|
|
23
|
-
- `
|
|
23
|
+
- `QueryManager`
|
|
24
24
|
- `CreateQuery`
|
|
25
25
|
- `CreateMutation`
|
|
26
26
|
- `QueryService`
|
|
@@ -43,32 +43,32 @@ Subpath exports:
|
|
|
43
43
|
```ts
|
|
44
44
|
import { QueryClient } from '@tanstack/query-core';
|
|
45
45
|
import {
|
|
46
|
-
|
|
46
|
+
setupQueryManager,
|
|
47
47
|
} from '@veams/status-quo-query';
|
|
48
48
|
|
|
49
49
|
const queryClient = new QueryClient();
|
|
50
|
-
const
|
|
50
|
+
const manager = setupQueryManager(queryClient);
|
|
51
51
|
|
|
52
|
-
const userQuery =
|
|
52
|
+
const userQuery = manager.createQuery(['user', 42], () => fetchUser(42), {
|
|
53
53
|
enabled: false,
|
|
54
54
|
});
|
|
55
55
|
await userQuery.refetch();
|
|
56
56
|
await userQuery.invalidate({ refetchType: 'none' });
|
|
57
57
|
|
|
58
|
-
const updateUser =
|
|
58
|
+
const updateUser = manager.createMutation((payload: UpdateUserPayload) => saveUser(payload));
|
|
59
59
|
await updateUser.mutate({ id: 42 });
|
|
60
60
|
|
|
61
|
-
await
|
|
62
|
-
|
|
61
|
+
await manager.invalidateQueries({ queryKey: ['user'] });
|
|
62
|
+
manager.setQueryData(['user', 42], (current) => current);
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
## API
|
|
66
66
|
|
|
67
|
-
### `
|
|
67
|
+
### `setupQueryManager(queryClient)`
|
|
68
68
|
|
|
69
|
-
Creates the package-level
|
|
69
|
+
Creates the package-level query manager facade around an existing TanStack `QueryClient`.
|
|
70
70
|
|
|
71
|
-
Returns `
|
|
71
|
+
Returns `QueryManager` with:
|
|
72
72
|
|
|
73
73
|
- `createQuery(queryKey, queryFn, options?)`
|
|
74
74
|
- `createMutation(mutationFn, options?)`
|
|
@@ -81,7 +81,7 @@ Returns `CacheApi` with:
|
|
|
81
81
|
- `setQueryData(...)`
|
|
82
82
|
- `unsafe_getClient()`
|
|
83
83
|
|
|
84
|
-
All
|
|
84
|
+
All manager methods forward directly to the corresponding `QueryClient` methods. `unsafe_getClient()` returns the raw TanStack client as an explicit escape hatch.
|
|
85
85
|
|
|
86
86
|
### `setupQuery(queryClient)`
|
|
87
87
|
|
|
@@ -170,4 +170,4 @@ Creates a `createMutation` factory bound to a `QueryClient`.
|
|
|
170
170
|
- `getSnapshot()` always returns passive state only.
|
|
171
171
|
- Commands live on the handle itself: `refetch`, `invalidate`, `mutate`, `reset`.
|
|
172
172
|
- Raw TanStack observer and client access is explicit through `unsafe_getResult()` and `unsafe_getClient()`.
|
|
173
|
-
-
|
|
173
|
+
- Manager-level operations live on `setupQueryManager()`, not on individual snapshots.
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
// Re-export all mutation-related types and functions.
|
|
1
2
|
export * from './mutation';
|
|
3
|
+
// Re-export all query-related types and functions.
|
|
2
4
|
export * from './query';
|
|
5
|
+
// Re-export all provider-related types and functions for cache management.
|
|
3
6
|
export * from './provider';
|
|
4
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,cAAc,YAAY,CAAC;AAC3B,mDAAmD;AACnD,cAAc,SAAS,CAAC;AACxB,2EAA2E;AAC3E,cAAc,YAAY,CAAC"}
|
package/dist/mutation.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type MutationFunction, type MutateOptions, type MutationObserverOptions, type MutationObserverResult, type MutationStatus as TanstackMutationStatus, type QueryClient } from '@tanstack/query-core';
|
|
2
2
|
export type MutationStatus = TanstackMutationStatus;
|
|
3
|
+
/**
|
|
4
|
+
* Represents a stable snapshot of the mutation service's state.
|
|
5
|
+
*/
|
|
3
6
|
export interface MutationServiceSnapshot<TData = unknown, TError = Error, TVariables = void> {
|
|
4
7
|
data: TData | undefined;
|
|
5
8
|
error: TError | null;
|
|
@@ -10,6 +13,9 @@ export interface MutationServiceSnapshot<TData = unknown, TError = Error, TVaria
|
|
|
10
13
|
isPending: boolean;
|
|
11
14
|
isSuccess: boolean;
|
|
12
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Defines the public API for a mutation service.
|
|
18
|
+
*/
|
|
13
19
|
export interface MutationService<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown> {
|
|
14
20
|
getSnapshot: () => MutationServiceSnapshot<TData, TError, TVariables>;
|
|
15
21
|
subscribe: (listener: (snapshot: MutationServiceSnapshot<TData, TError, TVariables>) => void) => () => void;
|
|
@@ -17,8 +23,17 @@ export interface MutationService<TData = unknown, TError = Error, TVariables = v
|
|
|
17
23
|
reset: () => void;
|
|
18
24
|
unsafe_getResult: () => MutationObserverResult<TData, TError, TVariables, TOnMutateResult>;
|
|
19
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Configuration options for creating a mutation service, excluding the mutation function itself.
|
|
28
|
+
*/
|
|
20
29
|
export type MutationServiceOptions<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown> = Omit<MutationObserverOptions<TData, TError, TVariables, TOnMutateResult>, 'mutationFn'>;
|
|
30
|
+
/**
|
|
31
|
+
* Function signature for the mutation factory.
|
|
32
|
+
*/
|
|
21
33
|
export interface CreateMutation {
|
|
22
34
|
<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown>(mutationFn: MutationFunction<TData, TVariables>, options?: MutationServiceOptions<TData, TError, TVariables, TOnMutateResult>): MutationService<TData, TError, TVariables, TOnMutateResult>;
|
|
23
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Prepares the mutation factory by binding it to a specific QueryClient instance.
|
|
38
|
+
*/
|
|
24
39
|
export declare function setupMutation(queryClient: QueryClient): CreateMutation;
|
package/dist/mutation.js
CHANGED
|
@@ -1,22 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
// Import MutationObserver to observe and manage mutations.
|
|
3
|
+
MutationObserver, } from '@tanstack/query-core';
|
|
4
|
+
/**
|
|
5
|
+
* Prepares the mutation factory by binding it to a specific QueryClient instance.
|
|
6
|
+
*/
|
|
2
7
|
export function setupMutation(queryClient) {
|
|
8
|
+
// Returns the actual factory function for creating individual mutation services.
|
|
3
9
|
return function createMutation(mutationFn, options) {
|
|
10
|
+
// Create a new MutationObserver instance to manage this specific mutation's lifecycle.
|
|
4
11
|
const observer = new MutationObserver(queryClient, {
|
|
5
12
|
...options,
|
|
6
13
|
mutationFn,
|
|
7
14
|
});
|
|
15
|
+
// Return the implementation of the MutationService interface.
|
|
8
16
|
return {
|
|
17
|
+
// Map the current observer state to our service's snapshot format.
|
|
9
18
|
getSnapshot: () => toMutationServiceSnapshot(observer.getCurrentResult()),
|
|
19
|
+
// Subscribe to observer changes and notify the listener with updated snapshots.
|
|
10
20
|
subscribe: (listener) => observer.subscribe((result) => {
|
|
11
21
|
listener(toMutationServiceSnapshot(result));
|
|
12
22
|
}),
|
|
23
|
+
// Proxy the mutate call to the underlying observer.
|
|
13
24
|
mutate: (variables, mutateOptions) => observer.mutate(variables, mutateOptions),
|
|
25
|
+
// Reset the underlying observer state.
|
|
14
26
|
reset: () => observer.reset(),
|
|
27
|
+
// Provide direct access to the raw observer result when needed.
|
|
15
28
|
unsafe_getResult: () => observer.getCurrentResult(),
|
|
16
29
|
};
|
|
17
30
|
};
|
|
18
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Internal helper to transform a raw Tanstack mutation result into our public snapshot format.
|
|
34
|
+
*/
|
|
19
35
|
function toMutationServiceSnapshot(result) {
|
|
36
|
+
// Extract and return the relevant fields for the UI or other services.
|
|
20
37
|
return {
|
|
21
38
|
data: result.data,
|
|
22
39
|
error: result.error,
|
package/dist/mutation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.js","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"mutation.js","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"AAAA,OAAO;AACL,2DAA2D;AAC3D,gBAAgB,GAajB,MAAM,sBAAsB,CAAC;AA2E9B;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,WAAwB;IACpD,iFAAiF;IACjF,OAAO,SAAS,cAAc,CAM5B,UAA+C,EAC/C,OAA4E;QAE5E,uFAAuF;QACvF,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CACnC,WAAW,EACX;YACE,GAAG,OAAO;YACV,UAAU;SACX,CACF,CAAC;QAEF,8DAA8D;QAC9D,OAAO;YACL,mEAAmE;YACnE,WAAW,EAAE,GAAG,EAAE,CAAC,yBAAyB,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YACzE,gFAAgF;YAChF,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CACtB,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC5B,QAAQ,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,CAAC,CAAC;YACJ,oDAAoD;YACpD,MAAM,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC;YAC/E,uCAAuC;YACvC,KAAK,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC7B,gEAAgE;YAChE,gBAAgB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE;SACpD,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAChC,MAA0E;IAE1E,uEAAuE;IACvE,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { type QueryClient } from '@tanstack/query-core';
|
|
2
2
|
import { type CreateMutation } from './mutation';
|
|
3
3
|
import { type CreateQuery } from './query';
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Defines the public API for the query manager facade.
|
|
6
|
+
*/
|
|
7
|
+
export interface QueryManager {
|
|
5
8
|
createMutation: CreateMutation;
|
|
6
9
|
createQuery: CreateQuery;
|
|
7
10
|
cancelQueries: QueryClient['cancelQueries'];
|
|
@@ -13,4 +16,7 @@ export interface CacheApi {
|
|
|
13
16
|
setQueryData: QueryClient['setQueryData'];
|
|
14
17
|
unsafe_getClient: () => QueryClient;
|
|
15
18
|
}
|
|
16
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Prepares the query manager facade by binding all actions to a specific QueryClient instance.
|
|
21
|
+
*/
|
|
22
|
+
export declare function setupQueryManager(queryClient: QueryClient): QueryManager;
|
package/dist/provider.js
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
|
+
// Import mutation and query setup functions and their factory types.
|
|
1
2
|
import { setupMutation } from './mutation';
|
|
2
3
|
import { setupQuery } from './query';
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Prepares the query manager facade by binding all actions to a specific QueryClient instance.
|
|
6
|
+
*/
|
|
7
|
+
export function setupQueryManager(queryClient) {
|
|
8
|
+
// Return the implementation of the QueryManager interface.
|
|
4
9
|
return {
|
|
10
|
+
// Bind mutation factory to this QueryClient.
|
|
5
11
|
createMutation: setupMutation(queryClient),
|
|
12
|
+
// Bind query factory to this QueryClient.
|
|
6
13
|
createQuery: setupQuery(queryClient),
|
|
14
|
+
// Proxy for canceling queries with this client context.
|
|
7
15
|
cancelQueries: queryClient.cancelQueries.bind(queryClient),
|
|
16
|
+
// Proxy for retrieving query data with this client context.
|
|
8
17
|
getQueryData: queryClient.getQueryData.bind(queryClient),
|
|
18
|
+
// Proxy for invalidating queries with this client context.
|
|
9
19
|
invalidateQueries: queryClient.invalidateQueries.bind(queryClient),
|
|
20
|
+
// Proxy for refetching queries with this client context.
|
|
10
21
|
refetchQueries: queryClient.refetchQueries.bind(queryClient),
|
|
22
|
+
// Proxy for removing queries with this client context.
|
|
11
23
|
removeQueries: queryClient.removeQueries.bind(queryClient),
|
|
24
|
+
// Proxy for resetting queries with this client context.
|
|
12
25
|
resetQueries: queryClient.resetQueries.bind(queryClient),
|
|
26
|
+
// Proxy for setting query data with this client context.
|
|
13
27
|
setQueryData: queryClient.setQueryData.bind(queryClient),
|
|
28
|
+
// Provide an accessor for the raw client instance.
|
|
14
29
|
unsafe_getClient: () => queryClient,
|
|
15
30
|
};
|
|
16
31
|
}
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAKA,qEAAqE;AACrE,OAAO,EAAuB,aAAa,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAoB,UAAU,EAAE,MAAM,SAAS,CAAC;AA4BvD;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAwB;IACxD,2DAA2D;IAC3D,OAAO;QACL,6CAA6C;QAC7C,cAAc,EAAE,aAAa,CAAC,WAAW,CAAC;QAC1C,0CAA0C;QAC1C,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC;QACpC,wDAAwD;QACxD,aAAa,EAAE,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;QAC1D,4DAA4D;QAC5D,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;QACxD,2DAA2D;QAC3D,iBAAiB,EAAE,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC;QAClE,yDAAyD;QACzD,cAAc,EAAE,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC;QAC5D,uDAAuD;QACvD,aAAa,EAAE,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;QAC1D,wDAAwD;QACxD,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;QACxD,yDAAyD;QACzD,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;QACxD,mDAAmD;QACnD,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW;KACpC,CAAC;AACJ,CAAC"}
|
package/dist/query.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type FetchStatus, type InvalidateOptions, type InvalidateQueryFilters, type QueryClient, type QueryFunction, type QueryKey, type QueryObserverOptions, type QueryObserverResult, type RefetchOptions, type QueryStatus as TanstackQueryStatus } from '@tanstack/query-core';
|
|
2
2
|
export type QueryFetchStatus = FetchStatus;
|
|
3
3
|
export type QueryStatus = TanstackQueryStatus;
|
|
4
|
+
/**
|
|
5
|
+
* Represents a stable snapshot of the query service's state.
|
|
6
|
+
*/
|
|
4
7
|
export interface QueryServiceSnapshot<TData, TError> {
|
|
5
8
|
data: TData | undefined;
|
|
6
9
|
error: TError | null;
|
|
@@ -11,10 +14,16 @@ export interface QueryServiceSnapshot<TData, TError> {
|
|
|
11
14
|
isPending: boolean;
|
|
12
15
|
isSuccess: boolean;
|
|
13
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Defines a subset of query state containing only the status and fetch status.
|
|
19
|
+
*/
|
|
14
20
|
export interface QueryMetaState {
|
|
15
21
|
fetchStatus: QueryFetchStatus;
|
|
16
22
|
status: QueryStatus;
|
|
17
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Defines the public API for a query service.
|
|
26
|
+
*/
|
|
18
27
|
export interface QueryService<TData, TError> {
|
|
19
28
|
getSnapshot: () => QueryServiceSnapshot<TData, TError>;
|
|
20
29
|
subscribe: (listener: (snapshot: QueryServiceSnapshot<TData, TError>) => void) => () => void;
|
|
@@ -22,12 +31,30 @@ export interface QueryService<TData, TError> {
|
|
|
22
31
|
invalidate: (options?: QueryInvalidateOptions) => Promise<void>;
|
|
23
32
|
unsafe_getResult: () => QueryObserverResult<TData, TError>;
|
|
24
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Combines options for invalidation behavior and filtering.
|
|
36
|
+
*/
|
|
25
37
|
export interface QueryInvalidateOptions extends Pick<InvalidateOptions, 'cancelRefetch' | 'throwOnError'>, Pick<InvalidateQueryFilters, 'refetchType'> {
|
|
26
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Function signature for the query factory.
|
|
41
|
+
*/
|
|
27
42
|
export interface CreateQuery {
|
|
28
43
|
<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(queryKey: TQueryKey, queryFn: QueryFunction<TQueryFnData, TQueryKey>, options?: QueryServiceOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>): QueryService<TData, TError>;
|
|
29
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Configuration options for creating a query service, excluding function and key.
|
|
47
|
+
*/
|
|
30
48
|
export type QueryServiceOptions<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> = Omit<QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>, 'queryFn' | 'queryKey'>;
|
|
49
|
+
/**
|
|
50
|
+
* Extracts and maps status and fetchStatus to our QueryMetaState interface.
|
|
51
|
+
*/
|
|
31
52
|
export declare function toQueryMetaState<TData, TError>(snapshot: Pick<QueryServiceSnapshot<TData, TError>, 'fetchStatus' | 'status'>): QueryMetaState;
|
|
53
|
+
/**
|
|
54
|
+
* Helper function to check if the query is in its initial loading state.
|
|
55
|
+
*/
|
|
32
56
|
export declare function isQueryLoading(query: QueryMetaState): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Prepares the query factory by binding it to a specific QueryClient instance.
|
|
59
|
+
*/
|
|
33
60
|
export declare function setupQuery(queryClient: QueryClient): CreateQuery;
|
package/dist/query.js
CHANGED
|
@@ -1,36 +1,61 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
// Import QueryObserver to monitor and manage individual queries.
|
|
3
|
+
QueryObserver, } from '@tanstack/query-core';
|
|
4
|
+
/**
|
|
5
|
+
* Extracts and maps status and fetchStatus to our QueryMetaState interface.
|
|
6
|
+
*/
|
|
2
7
|
export function toQueryMetaState(snapshot) {
|
|
8
|
+
// Return a simplified state object for UI or other services.
|
|
3
9
|
return {
|
|
4
10
|
fetchStatus: snapshot.fetchStatus,
|
|
5
11
|
status: snapshot.status,
|
|
6
12
|
};
|
|
7
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Helper function to check if the query is in its initial loading state.
|
|
16
|
+
*/
|
|
8
17
|
export function isQueryLoading(query) {
|
|
18
|
+
// Returns true if the query is both pending and actively fetching.
|
|
9
19
|
return query.status === 'pending' && query.fetchStatus === 'fetching';
|
|
10
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Prepares the query factory by binding it to a specific QueryClient instance.
|
|
23
|
+
*/
|
|
11
24
|
export function setupQuery(queryClient) {
|
|
25
|
+
// Returns the actual factory function for creating individual query services.
|
|
12
26
|
return function createQuery(queryKey, queryFn, options) {
|
|
27
|
+
// Create a new QueryObserver instance to manage this specific query's lifecycle.
|
|
13
28
|
const observer = new QueryObserver(queryClient, {
|
|
14
29
|
...options,
|
|
15
30
|
queryFn,
|
|
16
31
|
queryKey,
|
|
17
32
|
});
|
|
33
|
+
// Return the implementation of the QueryService interface.
|
|
18
34
|
return {
|
|
35
|
+
// Map the current observer state to our service's snapshot format.
|
|
19
36
|
getSnapshot: () => toQueryServiceSnapshot(observer.getCurrentResult()),
|
|
37
|
+
// Subscribe to observer changes and notify the listener with updated snapshots.
|
|
20
38
|
subscribe: (listener) => observer.subscribe((result) => {
|
|
21
39
|
listener(toQueryServiceSnapshot(result));
|
|
22
40
|
}),
|
|
41
|
+
// Proxy the refetch call and map the async result back to a snapshot.
|
|
23
42
|
refetch: async (options) => toQueryServiceSnapshot(await observer.refetch(options)),
|
|
43
|
+
// Trigger a targeted invalidation using the query's key and custom options.
|
|
24
44
|
invalidate: (options) => queryClient.invalidateQueries({
|
|
25
45
|
exact: true,
|
|
26
46
|
queryKey,
|
|
27
47
|
...(options?.refetchType === undefined ? {} : { refetchType: options.refetchType }),
|
|
28
48
|
}, toInvalidateOptions(options)),
|
|
49
|
+
// Provide direct access to the raw observer result when needed.
|
|
29
50
|
unsafe_getResult: () => observer.getCurrentResult(),
|
|
30
51
|
};
|
|
31
52
|
};
|
|
32
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Internal helper to transform a raw Tanstack query result into our public snapshot format.
|
|
56
|
+
*/
|
|
33
57
|
function toQueryServiceSnapshot(result) {
|
|
58
|
+
// Extract and return the relevant fields for the UI or other services.
|
|
34
59
|
return {
|
|
35
60
|
data: result.data,
|
|
36
61
|
error: result.error,
|
|
@@ -42,14 +67,20 @@ function toQueryServiceSnapshot(result) {
|
|
|
42
67
|
isSuccess: result.isSuccess,
|
|
43
68
|
};
|
|
44
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Internal helper to safely transform our QueryInvalidateOptions to Tanstack InvalidateOptions.
|
|
72
|
+
*/
|
|
45
73
|
function toInvalidateOptions(options) {
|
|
74
|
+
// Return undefined if no options were provided.
|
|
46
75
|
if (options === undefined) {
|
|
47
76
|
return undefined;
|
|
48
77
|
}
|
|
78
|
+
// Construct and filter the options object to avoid passing undefined values.
|
|
49
79
|
const invalidateOptions = {
|
|
50
80
|
...(options.cancelRefetch === undefined ? {} : { cancelRefetch: options.cancelRefetch }),
|
|
51
81
|
...(options.throwOnError === undefined ? {} : { throwOnError: options.throwOnError }),
|
|
52
82
|
};
|
|
83
|
+
// Return the resulting object if it contains any relevant properties.
|
|
53
84
|
return Object.keys(invalidateOptions).length > 0 ? invalidateOptions : undefined;
|
|
54
85
|
}
|
|
55
86
|
//# sourceMappingURL=query.js.map
|
package/dist/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { QueryClient } from '@tanstack/query-core';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { setupQueryManager } from '../provider';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
6
|
-
it('exposes
|
|
5
|
+
describe('Query Manager API', () => {
|
|
6
|
+
it('exposes manager-level query client operations', async () => {
|
|
7
7
|
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 0 } } });
|
|
8
8
|
const invalidateQueriesSpy = jest.spyOn(queryClient, 'invalidateQueries');
|
|
9
9
|
const refetchQueriesSpy = jest.spyOn(queryClient, 'refetchQueries');
|
|
10
10
|
const cancelQueriesSpy = jest.spyOn(queryClient, 'cancelQueries');
|
|
11
11
|
const resetQueriesSpy = jest.spyOn(queryClient, 'resetQueries');
|
|
12
12
|
const removeQueriesSpy = jest.spyOn(queryClient, 'removeQueries');
|
|
13
|
-
const
|
|
13
|
+
const manager = setupQueryManager(queryClient);
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
manager.setQueryData<{ id: number }>(['user', 42], { id: 42 });
|
|
16
16
|
|
|
17
|
-
expect(
|
|
18
|
-
expect(
|
|
17
|
+
expect(manager.getQueryData<{ id: number }>(['user', 42])).toEqual({ id: 42 });
|
|
18
|
+
expect(manager.unsafe_getClient()).toBe(queryClient);
|
|
19
19
|
|
|
20
|
-
await
|
|
21
|
-
await
|
|
22
|
-
await
|
|
23
|
-
await
|
|
24
|
-
|
|
20
|
+
await manager.invalidateQueries({ queryKey: ['user'] });
|
|
21
|
+
await manager.refetchQueries({ queryKey: ['user'] });
|
|
22
|
+
await manager.cancelQueries({ queryKey: ['user'] });
|
|
23
|
+
await manager.resetQueries({ queryKey: ['user'] });
|
|
24
|
+
manager.removeQueries({ queryKey: ['user'] });
|
|
25
25
|
|
|
26
26
|
expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['user'] });
|
|
27
27
|
expect(refetchQueriesSpy).toHaveBeenCalledWith({ queryKey: ['user'] });
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Re-export all mutation-related types and functions.
|
|
1
2
|
export * from './mutation';
|
|
3
|
+
// Re-export all query-related types and functions.
|
|
2
4
|
export * from './query';
|
|
5
|
+
// Re-export all provider-related types and functions for cache management.
|
|
3
6
|
export * from './provider';
|
package/src/mutation.ts
CHANGED
|
@@ -1,44 +1,74 @@
|
|
|
1
1
|
import {
|
|
2
|
+
// Import MutationObserver to observe and manage mutations.
|
|
2
3
|
MutationObserver,
|
|
4
|
+
// Import type for the mutation function itself.
|
|
3
5
|
type MutationFunction,
|
|
6
|
+
// Import options for executing a mutation.
|
|
4
7
|
type MutateOptions,
|
|
8
|
+
// Import configuration options for the mutation observer.
|
|
5
9
|
type MutationObserverOptions,
|
|
10
|
+
// Import the shape of the result returned by the mutation observer.
|
|
6
11
|
type MutationObserverResult,
|
|
12
|
+
// Import the status enum for mutations from Tanstack Query.
|
|
7
13
|
type MutationStatus as TanstackMutationStatus,
|
|
14
|
+
// Import the central QueryClient to interact with the cache.
|
|
8
15
|
type QueryClient,
|
|
9
16
|
} from '@tanstack/query-core';
|
|
10
17
|
|
|
18
|
+
// Re-export MutationStatus for consistent naming within the service.
|
|
11
19
|
export type MutationStatus = TanstackMutationStatus;
|
|
12
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Represents a stable snapshot of the mutation service's state.
|
|
23
|
+
*/
|
|
13
24
|
export interface MutationServiceSnapshot<TData = unknown, TError = Error, TVariables = void> {
|
|
25
|
+
// The data returned from a successful mutation.
|
|
14
26
|
data: TData | undefined;
|
|
27
|
+
// The error object if the mutation failed.
|
|
15
28
|
error: TError | null;
|
|
29
|
+
// The current lifecycle status (idle, pending, success, error).
|
|
16
30
|
status: MutationStatus;
|
|
31
|
+
// The variables used for the most recent mutation call.
|
|
17
32
|
variables: TVariables | undefined;
|
|
33
|
+
// Convenience flag: true if the status is 'error'.
|
|
18
34
|
isError: boolean;
|
|
35
|
+
// Convenience flag: true if the status is 'idle'.
|
|
19
36
|
isIdle: boolean;
|
|
37
|
+
// Convenience flag: true if the status is 'pending'.
|
|
20
38
|
isPending: boolean;
|
|
39
|
+
// Convenience flag: true if the status is 'success'.
|
|
21
40
|
isSuccess: boolean;
|
|
22
41
|
}
|
|
23
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Defines the public API for a mutation service.
|
|
45
|
+
*/
|
|
24
46
|
export interface MutationService<
|
|
25
47
|
TData = unknown,
|
|
26
48
|
TError = Error,
|
|
27
49
|
TVariables = void,
|
|
28
50
|
TOnMutateResult = unknown,
|
|
29
51
|
> {
|
|
52
|
+
// Returns the current state snapshot of the mutation.
|
|
30
53
|
getSnapshot: () => MutationServiceSnapshot<TData, TError, TVariables>;
|
|
54
|
+
// Subscribes a listener to state changes; returns an unsubscribe function.
|
|
31
55
|
subscribe: (
|
|
32
56
|
listener: (snapshot: MutationServiceSnapshot<TData, TError, TVariables>) => void
|
|
33
57
|
) => () => void;
|
|
58
|
+
// Triggers the mutation with the given variables and optional lifecycle callbacks.
|
|
34
59
|
mutate: (
|
|
35
60
|
variables: TVariables,
|
|
36
61
|
options?: MutateOptions<TData, TError, TVariables, TOnMutateResult>
|
|
37
62
|
) => Promise<TData>;
|
|
63
|
+
// Resets the mutation state back to its initial idle state.
|
|
38
64
|
reset: () => void;
|
|
65
|
+
// Escape hatch: provides direct access to the underlying Tanstack Query observer result.
|
|
39
66
|
unsafe_getResult: () => MutationObserverResult<TData, TError, TVariables, TOnMutateResult>;
|
|
40
67
|
}
|
|
41
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Configuration options for creating a mutation service, excluding the mutation function itself.
|
|
71
|
+
*/
|
|
42
72
|
export type MutationServiceOptions<
|
|
43
73
|
TData = unknown,
|
|
44
74
|
TError = Error,
|
|
@@ -46,14 +76,23 @@ export type MutationServiceOptions<
|
|
|
46
76
|
TOnMutateResult = unknown,
|
|
47
77
|
> = Omit<MutationObserverOptions<TData, TError, TVariables, TOnMutateResult>, 'mutationFn'>;
|
|
48
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Function signature for the mutation factory.
|
|
81
|
+
*/
|
|
49
82
|
export interface CreateMutation {
|
|
50
83
|
<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown>(
|
|
84
|
+
// The asynchronous function that performs the mutation.
|
|
51
85
|
mutationFn: MutationFunction<TData, TVariables>,
|
|
86
|
+
// Optional configuration for behavior like retry or lifecycle hooks.
|
|
52
87
|
options?: MutationServiceOptions<TData, TError, TVariables, TOnMutateResult>
|
|
53
88
|
): MutationService<TData, TError, TVariables, TOnMutateResult>;
|
|
54
89
|
}
|
|
55
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Prepares the mutation factory by binding it to a specific QueryClient instance.
|
|
93
|
+
*/
|
|
56
94
|
export function setupMutation(queryClient: QueryClient): CreateMutation {
|
|
95
|
+
// Returns the actual factory function for creating individual mutation services.
|
|
57
96
|
return function createMutation<
|
|
58
97
|
TData = unknown,
|
|
59
98
|
TError = Error,
|
|
@@ -63,6 +102,7 @@ export function setupMutation(queryClient: QueryClient): CreateMutation {
|
|
|
63
102
|
mutationFn: MutationFunction<TData, TVariables>,
|
|
64
103
|
options?: MutationServiceOptions<TData, TError, TVariables, TOnMutateResult>
|
|
65
104
|
): MutationService<TData, TError, TVariables, TOnMutateResult> {
|
|
105
|
+
// Create a new MutationObserver instance to manage this specific mutation's lifecycle.
|
|
66
106
|
const observer = new MutationObserver<TData, TError, TVariables, TOnMutateResult>(
|
|
67
107
|
queryClient,
|
|
68
108
|
{
|
|
@@ -71,22 +111,32 @@ export function setupMutation(queryClient: QueryClient): CreateMutation {
|
|
|
71
111
|
}
|
|
72
112
|
);
|
|
73
113
|
|
|
114
|
+
// Return the implementation of the MutationService interface.
|
|
74
115
|
return {
|
|
116
|
+
// Map the current observer state to our service's snapshot format.
|
|
75
117
|
getSnapshot: () => toMutationServiceSnapshot(observer.getCurrentResult()),
|
|
118
|
+
// Subscribe to observer changes and notify the listener with updated snapshots.
|
|
76
119
|
subscribe: (listener) =>
|
|
77
120
|
observer.subscribe((result) => {
|
|
78
121
|
listener(toMutationServiceSnapshot(result));
|
|
79
122
|
}),
|
|
123
|
+
// Proxy the mutate call to the underlying observer.
|
|
80
124
|
mutate: (variables, mutateOptions) => observer.mutate(variables, mutateOptions),
|
|
125
|
+
// Reset the underlying observer state.
|
|
81
126
|
reset: () => observer.reset(),
|
|
127
|
+
// Provide direct access to the raw observer result when needed.
|
|
82
128
|
unsafe_getResult: () => observer.getCurrentResult(),
|
|
83
129
|
};
|
|
84
130
|
};
|
|
85
131
|
}
|
|
86
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Internal helper to transform a raw Tanstack mutation result into our public snapshot format.
|
|
135
|
+
*/
|
|
87
136
|
function toMutationServiceSnapshot<TData, TError, TVariables, TOnMutateResult>(
|
|
88
137
|
result: MutationObserverResult<TData, TError, TVariables, TOnMutateResult>
|
|
89
138
|
): MutationServiceSnapshot<TData, TError, TVariables> {
|
|
139
|
+
// Extract and return the relevant fields for the UI or other services.
|
|
90
140
|
return {
|
|
91
141
|
data: result.data,
|
|
92
142
|
error: result.error,
|
package/src/provider.ts
CHANGED
|
@@ -1,34 +1,63 @@
|
|
|
1
1
|
import {
|
|
2
|
+
// Import the central QueryClient to handle management and state management.
|
|
2
3
|
type QueryClient,
|
|
3
4
|
} from '@tanstack/query-core';
|
|
4
5
|
|
|
6
|
+
// Import mutation and query setup functions and their factory types.
|
|
5
7
|
import { type CreateMutation, setupMutation } from './mutation';
|
|
6
8
|
import { type CreateQuery, setupQuery } from './query';
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Defines the public API for the query manager facade.
|
|
12
|
+
*/
|
|
13
|
+
export interface QueryManager {
|
|
14
|
+
// Factory for creating a mutation service within the context of this provider.
|
|
9
15
|
createMutation: CreateMutation;
|
|
16
|
+
// Factory for creating a query service within the context of this provider.
|
|
10
17
|
createQuery: CreateQuery;
|
|
18
|
+
// Cancels active queries for the specified filters.
|
|
11
19
|
cancelQueries: QueryClient['cancelQueries'];
|
|
20
|
+
// Synchronously retrieves a snapshot of the current query data.
|
|
12
21
|
getQueryData: QueryClient['getQueryData'];
|
|
22
|
+
// Marks queries as invalid to trigger a refetch if they are active.
|
|
13
23
|
invalidateQueries: QueryClient['invalidateQueries'];
|
|
24
|
+
// Forces a refetch of queries matching the specified filters.
|
|
14
25
|
refetchQueries: QueryClient['refetchQueries'];
|
|
26
|
+
// Removes queries from the management without canceling ongoing requests.
|
|
15
27
|
removeQueries: QueryClient['removeQueries'];
|
|
28
|
+
// Resets queries to their initial state and refetches them.
|
|
16
29
|
resetQueries: QueryClient['resetQueries'];
|
|
30
|
+
// Manually sets or updates data for a specific query in the manager.
|
|
17
31
|
setQueryData: QueryClient['setQueryData'];
|
|
32
|
+
// Escape hatch: provides direct access to the underlying Tanstack QueryClient.
|
|
18
33
|
unsafe_getClient: () => QueryClient;
|
|
19
34
|
}
|
|
20
35
|
|
|
21
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Prepares the query manager facade by binding all actions to a specific QueryClient instance.
|
|
38
|
+
*/
|
|
39
|
+
export function setupQueryManager(queryClient: QueryClient): QueryManager {
|
|
40
|
+
// Return the implementation of the QueryManager interface.
|
|
22
41
|
return {
|
|
42
|
+
// Bind mutation factory to this QueryClient.
|
|
23
43
|
createMutation: setupMutation(queryClient),
|
|
44
|
+
// Bind query factory to this QueryClient.
|
|
24
45
|
createQuery: setupQuery(queryClient),
|
|
46
|
+
// Proxy for canceling queries with this client context.
|
|
25
47
|
cancelQueries: queryClient.cancelQueries.bind(queryClient),
|
|
48
|
+
// Proxy for retrieving query data with this client context.
|
|
26
49
|
getQueryData: queryClient.getQueryData.bind(queryClient),
|
|
50
|
+
// Proxy for invalidating queries with this client context.
|
|
27
51
|
invalidateQueries: queryClient.invalidateQueries.bind(queryClient),
|
|
52
|
+
// Proxy for refetching queries with this client context.
|
|
28
53
|
refetchQueries: queryClient.refetchQueries.bind(queryClient),
|
|
54
|
+
// Proxy for removing queries with this client context.
|
|
29
55
|
removeQueries: queryClient.removeQueries.bind(queryClient),
|
|
56
|
+
// Proxy for resetting queries with this client context.
|
|
30
57
|
resetQueries: queryClient.resetQueries.bind(queryClient),
|
|
58
|
+
// Proxy for setting query data with this client context.
|
|
31
59
|
setQueryData: queryClient.setQueryData.bind(queryClient),
|
|
60
|
+
// Provide an accessor for the raw client instance.
|
|
32
61
|
unsafe_getClient: () => queryClient,
|
|
33
62
|
};
|
|
34
63
|
}
|
package/src/query.ts
CHANGED
|
@@ -1,48 +1,88 @@
|
|
|
1
1
|
import {
|
|
2
|
+
// Import the fetch status enum (idle, fetching, paused).
|
|
2
3
|
type FetchStatus,
|
|
4
|
+
// Import options for invalidating queries from the cache.
|
|
3
5
|
type InvalidateOptions,
|
|
6
|
+
// Import filters to target specific queries during invalidation.
|
|
4
7
|
type InvalidateQueryFilters,
|
|
8
|
+
// Import the central QueryClient to interact with the cache.
|
|
5
9
|
type QueryClient,
|
|
10
|
+
// Import the function signature for an individual query.
|
|
6
11
|
type QueryFunction,
|
|
12
|
+
// Import the stable identifier for a specific query in the cache.
|
|
7
13
|
type QueryKey,
|
|
14
|
+
// Import QueryObserver to monitor and manage individual queries.
|
|
8
15
|
QueryObserver,
|
|
16
|
+
// Import configuration options for the query observer.
|
|
9
17
|
type QueryObserverOptions,
|
|
18
|
+
// Import the result shape returned by the query observer.
|
|
10
19
|
type QueryObserverResult,
|
|
20
|
+
// Import options for manually refetching a query.
|
|
11
21
|
type RefetchOptions,
|
|
22
|
+
// Import the status enum for query results (pending, success, error).
|
|
12
23
|
type QueryStatus as TanstackQueryStatus,
|
|
13
24
|
} from '@tanstack/query-core';
|
|
14
25
|
|
|
26
|
+
// Re-export FetchStatus and QueryStatus for internal naming consistency.
|
|
15
27
|
export type QueryFetchStatus = FetchStatus;
|
|
16
28
|
export type QueryStatus = TanstackQueryStatus;
|
|
17
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Represents a stable snapshot of the query service's state.
|
|
32
|
+
*/
|
|
18
33
|
export interface QueryServiceSnapshot<TData, TError> {
|
|
34
|
+
// The data retrieved from a successful query.
|
|
19
35
|
data: TData | undefined;
|
|
36
|
+
// The error object if the query failed.
|
|
20
37
|
error: TError | null;
|
|
38
|
+
// The current network fetch status (idle, fetching, paused).
|
|
21
39
|
fetchStatus: QueryFetchStatus;
|
|
40
|
+
// The current lifecycle status of the query (pending, success, error).
|
|
22
41
|
status: QueryStatus;
|
|
42
|
+
// Convenience flag: true if the status is 'error'.
|
|
23
43
|
isError: boolean;
|
|
44
|
+
// Convenience flag: true if the query is currently fetching data.
|
|
24
45
|
isFetching: boolean;
|
|
46
|
+
// Convenience flag: true if the query is in the pending state.
|
|
25
47
|
isPending: boolean;
|
|
48
|
+
// Convenience flag: true if the status is 'success'.
|
|
26
49
|
isSuccess: boolean;
|
|
27
50
|
}
|
|
28
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Defines a subset of query state containing only the status and fetch status.
|
|
54
|
+
*/
|
|
29
55
|
export interface QueryMetaState {
|
|
30
56
|
fetchStatus: QueryFetchStatus;
|
|
31
57
|
status: QueryStatus;
|
|
32
58
|
}
|
|
33
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Defines the public API for a query service.
|
|
62
|
+
*/
|
|
34
63
|
export interface QueryService<TData, TError> {
|
|
64
|
+
// Returns the current state snapshot of the query.
|
|
35
65
|
getSnapshot: () => QueryServiceSnapshot<TData, TError>;
|
|
66
|
+
// Subscribes a listener to state changes; returns an unsubscribe function.
|
|
36
67
|
subscribe: (listener: (snapshot: QueryServiceSnapshot<TData, TError>) => void) => () => void;
|
|
68
|
+
// Manually triggers a refetch of this query.
|
|
37
69
|
refetch: (options?: RefetchOptions) => Promise<QueryServiceSnapshot<TData, TError>>;
|
|
70
|
+
// Marks this specific query as invalid in the cache to trigger a refetch if active.
|
|
38
71
|
invalidate: (options?: QueryInvalidateOptions) => Promise<void>;
|
|
72
|
+
// Escape hatch: provides direct access to the underlying Tanstack Query observer result.
|
|
39
73
|
unsafe_getResult: () => QueryObserverResult<TData, TError>;
|
|
40
74
|
}
|
|
41
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Combines options for invalidation behavior and filtering.
|
|
78
|
+
*/
|
|
42
79
|
export interface QueryInvalidateOptions
|
|
43
80
|
extends Pick<InvalidateOptions, 'cancelRefetch' | 'throwOnError'>,
|
|
44
81
|
Pick<InvalidateQueryFilters, 'refetchType'> {}
|
|
45
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Function signature for the query factory.
|
|
85
|
+
*/
|
|
46
86
|
export interface CreateQuery {
|
|
47
87
|
<
|
|
48
88
|
TQueryFnData = unknown,
|
|
@@ -51,12 +91,18 @@ export interface CreateQuery {
|
|
|
51
91
|
TQueryData = TQueryFnData,
|
|
52
92
|
TQueryKey extends QueryKey = QueryKey,
|
|
53
93
|
>(
|
|
94
|
+
// The key that uniquely identifies the query in the cache.
|
|
54
95
|
queryKey: TQueryKey,
|
|
96
|
+
// The asynchronous function that performs the data fetch.
|
|
55
97
|
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
|
|
98
|
+
// Optional configuration for behavior like staleness, retry, and refetching.
|
|
56
99
|
options?: QueryServiceOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
|
|
57
100
|
): QueryService<TData, TError>;
|
|
58
101
|
}
|
|
59
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Configuration options for creating a query service, excluding function and key.
|
|
105
|
+
*/
|
|
60
106
|
export type QueryServiceOptions<
|
|
61
107
|
TQueryFnData = unknown,
|
|
62
108
|
TError = Error,
|
|
@@ -68,20 +114,32 @@ export type QueryServiceOptions<
|
|
|
68
114
|
'queryFn' | 'queryKey'
|
|
69
115
|
>;
|
|
70
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Extracts and maps status and fetchStatus to our QueryMetaState interface.
|
|
119
|
+
*/
|
|
71
120
|
export function toQueryMetaState<TData, TError>(
|
|
72
121
|
snapshot: Pick<QueryServiceSnapshot<TData, TError>, 'fetchStatus' | 'status'>
|
|
73
122
|
): QueryMetaState {
|
|
123
|
+
// Return a simplified state object for UI or other services.
|
|
74
124
|
return {
|
|
75
125
|
fetchStatus: snapshot.fetchStatus,
|
|
76
126
|
status: snapshot.status,
|
|
77
127
|
};
|
|
78
128
|
}
|
|
79
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Helper function to check if the query is in its initial loading state.
|
|
132
|
+
*/
|
|
80
133
|
export function isQueryLoading(query: QueryMetaState): boolean {
|
|
134
|
+
// Returns true if the query is both pending and actively fetching.
|
|
81
135
|
return query.status === 'pending' && query.fetchStatus === 'fetching';
|
|
82
136
|
}
|
|
83
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Prepares the query factory by binding it to a specific QueryClient instance.
|
|
140
|
+
*/
|
|
84
141
|
export function setupQuery(queryClient: QueryClient): CreateQuery {
|
|
142
|
+
// Returns the actual factory function for creating individual query services.
|
|
85
143
|
return function createQuery<
|
|
86
144
|
TQueryFnData = unknown,
|
|
87
145
|
TError = Error,
|
|
@@ -93,6 +151,7 @@ export function setupQuery(queryClient: QueryClient): CreateQuery {
|
|
|
93
151
|
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
|
|
94
152
|
options?: QueryServiceOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>
|
|
95
153
|
): QueryService<TData, TError> {
|
|
154
|
+
// Create a new QueryObserver instance to manage this specific query's lifecycle.
|
|
96
155
|
const observer = new QueryObserver<TQueryFnData, TError, TData, TQueryData, TQueryKey>(
|
|
97
156
|
queryClient,
|
|
98
157
|
{
|
|
@@ -102,13 +161,18 @@ export function setupQuery(queryClient: QueryClient): CreateQuery {
|
|
|
102
161
|
}
|
|
103
162
|
);
|
|
104
163
|
|
|
164
|
+
// Return the implementation of the QueryService interface.
|
|
105
165
|
return {
|
|
166
|
+
// Map the current observer state to our service's snapshot format.
|
|
106
167
|
getSnapshot: () => toQueryServiceSnapshot(observer.getCurrentResult()),
|
|
168
|
+
// Subscribe to observer changes and notify the listener with updated snapshots.
|
|
107
169
|
subscribe: (listener) =>
|
|
108
170
|
observer.subscribe((result) => {
|
|
109
171
|
listener(toQueryServiceSnapshot(result));
|
|
110
172
|
}),
|
|
173
|
+
// Proxy the refetch call and map the async result back to a snapshot.
|
|
111
174
|
refetch: async (options) => toQueryServiceSnapshot(await observer.refetch(options)),
|
|
175
|
+
// Trigger a targeted invalidation using the query's key and custom options.
|
|
112
176
|
invalidate: (options) =>
|
|
113
177
|
queryClient.invalidateQueries(
|
|
114
178
|
{
|
|
@@ -118,14 +182,19 @@ export function setupQuery(queryClient: QueryClient): CreateQuery {
|
|
|
118
182
|
},
|
|
119
183
|
toInvalidateOptions(options)
|
|
120
184
|
),
|
|
185
|
+
// Provide direct access to the raw observer result when needed.
|
|
121
186
|
unsafe_getResult: () => observer.getCurrentResult(),
|
|
122
187
|
};
|
|
123
188
|
};
|
|
124
189
|
}
|
|
125
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Internal helper to transform a raw Tanstack query result into our public snapshot format.
|
|
193
|
+
*/
|
|
126
194
|
function toQueryServiceSnapshot<TData, TError>(
|
|
127
195
|
result: QueryObserverResult<TData, TError>
|
|
128
196
|
): QueryServiceSnapshot<TData, TError> {
|
|
197
|
+
// Extract and return the relevant fields for the UI or other services.
|
|
129
198
|
return {
|
|
130
199
|
data: result.data,
|
|
131
200
|
error: result.error,
|
|
@@ -138,15 +207,21 @@ function toQueryServiceSnapshot<TData, TError>(
|
|
|
138
207
|
};
|
|
139
208
|
}
|
|
140
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Internal helper to safely transform our QueryInvalidateOptions to Tanstack InvalidateOptions.
|
|
212
|
+
*/
|
|
141
213
|
function toInvalidateOptions(options?: QueryInvalidateOptions): InvalidateOptions | undefined {
|
|
214
|
+
// Return undefined if no options were provided.
|
|
142
215
|
if (options === undefined) {
|
|
143
216
|
return undefined;
|
|
144
217
|
}
|
|
145
218
|
|
|
219
|
+
// Construct and filter the options object to avoid passing undefined values.
|
|
146
220
|
const invalidateOptions: InvalidateOptions = {
|
|
147
221
|
...(options.cancelRefetch === undefined ? {} : { cancelRefetch: options.cancelRefetch }),
|
|
148
222
|
...(options.throwOnError === undefined ? {} : { throwOnError: options.throwOnError }),
|
|
149
223
|
};
|
|
150
224
|
|
|
225
|
+
// Return the resulting object if it contains any relevant properties.
|
|
151
226
|
return Object.keys(invalidateOptions).length > 0 ? invalidateOptions : undefined;
|
|
152
227
|
}
|