Skip to content

Commit f259d73

Browse files
authored
fix(tanstack): make sure vue-query hooks' input is reactive (#1185)
1 parent 10b492b commit f259d73

File tree

3 files changed

+59
-81
lines changed

3 files changed

+59
-81
lines changed

packages/plugins/tanstack-query/src/generator.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ function generateQueryHook(
9898
const capOperation = upperCaseFirst(operation);
9999

100100
const argsType = overrideInputType ?? `Prisma.${model}${capOperation}Args`;
101-
const inputType = `Prisma.SelectSubset<TArgs, ${argsType}>`;
101+
const inputType = makeQueryArgsType(target, argsType);
102102

103103
const infinite = generateMode.includes('Infinite');
104104
const suspense = generateMode.includes('Suspense');
@@ -589,6 +589,7 @@ function makeBaseImports(target: TargetFramework, version: TanStackVersion) {
589589
return [
590590
`import type { UseMutationOptions, UseQueryOptions, UseInfiniteQueryOptions, InfiniteData } from '@tanstack/vue-query';`,
591591
`import { getHooksContext } from '${runtimeImportBase}/${target}';`,
592+
`import type { MaybeRefOrGetter, ComputedRef } from 'vue';`,
592593
...shared,
593594
];
594595
}
@@ -608,6 +609,15 @@ function makeBaseImports(target: TargetFramework, version: TanStackVersion) {
608609
}
609610
}
610611

