Skip to content

Commit

Permalink
fix: optimize generated trpc typing and fix "select" issue (#972)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymc9 authored Jan 31, 2024
1 parent ec85058 commit c0d60a0
Show file tree
Hide file tree
Showing 33 changed files with 1,923 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:

strategy:
matrix:
node-version: [18.x]
node-version: [20.x]
prisma-version: [v4, v5]

steps:
Expand Down
7 changes: 6 additions & 1 deletion packages/plugins/swr/tests/swr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ ${sharedModel}
{
provider: 'postgresql',
pushDb: false,
extraDependencies: [`${origDir}/dist`, '[email protected]', '@types/[email protected]', 'swr@^2'],
extraDependencies: [
`${path.join(__dirname, '../dist')}`,
'[email protected]',
'@types/[email protected]',
'swr@^2',
],
compile: true,
}
);
Expand Down
86 changes: 15 additions & 71 deletions packages/plugins/trpc/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ function createAppRouter(
appRouter.addImportDeclarations([
{
namedImports: [
'unsetMarker',
'type AnyRouter',
'type AnyRootConfig',
'type CreateRouterInner',
Expand All @@ -111,15 +112,12 @@ function createAppRouter(
moduleSpecifier: '@trpc/server',
},
{
namedImports: ['type PrismaClient', 'type Prisma'],
namedImports: ['type PrismaClient'],
moduleSpecifier: prismaImport,
},
{ defaultImport: 'z', moduleSpecifier: 'zod', isTypeOnly: true },
]);

appRouter.addStatements(`
${/** to be used by the other routers without making a bigger commit */ ''}
export { PrismaClient } from '${prismaImport}';
export type BaseConfig = AnyRootConfig;
Expand All @@ -129,56 +127,11 @@ function createAppRouter(
procedures: ProcRouterRecord
) => CreateRouterInner<Config, ProcRouterRecord>;
${
/** this is needed in order to prevent type errors between a procedure and a middleware-extended procedure */ ''
}
export type ProcBuilder<Config extends BaseConfig> = ProcedureBuilder<{
_config: Config;
_ctx_out: Config['$types']['ctx'];
_input_in: any;
_input_out: any;
_output_in: any;
_output_out: any;
_meta: Config['$types']['meta'];
}>;
type ExtractParamsFromProcBuilder<Builder extends ProcedureBuilder<any>> =
Builder extends ProcedureBuilder<infer P> ? P : never;
type FromPromise<P extends Promise<any>> = P extends Promise<infer T>
? T
: never;
${/** workaround to avoid creating 'typeof unsetMarker & object' on the procedure output */ ''}
type Join<A, B> = A extends symbol ? B : A & B;
${
/** you can name it whatever you want, but this is to make sure that
the types from the middleware and the procedure are correctly merged */ ''
}
export type ProcReturns<
PType extends ProcedureType,
PBuilder extends ProcBuilder<BaseConfig>,
ZType extends z.ZodType,
PPromise extends Prisma.PrismaPromise<any>
> = Procedure<
PType,
ProcedureParams<
ExtractParamsFromProcBuilder<PBuilder>["_config"],
ExtractParamsFromProcBuilder<PBuilder>["_ctx_out"],
Join<ExtractParamsFromProcBuilder<PBuilder>["_input_in"], z.infer<ZType>>,
Join<ExtractParamsFromProcBuilder<PBuilder>["_input_out"], z.infer<ZType>>,
Join<
ExtractParamsFromProcBuilder<PBuilder>["_output_in"],
FromPromise<PPromise>
>,
Join<
ExtractParamsFromProcBuilder<PBuilder>["_output_out"],
FromPromise<PPromise>
>,
ExtractParamsFromProcBuilder<PBuilder>["_meta"]
>
>;
export type UnsetMarker = typeof unsetMarker;
export type ProcBuilder<Config extends BaseConfig> = ProcedureBuilder<
ProcedureParams<Config, any, any, any, UnsetMarker, UnsetMarker, any>
>;
export function db(ctx: any) {
if (!ctx.prisma) {
Expand All @@ -193,10 +146,10 @@ function createAppRouter(

appRouter
.addFunction({
name: 'createRouter<Router extends RouterFactory<BaseConfig>, Proc extends ProcBuilder<BaseConfig>>',
name: 'createRouter<Config extends BaseConfig>',
parameters: [
{ name: 'router', type: 'Router' },
{ name: 'procedure', type: 'Proc' },
{ name: 'router', type: 'RouterFactory<Config>' },
{ name: 'procedure', type: 'ProcBuilder<Config>' },
],
isExported: true,
})
Expand Down Expand Up @@ -225,9 +178,7 @@ function createAppRouter(
moduleSpecifier: `./${model}.router`,
});

writer.writeLine(
`${lowerCaseFirst(model)}: create${model}Router<Router, Proc>(router, procedure),`
);
writer.writeLine(`${lowerCaseFirst(model)}: create${model}Router(router, procedure),`);
}
});
writer.write(');');
Expand Down Expand Up @@ -299,14 +250,7 @@ function generateModelCreateRouter(

modelRouter.addImportDeclarations([
{
namedImports: [
'type RouterFactory',
'type ProcBuilder',
'type BaseConfig',
'type ProcReturns',
'type PrismaClient',
'db',
],
namedImports: ['type RouterFactory', 'type ProcBuilder', 'type BaseConfig', 'db'],
moduleSpecifier: '.',
},
]);
Expand All @@ -318,10 +262,10 @@ function generateModelCreateRouter(
}

const createRouterFunc = modelRouter.addFunction({
name: 'createRouter<Router extends RouterFactory<BaseConfig>, Proc extends ProcBuilder<BaseConfig>>',
name: 'createRouter<Config extends BaseConfig>',
parameters: [
{ name: 'router', type: 'Router' },
{ name: 'procedure', type: 'Proc' },
{ name: 'router', type: 'RouterFactory<Config>' },
{ name: 'procedure', type: 'ProcBuilder<Config>' },
],
isExported: true,
isDefaultExport: true,
Expand Down
24 changes: 7 additions & 17 deletions packages/plugins/trpc/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,14 @@ export function generateProcedure(
writer.write(`
${opType}: procedure.input(${typeName}).query(({ctx, input}) => checkRead(db(ctx).${lowerCaseFirst(
modelName
)}.${prismaMethod}(input as any))) as ProcReturns<
"query",
Proc,
(typeof $Schema.${upperCaseFirst(modelName)}InputSchema)["${opType.replace('OrThrow', '')}"],
ReturnType<PrismaClient["${lowerCaseFirst(modelName)}"]["${opType}"]>
>,
)}.${prismaMethod}(input as any))),
`);
} else if (procType === 'mutation') {
// the cast "as any" is to circumvent a TS compiler misfired error in certain cases
writer.write(`
${opType}: procedure.input(${typeName}).mutation(async ({ctx, input}) => checkMutate(db(ctx).${lowerCaseFirst(
modelName
)}.${prismaMethod}(input as any))) as ProcReturns<
"mutation",
Proc,
(typeof $Schema.${upperCaseFirst(modelName)}InputSchema)["${opType.replace('OrThrow', '')}"],
ReturnType<PrismaClient["${lowerCaseFirst(modelName)}"]["${opType}"]>
>,
)}.${prismaMethod}(input as any))),
`);
}
}
Expand Down Expand Up @@ -203,18 +193,18 @@ export function generateRouterTyping(writer: CodeBlockWriter, opType: string, mo
writer.block(() => {
if (procType === 'query') {
writer.writeLine(`
useQuery: <T extends ${genericBase}>(
useQuery: <T extends ${genericBase}, TData = ${resultType}>(
input: ${argsType},
opts?: UseTRPCQueryOptions<string, T, ${resultType}, ${resultType}, Error>
opts?: UseTRPCQueryOptions<string, T, ${resultType}, TData, Error>
) => UseTRPCQueryResult<
${resultType},
TData,
${errorType}
>;
useInfiniteQuery: <T extends ${genericBase}>(
input: Omit<${argsType}, 'cursor'>,
opts?: UseTRPCInfiniteQueryOptions<string, T, ${resultType}, Error>
) => UseTRPCInfiniteQueryResult<
${resultType},
${resultType},
${errorType}
>;
`);
Expand All @@ -223,7 +213,7 @@ export function generateRouterTyping(writer: CodeBlockWriter, opType: string, mo
useMutation: <T extends ${genericBase}>(opts?: UseTRPCMutationOptions<
${genericBase},
${errorType},
Prisma.${upperCaseFirst(modelName)}GetPayload<null>,
${resultType},
Context
>,) =>
Omit<UseTRPCMutationResult<${resultType}, ${errorType}, ${argsType}, Context>, 'mutateAsync'> & {
Expand Down
37 changes: 37 additions & 0 deletions packages/plugins/trpc/tests/projects/t3-trpc-v10/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/** @type {import("eslint").Linter.Config} */
const config = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
plugins: ["@typescript-eslint"],
extends: [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended-type-checked",
"plugin:@typescript-eslint/stylistic-type-checked",
],
rules: {
// These opinionated rules are enabled in stylistic-type-checked above.
// Feel free to reconfigure them to your own preference.
"@typescript-eslint/array-type": "off",
"@typescript-eslint/consistent-type-definitions": "off",

"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"@typescript-eslint/require-await": "off",
"@typescript-eslint/no-misused-promises": [
"error",
{
checksVoidReturn: { attributes: false },
},
],
},
};

module.exports = config;
43 changes: 43 additions & 0 deletions packages/plugins/trpc/tests/projects/t3-trpc-v10/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# database
/prisma/db.sqlite
/prisma/db.sqlite-journal

# next.js
/.next/
/out/
next-env.d.ts

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
.env
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
package-lock.json
28 changes: 28 additions & 0 deletions packages/plugins/trpc/tests/projects/t3-trpc-v10/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Create T3 App

This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.

## What's next? How do I make an app with this?

We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.

If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.

- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)

## Learn More

To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:

- [Documentation](https://create.t3.gg/)
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials

You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!

## How do I deploy this?

Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.
22 changes: 22 additions & 0 deletions packages/plugins/trpc/tests/projects/t3-trpc-v10/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
await import("./src/env.js");

/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,

/**
* If you are using `appDir` then you must comment the below `i18n` config out.
*
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};

export default config;
Loading

0 comments on commit c0d60a0

Please sign in to comment.