Skip to content

Conversation

@ScriptType
Copy link
Contributor

@ScriptType ScriptType commented Dec 23, 2025

Summary

This PR introduces configuration-based query invalidation support, initially implemented for angular-query. This allows developers to define cache invalidation rules directly in orval.config.ts rather than manually calling queryClient.invalidateQueries() in every component.

This is based on #2676 but without the optimistic update for now.

Usage

In your orval.config.ts, you can now specify mutationInvalidates within the query options:

export default defineConfig({
  petstore: {
    // ...
    output: {
      override: {
        query: {
          useInvalidate: true,
          signal: true,
          mutationInvalidates: [
            // Broad invalidation - invalidates all listPets queries
            {
              onMutations: ['createPets'],
              invalidates: ['listPets'],
            },
            // Targeted invalidation - invalidates specific pet by ID
            {
              onMutations: ['deletePet', 'updatePet', 'patchPet'],
              invalidates: [
                'listPets',
                { query: 'showPetById', params: ['petId'] },
              ],
            },
            {
              onMutations: ['uploadFile'],
              invalidates: ['listPets'],
            },
          ],
        },
      },
    },
  },
});

Invalidation Target Formats

Format Description Generated Code
'listPets' Broad invalidation getListPetsQueryKey()
{ query: 'showPetById', params: ['petId'] } Same-name param mapping getShowPetByIdQueryKey(variables.petId)
{ query: 'showPetById', params: { petId: 'id' } } Explicit param mapping getShowPetByIdQueryKey(variables.id)

Generated Code Example

For deletePet with the config above, orval generates:

const onSuccess = (data, variables, onMutateResult, context) => {
  queryClient.invalidateQueries({ queryKey: getListPetsQueryKey() });
  queryClient.invalidateQueries({ queryKey: getShowPetByIdQueryKey(variables.petId) });
  mutationOptions?.onSuccess?.(data, variables, onMutateResult, context);
};

Implementation Guide for Other Generators

The core types and normalization logic have been added to @orval/core, making this feature available for all generators to implement.

Types

// packages/core/src/types.ts
export type InvalidateTarget =
  | string
  | {
      query: string;
      params: string[] | Record<string, string>;
    };

export type MutationInvalidatesRule = {
  onMutations: string[];
  invalidates: InvalidateTarget[];
};

export type MutationInvalidatesConfig = MutationInvalidatesRule[];

Steps to Support in Other Clients

To support this in other clients (e.g., react-query, vue-query, svelte-query), generators need to:

  1. Read the Config: Access mutationInvalidates from the query options object (available in NormalizedQueryOptions).

  2. Filter Rules for Current Operation:

    const invalidatesConfig = (query.mutationInvalidates ?? [])
      .filter((rule) => rule.onMutations.includes(operationName))
      .flatMap((rule) => rule.invalidates);
  3. Normalize and Deduplicate Targets:

    const normalizeTarget = (target) =>
      typeof target === 'string' ? { query: target } : target;
  4. Generate Invalidation Code:

    • Inside the mutation's onSuccess callback, generate code to invalidate the target queries.
    • Use the existing query key generators (e.g., getListPetsQueryKey()) to ensure type safety.
    • For params, reference variables.<paramName> from the mutation.

Checklist

  • Core config types added (InvalidateTarget, MutationInvalidatesRule)
  • Logic implemented for angular-query
  • Signal support enabled for all HTTP verbs (DELETE, PUT, PATCH)
  • Params-based targeted invalidation support
  • Sample app demonstrates all mutation types
  • Comprehensive test coverage (15 tests)
  • Tests passed

@ScriptType ScriptType marked this pull request as draft December 23, 2025 15:31
@ScriptType ScriptType marked this pull request as ready for review December 25, 2025 23:15
@melloware melloware force-pushed the feat/config-based-invalidation branch from 9320178 to 8c4ca53 Compare December 27, 2025 14:52
@melloware melloware added the tanstack-query TanStack Query related issue label Dec 27, 2025
@melloware melloware added this to the 8.0.0 milestone Dec 27, 2025
@melloware
Copy link
Collaborator

can you update the /docs too for this new configuration?

@ScriptType
Copy link
Contributor Author

Sure, are there any other regards? Like stuff which you think could change? Or do you like the way?

