Skip to content

Commit

Permalink
Implement query cancellation (#18)
Browse files Browse the repository at this point in the history
* feat: add query cancellation

* feat: add initialCursor to infinite queries

* docs: update README

* chore: bump version
  • Loading branch information
vishalbalaji committed Dec 16, 2023
1 parent 81ebe9a commit 481aa9b
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 32 deletions.
22 changes: 8 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,16 @@ Which can then be used in a component as such:
import { trpc } from "$lib/trpc/client";
const client = trpc();
const hello = client.greeting.createQuery("foo", { retry: false });
const foo = client.greeting.createQuery("foo", { retry: false });
</script>
<p>
{#if $hello.isLoading}
{#if $foo.isLoading}
Loading...
{:else if $hello.isError}
Error: {$hello.error.message}
{:else if $foo.isError}
Error: {$foo.error.message}
{:else}
{$hello.data}
{$foo.data}
{/if}
</p>
```
Expand Down Expand Up @@ -202,7 +202,7 @@ By default, these 3 procedures will pre-fetch the data required to pre-render th

These procedures can be used as such:

> **NOTE:** You can await the procedures first, but it is better to pass the promises directly as SvelteKit automatically resolves all these promises at the same time. [This excellent video by **Huntabyte**](https://www.youtube.com/watch?v=Ymk22rD8Lb4) explains this in detail.
> **NOTE:** [Gotta await top-level promises from SvelteKit v2](https://kit.svelte.dev/docs/migrating-to-sveltekit-2#top-level-promises-are-no-longer-awaited).
```typescript
// +page.ts
Expand All @@ -215,8 +215,8 @@ export const load = (async (event) => {
const client = trpc(event, queryClient);

return {
foo: client.greeting.createServerQuery('foo'),
queries: client.createServerQueries((t) =>
foo: await client.greeting.createServerQuery('foo'),
queries: await client.createServerQueries((t) =>
['bar', 'baz'].map((name) => t.greeting(name, { ssr: name !== 'baz' })), // pre-fetching disabled for the `baz` query.
),
};
Expand Down Expand Up @@ -257,12 +257,6 @@ Then, in the component:
<br />
{/each}
```

## Some Notes

* This wrapper only supports `tRPC v10` onward.
* This project was made purely for fun and not linked to official `tRPC` or `tanstack-query` development in any way. If any official adapters of this sort were to be released, this project would most likely be discontinued.

[npm-url]: https://npmjs.org/package/trpc-svelte-query-adapter
[npm-image]: https://img.shields.io/npm/v/trpc-svelte-query-adapter.svg
[license-url]: LICENSE
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "trpc-svelte-query-adapter",
"version": "2.2.0",
"version": "2.2.1",
"description": "A simple adapter to use `@tanstack/svelte-query` with trpc, similar to `@trpc/react-query`.",
"keywords": [
"trpc",
Expand Down
68 changes: 51 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,16 @@ interface CreateServerQueryOptions<TOutput, TError, TData>
ssr?: boolean
}

type TRPCQueryOpts = {
trpc: {
abortOnUnmount: boolean;
},
};

type CreateQueryProcedure<TInput, TOutput, TError> = {
[ProcedureNames.query]: <TData = TOutput>(input: TInput, opts?: CreateQueryOptions<TOutput, TError, TData>)
[ProcedureNames.query]: <TData = TOutput>(input: TInput, opts?: CreateQueryOptions<TOutput, TError, TData> & TRPCQueryOpts)
=> CreateQueryResult<TData, TError>,
[ProcedureNames.serverQuery]: <TData = TOutput>(input: TInput, opts?: CreateServerQueryOptions<TOutput, TError, TData>)
[ProcedureNames.serverQuery]: <TData = TOutput>(input: TInput, opts?: CreateServerQueryOptions<TOutput, TError, TData> & TRPCQueryOpts)
=> Promise<() => CreateQueryResult<TData, TError>>,
} & {}

Expand All @@ -209,11 +215,19 @@ interface CreateServerInfiniteQueryOptions<TOutput, TError, TData>
ssr?: boolean
}

export type ExtractCursorType<TInput> = TInput extends { cursor: any }
? TInput['cursor']
: unknown;

type InfiniteQueryOpts<TInput> = {
initialCursor?: ExtractCursorType<TInput>;
}

type CreateInfiniteQueryProcedure<TInput, TOutput, TError> = (TInput extends { cursor?: any }
? {
[ProcedureNames.infiniteQuery]: <TData = TOutput>(input: Omit<TInput, 'cursor'>, opts?: CreateInfiniteQueryOptions<TOutput, TError, TData>)
[ProcedureNames.infiniteQuery]: <TData = TOutput>(input: Omit<TInput, 'cursor'>, opts?: CreateInfiniteQueryOptions<TOutput, TError, TData> & InfiniteQueryOpts<TInput> & TRPCQueryOpts)
=> CreateInfiniteQueryResult<TData, TError>,
[ProcedureNames.serverInfiniteQuery]: <TData = TOutput>(input: Omit<TInput, 'cursor'>, opts?: CreateServerInfiniteQueryOptions<TOutput, TError, TData>)
[ProcedureNames.serverInfiniteQuery]: <TData = TOutput>(input: Omit<TInput, 'cursor'>, opts?: CreateServerInfiniteQueryOptions<TOutput, TError, TData> & InfiniteQueryOpts<TInput> & TRPCQueryOpts)
=> Promise<() => CreateInfiniteQueryResult<TData, TError>>,
}
: {}) & {}
Expand Down Expand Up @@ -306,7 +320,7 @@ const utilsProcedures: Record<PropertyKey,
return queryClient.prefetchInfiniteQuery({
...opts,
queryKey: getArrayQueryKey(path, input, 'infinite'),
queryFn: ({ pageParam }:{ pageParam: number }) => target.query({ ...input, cursor: pageParam }),
queryFn: ({ pageParam }: { pageParam: number }) => target.query({ ...input, cursor: pageParam }),
});
};
},
Expand Down Expand Up @@ -377,7 +391,7 @@ const utilsProcedures: Record<PropertyKey,
},
[UtilsProcedureNames.getData]: ({ queryClient, path }) => {
return (input?: any, filters?: any) => {
return queryClient.getQueryData( {
return queryClient.getQueryData({
...filters,
queryKey: getArrayQueryKey(path, input, 'query'),
});
Expand Down Expand Up @@ -415,29 +429,36 @@ const procedures: Record<PropertyKey,
queryClient: QueryClient,
queriesProxy: () => any,
utilsProxy: () => any
abortOnUnmount?: boolean,
}) => any>
= {
[ProcedureNames.queryKey]: ({ path }) => {
return (input: any, opts?: any) => getArrayQueryKey(path, input, opts);
},
[ProcedureNames.query]: ({ path, target }) => {
[ProcedureNames.query]: ({ path, target, abortOnUnmount }) => {
const targetFn = target.query;

return (input: any, opts?: any) => {
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
return createQuery({
...opts,
queryKey: getArrayQueryKey(path, input, 'query'),
queryFn: () => targetFn(input),
queryFn: ({ signal }) => targetFn(input, {
...(shouldAbortOnUnmount && { signal }),
}),
});
};
},
[ProcedureNames.serverQuery]: ({ path, target, queryClient }) => {
[ProcedureNames.serverQuery]: ({ path, target, queryClient, abortOnUnmount }) => {
const targetFn = target.query;

return async (input: any, opts?: any) => {
const query = {
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
const query: FetchQueryOptions = {
queryKey: getArrayQueryKey(path, input, 'query'),
queryFn: () => targetFn(input),
queryFn: ({ signal }) => targetFn(input, {
...(shouldAbortOnUnmount && { signal }),
}),
};

const cache = queryClient.getQueryCache().find({ queryKey: query.queryKey });
Expand All @@ -455,22 +476,33 @@ const procedures: Record<PropertyKey,
});
};
},
[ProcedureNames.infiniteQuery]: ({ path, target }) => {
[ProcedureNames.infiniteQuery]: ({ path, target, abortOnUnmount }) => {
return (input: any, opts?: any) => {
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
return createInfiniteQuery({
...opts,
queryKey: getArrayQueryKey(path, input, 'infinite'),
queryFn: ({ pageParam }: { pageParam: number }) => target.query({ ...input, cursor: pageParam }),
queryFn: ({ pageParam, signal }) => target.query({
...input,
cursor: pageParam ?? opts?.initialCursor,
...(shouldAbortOnUnmount && { signal }),

}),
});
};
},
[ProcedureNames.serverInfiniteQuery]: ({ path, target, queryClient }) => {
[ProcedureNames.serverInfiniteQuery]: ({ path, target, queryClient, abortOnUnmount }) => {
const targetFn = target.query;

return async (input: any, opts?: any) => {
const query = {
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
const query: Omit<FetchInfiniteQueryOptions, 'initialPageParam'> = {
queryKey: getArrayQueryKey(path, input, 'infinite'),
queryFn: ({ pageParam }: { pageParam: number }) => targetFn({ ...input, cursor: pageParam }),
queryFn: ({ pageParam, signal }) => targetFn({
...input,
cursor: pageParam ?? opts?.initialCursor,
...(shouldAbortOnUnmount && { signal }),
}),
};

const cache = queryClient.getQueryCache().find({ queryKey: query.queryKey });
Expand Down Expand Up @@ -611,7 +643,8 @@ type GetQueryKey<TInput = undefined> = TInput extends undefined
export function svelteQueryWrapper<TRouter extends AnyRouter>({
client,
queryClient,
}: { client: CreateTRPCProxyClient<TRouter>, queryClient?: QueryClient }) {
abortOnUnmount,
}: { client: CreateTRPCProxyClient<TRouter>, queryClient?: QueryClient, abortOnUnmount?: boolean }) {

type Client = typeof client;
type RouterError = TRPCClientErrorLike<TRouter>;
Expand Down Expand Up @@ -645,6 +678,7 @@ export function svelteQueryWrapper<TRouter extends AnyRouter>({
queryClient: qc,
queriesProxy: () => createQueriesProxy(client),
utilsProxy: () => createUtilsProxy(client, qc),
abortOnUnmount,
});
}
return this.nest(() => { });
Expand Down

0 comments on commit 481aa9b

Please sign in to comment.