Skip to content

Commit

Permalink
Client side inputs for server queries (#37)
Browse files Browse the repository at this point in the history
* feat: allow client-side inputs for server queries

* docs: update README

* feat: add client-side inputs for createServerQueries

* bump version

* Update README
  • Loading branch information
vishalbalaji committed May 13, 2024
1 parent dc2874d commit bcc57a7
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 24 deletions.
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export function trpc(queryClient?: QueryClient) {
Which can then be used in a component as such:

```svelte
<!-- routes/+page.ts -->
<!-- routes/+page.svelte -->
<script lang="ts">
import { trpc } from "$lib/trpc/client";
Expand Down Expand Up @@ -257,6 +257,61 @@ Then, in the component:
<br />
{/each}
```

You can also optionally pass new inputs to the queries and infinite queries from the client side(see [#34](/../../issues/34)) like so:

```svelte
<script lang="ts">
import { page } from "$app/stores";
import type { PageData } from "./$types";
export let data: PageData;
let name = 'foo';
let newNames: string[] = [];
$: foo = data.foo(name); // `$` label to make the query reactive to the input
// You can also access the default input if you pass in a callback as the new input:
// $: foo = data.foo((old) => old + name);
$: queries = data.queries((t, old) => [...old, ...newNames.map((name) => t.greeting(name))]);
</script>
{#if $foo.isPending}
Loading...
{:else if $foo.isError}
{$foo.error}
{:else if $foo.data}
{$foo.data}
{/if}
<br />
<input bind:value={name} />
<br /><br />
{#each $queries as query}
{#if query.isPending}
Loading...
{:else if query.isError}
{query.error.message}
{:else if query.data}
{query.data}
{/if}
<br />
{/each}
<form on:submit|preventDefault={(e) => {
const data = new FormData(e.currentTarget).get('name');
if (typeof data === 'string') newNames.push(data);
newNames = newNames;
}}>
<input name="name" />
<button type="submit">Submit</button>
</form>
```

[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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "trpc-svelte-query-adapter",
"version": "2.2.7",
"version": "2.3.0",
"description": "A simple adapter to use `@tanstack/svelte-query` with trpc, similar to `@trpc/react-query`.",
"keywords": [
"trpc",
Expand Down Expand Up @@ -30,7 +30,8 @@
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc"
"build": "tsc",
"lint": "eslint src/**/* --ext .js --ext .ts"
},
"dependencies": {
"proxy-deep": "^3.1.1"
Expand Down
80 changes: 59 additions & 21 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ type CreateServerQueriesRecord<TClient, TError> = { [K in keyof TClient]:

type CreateServerQueries<TClient, TError> = <TOpts extends CreateQueryOptionsForCreateQueries<any, any, any>[]>(
queriesCallback: (t: CreateServerQueriesRecord<OnlyQueries<TClient>, TError>) => readonly [...TOpts]
) => Promise<() => CreateQueriesResult<TOpts>>
) => Promise<(queriesCallback?: (t: CreateQueriesRecord<OnlyQueries<TClient>, TError>, old: readonly [...TOpts]) => readonly [...TOpts]) => CreateQueriesResult<TOpts>>

// Procedures
const ProcedureNames = {
Expand Down Expand Up @@ -204,7 +204,7 @@ type CreateQueryProcedure<TInput, TOutput, TError> = {
[ProcedureNames.query]: <TData = TOutput>(input: TInput, opts?: CreateTRPCQueryOptions<TOutput, TError, TData> & TRPCQueryOpts)
=> CreateQueryResult<TData, TError>,
[ProcedureNames.serverQuery]: <TData = TOutput>(input: TInput, opts?: CreateTRPCServerQueryOptions<TOutput, TError, TData> & TRPCQueryOpts)
=> Promise<() => CreateQueryResult<TData, TError>>,
=> Promise<(input?: TInput | ((old: TInput) => TInput)) => CreateQueryResult<TData, TError>>,
} & {}

type CreateTRPCInfiniteQueryOptions<TOutput, TError, TData> = Omit<CreateInfiniteQueryOptions<TOutput, TError, TData>, 'queryKey' | 'queryFn'>;
Expand All @@ -225,7 +225,7 @@ type CreateInfiniteQueryProcedure<TInput, TOutput, TError> = (TInput extends { c
[ProcedureNames.infiniteQuery]: <TData = TOutput>(input: Omit<TInput, 'cursor'>, opts?: CreateTRPCInfiniteQueryOptions<TOutput, TError, TData> & InfiniteQueryOpts<TInput> & TRPCQueryOpts)
=> CreateInfiniteQueryResult<InfiniteData<TData>, TError>,
[ProcedureNames.serverInfiniteQuery]: <TData = TOutput>(input: Omit<TInput, 'cursor'>, opts?: CreateTRPCServerInfiniteQueryOptions<TOutput, TError, TData> & InfiniteQueryOpts<TInput> & TRPCQueryOpts)
=> Promise<() => CreateInfiniteQueryResult<InfiniteData<TData>, TError>>,
=> Promise<(input?: TInput | ((old: TInput) => TInput)) => CreateInfiniteQueryResult<InfiniteData<TData>, TError>>,
}
: {}) & {}

Expand Down Expand Up @@ -458,13 +458,28 @@ const procedures: Record<PropertyKey,
await queryClient.prefetchQuery(query);
}

return () => createQuery({
...opts,
...query,
...(cacheNotFound ?
{ refetchOnMount: opts?.refetchOnMount ?? false } : {}
),
});
return (newInput?: any) => {
let newQuery = query;

if (newInput) {
let i = newInput;
if (typeof newInput === 'function') i = newInput(input);
newQuery = {
queryKey: getArrayQueryKey(path, i, 'query'),
queryFn: ({ signal }) => targetFn(i, {
...(shouldAbortOnUnmount && { signal }),
}),
};
}

return createQuery({
...opts,
...newQuery,
...(cacheNotFound ?
{ refetchOnMount: opts?.refetchOnMount ?? false } : {}
),
});
};
};
},
[ProcedureNames.infiniteQuery]: ({ path, target, abortOnUnmount }) => {
Expand Down Expand Up @@ -502,13 +517,30 @@ const procedures: Record<PropertyKey,
await queryClient.prefetchInfiniteQuery(query as any);
}

return () => createInfiniteQuery({
...opts,
...query,
...(cacheNotFound ?
{ refetchOnMount: opts?.refetchOnMount ?? false } : {}
),
});
return (newInput?: any) => {
let newQuery = query;

if (newInput) {
let i = newInput;
if (typeof newInput === 'function') i = newInput(input);
newQuery = {
queryKey: getArrayQueryKey(path, i, 'infinite'),
queryFn: ({ pageParam, signal }) => targetFn({
...i,
cursor: pageParam ?? opts?.initialCursor,
...(shouldAbortOnUnmount && { signal }),
}),
};
}

return createInfiniteQuery({
...opts,
...newQuery,
...(cacheNotFound ?
{ refetchOnMount: opts?.refetchOnMount ?? false } : {}
),
});
};
};
},
[ProcedureNames.mutate]: ({ path, target }) => {
Expand Down Expand Up @@ -556,7 +588,7 @@ const procedures: Record<PropertyKey,
const proxy = queriesProxy();

return async (input: (...args: any[]) => any) => {
const queryKeys = await Promise.all(
const queries = await Promise.all(
input(proxy).map(async (query: any) => {
const cache = queryClient.getQueryCache().find(query.queryKey);
const cacheNotFound = !cache?.state?.data;
Expand All @@ -573,7 +605,12 @@ const procedures: Record<PropertyKey,
};
})
);
return () => createQueries({ queries: queryKeys });

return (newInput?: (...args: any[]) => any) => {
let newQueries = queries;
if (newInput) newQueries = newInput(proxy, queries);
return createQueries({ queries: newQueries });
};
};
},
[ProcedureNames.utils]: ({ path, utilsProxy }) => {
Expand Down Expand Up @@ -674,6 +711,7 @@ export function svelteQueryWrapper<TRouter extends AnyRouter>({
}
return this.nest(() => { });
},
}
);
});
}


0 comments on commit bcc57a7

Please sign in to comment.