Skip to content

Commit db543a4

Browse files
committed
feat(vue-query): add new methods to vue-query
1 parent 677b0af commit db543a4

14 files changed

Lines changed: 686 additions & 218 deletions

.changeset/cold-islands-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/vue-query': minor
3+
---
4+
5+
add new imperitive methods to QueryClient proxy

packages/vue-query/src/__tests__/infiniteQueryOptions.test-d.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assertType, describe, expectTypeOf, it } from 'vitest'
22
import { dataTagSymbol } from '@tanstack/query-core'
3-
import { reactive } from 'vue-demi'
3+
import { reactive, unref } from 'vue-demi'
44
import { queryKey } from '@tanstack/query-test-utils'
55
import { infiniteQueryOptions } from '../infiniteQueryOptions'
66
import { QueryClient } from '../queryClient'
@@ -49,6 +49,41 @@ describe('infiniteQueryOptions', () => {
4949
InfiniteData<string, unknown> | undefined
5050
>()
5151
})
52+
it('should work when passed to infiniteQuery', async () => {
53+
const options = infiniteQueryOptions({
54+
queryKey: ['key'],
55+
queryFn: () => Promise.resolve('string'),
56+
getNextPageParam: () => 1,
57+
initialPageParam: 1,
58+
})
59+
60+
const data = await new QueryClient().infiniteQuery({
61+
...unref(options),
62+
enabled: true,
63+
staleTime: 0,
64+
pages: 1,
65+
})
66+
67+
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
68+
})
69+
it('should work when passed to infiniteQuery with select', async () => {
70+
const options = infiniteQueryOptions({
71+
queryKey: ['key'],
72+
queryFn: () => Promise.resolve('string'),
73+
getNextPageParam: () => 1,
74+
initialPageParam: 1,
75+
select: (data) => data.pages,
76+
})
77+
78+
const data = await new QueryClient().infiniteQuery({
79+
...unref(options),
80+
enabled: true,
81+
staleTime: 0,
82+
pages: 1,
83+
})
84+
85+
expectTypeOf(data).toEqualTypeOf<Array<string>>()
86+
})
5287
it('should tag the queryKey with the result type of the QueryFn', () => {
5388
const key = queryKey()
5489
const { queryKey: tagged } = infiniteQueryOptions({

packages/vue-query/src/__tests__/queryClient.test-d.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { assertType, describe, expectTypeOf, it } from 'vitest'
2+
import { skipToken } from '@tanstack/query-core'
23
import { queryKey } from '@tanstack/query-test-utils'
34
import { QueryClient } from '../queryClient'
45
import type { DataTag, InfiniteData } from '@tanstack/query-core'
@@ -151,3 +152,108 @@ describe('fetchInfiniteQuery', () => {
151152
])
152153
})
153154
})
155+
156+
describe('query', () => {
157+
it('should return the selected type', () => {
158+
const result = new QueryClient().query({
159+
queryKey: ['key'],
160+
queryFn: () => Promise.resolve('string'),
161+
select: (data) => data.length,
162+
})
163+
164+
expectTypeOf(result).toEqualTypeOf<Promise<number>>()
165+
})
166+
167+
it('should infer select type with skipToken', () => {
168+
const result = new QueryClient().query({
169+
queryKey: ['key'],
170+
queryFn: skipToken,
171+
select: (data: string) => data.length,
172+
})
173+
174+
expectTypeOf(result).toEqualTypeOf<Promise<number>>()
175+
})
176+
177+
it('should infer select type with skipToken and enabled false', () => {
178+
const result = new QueryClient().query({
179+
queryKey: ['key'],
180+
queryFn: skipToken,
181+
enabled: false,
182+
select: (data: string) => data.length,
183+
})
184+
185+
expectTypeOf(result).toEqualTypeOf<Promise<number>>()
186+
})
187+
188+
it('should infer select type with skipToken and enabled true', () => {
189+
const result = new QueryClient().query({
190+
queryKey: ['key'],
191+
queryFn: skipToken,
192+
enabled: true,
193+
select: (data: string) => data.length,
194+
})
195+
196+
expectTypeOf(result).toEqualTypeOf<Promise<number>>()
197+
})
198+
})
199+
200+
describe('infiniteQuery', () => {
201+
it('should return infinite data', async () => {
202+
const data = await new QueryClient().infiniteQuery({
203+
queryKey: ['key'],
204+
queryFn: () => Promise.resolve('string'),
205+
getNextPageParam: () => 1,
206+
initialPageParam: 1,
207+
})
208+
209+
expectTypeOf(data).toEqualTypeOf<InfiniteData<string, number>>()
210+
})
211+
212+
it('should return the selected type', () => {
213+
const result = new QueryClient().infiniteQuery({
214+
queryKey: ['key'],
215+
queryFn: () => Promise.resolve({ count: 1 }),
216+
getNextPageParam: () => 2,
217+
initialPageParam: 1,
218+
select: (data) => data.pages.map((page) => page.count),
219+
})
220+
221+
expectTypeOf(result).toEqualTypeOf<Promise<Array<number>>>()
222+
})
223+
224+
it('should allow passing pages with getNextPageParam', () => {
225+
assertType<Parameters<QueryClient['infiniteQuery']>>([
226+
{
227+
queryKey: ['key'],
228+
queryFn: () => Promise.resolve('string'),
229+
initialPageParam: 1,
230+
getNextPageParam: () => 1,
231+
pages: 5,
232+
},
233+
])
234+
})
235+
236+
it('should not allow passing pages without getNextPageParam', () => {
237+
assertType<Parameters<QueryClient['infiniteQuery']>>([
238+
// @ts-expect-error Property 'getNextPageParam' is missing
239+
{
240+
queryKey: ['key'],
241+
queryFn: () => Promise.resolve('string'),
242+
initialPageParam: 1,
243+
pages: 5,
244+
},
245+
])
246+
})
247+
248+
it('should preserve page param inference', () => {
249+
new QueryClient().infiniteQuery({
250+
queryKey: ['key'],
251+
queryFn: ({ pageParam }) => {
252+
expectTypeOf(pageParam).toEqualTypeOf<number>()
253+
return Promise.resolve(pageParam.toString())
254+
},
255+
initialPageParam: 1,
256+
getNextPageParam: () => undefined,
257+
})
258+
})
259+
})

