Skip to content
This repository has been archived by the owner on Dec 19, 2022. It is now read-only.

[RFC] Chainable resolvers #33

Merged
merged 25 commits into from
Apr 11, 2022
8 changes: 2 additions & 6 deletions .big/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@ import type { appRouter } from './server/routers/_app';
const client = createClient<typeof appRouter>();

async function main() {
const result = await client.query.r0q0({ hello: 'world' });
const result = await client.query.r0q0({ input: { hello: 'world' } });

if (result.ok) {
console.log(result.data);
} else {
console.log(result.error.code);
}
console.log(result);
}

main();
13 changes: 6 additions & 7 deletions scripts/generate-big-f-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,22 @@ for (let routerIndex = 0; routerIndex < NUM_ROUTERS; routerIndex++) {
routerFile.push(
'\n' +
`
r${routerIndex}q${procIndex}: trpc.resolver(
trpc.zod(
r${routerIndex}q${procIndex}: trpc.procedure
.input(
z.object({
hello: z.string(),
lengthOf: z
.string()
.transform((s) => s.length)
.optional()
.default(''),
}),
),
(params) => {
})
)
.resolve((params) => {
return {
input: params.input,
}
}
),
}),
`.trim(),
);
}
Expand Down
12 changes: 4 additions & 8 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ const client = createClient<typeof appRouter>();
async function main() {
// you can CMD+click `postAll` / `postById` here
const greeting = await client.query.postList();
const byId = await client.query.postById({ id: '1' });
const byId = await client.query.postById({
input: { id: '1' },
});

if (byId.ok) {
console.log('data', byId.data);
} else {
console.log(byId.error.code);
}

console.log({ greeting, byId });
console.log('data', { greeting, byId });
}

main();
129 changes: 71 additions & 58 deletions src/server.test.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,90 @@
import { expectTypeOf } from 'expect-type';
import { z } from 'zod';
import { appRouter } from './server';
import { inferProcedure, initTRPC } from './trpc/server';

///////////// this below are just tests that the type checking is doing it's thing right ////////////
async function main() {
{
// query 'whoami'
const result = await appRouter.queries['viewerWhoami']();
if (result.error) {
expectTypeOf<typeof result['error']>().toMatchTypeOf<
| {
code: 'UNAUTHORIZED';
}
| {
code: 'BAD_REQUEST';
zod: z.ZodFormattedError<{
lengthOf?: string | undefined;
hello: string;
}>;
}
>();
}
const output = await appRouter.queries.viewerWhoAmi();
console.log({ output });
expectTypeOf(output).toBeString();

// should work
await appRouter.queries.viewerWhoAmi({});
await appRouter.queries.viewerWhoAmi({
input: undefined,
});
}
{
// if you hover result we can see that we can infer both the result and every possible expected error
const result = await appRouter.queries.greeting({ hello: 'there' });
if ('error' in result && result.error) {
if ('zod' in result.error) {
// zod error inferred - useful for forms w/o libs
console.log(result.error.zod.hello?._errors);
}
} else {
console.log(result);
}

// some type testing below
type MyProcedure = inferProcedure<typeof appRouter['queries']['greeting']>;

expectTypeOf<MyProcedure['ctx']>().toMatchTypeOf<{
user?: { id: string };
}>();

expectTypeOf<MyProcedure['data']>().toMatchTypeOf<{
greeting: string;
}>();

expectTypeOf<MyProcedure['_input_in']>().toMatchTypeOf<{
hello: string;
lengthOf?: string;
}>();
expectTypeOf<MyProcedure['_input_out']>().toMatchTypeOf<{
hello: string;
lengthOf: number;
}>();
const output = await appRouter.mutations.updateToken({ input: 'asd' });
expectTypeOf(output).toMatchTypeOf<string>();
}

{
// no leaky
const trpc = initTRPC();
trpc.router({
queries: {
test: trpc.resolver(() => {
return 'ok';
}),
const output = await appRouter.mutations.editOrg({
input: {
organizationId: '123',
data: {
name: 'asd',
},
},
// @ts-expect-error should error
doesNotExist: {},
});
expectTypeOf(output).toMatchTypeOf<{
name?: string;
id: string;
}>();
}
{
const result = await appRouter.mutations['fireAndForget']('hey');
console.log(result);
const output = await appRouter.mutations.updateToken({ input: 'hey' });

expectTypeOf(output).toMatchTypeOf<'ok'>();
}

{
// if you hover result we can see that we can infer both the result and every possible expected error
// const result = await appRouter.queries.greeting({ hello: 'there' });
// if ('error' in result && result.error) {
// if ('zod' in result.error) {
// // zod error inferred - useful for forms w/o libs
// console.log(result.error.zod.hello?._errors);
// }
// } else {
// console.log(result);
// }
// // some type testing below
// type MyProcedure = inferProcedure<typeof appRouter['queries']['greeting']>;
// expectTypeOf<MyProcedure['ctx']>().toMatchTypeOf<{
// user?: { id: string };
// }>();
// expectTypeOf<MyProcedure['data']>().toMatchTypeOf<{
// greeting: string;
// }>();
// expectTypeOf<MyProcedure['_input_in']>().toMatchTypeOf<{
// hello: string;
// lengthOf?: string;
// }>();
// expectTypeOf<MyProcedure['_input_out']>().toMatchTypeOf<{
// hello: string;
// lengthOf: number;
// }>();
}
// {
// // no leaky
// const trpc = initTRPC();
// trpc.router({
// queries: {
// test: trpc.resolver(() => {
// return 'ok';
// }),
// },
// // @ts-expect-error should error
// doesNotExist: {},
// });
// }
// {
// const result = await appRouter.mutations['fireAndForget']('hey');
// console.log(result);
// }
}

main();
Loading