lukeautry / tsoa

Build OpenAPI-compliant REST APIs using TypeScript and Node
MIT License
3.6k stars 504 forks source link

Using Prisma with TSOA #1704

Open wolffsteinn opened 1 month ago

wolffsteinn commented 1 month ago

Sorting

Expected Behavior

import { CoreDatabaseService } from './databaseService';
import type { admin_roles } from '@prisma/client; // ideally reads the type from prisma itself

export class CoreService {
  constructor(private coreDatabaseService: CoreDatabaseService) {}

  async getAdminRoles(): Promise<admin_roles[] | null> {
    try {
      const roles = await this.coreDatabaseService.admin_roles.findMany();
      console.log(roles);
      return roles;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
}

Current Behavior

import { CoreDatabaseService } from './databaseService';

// i have to recreate the types in an interface, which might be out of sync from prisma if multiple people are working on it
interface admin_roles {
  id: number,
  role_name: string
}

export class CoreService {
  constructor(private coreDatabaseService: CoreDatabaseService) {}

  async getAdminRoles(): Promise<admin_roles[] | null> {
    try {
      const roles = await this.coreDatabaseService.admin_roles.findMany();
      console.log(roles);
      return roles;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
}

An error is shown stating that tsoa is unable to reference the type admin_roles from prisma client

Generate routes error.
 GenerateMetadataError: No declarations found for referenced type admin_roles.
    at TypeResolver.getModelTypeDeclarations (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:871:62)
    at TypeResolver.calcRefTypeName (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:536:39)
    at TypeResolver.calcTypeReferenceTypeName (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:712:34)
    at TypeResolver.getReferenceType (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:721:35)
    at TypeResolver.resolveTypeReferenceNode (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:468:21)
    at TypeResolver.resolve (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:293:21)
    at TypeResolver.resolve (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:81:119)
    at TypeResolver.resolveTypeReferenceNode (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:458:93)
    at TypeResolver.resolve (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:293:21)
    at MethodGenerator.Generate (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/methodGenerator.js:62:78)

Possible Solution

allow tsoa's typeresolver to be able to read the prisma types that have been generated in the schema?

Steps to Reproduce

      1. 4.

Context (Environment)

Version of the library: 6.5.0 Version of NodeJS: 20.17.0

Note: i was using npm for this

Detailed Description

Breaking change?

github-actions[bot] commented 1 month ago

Hello there wolffsteinn 👋

Thank you for opening your very first issue in this project.

We will try to get back to you as soon as we can.👀

WoH commented 1 month ago

Is the declaration included in your tsc config?

yarn tsc --listFilesOnly

wolffsteinn commented 1 month ago

@WoH sorry, im not sure if these are the stuff that you are looking for? i just selected those that seem to be most likely the ones that we require for this discussion!

/Users/annabel/Work/node_modules/typescript/lib/lib.decorators.d.ts
/Users/annabel/Work/node_modules/typescript/lib/lib.decorators.legacy.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/deprecated.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/example.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/parameter.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/methods.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/tags.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/operationid.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/route.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/security.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/extension.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/middlewares.d.ts
/Users/annabel/Work/node_modules/@tsoa/runtime/dist/decorators/response.d.ts

this is my tsconfig for now

{
  "compilerOptions": {
    "outDir": "./dist",
    "module": "CommonJS",
    "target": "es2022",
    "baseUrl": "./",
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "allowSyntheticDefaultImports": true,
    "removeComments": true,
    "strict": true,
    "noImplicitAny": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "sourceMap": true,
    "strictPropertyInitialization": false,
    "sourceRoot": "/"
  },
  "include": ["src/**/*", "prisma/generated/core"],
  "exclude": ["node_modules", "**/dist/**"]
}

Note: I had to customize my prisma output because I am creating two separate database connections and hence, i wont be able to call @prisma/client for my types, and have to call prisma/generated/cores to get my types from there

Additional context, the admin_roles table has an id of bigint. Ive read from the issues that tsoa does not (and probably does not intend to) support bigint so i have tried to type it into a string but to no avail as well.

 type BigIntType = string; 

  async getAdminRole(): Promise<admin_roles[] | null> {
    try {
      const adminRoles = await this.coreDatabaseService.admin_roles.findMany();
      const response = adminRoles.map((role) => ({
        ...role,
        id: role.id.toString() as BigIntType,
      }));
      return response as admin_roles[] | null;
    } catch (error) {
      console.error(error);
      throw error;
    }
  }
WoH commented 1 month ago

As the error says, the file where the declaration is is probably not part of your files. The tsoa ones should not matter, but the file where admin_roles is declared should be

wolffsteinn commented 1 month ago

@WoH ah i think yeah i got nipped this prisma declaration issue in the bud, but facing a new error now which is:

Generate routes error.
 GenerateMetadataError: Unknown type: BigIntKeyword
At unknown position...
This was caused by '<unknown name>'
    at TypeResolver.resolve (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:292:90)
    at /Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:120:118
    at Array.reduce (<anonymous>)
    at TypeResolver.resolve (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:119:85)
    at TypeResolver.resolveTypeReferenceNode (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:458:93)
    at TypeResolver.resolve (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:293:21)
    at MethodGenerator.Generate (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/methodGenerator.js:62:78)
    at /Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/controllerGenerator.js:46:41
    at Array.map (<anonymous>)
    at ControllerGenerator.buildMethods (/Users/annabel/Work/rapidzpay-tsoa/node_modules/@tsoa/cli/dist/metadataGeneration/controllerGenerator.js:46:14)

i think now it cant read bigint?

WoH commented 4 weeks ago

Rather tsoa does not know how you'll serialize it in JSON