Skip to content

Commit 2c006ff

Browse files
committed
add tag operations to query client
1 parent 3fb5e68 commit 2c006ff

File tree

8 files changed

+67
-65
lines changed

8 files changed

+67
-65
lines changed

examples/vite/src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import './mocks';
22
import { useRef, useState } from 'react';
33
import { CommentData, PostData, baseUrl } from './mocks';
44
import './App.css';
5-
import { HttpQueryBuilder, useOperateOnTags } from 'react-query-builder';
5+
import { HttpQueryBuilder } from 'react-query-builder';
66
import { queryClient } from './client';
77

88
const baseQuery = new HttpQueryBuilder({
@@ -92,13 +92,13 @@ function App() {
9292

9393
const deleteErrors = deletePostMutation.useMutationState(undefined, { status: 'error' }, (x) => x.state.variables?.params.id);
9494

95-
const [refresh] = useOperateOnTags({ tags: 'refreshable' });
95+
const refresh = () => baseQuery.client.operateTags({ tags: 'refreshable', operation: 'reset' });
9696

9797
if (postId) return <PostPage postId={postId} onBack={() => setPostId(null)} />;
9898

9999
return (
100100
<>
101-
<button onClick={() => refresh()} disabled={posts.isFetching}>
101+
<button onClick={refresh} disabled={posts.isFetching}>
102102
Refresh
103103
</button>
104104

src/builder/QueryBuilder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class QueryBuilder<TVars, TData, TError, TKey extends unknown[], TTags ex
8989
return this as any;
9090
}
9191

92-
freeze(): QueryBuilderFrozen<TVars, TData, TError, TKey> {
92+
freeze(): QueryBuilderFrozen<TVars, TData, TError, TKey, TTags> {
9393
return this;
9494
}
9595

src/builder/QueryBuilderClient.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
import type { CancelOptions, InvalidateOptions, QueryFilters, RefetchOptions, ResetOptions, SetDataOptions } from '@tanstack/react-query';
2+
import { operateOnTags } from '../tags/operateOnTags';
3+
import { QueryTagContext, QueryUpdateTag, TagOperationOptions } from '../tags/types';
4+
import { updateTags } from '../tags/updateTags';
5+
import { WithOptional } from '../type-utils';
26
import { QueryBuilderConfig, QueryBuilderFrozen } from './QueryBuilderFrozen';
37

4-
export class QueryBuilderClient<TVars, TData, TError, TKey extends unknown[], TFilters = QueryFilters<TData, TError, TData, TKey>> {
8+
export class QueryBuilderClient<
9+
TVars,
10+
TData,
11+
TError,
12+
TKey extends unknown[],
13+
TTags extends Record<string, unknown>,
14+
TFilters = QueryFilters<TData, TError, TData, TKey>,
15+
> {
516
private declare _options: QueryBuilderConfig<TVars, TData, TError, TKey>['options'];
6-
constructor(private builder: QueryBuilderFrozen<TVars, TData, TError, TKey>) {}
17+
constructor(private builder: QueryBuilderFrozen<TVars, TData, TError, TKey, TTags>) {}
718

819
readonly ensureData = (vars: TVars, opts?: typeof this._options) =>
920
this.builder.config.queryClient?.ensureQueryData(this.builder.getQueryOptions(vars, opts));
@@ -47,6 +58,22 @@ export class QueryBuilderClient<TVars, TData, TError, TKey extends unknown[], TF
4758
this.builder.config.queryClient?.setQueryData<TData>(this.builder.getQueryKey(vars), updater, opts);
4859

4960
readonly getState = (vars: TVars) => this.builder.config.queryClient?.getQueryState<TData, TError>(this.builder.getQueryKey(vars));
61+
62+
readonly operateTags = ({ tags = [], operation = 'invalidate', filters, options }: TagOperationOptions<TTags>) =>
63+
operateOnTags({ queryClient: this.builder.config.queryClient!, tags, operation }, filters, options);
64+
65+
/**
66+
* This function can be used to operate on queries based on tags.
67+
*/
68+
readonly updateTags = ({
69+
tags = [],
70+
ctx: { client = this.builder.config.queryClient, ...ctx },
71+
optimistic = false,
72+
}: {
73+
tags: readonly QueryUpdateTag<TVars, TData, TError, TTags>[];
74+
ctx: WithOptional<QueryTagContext<TVars, TData, TError>, 'client'>;
75+
optimistic?: boolean;
76+
}) => updateTags({ tags, queryClient: client!, ctx: { client: client!, ...ctx }, optimistic });
5077
}
5178

5279
type SetDataUpdater<T> = T | undefined | ((oldData: T | undefined) => T | undefined);

src/builder/QueryBuilderFrozen.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
DataTag,
33
InfiniteData,
44
InfiniteQueryPageParamsOptions,
5+
MutationFunction,
56
QueryFilters,
67
QueryFunction,
78
UseInfiniteQueryOptions,
@@ -10,14 +11,18 @@ import {
1011
UseSuspenseInfiniteQueryResult,
1112
useInfiniteQuery,
1213
useIsFetching,
14+
useMutation,
1315
usePrefetchInfiniteQuery,
1416
usePrefetchQuery,
1517
useQueries,
1618
useQuery,
19+
useQueryClient,
1720
useSuspenseInfiniteQuery,
1821
useSuspenseQueries,
1922
useSuspenseQuery,
2023
} from '@tanstack/react-query';
24+
import { operateOnTags } from '../tags/operateOnTags';
25+
import { TagOperationOptions } from '../tags/types';
2126
import { FunctionType, TODO } from '../type-utils';
2227
import { QueryBuilderClient } from './QueryBuilderClient';
2328
import { BuilderConfig, BuilderQueriesResult } from './types';
@@ -174,7 +179,24 @@ export class QueryBuilderFrozen<
174179
return useSuspenseInfiniteQuery(this.getInfiniteQueryOptions(vars, opts), this.config.queryClient);
175180
};
176181

177-
private _client?: QueryBuilderClient<TVars, TData, TError, TKey>;
182+
/**
183+
* This hook returns a function that can be used to operate on queries based on tags.
184+
* It also returns the mutation object that can be used to track the state of the operation.
185+
* See `operateOnTags` for more information.
186+
*/
187+
useTagOperation(opts?: TagOperationOptions<TTags> | void) {
188+
const queryClient = useQueryClient();
189+
const mutationFn: MutationFunction<unknown, TagOperationOptions<TTags> | void> = (
190+
{ tags = [], operation = 'invalidate', filters, options } = opts || {},
191+
) => operateOnTags({ queryClient, tags, operation }, filters, options);
192+
193+
const mutation = useMutation({ mutationFn });
194+
const operate = mutation.mutateAsync;
195+
196+
return [operate, mutation] as const;
197+
}
198+
199+
private _client?: QueryBuilderClient<TVars, TData, TError, TKey, TTags>;
178200
get client() {
179201
return (this._client ??= new QueryBuilderClient(this));
180202
}

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ export * from './builder/MutationBuilder';
44
export * from './builder/HttpMutationBuilder';
55
export type { MiddlewareFn, MiddlewareContext, MiddlewareNextFn } from './builder/createMiddlewareFunction';
66
export * from './http/request';
7-
export * from './tags/useOperateOnTags';

src/tags/types.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import type { QueryClient } from '@tanstack/react-query';
1+
import type { InvalidateOptions, InvalidateQueryFilters, QueryClient } from '@tanstack/react-query';
22
import { KeysOfValue, StringLiteral } from '../type-utils';
3+
import { OperateOnTagsOperation } from './operateOnTags';
34

45
export type TagMap = Record<string, unknown>;
56

@@ -23,7 +24,7 @@ export type QueryTagCallback<TVars = void, TData = unknown, TErr = unknown, TTag
2324
ctx: QueryTagContext<TVars, TData, TErr>,
2425
) => TTag | readonly TTag[];
2526

26-
export type QueryTagStaticOption<TTag extends QueryTagObject = QueryTagObject> = '*' | QueryTag<TTag> | readonly QueryTag<TTag>[];
27+
export type QueryTagStaticOption<TTag extends QueryTagObject<any> = QueryTagObject<any>> = '*' | QueryTag<TTag> | readonly QueryTag<TTag>[];
2728

2829
export type QueryTagOption<TVars = unknown, TData = unknown, TErr = unknown, TTag extends QueryTagObject<any> = QueryTagObject<any>> =
2930
| QueryTagStaticOption<TTag>
@@ -81,3 +82,10 @@ export type QueryUpdateTag<TVars = unknown, TData = unknown, TErr = unknown, TMa
8182
>;
8283

8384
export type QueryTagCache = Record<string | number, Record<string, QueryTagObject[]>>;
85+
86+
export type TagOperationOptions<TMap extends TagMap = TagMap> = {
87+
tags?: QueryTagStaticOption<QueryTagObject<TMap>>;
88+
operation?: OperateOnTagsOperation;
89+
filters?: InvalidateQueryFilters;
90+
options?: InvalidateOptions;
91+
};

src/tags/updateTags.ts

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { type InfiniteData, InfiniteQueryObserver, type QueryClient, type QueryState, useQueryClient } from '@tanstack/react-query';
2-
import { useStableCallback } from '../hooks/useStableCallback';
3-
import type { WithOptional } from '../type-utils';
1+
import { type InfiniteData, InfiniteQueryObserver, type QueryClient, type QueryState } from '@tanstack/react-query';
42
import { queryMatchesTag } from './operateOnTags';
53
import type { QueryTagContext, QueryUpdateTag } from './types';
64
import { getUpdater } from './updaters';
@@ -93,28 +91,3 @@ function setDataToExistingQuery(
9391
query?.setData(newData);
9492
if (state || meta) query?.setState(state || {}, { meta });
9593
}
96-
97-
/**
98-
* This hook returns a function that can be used to operate on queries based on tags.
99-
* It also returns the mutation object that can be used to track the state of the operation.
100-
* See `operateOnTags` for more information.
101-
*/
102-
export function useUpdateTags(base?: {
103-
tags?: readonly QueryUpdateTag<any, any, any, any>[];
104-
ctx?: QueryTagContext<unknown>;
105-
optimistic?: boolean;
106-
}) {
107-
const queryClient = useQueryClient();
108-
const update = useStableCallback(
109-
({
110-
tags = base?.tags || [],
111-
ctx = base?.ctx || { client: queryClient, vars: undefined, data: undefined },
112-
optimistic = base?.optimistic,
113-
}: {
114-
tags: readonly QueryUpdateTag<any, any, any, any>[];
115-
ctx: WithOptional<QueryTagContext<unknown>, 'client'>;
116-
optimistic?: boolean;
117-
}) => updateTags({ tags, queryClient, ctx: { client: queryClient, ...ctx }, optimistic }),
118-
);
119-
return update;
120-
}

src/tags/useOperateOnTags.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)