feat(@tanstack/query): generate mutation keys for mutation options#3858
feat(@tanstack/query): generate mutation keys for mutation options#3858slmnsh wants to merge 6 commits into
Conversation
|
|
|
|
@slmnsh is attempting to deploy a commit to the Hey API Team on Vercel. A member of the Team first needs to authorize it. |
|
@mrlubos Can you check? |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3858 +/- ##
==========================================
- Coverage 39.58% 39.49% -0.09%
==========================================
Files 532 533 +1
Lines 19581 19636 +55
Branches 5835 5837 +2
==========================================
+ Hits 7751 7756 +5
- Misses 9582 9630 +48
- Partials 2248 2250 +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:
|
There was a problem hiding this comment.
Important
Consider wiring up mutationKeys.enabled, regenerating examples, adding a changeset, and documenting the new option before merging. The implementation faithfully mirrors the existing queryKey machinery and the snapshots are consistent across all six framework plugins, but the new public config has a dead flag and no test coverage beyond the default cell.
TL;DR — Adds a mutationKeys plugin config and emits a per-operation <name>MutationKey() factory plus a shared MutationKey<TOptions> type and createMutationKey helper for every Tanstack Query plugin (angular/preact/react/solid/svelte/vue). Every mutationOptions(...) result now carries a mutationKey tuple, mirroring how queryOptions already carries a queryKey. Resolves #3845.
Key changes
- Add shared mutation-key emitters — new
mutationKey.tsparallelsqueryKey.tswithcreateMutationKeyType,createMutationKeyFunction, andmutationKeyStatement. - Wire mutation key into
mutationOptions— emit a<op>MutationKeyfactory and addmutationKey: <op>MutationKey(options)to the returned options object. - Add
mutationKeysuser config — six frameworktypes.ts/config.tsfiles gainmutationKeys: boolean | NameTransformer | { case, enabled, name, tags }with defaults{ enabled: true, name: '{{name}}MutationKey', tags: false }. - Regenerate 86 tanstack-query snapshots — every existing fixture under
packages/openapi-ts-tests/tanstack-query/v5/__snapshots__/**now contains the new type, helper, and per-operation key factory.
Summary | 92 files | 1 commit | base: main ← 1285e02
mutationKeys.enabled is silently ignored
Before: users could opt out of
queryKeys/infiniteQueryKeysonly by knowing the existing flags don't actually gate emission either.
After:mutationKeysadds a third user-visibleenabledflag with the same problem —mutationKeys: falseand{ enabled: false }parse correctly through themappersand resolver, but no consumer ever readsplugin.config.mutationKeys.enabled.
createMutationOptions in packages/openapi-ts/src/plugins/@tanstack/query-core/v5/mutationOptions.ts unconditionally calls mutationKeyStatement(...) and assigns .prop('mutationKey', $(symbolMutationKey).call('options')) regardless of the flag. mutationKey.ts only reads config.tags. A user setting mutationKeys: false still gets the full MutationKey type, the createMutationKey helper, every <op>MutationKey() export, and the mutationKey field on every mutation. Either gate the emissions on plugin.config.mutationKeys.enabled (matching the precedent in packages/openapi-ts/src/plugins/@pinia/colada/queryOptions.ts:48) or drop the flag from the type and resolver. The same sin exists for queryKeys.enabled in this plugin today, but this PR adds a fresh instance.
mutationOptions.ts · mutationKey.ts · react-query/types.ts
Test matrix only covers the default cell
Before: a four-axis config (
enabled,name,tags,case) shipped with no behavioural verification.
After: the same is still true — 86 snapshot diffs all use defaults, so three of the four axes are unproven.
A grep for a 3-arg createMutationKey('id', options, [ literal across every snapshot returns zero hits, so the tags: true branch in mutationKey.ts (which emits $.array().elements(...operation.tags) as the third arg) is never exercised. The name-builder scenario in packages/openapi-ts-tests/tanstack-query/v5/test/plugins.test.ts overrides name for infiniteQueryKeys, queryKeys, queryOptions, mutationOptions, etc. but conspicuously skips mutationKeys — the snapshot still emits fooPostMutationKey instead of a custom name. No scenario sets mutationKeys: false (which would have surfaced the dead-flag bug above), and no scenario overrides case. Adding three small scenarios — mutationKeys: false, mutationKeys: { tags: true }, and mutationKeys: { name: '{{name}}F' } — would lock in the contract documented in the JSDoc.
plugins.test.ts · mutationKey.ts
Examples not regenerated, so examples:check will fail in CI
Before:
examples/openapi-ts-tanstack-{react,vue,svelte,angular-query-experimental}-query/src/client/@tanstack/*.gen.tscarry the old output.
After: they still do — agrepforMutationKey|mutationKey:underexamples/returns nothing.
Default mutationKeys: { enabled: true } means every regenerated tanstack example will diff. scripts/examples-check.sh calls git diff --quiet after running pnpm examples:generate and exits non-zero on any drift. Run pnpm examples:generate and commit the four updated @tanstack/*.gen.ts files before this PR can land green.
scripts/examples-check.sh · examples/openapi-ts-tanstack-react-query
Missing changeset and docs
Before:
.changeset/only contains the README,changelog.js, andconfig.json.
After: still no entry for this PR.
This repo uses Changesets — without a .md entry the next release won't bump or surface the new config in CHANGELOG. Add one at minor for @hey-api/openapi-ts. Separately, docs/openapi-ts/plugins/tanstack-query.md has no mention of mutationKey anywhere; the symmetrical Queries section documents queryKeys, the per-operation getXQueryKey() accessor, the tags sub-option, and case/name customization (around lines 282–446). Mirror that structure for mutations, and consider a note in docs/openapi-ts/migrating.md since every existing useMutation({ ...fooMutation() }) consumer now silently inherits a default mutationKey tuple where there used to be undefined.
docs/openapi-ts/plugins/tanstack-query.md · docs/openapi-ts/migrating.md
Smaller notes
- The exported
type MutationKey<TOptions extends Options>shadows@tanstack/react-query's ownMutationKeytype for any user who re-exports both from the same module. This already happens forQueryKey, so it's consistent rather than novel — but worth a doc callout. (Observable in every regenerated snapshot, e.g.packages/openapi-ts-tests/tanstack-query/v5/__snapshots__/2.0.x/plugins/asClass/@tanstack/react-query.gen.ts:57.) - The
createMutationKeyemission is guarded byplugin.querySymbol({ category: 'utility', resource: 'createMutationKey', tool: plugin.name })but theMutationKeytype is created in the same conditional. If anything else ever emits aMutationKeytype symbol first, the guard would skip the helper while leaving a foreign type referenced viareferenceSymbolonmutationOptions.ts:39. No current emitter does this; flagging only as a latent fragility shared withqueryKey. - Positional-arg passing in
createMutationKeyLiteralis correct —createMutationKeyhas signature(id, options?, tags?), distinct fromcreateQueryKey's(id, options?, infinite?, tags?), so passingtagsArrayas the third arg is right. Worth a comment if it ever causes confusion during review.
Claude Opus | 𝕏
| return data; | ||
| } | ||
| }, | ||
| mutationKey: patchApiVbyApiVersionNoTagMutationKey(options) |
There was a problem hiding this comment.
This mutationKey line is emitted unconditionally in createMutationOptions (see packages/openapi-ts/src/plugins/@tanstack/query-core/v5/mutationOptions.ts:117). Setting mutationKeys: false or { enabled: false } does not suppress it because nothing reads plugin.config.mutationKeys.enabled. Gate this assignment (and the upstream mutationKeyStatement(...) + createMutationKeyType/createMutationKeyFunction emissions) on the enabled flag, or remove the flag from the public type.
fix(@tanstack/query): mutation option types when it has required operation data
fix(@tanstack/query): removed body from mutation key gen
@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: |

Fixes #3845