Search code examples
typescriptprisma

Display Prisma model using model name


I need to create a function that shows a Prisma model using the name of the model as a parameter. Every time the model name can change and TypeScript should automatically check if that Prisma model exists.

/* 
file schema.prisma models:

model User {
  id          Int      @id @default(autoincrement())
  name        String
  password    String
  job         String   @default("")
  location    String   @default("")
  phone       String   @default("")
  email       String
}

model Participant {
  id         Int       @id @default(autoincrement())
  userID     Int
  groupID    Int
}

*/

import { PrismaClient } from "@prisma/client";

function loadModel(modelName: /* string */) {
  const prisma = new PrismaClient();
  const Model = prisma[modelName]
}

loadModel("user")

Following code will return a error:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'PrismaClient<PrismaClientOptions, never, RejectOnNotFound | RejectPerOperation | undefined>'. No index signature with a parameter of type 'string' was found on type 'PrismaClient<PrismaClientOptions, never, RejectOnNotFound | RejectPerOperation | undefined>'.

After that error I tried to add to modelName parameter : keyof PrismaClient it worked, but when I tried adding something like Model.create({...}) - it returned following error:

Property 'create' does not exist on type '(<V extends "beforeExit">(eventType: V, callback: (event: V extends "query" ? QueryEvent : V extends "beforeExit" ? () => Promise : LogEvent) => void) => void) | ... 11 more ... | MessageDelegate<...>'. Property 'create' does not exist on type '<V extends "beforeExit">(eventType: V, callback: (event: V extends "query" ? QueryEvent : V extends "beforeExit" ? () => Promise : LogEvent) => void) => void'.

How could I fix this problem?


Solution

  • You get error because modelName could be any string, while it can only receive "user" or "participant" (according to schema.prisma model).

    So to get list of your model you can get it with Prisma type

    /* 
    file schema.prisma models:
    
    model User {
      id          Int      @id @default(autoincrement())
      name        String
      password    String
      job         String   @default("")
      location    String   @default("")
      phone       String   @default("")
      email       String
    }
    
    model Participant {
      id         Int       @id @default(autoincrement())
      userID     Int
      groupID    Int
    }
    
    */
    
    import { Prisma, PrismaClient } from "@prisma/client";
    
    type PrismaOption = PrismaClient<
      Prisma.PrismaClientOptions,
      never,
      Prisma.RejectOnNotFound | Prisma.RejectPerOperation | undefined
    >
    
    // this will return "user" | "participant"
    export type PrismaModel = keyof Omit<
      PrismaOption,
      | "$connect"
      | "$disconnect"
      | "$executeRaw"
      | "$executeRawUnsafe"
      | "$on"
      | "$queryRaw"
      | "$queryRawUnsafe"
      | "$transaction"
      | "$use"
    >
    
    function loadModel(modelName: PrismaModel) { // modelName type will be "user" | "participant"
      const prisma = new PrismaClient();
      return prisma[modelName]
    }
    
    loadModel("user")