@melloware
Copy link
Collaborator

Let's get some others to weigh in.

@AllieJonsson
Copy link
Contributor

I think this is great!

Copy link
Member

@soartec-lab soartec-lab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ScriptType
It's a great idea, and I'm in favor of moving forward with it. However, I have one suggestion for improvement:

As written in the example, invalidating listPets depends on updating createPets, but the optional keys implicitly state the dependency.
Rather than assigning meaning to keys, make the keys explicitly descriptive and the values explicit.
Also, there may be multiple operations that can be disabled.

Taking this into consideration, how about doing it like this?

For example:

mutationInvalidates: [
  {
    invalidates: ['listPets', 'showPetById'],
    dependsOn: ['createPets', 'deletePet']
  },
  {
    invalidates: ['listPets'],
    dependsOn: ['createPets']
  },
]

@ScriptType ScriptType force-pushed the feat/config-based-invalidation branch from 8c4ca53 to 68d47d1 Compare January 9, 2026 14:56
@ScriptType
Copy link
Contributor Author

@soartec-lab i agree, its a "bit" more complex to do it for the generation, but if we imagine when we have like 20 queries its much easier to maintain in the config.

@ScriptType ScriptType requested a review from soartec-lab January 9, 2026 17:38
Previously, getHasSignal() only enabled signal support for GET and POST
verbs. This caused DELETE, PUT, and PATCH mutations to generate code
that referenced an undefined 'options' parameter.

- Remove verb restriction from getHasSignal()
- Remove unused getIsBodyVerb and Verbs imports
- Update call sites to not pass verb parameter
Add ability to specify mutation variable-to-query param mappings:
- string: broad invalidation (no params)
- { query, params: string[] }: same-name shorthand
- { query, params: Record<string, string> }: explicit mapping

This enables targeted cache invalidation based on mutation variables.
Add code generation for targeted cache invalidation:
- normalizeTarget(): converts string to { query } format
- serializeTarget(): deduplicates by query+params combination
- generateVariableRef(): handles nested variables (data.petId)
- generateParamArgs(): generates query key function arguments
- generateInvalidateCall(): builds invalidateQueries() calls

Generated onSuccess now passes mutation variables to query key
functions for precise cache invalidation.
Expand petstore.yaml with mutation operations:
- DELETE /pets/{petId}: deletePet
- PUT /pets/{petId}: updatePet
- PATCH /pets/{petId}: patchPet

Update orval.config.ts:
- Enable signal: true for all verbs
- Configure deletePet, updatePet, patchPet to invalidate both
  listPets (broad) and showPetById with petId param (targeted)
Generated files include:
- deletePet, updatePet, patchPet mutations with signal support
- onSuccess handlers with targeted invalidation:
  - getListPetsQueryKey() for broad list invalidation
  - getShowPetByIdQueryKey(variables.petId) for specific pet
- New PatchPetBody model type
- Updated MSW handlers for new endpoints
Add UI controls for mutation operations:
- Update Pet: calls updatePet mutation
- Patch Tag: calls patchPet mutation
- Delete Pet: calls deletePet mutation

Each mutation triggers automatic cache invalidation via
mutationInvalidates, demonstrating the feature in action.
Test coverage for mutationInvalidates feature:
- getCreatePetsMutationOptions: onSuccess, mutationFn, list invalidation
- getDeletePetMutationOptions: dual invalidation (list + specific pet)
- getUpdatePetMutationOptions: dual invalidation
- getPatchPetMutationOptions: dual invalidation
- Params invalidation: verifies only matching petId is invalidated
- User callback chaining: confirms custom onSuccess is called

All 15 tests passing.
Wrap function references in arrow functions to satisfy
unicorn/no-array-callback-reference rule.
@melloware melloware force-pushed the feat/config-based-invalidation branch from b5e6d28 to ad11ea9 Compare January 9, 2026 18:00
@melloware
Copy link
Collaborator

ok i rebased your branch and its all working now

@melloware
Copy link
Collaborator

Build is all passing now!

Copy link
Member

@soartec-lab soartec-lab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@melloware melloware merged commit 5c62bd2 into orval-labs:master Jan 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tanstack-query TanStack Query related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Idea] Automatic optimistic Updates / config based optimistic Updates

4 participants