Skip to content

Commit f2e50c2

Browse files
committed
feat: create prefetch functions
1 parent 9017a13 commit f2e50c2

File tree

4 files changed

+284
-7
lines changed

4 files changed

+284
-7
lines changed

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

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ function generateQueryHook(
7676
overrideInputType?: string,
7777
overrideTypeParameters?: string[],
7878
supportInfinite = false,
79-
supportOptimistic = false
79+
supportOptimistic = false,
80+
supportPrefetching = false,
8081
) {
81-
const generateModes: ('' | 'Infinite' | 'Suspense' | 'SuspenseInfinite')[] = [''];
82+
const generateModes: ('' | 'Infinite' | 'Suspense' | 'SuspenseInfinite' | 'Prefetch' | 'PrefetchInfinite')[] = [''];
8283
if (supportInfinite) {
8384
generateModes.push('Infinite');
8485
}
@@ -89,6 +90,22 @@ function generateQueryHook(
8990
if (supportInfinite) {
9091
generateModes.push('SuspenseInfinite');
9192
}
93+
94+
if (supportPrefetching) {
95+
generateModes.push('Prefetch');
96+
97+
if (supportInfinite) {
98+
generateModes.push('PrefetchInfinite');
99+
}
100+
}
101+
}
102+
103+
if (target === 'svelte' && supportPrefetching) {
104+
generateModes.push('Prefetch');
105+
106+
if (supportInfinite) {
107+
generateModes.push('PrefetchInfinite');
108+
}
92109
}
93110

94111
for (const generateMode of generateModes) {
@@ -99,6 +116,9 @@ function generateQueryHook(
99116

100117
const infinite = generateMode.includes('Infinite');
101118
const suspense = generateMode.includes('Suspense');
119+
const prefetch = generateMode.includes('Prefetch');
120+
const prefetchInfinite = generateMode.includes('PrefetchInfinite');
121+
102122
const optimistic =
103123
supportOptimistic &&
104124
// infinite queries are not subject to optimistic updates
@@ -111,6 +131,9 @@ function generateQueryHook(
111131
if (returnArray) {
112132
defaultReturnType = `Array<${defaultReturnType}>`;
113133
}
134+
if (prefetch || prefetchInfinite) {
135+
defaultReturnType = `Promise<void>`;
136+
}
114137

115138
const returnType = overrideReturnType ?? defaultReturnType;
116139
const optionsType = makeQueryOptions(target, 'TQueryFnData', 'TData', infinite, suspense, version);
@@ -370,6 +393,7 @@ function generateModelHooks(
370393
undefined,
371394
undefined,
372395
true,
396+
true,
373397
true
374398
);
375399
}
@@ -388,6 +412,7 @@ function generateModelHooks(
388412
undefined,
389413
undefined,
390414
false,
415+
true,
391416
true
392417
);
393418
}
@@ -406,6 +431,7 @@ function generateModelHooks(
406431
undefined,
407432
undefined,
408433
false,
434+
true,
409435
true
410436
);
411437
}
@@ -601,7 +627,7 @@ function makeGetContext(target: TargetFramework) {
601627
function makeBaseImports(target: TargetFramework, version: TanStackVersion) {
602628
const runtimeImportBase = makeRuntimeImportBase(version);
603629
const shared = [
604-
`import { useModelQuery, useInfiniteModelQuery, useModelMutation } from '${runtimeImportBase}/${target}';`,
630+
`import { useModelQuery, useInfiniteModelQuery, useModelMutation, usePrefetchModelQuery, usePrefetchInfiniteModelQuery } from '${runtimeImportBase}/${target}';`,
605631
`import type { PickEnumerable, CheckSelect, QueryError, ExtraQueryOptions, ExtraMutationOptions } from '${runtimeImportBase}';`,
606632
`import type { PolicyCrudKind } from '${RUNTIME_PACKAGE}'`,
607633
`import metadata from './__model_meta';`,

packages/plugins/tanstack-query/src/runtime-v5/react.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
useQueryClient,
99
useSuspenseInfiniteQuery,
1010
useSuspenseQuery,
11+
usePrefetchQuery,
12+
usePrefetchInfiniteQuery,
1113
type InfiniteData,
1214
type UseInfiniteQueryOptions,
1315
type UseMutationOptions,
@@ -78,6 +80,34 @@ export function useModelQuery<TQueryFnData, TData, TError>(
7880
});
7981
}
8082

83+
/**
84+
* Creates a react-query prefetch query.
85+
*
86+
* @param model The name of the model under query.
87+
* @param url The request URL.
88+
* @param args The request args object, URL-encoded and appended as "?q=" parameter
89+
* @param options The react-query options object
90+
* @param fetch The fetch function to use for sending the HTTP request
91+
* @returns usePrefetchQuery hook
92+
*/
93+
export function usePrefetchModelQuery<TQueryFnData, TData, TError>(
94+
model: string,
95+
url: string,
96+
args?: unknown,
97+
options?: Omit<UseQueryOptions<TQueryFnData, TError, TData>, 'queryKey'> & ExtraQueryOptions,
98+
fetch?: FetchFn
99+
) {
100+
const reqUrl = makeUrl(url, args);
101+
return usePrefetchQuery({
102+
queryKey: getQueryKey(model, url, args, {
103+
infinite: false,
104+
optimisticUpdate: options?.optimisticUpdate !== false,
105+
}),
106+
queryFn: () => fetcher<TQueryFnData, false>(reqUrl, undefined, fetch, false),
107+
...options,
108+
});
109+
}
110+
81111
/**
82112
* Creates a react-query suspense query.
83113
*
@@ -133,6 +163,33 @@ export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
133163
});
134164
}
135165

166+
/**
167+
* Creates a react-query prefetch infinite query.
168+
*
169+
* @param model The name of the model under query.
170+
* @param url The request URL.
171+
* @param args The initial request args object, URL-encoded and appended as "?q=" parameter
172+
* @param options The react-query infinite query options object
173+
* @param fetch The fetch function to use for sending the HTTP request
174+
* @returns usePrefetchInfiniteQuery hook
175+
*/
176+
export function usePrefetchInfiniteModelQuery<TQueryFnData, TData, TError>(
177+
model: string,
178+
url: string,
179+
args: unknown,
180+
options: Omit<UseInfiniteQueryOptions<TQueryFnData, TError, InfiniteData<TData>>, 'queryKey' | 'initialPageParam'>,
181+
fetch?: FetchFn
182+
) {
183+
return usePrefetchInfiniteQuery({
184+
queryKey: getQueryKey(model, url, args, { infinite: true, optimisticUpdate: false }),
185+
queryFn: ({ pageParam }) => {
186+
return fetcher<TQueryFnData, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);
187+
},
188+
initialPageParam: args,
189+
...options,
190+
});
191+
}
192+
136193
/**
137194
* Creates a react-query infinite suspense query.
138195
*

packages/plugins/tanstack-query/src/runtime-v5/svelte.ts

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function getHooksContext() {
5757
* @param args The request args object, URL-encoded and appended as "?q=" parameter
5858
* @param options The svelte-query options object
5959
* @param fetch The fetch function to use for sending the HTTP request
60-
* @returns useQuery hook
60+
* @returns createQuery hook
6161
*/
6262
export function useModelQuery<TQueryFnData, TData, TError>(
6363
model: string,
@@ -94,14 +94,65 @@ export function useModelQuery<TQueryFnData, TData, TError>(
9494
return createQuery<TQueryFnData, TError, TData>(mergedOpt);
9595
}
9696

97+
/**
98+
* Creates a svelte-query prefetch query.
99+
*
100+
* @param model The name of the model under query.
101+
* @param url The request URL.
102+
* @param args The request args object, URL-encoded and appended as "?q=" parameter
103+
* @param options The svelte-query options object
104+
* @param fetch The fetch function to use for sending the HTTP request
105+
* @returns createPrefetchQuery hook
106+
*/
107+
export function usePrefetchModelQuery<TQueryFnData, TData, TError>(
108+
model: string,
109+
url: string,
110+
args?: unknown,
111+
options?: StoreOrVal<Omit<CreateQueryOptions<TQueryFnData, TError, TData>, 'queryKey'>> & ExtraQueryOptions,
112+
fetch?: FetchFn
113+
) {
114+
const reqUrl = makeUrl(url, args);
115+
const queryKey = getQueryKey(model, url, args, {
116+
infinite: false,
117+
optimisticUpdate: options?.optimisticUpdate !== false,
118+
});
119+
const queryFn = () => fetcher<TQueryFnData, false>(reqUrl, undefined, fetch, false);
120+
121+
let mergedOpt: any;
122+
if (isStore(options)) {
123+
// options is store
124+
mergedOpt = derived([options], ([$opt]) => {
125+
return {
126+
queryKey,
127+
queryFn,
128+
...($opt as object),
129+
};
130+
});
131+
} else {
132+
// options is value
133+
mergedOpt = {
134+
queryKey,
135+
queryFn,
136+
...options,
137+
};
138+
}
139+
140+
// Todo : When createPrefetchQuery is available in svelte-query, use it
141+
const queryClient = useQueryClient();
142+
143+
return queryClient.prefetchQuery(mergedOpt);
144+
// return createPrefetchQuery<TQueryFnData, TError, TData>(mergedOpt);
145+
}
146+
97147
/**
98148
* Creates a svelte-query infinite query.
99149
*
100150
* @param model The name of the model under query.
101151
* @param url The request URL.
102152
* @param args The initial request args object, URL-encoded and appended as "?q=" parameter
103153
* @param options The svelte-query infinite query options object
104-
* @returns useQuery hook
154+
* @param fetch The fetch function to use for sending the HTTP request
155+
* @returns createInfiniteQuery hook
105156
*/
106157
export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
107158
model: string,
@@ -143,6 +194,61 @@ export function useInfiniteModelQuery<TQueryFnData, TData, TError>(
143194
return createInfiniteQuery<TQueryFnData, TError, InfiniteData<TData>>(mergedOpt);
144195
}
145196

197+
/**
198+
* Creates a svelte-query prefetch infinite query.
199+
*
200+
* @param model The name of the model under query.
201+
* @param url The request URL.
202+
* @param args The initial request args object, URL-encoded and appended as "?q=" parameter
203+
* @param options The svelte-query infinite query options object
204+
* @param fetch The fetch function to use for sending the HTTP request
205+
* @returns createPrefetchInfiniteQuery hook
206+
*/
207+
export function usePrefetchInfiniteModelQuery<TQueryFnData, TData, TError>(
208+
model: string,
209+
url: string,
210+
args: unknown,
211+
options: StoreOrVal<
212+
Omit<CreateInfiniteQueryOptions<TQueryFnData, TError, InfiniteData<TData>>, 'queryKey' | 'initialPageParam'>
213+
>,
214+
fetch?: FetchFn
215+
) {
216+
const queryKey = getQueryKey(model, url, args, { infinite: true, optimisticUpdate: false });
217+
const queryFn = ({ pageParam }: { pageParam: unknown }) =>
218+
fetcher<TQueryFnData, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false);
219+
220+
let mergedOpt: StoreOrVal<any>;
221+
if (
222+
isStore<
223+
Omit<CreateInfiniteQueryOptions<TQueryFnData, TError, InfiniteData<TData>>, 'queryKey' | 'initialPageParam'>
224+
>(options)
225+
) {
226+
// options is store
227+
mergedOpt = derived([options], ([$opt]) => {
228+
return {
229+
queryKey,
230+
queryFn,
231+
initialPageParam: args,
232+
...$opt,
233+
};
234+
});
235+
} else {
236+
// options is value
237+
mergedOpt = {
238+
queryKey,
239+
queryFn,
240+
initialPageParam: args,
241+
...options,
242+
};
243+
}
244+
245+
// Todo : When createPrefetchInfiniteQuery is available in svelte-query, use it
246+
const queryClient = useQueryClient();
247+
248+
return queryClient.prefetchInfiniteQuery(mergedOpt);
249+
// return createPrefetchInfiniteQuery<TQueryFnData, TError, InfiniteData<TData>>(mergedOpt);
250+
}
251+
146252
function isStore<T>(opt: unknown): opt is Readable<T> {
147253
return typeof (opt as any)?.subscribe === 'function';
148254
}
@@ -155,7 +261,9 @@ function isStore<T>(opt: unknown): opt is Readable<T> {
155261
* @param modelMeta The model metadata.
156262
* @param url The request URL.
157263
* @param options The svelte-query options.
158-
* @returns useMutation hooks
264+
* @param fetch The fetch function to use for sending the HTTP request
265+
* @param checkReadBack Whether to check for read back errors and return undefined if found.
266+
* @returns createMutation hook
159267
*/
160268
export function useModelMutation<
161269
TArgs,

0 commit comments

Comments
 (0)