612+
function makeQueryArgsType(target: string, argsType: string) {
613+
const type = `Prisma.SelectSubset<TArgs, ${argsType}>`;
614+
if (target === 'vue') {
615+
return `MaybeRefOrGetter<${type}> | ComputedRef<${type}>`;
616+
} else {
617+
return type;
618+
}
619+
}
620+
611621
function makeQueryOptions(
612622
target: string,
613623
returnType: string,
@@ -625,8 +635,12 @@ function makeQueryOptions(
625635
suspense ? 'Suspense' : ''
626636
}InfiniteQueryOptions<${returnType}, TError, InfiniteData<${dataType}>>, 'queryKey'>`
627637
: `Omit<Use${suspense ? 'Suspense' : ''}QueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`;
628-
case 'vue':
629-
return `Omit<Use${infinite ? 'Infinite' : ''}QueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`;
638+
case 'vue': {
639+
const baseOption = `Omit<Use${
640+
infinite ? 'Infinite' : ''
641+
}QueryOptions<${returnType}, TError, ${dataType}>, 'queryKey'>`;
642+
return `MaybeRefOrGetter<${baseOption}> | ComputedRef<${baseOption}>`;
643+
}
630644
case 'svelte':
631645
return infinite
632646
? version === 'v4'
@@ -644,8 +658,10 @@ function makeMutationOptions(target: string, returnType: string, argsType: strin
644658
switch (target) {
645659
case 'react':
646660
return `UseMutationOptions<${returnType}, DefaultError, ${argsType}>`;
647-
case 'vue':
648-
return `UseMutationOptions<${returnType}, DefaultError, ${argsType}, unknown>`;
661+
case 'vue': {
662+
const baseOption = `UseMutationOptions<${returnType}, DefaultError, ${argsType}, unknown>`;
663+
return `MaybeRefOrGetter<${baseOption}> | ComputedRef<${baseOption}>`;
664+
}
649665
case 'svelte':
650666
return `MutationOptions<${returnType}, DefaultError, ${argsType}>`;
651667
default:

packages/plugins/tanstack-query/src/runtime/vue.ts

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import {
55
useMutation,
66
useQuery,
77
useQueryClient,
8+
type QueryKey,
89
type UseInfiniteQueryOptions,
910
type UseMutationOptions,
1011
type UseQueryOptions,
1112
} from '@tanstack/vue-query';
1213
import type { ModelMeta } from '@zenstackhq/runtime/cross';
13-
import { inject, provide } from 'vue';
14+
import { computed, inject, provide, toValue, type ComputedRef, type MaybeRefOrGetter } from 'vue';
1415
import {
1516
APIContext,
1617
DEFAULT_QUERY_ENDPOINT,
@@ -60,17 +61,25 @@ export function getHooksContext() {
6061
export function useModelQuery<TQueryFnData, TData, TError>(
6162
model: string,
6263
url: string,
63-
args?: unknown,
64-
options?: Omit<UseQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>,
64+
args?: MaybeRefOrGetter<unknown> | ComputedRef<unknown>,
65+
options?:
66+
| MaybeRefOrGetter<Omit<UseQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>>
67+
| ComputedRef<Omit<UseQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>>,
6568
fetch?: FetchFn,
6669
optimisticUpdate = false
6770
) {
68-
const reqUrl = makeUrl(url, args);
69-
return useQuery<TQueryFnData, TError, TData>({
70-
queryKey: getQueryKey(model, url, args, false, optimisticUpdate),
71-
queryFn: () => fetcher<TQueryFnData, false>(reqUrl, undefined, fetch, false),
72-
...options,
71+
const queryOptions = computed(() => {
72+
return {
73+
queryKey: getQueryKey(model, url, toValue(args), false, optimisticUpdate),
74+
queryFn: ({ queryKey }: { queryKey: QueryKey }) => {
75+
const [_prefix, _model, _op, args] = queryKey;
76+
const reqUrl = makeUrl(url, toValue(args));
77+
return fetcher<TQueryFnData, false>(reqUrl, undefined, fetch, false);
78+
},
79+
...toValue(options),
80+
};
7381
});
82+
return useQuery<TQueryFnData, TError, TData>(queryOptions);
7483
}
7584

7685
/**
@@ -86,17 +95,24 @@ export function useModelQuery<TQueryFnData, TData, TError>(
8695
export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
8796
model: string,
8897
url: string,
89-
args?: unknown,
90-
options?: Omit<UseInfiniteQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>,
98+
args?: MaybeRefOrGetter<unknown> | ComputedRef<unknown>,
99+
options?:
100+
| MaybeRefOrGetter<Omit<UseInfiniteQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>>
101+
| ComputedRef<Omit<UseInfiniteQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>>,
91102
fetch?: FetchFn
92103
) {
93-
return useInfiniteQuery<TQueryFnData, TError, TData>({
94-
queryKey: getQueryKey(model, url, args, true),
95-
queryFn: ({ pageParam }) => {
96-
return fetcher<TQueryFnData, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);
104+
// CHECKME: vue-query's `useInfiniteQuery`'s input typing seems wrong
105+
const queryOptions: any = computed(() => ({
106+
queryKey: getQueryKey(model, url, toValue(args), true),
107+
queryFn: ({ queryKey, pageParam }: { queryKey: QueryKey; pageParam?: unknown }) => {
108+
const [_prefix, _model, _op, args] = queryKey;
109+
const reqUrl = makeUrl(url, pageParam ?? toValue(args));
110+
return fetcher<TQueryFnData, false>(reqUrl, undefined, fetch, false);
97111
},
98-
...options,
99-
});
112+
...toValue(options),
113+
}));
114+
115+
return useInfiniteQuery<TQueryFnData, TError, TData>(queryOptions);
100116
}
101117

102118
/**
@@ -124,7 +140,9 @@ export function useModelMutation<
124140
method: 'POST' | 'PUT' | 'DELETE',
125141
url: string,
126142
modelMeta: ModelMeta,
127-
options?: Omit<UseMutationOptions<Result, TError, TArgs, unknown>, 'mutationFn'>,
143+
options?:
144+
| MaybeRefOrGetter<Omit<UseMutationOptions<Result, TError, TArgs, unknown>, 'mutationFn'>>
145+
| ComputedRef<Omit<UseMutationOptions<Result, TError, TArgs, unknown>, 'mutationFn'>>,
128146
fetch?: FetchFn,
129147
invalidateQueries = true,
130148
checkReadBack?: C,
@@ -146,7 +164,7 @@ export function useModelMutation<
146164
};
147165

148166
// TODO: figure out the typing problem
149-
const finalOptions: any = { ...options, mutationFn };
167+
const finalOptions: any = computed(() => ({ ...toValue(options), mutationFn }));
150168
const operation = url.split('/').pop();
151169
if (operation) {
152170
const { logging } = getHooksContext();
@@ -155,7 +173,7 @@ export function useModelMutation<
155173
model,
156174
operation,
157175
modelMeta,
158-
finalOptions,
176+
toValue(finalOptions),
159177
(predicate) => queryClient.invalidateQueries({ predicate }),
160178
logging
161179
);
@@ -166,7 +184,7 @@ export function useModelMutation<
166184
model,
167185
operation,
168186
modelMeta,
169-
finalOptions,
187+
toValue(finalOptions),
170188
queryClient.getQueryCache().getAll(),
171189
(queryKey, data) => queryClient.setQueryData<unknown>(queryKey, data),
172190
invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : undefined,

tests/integration/tests/regression/issue-1162.test.ts

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

0 commit comments

Comments
 (0)