diff --git a/packages/plugins/tanstack-query/package.json b/packages/plugins/tanstack-query/package.json index ed1f76527..f8dc9ca6a 100644 --- a/packages/plugins/tanstack-query/package.json +++ b/packages/plugins/tanstack-query/package.json @@ -92,7 +92,7 @@ }, "devDependencies": { "@tanstack/react-query": "^4.29.7", - "@tanstack/react-query-v5": "npm:@tanstack/react-query@^5.0.0", + "@tanstack/react-query-v5": "npm:@tanstack/react-query@5.56.x", "@tanstack/svelte-query": "^4.29.7", "@tanstack/svelte-query-v5": "npm:@tanstack/svelte-query@^5.0.0", "@tanstack/vue-query": "^4.37.0", diff --git a/packages/plugins/tanstack-query/src/runtime/common.ts b/packages/plugins/tanstack-query/src/runtime/common.ts index 40830b3ee..2d6793c8a 100644 --- a/packages/plugins/tanstack-query/src/runtime/common.ts +++ b/packages/plugins/tanstack-query/src/runtime/common.ts @@ -385,6 +385,11 @@ async function optimisticUpdate( state: { data, error }, } = cacheItem; + if (!isZenStackQueryKey(queryKey)) { + // skip non-zenstack queries + continue; + } + if (error) { if (logging) { console.warn(`Skipping optimistic update for ${JSON.stringify(queryKey)} due to error:`, error); @@ -392,8 +397,8 @@ async function optimisticUpdate( continue; } - const [_, queryModel, queryOperation, queryArgs, { optimisticUpdate }] = queryKey as QueryKey; - if (!optimisticUpdate) { + const [_, queryModel, queryOperation, queryArgs, queryOptions] = queryKey; + if (!queryOptions?.optimisticUpdate) { if (logging) { console.log(`Skipping optimistic update for ${JSON.stringify(queryKey)} due to opt-out`); } @@ -450,3 +455,15 @@ async function optimisticUpdate( } } } + +function isZenStackQueryKey(queryKey: readonly unknown[]): queryKey is QueryKey { + if (queryKey.length < 5) { + return false; + } + + if (queryKey[0] !== QUERY_KEY_PREFIX) { + return false; + } + + return true; +} diff --git a/packages/plugins/tanstack-query/tests/plugin.test.ts b/packages/plugins/tanstack-query/tests/plugin.test.ts index 42cb3da29..7fc7a18b3 100644 --- a/packages/plugins/tanstack-query/tests/plugin.test.ts +++ b/packages/plugins/tanstack-query/tests/plugin.test.ts @@ -113,7 +113,7 @@ ${sharedModel} { provider: 'postgresql', pushDb: false, - extraDependencies: ['react@18.2.0', '@types/react@18.2.0', '@tanstack/react-query@^5.0.0'], + extraDependencies: ['react@18.2.0', '@types/react@18.2.0', '@tanstack/react-query@5.56.x'], copyDependencies: [path.resolve(__dirname, '../dist')], compile: true, extraSourceFiles: [ diff --git a/packages/plugins/tanstack-query/tests/react-hooks-v5.test.tsx b/packages/plugins/tanstack-query/tests/react-hooks-v5.test.tsx index 63c22e4eb..51f7de64f 100644 --- a/packages/plugins/tanstack-query/tests/react-hooks-v5.test.tsx +++ b/packages/plugins/tanstack-query/tests/react-hooks-v5.test.tsx @@ -3,7 +3,7 @@ */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/ban-ts-comment */ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query-v5'; +import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query-v5'; import { act, renderHook, waitFor } from '@testing-library/react'; import nock from 'nock'; import React from 'react'; @@ -863,4 +863,69 @@ describe('Tanstack Query React Hooks V5 Test', () => { expect(cacheData[0].name).toBe('foohooray'); }); }); + + it('optimistic update mixed with non-zenstack queries', async () => { + const { queryClient, wrapper } = createWrapper(); + + // non-zenstack query + const { result: myQueryResult } = renderHook( + () => useQuery({ queryKey: ['myQuery'], queryFn: () => ({ data: 'myData' }) }), + { + wrapper, + } + ); + await waitFor(() => { + expect(myQueryResult.current.data).toEqual({ data: 'myData' }); + }); + + const data: any[] = []; + + nock(makeUrl('User', 'findMany')) + .get(/.*/) + .reply(200, () => { + console.log('Querying data:', JSON.stringify(data)); + return { data }; + }) + .persist(); + + const { result } = renderHook( + () => useModelQuery('User', makeUrl('User', 'findMany'), undefined, { optimisticUpdate: true }), + { + wrapper, + } + ); + await waitFor(() => { + expect(result.current.data).toHaveLength(0); + }); + + nock(makeUrl('User', 'create')) + .post(/.*/) + .reply(200, () => { + console.log('Not mutating data'); + return { data: null }; + }); + + const { result: mutationResult } = renderHook( + () => + useModelMutation('User', 'POST', makeUrl('User', 'create'), modelMeta, { + optimisticUpdate: true, + invalidateQueries: false, + }), + { + wrapper, + } + ); + + act(() => mutationResult.current.mutate({ data: { name: 'foo' } })); + + await waitFor(() => { + const cacheData: any = queryClient.getQueryData( + getQueryKey('User', 'findMany', undefined, { infinite: false, optimisticUpdate: true }) + ); + expect(cacheData).toHaveLength(1); + expect(cacheData[0].$optimistic).toBe(true); + expect(cacheData[0].id).toBeTruthy(); + expect(cacheData[0].name).toBe('foo'); + }); + }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 286f2a3fb..56b2c4ec7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -284,8 +284,8 @@ importers: specifier: ^4.29.7 version: 4.36.1(react-dom@18.3.1(react@18.2.0))(react@18.2.0) '@tanstack/react-query-v5': - specifier: npm:@tanstack/react-query@^5.0.0 - version: '@tanstack/react-query@5.48.0(react@18.2.0)' + specifier: npm:@tanstack/react-query@5.56.x + version: '@tanstack/react-query@5.56.2(react@18.2.0)' '@tanstack/svelte-query': specifier: ^4.29.7 version: 4.36.1(svelte@4.2.18) @@ -365,10 +365,10 @@ importers: devDependencies: '@trpc/next': specifier: ^10.32.0 - version: 10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/react-query@10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(@trpc/server@10.45.2)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + version: 10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/react-query@10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(@trpc/server@10.45.2)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(react-dom@18.3.1(react@18.2.0))(react@18.2.0) '@trpc/react-query': specifier: ^10.32.0 - version: 10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + version: 10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) '@trpc/server': specifier: ^10.32.0 version: 10.45.2 @@ -2813,6 +2813,9 @@ packages: '@tanstack/query-core@5.48.0': resolution: {integrity: sha512-lZAfPPeVIqXCswE9SSbG33B6/91XOWt/Iq41bFeWb/mnHwQSIfFRbkS4bfs+WhIk9abRArF9Id2fp0Mgo+hq6Q==} + '@tanstack/query-core@5.56.2': + resolution: {integrity: sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q==} + '@tanstack/react-query@4.36.1': resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==} peerDependencies: @@ -2825,10 +2828,10 @@ packages: react-native: optional: true - '@tanstack/react-query@5.48.0': - resolution: {integrity: sha512-GDExbjYWzvDokyRqMSWXdrPiYpp95Aig0oeMIrxTaruOJJgWiWfUP//OAaowm2RrRkGVsavSZdko/XmIrrV2Nw==} + '@tanstack/react-query@5.56.2': + resolution: {integrity: sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg==} peerDependencies: - react: ^18.0.0 + react: ^18 || ^19 '@tanstack/svelte-query@4.36.1': resolution: {integrity: sha512-5fj79QuAu5HuS6G/fairU6ywgILXfs4TGl3+Xc9+MBlmB1aPoQBvGsgJrNyhqvXQcnxro8wDNyZOH8S+Qitycw==} @@ -3983,7 +3986,7 @@ packages: engines: {node: '>= 14'} concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} @@ -4421,7 +4424,7 @@ packages: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} electron-to-chromium@1.4.814: resolution: {integrity: sha512-GVulpHjFu1Y9ZvikvbArHmAhZXtm3wHlpjTMcXNGKl4IQ4jMQjlnz8yMQYYqdLHKi/jEL2+CBC2akWVCoIGUdw==} @@ -6097,7 +6100,7 @@ packages: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} engines: {node: '>= 0.6'} merge-descriptors@1.0.1: @@ -8257,7 +8260,7 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=} engines: {node: '>= 0.4.0'} uuid@10.0.0: @@ -11075,6 +11078,8 @@ snapshots: '@tanstack/query-core@5.48.0': {} + '@tanstack/query-core@5.56.2': {} + '@tanstack/react-query@4.36.1(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@tanstack/query-core': 4.36.1 @@ -11083,9 +11088,9 @@ snapshots: optionalDependencies: react-dom: 18.3.1(react@18.2.0) - '@tanstack/react-query@5.48.0(react@18.2.0)': + '@tanstack/react-query@5.56.2(react@18.2.0)': dependencies: - '@tanstack/query-core': 5.48.0 + '@tanstack/query-core': 5.56.2 react: 18.2.0 '@tanstack/svelte-query@4.36.1(svelte@4.2.18)': @@ -11139,19 +11144,19 @@ snapshots: dependencies: '@trpc/server': 10.45.2 - '@trpc/next@10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/react-query@10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(@trpc/server@10.45.2)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + '@trpc/next@10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/react-query@10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(@trpc/server@10.45.2)(next@14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.2.0))(react@18.2.0))(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: - '@tanstack/react-query': 5.48.0(react@18.2.0) + '@tanstack/react-query': 5.56.2(react@18.2.0) '@trpc/client': 10.45.2(@trpc/server@10.45.2) - '@trpc/react-query': 10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@trpc/react-query': 10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) '@trpc/server': 10.45.2 next: 14.2.4(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.3.1(react@18.2.0) - '@trpc/react-query@10.45.2(@tanstack/react-query@5.48.0(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + '@trpc/react-query@10.45.2(@tanstack/react-query@5.56.2(react@18.2.0))(@trpc/client@10.45.2(@trpc/server@10.45.2))(@trpc/server@10.45.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: - '@tanstack/react-query': 5.48.0(react@18.2.0) + '@tanstack/react-query': 5.56.2(react@18.2.0) '@trpc/client': 10.45.2(@trpc/server@10.45.2) '@trpc/server': 10.45.2 react: 18.2.0 diff --git a/tests/integration/tests/cli/plugins.test.ts b/tests/integration/tests/cli/plugins.test.ts index 4bacf425c..2a23620ef 100644 --- a/tests/integration/tests/cli/plugins.test.ts +++ b/tests/integration/tests/cli/plugins.test.ts @@ -73,7 +73,7 @@ describe('CLI Plugins Tests', () => { 'zod@3.21.1', 'react', 'swr', - '@tanstack/react-query@^5.0.0', + '@tanstack/react-query@5.56.x', '@trpc/server', '@prisma/client@5.20.x', `${path.join(__dirname, '../../../../.build/zenstackhq-language-' + ver + '.tgz')}`, diff --git a/tests/integration/tests/enhancements/with-delegate/plugin-interaction.test.ts b/tests/integration/tests/enhancements/with-delegate/plugin-interaction.test.ts index b0fb0d343..8247c2e45 100644 --- a/tests/integration/tests/enhancements/with-delegate/plugin-interaction.test.ts +++ b/tests/integration/tests/enhancements/with-delegate/plugin-interaction.test.ts @@ -19,7 +19,7 @@ describe('Polymorphic Plugin Interaction Test', () => { await loadSchema(schema, { compile: true, copyDependencies: [tanstackPlugin], - extraDependencies: ['@tanstack/react-query'], + extraDependencies: ['@tanstack/react-query@5.56.x'], }); });