Skip to content

Commit 31fa19f

Browse files
committed
feat: useQueries()
1 parent 2a5830f commit 31fa19f

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

src/index.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import {
55
type InfiniteQueryPageParamsOptions,
66
type QueryClient,
7+
queryOptions as defineQueryOptions,
78
skipToken,
89
useInfiniteQuery,
910
useMutation,
11+
useQueries,
1012
useQuery,
1113
} from '@tanstack/vue-query'
1214
import {
@@ -72,11 +74,13 @@ function createVueQueryProxyDecoration<TRouter extends AnyTRPCRouter>(
7274
if (prop === 'query') {
7375
return trpc.query(joinedPath, firstArg, opts)
7476
}
75-
if (prop === 'useQuery') {
76-
const { trpc: trpcOptions, ...queryOptions } = opts
7777

78-
return useQuery({
79-
queryKey: computed(() => getQueryKey(path, toValue(firstArg), 'query')),
78+
function createQuery(
79+
input: MaybeRefOrGetter<unknown>,
80+
{ trpcOptions, queryOptions }: { trpcOptions: any; queryOptions: any },
81+
) {
82+
return defineQueryOptions({
83+
queryKey: computed(() => getQueryKey(path, toValue(input), 'query')),
8084
queryFn: async ({ queryKey, signal }) =>
8185
trpc.query(joinedPath, queryKey[1]?.input, {
8286
signal,
@@ -85,6 +89,25 @@ function createVueQueryProxyDecoration<TRouter extends AnyTRPCRouter>(
8589
...maybeToRefs(queryOptions),
8690
})
8791
}
92+
if (prop === 'useQuery') {
93+
const { trpc: trpcOptions, ...queryOptions } = opts
94+
const input = firstArg
95+
96+
return useQuery(createQuery(input, { trpcOptions, queryOptions }))
97+
}
98+
99+
if (prop === 'useQueries') {
100+
const { trpc: trpcOptions, combine, shallow, ...queryOptions } = opts
101+
const inputs = firstArg as MaybeRefOrGetter<unknown[]>
102+
103+
return useQueries({
104+
queries: computed(() =>
105+
toValue(inputs).map((i) => createQuery(i, { trpcOptions, queryOptions })),
106+
),
107+
combine,
108+
...maybeToRefs({ shallow }),
109+
})
110+
}
88111

89112
if (prop === 'invalidate') {
90113
return queryClient.invalidateQueries({

src/types.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
UseInfiniteQueryReturnType,
88
UseMutationOptions,
99
UseMutationReturnType,
10+
UseQueriesResults,
1011
UseQueryOptions,
1112
UseQueryReturnType,
1213
} from '@tanstack/vue-query'
@@ -23,7 +24,7 @@ import type {
2324
} from '@trpc/server'
2425
import type { Unsubscribable } from '@trpc/server/observable'
2526
import type { ProcedureOptions } from '@trpc/server/unstable-core-do-not-import'
26-
import type { MaybeRefOrGetter, UnwrapRef } from 'vue'
27+
import type { MaybeRefOrGetter, Ref, UnwrapRef } from 'vue'
2728

2829
type inferAsyncIterableYield<T> = T extends AsyncIterable<infer U> ? U : T
2930

@@ -79,6 +80,26 @@ export type DecorateProcedure<
7980
}
8081
>,
8182
) => UseQueryReturnType<TData, TError>
83+
useQueries: <
84+
TQueryFnData extends inferTransformedProcedureOutput<TRouter, TProcedure>,
85+
TError extends TRPCClientErrorLike<TRouter>,
86+
TData extends TQueryFnData,
87+
TQueryData extends TQueryFnData,
88+
TQueryKey extends QueryKey,
89+
TInput extends inferProcedureInput<TProcedure>,
90+
TQueries extends UseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
91+
TCombinedResult = UseQueriesResults<TQueries[]>,
92+
>(
93+
inputs: MaybeRefOrGetter<Exact<inferProcedureInput<TProcedure>, TInput>[]>,
94+
opts?: MaybeRefOrGetter<
95+
Omit<UnwrapRef<TQueries>, 'queryKey'> & {
96+
trpc?: TRPCRequestOptions
97+
queryKey?: never
98+
combine?: (result: UseQueriesResults<TQueries[]>) => TCombinedResult
99+
shallow?: boolean
100+
}
101+
>,
102+
) => Readonly<Ref<TCombinedResult>>
82103
query: <TInput extends inferProcedureInput<TProcedure>>(
83104
input: Exact<inferProcedureInput<TProcedure>, TInput>,
84105
opts?: ProcedureOptions,

test/basic.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { keepPreviousData } from '@tanstack/vue-query'
2+
import { until } from '@vueuse/core'
23
import { describe, expect, test, vi } from 'vitest'
34
import { ref } from 'vue'
45

@@ -168,3 +169,25 @@ test('useSubscription()', async () => {
168169
subscription.unsubscribe()
169170
})
170171
})
172+
173+
test('useQueries()', async () => {
174+
await app.runWithContext(async () => {
175+
const trpc = useTRPC()
176+
177+
const hellos = Array.from({ length: 5 }, (_, i) => ({ name: i.toString() }))
178+
179+
const queries = trpc.hello.useQueries(() => hellos, {
180+
suspense: true,
181+
combine: (results) => {
182+
return {
183+
data: results.map((result) => result.data),
184+
pending: results.some((result) => result.isPending),
185+
}
186+
},
187+
})
188+
189+
await until(() => queries.value.pending).toBe(false)
190+
191+
expect(queries.value.data).toEqual(hellos.map((hello) => `Hello ${hello.name}!`))
192+
})
193+
})

test/trpc/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ export const appRouter = router({
1919
emptyMutation: publicProcedure.mutation(() => null),
2020

2121
count: publicProcedure
22-
.input(z.object({ max: z.number(), delayMs: z.number().optional().default(100) }))
22+
.input(
23+
z.object({
24+
max: z.number(),
25+
delayMs: z.number().optional().default(100),
26+
}),
27+
)
2328
.subscription(async function* ({ input }) {
2429
let i = 1
2530
while (i <= input.max) {

0 commit comments

Comments
 (0)