packages/vue-query/src/__tests__/queryClient.test.ts

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2-
import { ref } from 'vue-demi'
2+
import { ref, unref } from 'vue-demi'
33
import { QueryClient as QueryClientOrigin } from '@tanstack/query-core'
44
import { QueryClient } from '../queryClient'
55
import { infiniteQueryOptions } from '../infiniteQueryOptions'
6+
import { queryOptions } from '../queryOptions'
67

78
vi.mock('@tanstack/query-core', async () => {
89
const actual = await vi.importActual<{
@@ -338,6 +339,57 @@ describe('QueryCache', () => {
338339
})
339340
})
340341

342+
describe('query', () => {
343+
it('should properly unwrap queryKey', () => {
344+
const queryClient = new QueryClient()
345+
346+
queryClient.query({
347+
queryKey: queryKeyRef,
348+
})
349+
350+
expect(QueryClientOrigin.prototype.query).toBeCalledWith({
351+
queryKey: queryKeyUnref,
352+
})
353+
})
354+
355+
it('should properly unwrap enabled, staleTime, and select', () => {
356+
const queryClient = new QueryClient()
357+
const enabled = () => false
358+
const staleTime = () => 1000
359+
const select = (data: string) => data.length
360+
361+
queryClient.query({
362+
queryKey: queryKeyRef,
363+
enabled: ref(enabled),
364+
staleTime: ref(staleTime),
365+
select: ref(select),
366+
})
367+
368+
expect(QueryClientOrigin.prototype.query).toBeCalledWith({
369+
queryKey: queryKeyUnref,
370+
enabled,
371+
staleTime,
372+
select,
373+
})
374+
})
375+
376+
it('should properly unwrap queryOptions getter', () => {
377+
const queryClient = new QueryClient()
378+
379+
const options = queryOptions(() => ({
380+
queryKey: queryKeyRef,
381+
queryFn: fn,
382+
}))
383+
384+
queryClient.query(options)
385+
386+
expect(QueryClientOrigin.prototype.query).toBeCalledWith({
387+
queryKey: queryKeyUnref,
388+
queryFn: fn,
389+
})
390+
})
391+
})
392+
341393
describe('prefetchQuery', () => {
342394
it('should properly unwrap parameters', () => {
343395
const queryClient = new QueryClient()
@@ -387,6 +439,80 @@ describe('QueryCache', () => {
387439
})
388440
})
389441

442+
describe('infiniteQuery', () => {
443+
it('should properly unwrap queryKey, initialPageParam, pages, and select', () => {
444+
const queryClient = new QueryClient()
445+
const getNextPageParam = () => 1
446+
const select = (data: { pages: Array<string> }) => data.pages.length
447+
448+
queryClient.infiniteQuery({
449+
queryKey: queryKeyRef,
450+
initialPageParam: ref(0),
451+
pages: ref(2),
452+
getNextPageParam: ref(getNextPageParam),
453+
select: ref(select),
454+
})
455+
456+
expect(QueryClientOrigin.prototype.infiniteQuery).toBeCalledWith(
457+
expect.objectContaining({
458+
queryKey: queryKeyUnref,
459+
initialPageParam: 0,
460+
pages: 2,
461+
getNextPageParam,
462+
select,
463+
}),
464+
)
465+
})
466+
467+
it('should properly unwrap getNextPageParam when using infiniteQueryOptions', () => {
468+
const queryClient = new QueryClient()
469+
const getNextPageParam = () => 12
470+
471+
const options = infiniteQueryOptions({
472+
queryKey: queryKeyRef,
473+
initialPageParam: ref(0),
474+
getNextPageParam: ref(getNextPageParam),
475+
})
476+
477+
queryClient.infiniteQuery({
478+
...unref(options),
479+
enabled: true,
480+
staleTime: 0,
481+
pages: 1,
482+
})
483+
484+
expect(QueryClientOrigin.prototype.infiniteQuery).toBeCalledWith(
485+
expect.objectContaining({
486+
queryKey: queryKeyUnref,
487+
initialPageParam: 0,
488+
pages: 1,
489+
getNextPageParam,
490+
}),
491+
)
492+
})
493+
494+
it('should properly unwrap options getter', () => {
495+
const queryClient = new QueryClient()
496+
const getNextPageParam = () => 12
497+
498+
queryClient.infiniteQuery(() => ({
499+
queryKey: queryKeyRef,
500+
initialPageParam: ref(0),
501+
pages: ref(1),
502+
getNextPageParam: ref(getNextPageParam),
503+
}))
504+
505+
expect(QueryClientOrigin.prototype.infiniteQuery).toBeCalledWith(
506+
expect.objectContaining({
507+
queryKey: queryKeyUnref,
508+
initialPageParam: 0,
509+
pages: 1,
510+
getNextPageParam,
511+
}),
512+
)
513+
})
514+
})
515+
390516
describe('prefetchInfiniteQuery', () => {
391517
it('should properly unwrap parameters', () => {
392518
const queryClient = new QueryClient()

packages/vue-query/src/__tests__/queryOptions.test-d.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ describe('queryOptions', () => {
3939
const { data } = reactive(useQuery(options))
4040
expectTypeOf(data).toEqualTypeOf<number | undefined>()
4141
})
42+
it('should work when passed to query', async () => {
43+
const options = queryOptions({
44+
queryKey: ['key'],
45+
queryFn: () => Promise.resolve(5),
46+
})
47+
48+
const data = await new QueryClient().query(options)
49+
expectTypeOf(data).toEqualTypeOf<number>()
50+
})
51+
it('should work when passed to query with select', async () => {
52+
const options = queryOptions({
53+
queryKey: ['key'],
54+
queryFn: () => Promise.resolve(5),
55+
select: (data) => data.toString(),
56+
})
57+
58+
const data = await new QueryClient().query(options)
59+
expectTypeOf(data).toEqualTypeOf<string>()
60+
})
4261
it('should tag the queryKey with the result type of the QueryFn', () => {
4362
const key = queryKey()
4463
const { queryKey: tagged } = queryOptions({
@@ -132,10 +151,13 @@ describe('queryOptions', () => {
132151
// Should not error
133152
const data = queryClient.invalidateQueries(options)
134153
// Should not error
135-
const data2 = queryClient.fetchQuery(options)
154+
const data2 = queryClient.query(options)
155+
// Should not error
156+
const data3 = queryClient.fetchQuery(options)
136157

137158
expectTypeOf(data).toEqualTypeOf<Promise<void>>()
138159
expectTypeOf(data2).toEqualTypeOf<Promise<number>>()
160+
expectTypeOf(data3).toEqualTypeOf<Promise<number>>()
139161
})
140162

141163
it('TData should always be defined when initialData is provided as a function which ALWAYS returns the data', () => {

0 commit comments

Comments
 (0)