Skip to content

Commit

Permalink
feat: getQueryKey helper
Browse files Browse the repository at this point in the history
  • Loading branch information
wobsoriano committed Dec 7, 2023
1 parent 7896b95 commit fc2c7f9
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 48 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
},
"devDependencies": {
"@nuxt/eslint-config": "^0.2.0",
"@trpc/client": "^10.41.0",
"@trpc/server": "^10.41.0",
"@trpc/client": "^10.44.1",
"@trpc/server": "^10.44.1",
"changelogen": "^0.5.5",
"eslint": "^8.52.0",
"taze": "^0.11.4",
Expand Down Expand Up @@ -75,8 +75,8 @@
"pnpm": {
"overrides": {
"nuxt": "3.8.0",
"@trpc/client": "^10.41.0",
"@trpc/server": "^10.41.0"
"@trpc/client": "^10.44.1",
"@trpc/server": "^10.44.1"
}
}
}
4 changes: 2 additions & 2 deletions playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"postinstall": "nuxi prepare"
},
"dependencies": {
"@trpc/client": "^10.41.0",
"@trpc/server": "^10.41.0",
"@trpc/client": "^10.44.1",
"@trpc/server": "^10.44.1",
"superjson": "^2.1.0",
"trpc-nuxt": "workspace:*",
"zod": "^3.22.4"
Expand Down
27 changes: 16 additions & 11 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
<script setup lang="ts">
import { getQueryKey } from 'trpc-nuxt/client'
const { $client } = useNuxtApp()
const todosKey = getQueryKey('asd', undefined)
const { data } = useNuxtData(todosKey)
const { data: todos, pending, error, refresh } = await $client.todo.getTodos.useQuery()
const addTodo = async () => {
const title = Math.random().toString(36).slice(2, 7)
const newData = {
id: Date.now(),
userId: 69,
title,
completed: false
}
data.value.push(newData)
try {
const x = await $client.todo.addTodo.mutate({
id: Date.now(),
userId: 69,
title,
completed: false
})
console.log(x)
const x = await $client.todo.addTodo.mutate(newData)
} catch (e) {
console.log(e)
}
}
const { data: todos, pending, error, refresh } = await $client.todo.getTodos.useLazyQuery()
</script>

<template>
Expand All @@ -31,7 +36,7 @@ const { data: todos, pending, error, refresh } = await $client.todo.getTodos.use
<div v-else>
<ul>
<li
v-for="t in todos?.slice(0, 10)"
v-for="t in todos"
:key="t.id"
>
<NuxtLink
Expand Down
2 changes: 1 addition & 1 deletion playground/server/trpc/routers/todo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type Todo = z.infer<typeof TodoShape>
export const todoRouter = router({
getTodos: publicProcedure
.query(() => {
return $fetch<Todo[]>(`${baseURL}/todos`)
return $fetch<Todo[]>(`${baseURL}/todos?_limit=5`)
}),
getTodo: publicProcedure
.input(z.number())
Expand Down
14 changes: 7 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions src/client/getQueryKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
AnyQueryProcedure,
AnyRouter,
DeepPartial,
inferProcedureInput,
} from '@trpc/server';
import { hash } from 'ohash'
import { DecorateProcedure } from './types';

export type GetQueryParams<
TProcedureOrRouter extends AnyQueryProcedure,
TProcedureInput = inferProcedureInput<TProcedureOrRouter>,
> = DeepPartial<TProcedureInput>;

type GetParams<
TProcedureOrRouter extends AnyQueryProcedure,
> = [
procedureOrRouter: DecorateProcedure<TProcedureOrRouter, AnyRouter> | string,
params: GetQueryParams<TProcedureOrRouter>,
];

type GetQueryKeyParams<
TProcedureOrRouter extends AnyQueryProcedure,
> = GetParams<TProcedureOrRouter>;

export function getQueryKey<
TProcedure extends AnyQueryProcedure,
>(..._params: GetQueryKeyParams<TProcedure>): string {
const [procedure, input] = _params;

if (typeof procedure === 'string') {
// TODO: Warn here if string is passed that it will be deprecated in the future.
return getQueryKeyInternal(procedure, input);
}

// @ts-expect-error: we don't expose _def on the type layer
const path = procedure._def().path as string[];
const dotPath = path.join('.');

return getQueryKeyInternal(dotPath, input)
}

/**
* @internal
*/
export function getQueryKeyInternal (
path: string,
input: unknown
): string {
return input === undefined ? path : `${path}-${hash(input || '')}`
}
32 changes: 10 additions & 22 deletions src/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
import { type CreateTRPCClientOptions, type inferRouterProxyClient, createTRPCProxyClient } from '@trpc/client'
import { type AnyRouter } from '@trpc/server'
import { createFlatProxy, createRecursiveProxy } from '@trpc/server/shared'
import { hash } from 'ohash'
import { type DecoratedProcedureRecord } from './types'
// @ts-expect-error: Nuxt auto-imports
import { getCurrentInstance, onScopeDispose, useAsyncData, unref, isRef } from '#imports'
import { getQueryKeyInternal, getQueryKey } from './getQueryKey'

/**
* Calculates the key used for `useAsyncData` call.
*
* @example
*
* ```ts
* import { getQueryKey } from 'trpc-nuxt/client'
*
* $client.todo.getTodo(1)
*
* const queryKey = getQueryKey('todo.getTodo', 1)
* ```
*/
export function getQueryKey (
path: string,
input: unknown
): string {
return input === undefined ? path : `${path}-${hash(input || '')}`
}
export { getQueryKey }

export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: string, client: inferRouterProxyClient<TRouter>) {
return createRecursiveProxy((opts) => {
Expand All @@ -40,6 +22,12 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: stri

const [input, otherOptions] = args

if (lastArg === '_def') {
return {
path: pathCopy,
};
}

if (['useQuery', 'useLazyQuery'].includes(lastArg)) {
const { trpc, queryKey: customQueryKey, ...asyncDataOptions } = otherOptions || {} as any

Expand All @@ -54,7 +42,7 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: stri
controller = typeof AbortController !== 'undefined' ? new AbortController() : {} as AbortController
}

const queryKey = customQueryKey || getQueryKey(path, unref(input))
const queryKey = customQueryKey || getQueryKeyInternal(path, unref(input))
const watch = isRef(input) ? [...(asyncDataOptions.watch || []), input] : asyncDataOptions.watch
const isLazy = lastArg === 'useLazyQuery' ? true : (asyncDataOptions.lazy || false)

Expand All @@ -67,7 +55,7 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: stri
lazy: isLazy
})
}

return (client as any)[path][lastArg](...args)
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type SubscriptionResolver<

type MaybeRef<T> = T | Ref<T>

type DecorateProcedure<
export type DecorateProcedure<
TProcedure extends AnyProcedure,
TRouter extends AnyRouter,
> = TProcedure extends AnyQueryProcedure
Expand Down

0 comments on commit fc2c7f9

Please sign in to comment.