feat: add skipToken support and queryOptions override to TanStack Query useQuery hooks#3528
feat: add skipToken support and queryOptions override to TanStack Query useQuery hooks#3528nmokkenstorm wants to merge 2 commits intohey-api:mainfrom
Conversation
|
|
|
@nmokkenstorm is attempting to deploy a commit to the Hey API Team on Vercel. A member of the Team first needs to authorize it. |
|
6d07fd5 to
cf8e859
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3528 +/- ##
==========================================
+ Coverage 40.24% 40.39% +0.14%
==========================================
Files 520 521 +1
Lines 19302 19337 +35
Branches 5726 5727 +1
==========================================
+ Hits 7769 7811 +42
+ Misses 9337 9332 -5
+ Partials 2196 2194 -2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@hey-api/codegen-core
@hey-api/json-schema-ref-parser
@hey-api/nuxt
@hey-api/openapi-ts
@hey-api/shared
@hey-api/spec-types
@hey-api/types
@hey-api/vite-plugin
commit: |
|
@nmokkenstorm Why is it an optional configuration flag? Why not add it for everyone? |
|
@nandorojo will like this |
|
@nmokkenstorm I updated your description with linked issue |
habit to make it opt-in tbh. I think the skipToken is a breaking change too on type level and it also slightly increases the generated bundle size but I will check. |
|
@nmokkenstorm I didn't look at the code yet, stopped after seeing the configuration haha. If it's going to be breaking either way, I'd much rather deprecate the old approach because we wouldn't want new users to start with the flag disabled, realize one day they need to enable it, and face a lot of breaking changes. We can talk through it when you feel the pull request is more ready. I'm pretty sure there was another thread where we talked about skip tokens but can't find it, I'd like to ideally avoid another breaking change when that thread gets addressed |
I'll double check, I think it's definately doable to have it be backwards compatible without a breaking change. The useQuery/Mutation stuff was opt in so I stuck to the pattern but I think this can be done without losing ergonomics. I'll update the pr description and ping you if it's reviewable, I needed a remote public ref to do some internal testing with first anyways. Thanks for the feedback! |
7df42fb to
3007b3c
Compare
|
@nmokkenstorm Can you clarify what do you mean by "add useQuery hooks" in the title? React/Preact Query already support generating useQuery hooks so I'm confused what it's referencing |
its about having the generated useQuery hooks exist per entity, with queryoptions and skiptoken enabled. the reason it's named like that is because the original code/branch orginates from a fork that pre-dates the support we had in our project. still tinkering on this, nothing to see/review here yet! |
|
Just making sure we're aligned on the scope! I shall retreat once more |
d6ebc7c to
b1fc4b9
Compare
b1fc4b9 to
2ffe100
Compare
d8bbba0 to
5eb6a92
Compare
|
@mrlubos I think it does what it needs to do now, below a redacted diff of how we're currently using it in the fork. I ran into an issue where the auto paginated version of useQuery has ts-ignore inserted and I needed it somewhere else to stay compliant, so I added support for a new case to the DSL for that. Probably worthwhile to check a) if that's correct and b) if maybe we can improve the related code to no longer need the ts-ignore, but that seemed a bit out of scope for this PR. lmk what you think? I'll see if I can get the merge checks to behave a bit more but I'm not sure what I actually can and can not influence there, you mentioned they are a bit flaky before. Before (query)import { getSomeResourceOptions } from '@org/api';
import { useQuery } from '@tanstack/react-query';
const { data, isLoading } = useQuery({
...getSomeResourceOptions({ path: { id: id ?? '' } }),
enabled: !!id,
});After (query)import { useGetSomeResource } from '@org/api';
import { skipToken } from '@tanstack/react-query';
const { data, isLoading } = useGetSomeResource(
id ? { path: { id } } : skipToken
);Before (query with extra options)import { getStatusOptions } from '@org/api';
import { useQuery } from '@tanstack/react-query';
const { data, isLoading } = useQuery({
...getStatusOptions(),
enabled: shouldPoll,
refetchInterval: shouldPoll ? 5000 : false,
});After (query with extra options)import { useGetStatus } from '@org/api';
const { data, isLoading } = useGetStatus({
queryOptions: {
enabled: shouldPoll,
refetchInterval: shouldPoll ? 5000 : false,
},
});Before (mutation)import { updateResourceMutation, getResourceQueryKey } from '@org/api';
import { useMutation, useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
const { mutate, isPending } = useMutation({
...updateResourceMutation(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: getResourceQueryKey() });
},
});After (mutation)import { useUpdateResource, getResourceQueryKey } from '@org/api';
import { useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
const { mutate, isPending } = useUpdateResource({
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: getResourceQueryKey() });
},
}); |
|
Reviewed PR #3528. The Task list (5/5 completed)
|
5eb6a92 to
5132bc5
Compare
|
TL;DR — Adds Key changes
Summary | 147 files | 1 commit | base:
|
|
TL;DR — Adds Key changes
Summary | 153 files | 2 commits | base:
|
There was a problem hiding this comment.
Important
Changing useQuery default from false to true is a breaking change that should be called out more explicitly.
The implementation is solid — skipToken support is cleanly wired through a shared unwrapSkipToken utility, the useQuery hooks handle both skipToken early-return and queryOptions override merging correctly, and the intersection type (Options<T> | typeof skipToken) & { queryOptions?: ... } is valid since queryOptions is optional. The @ts-ignore placement refactor on infiniteQueryOptions (moving from object literal to call expression via HintMixin) is a nice structural improvement.
Three things to address before merge:
| @@ -85,7 +85,7 @@ export const defaultConfig: TanStackReactQueryPlugin['Config'] = { | |||
| plugin.config.useQuery = context.valueToObject({ | |||
| defaultValue: { | |||
| case: plugin.config.case ?? 'camelCase', | |||
| enabled: false, | |||
| enabled: true, | |||
There was a problem hiding this comment.
Changing this default from false to true means existing users who run codegen will suddenly get new useQuery hook exports, new skipToken + useQuery imports, and a new unwrapSkipToken utility in their generated output — without changing their config. The PR description says "None" under breaking changes, but this is a behavioral change that affects all @tanstack/react-query users who haven't explicitly set useQuery.
Consider keeping the default as false and letting users opt in, or at minimum flagging this as a breaking change that requires a changeset with a major/minor bump and migration note.
There was a problem hiding this comment.
@mrlubos I think this matches exactly our conversation re: not opting in, but maybe you see that differently
There was a problem hiding this comment.
Makes sense — if that's the agreed-upon direction with @mrlubos, I'd just suggest updating the PR description's "Breaking changes" section to mention that useQuery hooks are now generated by default (previously off), so downstream users are aware when upgrading.
| @@ -85,7 +85,7 @@ export const defaultConfig: TanStackPreactQueryPlugin['Config'] = { | |||
| plugin.config.useQuery = context.valueToObject({ | |||
| defaultValue: { | |||
| case: plugin.config.case ?? 'camelCase', | |||
| enabled: false, | |||
| enabled: true, | |||
There was a problem hiding this comment.
Same concern as react-query — changing this default from false to true is a breaking change for preact-query users.
| @@ -39,6 +45,22 @@ export const handlerV5: PluginHandler = ({ plugin }) => { | |||
| plugin.symbol('useQuery', { | |||
| external: plugin.name, | |||
| }); | |||
| plugin.symbol(getQueryOptionsType(plugin.name), { | |||
There was a problem hiding this comment.
This UseQueryOptions/CreateQueryOptions symbol is registered but never referenced by any generated AST node. The useQuery.ts hook builds its override type inline via Partial<Omit<ReturnType<typeof queryOptionsFn>, 'queryKey' | 'queryFn'>> rather than using this external type. The symbol system will tree-shake it from the output (confirmed by snapshots), but the registration is dead code.
Either remove it or use it — e.g., the queryOptionsType in useQuery.ts could reference this external type instead of building Partial<Omit<...>> inline.
|
Replied to the PR author's comment acknowledging that the Task list (2/2 completed)
|
5132bc5 to
db13143
Compare
|
@nmokkenstorm thanks! CI should be fixed now so if it's failing, it's likely a code issue (like in this instance with needing to re-generate examples) |
I that case I will actually give it a proper look hah, will keep you posted |
db13143 to
9b84628
Compare
42e45e5 to
0a22602
Compare
0a22602 to
2071133
Compare

Summary
Adds
skipTokensupport andqueryOptionsoverride to generateduseQueryhooks for TanStack Query plugins (React, Preact).useQueryhooks are now generated by default (no config flag needed)skipTokenis always supported — pass it instead of options to conditionally disable a queryqueryOptionsoverride parameter allows customizing the underlying query optionsuseQuery: falseto opt out of generatinguseQueryhooksCloses #2766
Breaking changes
useQueryhooks are now generated by default for React Query and Preact Query plugins (previously disabled). Existing users will see newuseQueryhook exports,skipToken+useQueryimports, and anunwrapSkipTokenutility in their generated output. To opt out, setuseQuery: falsein your plugin config.