Giter Club home page Giter Club logo

prisma-class-generator's Introduction

Prisma Class Generator

Prisma

Prisma is Database ORM Library for Node.js, Typescript.

Prisma basically generate each models type definition defined in schema.prisma. Therefore, it does not require additional entry classes or repository layers.

This is Prisma's basic way of doing things, and I love this approach.

However, there are limitations because of these characteristics. A typical example is NestJS. In order to use @nestjs/swagger, the entity must be defined as class.

So I created a simple tool that generates a typescript file based on schema.prisma. The generated Classes are formatted with prettier, using the user's prettier config file if present. This will reduce the effort to define classes directly while using the same single source of truth (schema.prisma)

The Prisma JS Client returns objects that does not contain the model's relational fields. The Generator can create two separate files per model, one that matches the Prisma Js Client's interfaces, and one that contains only the relational fields. You can set the separateRelationFields option to true if you want to generate two separate classes for each model. The default value is false.

NestJS

NestJS is a framework for building efficient, scalable Node.js server-side applications.

and also, this is one of the frameworks with class and decorator as the basic structure.

Let's think about it like this: If the NestJS model is defined as class as below, it will be easier to apply swagger, TypeGraphQL, etc. through decorator.

And if the schema changes, redefine and create accordingly so that the schema and class syncs.

Using this library, it becomes possible.

export class Company {
	@ApiProperty({ type: Number }) // swagger
	@Field((type) => Int) // TypeGraphQL
	id: number

	@ApiProperty({ type: String }) // swagger
	name: string

	@ApiProperty({ type: Boolean }) // swagger
	isUse: boolean
}

If you set the separateRelationFields option to true and generate separate relational classes, you can compose a class from the two, only contanining the included relations. This example below is using methods from the @nestjs/swagger package. This example creates a class with all of the properties of the Product class and the category relational property from the generated relational class.

import { IntersectionType, PickType } from '@nestjs/swagger'
import { Product } from './product'
import { ProductRelations } from './product_relations'

export class ProductDto extends IntersectionType(
	Product,
	PickType(ProductRelations, ['category'] as const),
) {}

Usage

  1. Install

    npm install prisma-class-generator
    yarn add prisma-class-generator
  2. Define Generator in schema.prisma

    generator prismaClassGenerator {
        provider = "prisma-class-generator"
    }
  3. ๐Ÿ˜Ž done! Let's check out generated files.

    if this models were defined in your prisma.schema file,

    model Product {
      id            Int         @id
      title         String      @db.VarChar(255)
      desc          String      @db.VarChar(1024)
      images        Json        @db.Json
      isShown       Boolean?    @default(false)
      stock         Int?        @default(0)
      type          ProductType
      averageRating Float?
      categoryId    Int
      companyId     Int
      category      Category    @relation(fields: [categoryId], references: [id])
      company       Company     @relation(fields: [companyId], references: [id])
      createdAt     DateTime    @default(now()) @db.Timestamp(6)
      updatedAt     DateTime    @updatedAt @db.Timestamp(6)
    }
    
    model Category {
      id       Int       @id
      products Product[]
    }
    
    model Company {
      id          Int       @id
      name        String
      totalIncome BigInt
      lat         Decimal
      lng         Decimal
      by          Bytes
      products    Product[]
    }
    

    then this class is generated in <PROJECT_PATH>/src/_gen/prisma-class.

    ( The generating path can be customized through output option. )

    // category.ts
    import { Product } from './product'
    import { ApiProperty } from '@nestjs/swagger'
    
    export class Category {
    	@ApiProperty({ type: Number })
    	id: number
    
    	@ApiProperty({ isArray: true, type: () => Product })
    	products: Product
    }
    // company.ts
    import { Product } from './product'
    import { ApiProperty } from '@nestjs/swagger'
    
    export class Company {
    	@ApiProperty({ type: Number })
    	id: number
    
    	@ApiProperty({ type: String })
    	name: string
    
    	@ApiProperty({ type: Bigint })
    	totalIncome: bigint
    
    	@ApiProperty({ type: Number })
    	lat: number
    
    	@ApiProperty({ type: Number })
    	lng: number
    
    	@ApiProperty({ type: Buffer })
    	by: Buffer
    
    	@ApiProperty({ isArray: true, type: () => Product })
    	products: Product
    }
    // product.ts
    import { Category } from './category'
    import { Company } from './company'
    import { ProductType } from '@prisma/client'
    import { ApiProperty } from '@nestjs/swagger'
    
    export class Product {
    	@ApiProperty({ type: Number })
    	id: number
    
    	@ApiProperty({ type: String })
    	title: string
    
    	@ApiProperty({ type: String })
    	desc: string
    
    	@ApiProperty()
    	images: any
    
    	@ApiProperty({ type: Boolean })
    	isShown: boolean
    
    	@ApiProperty({ type: Number })
    	stock: number
    
    	@ApiProperty({ enum: ProductType, enumName: 'ProductType' })
    	type: ProductType
    
    	@ApiProperty({ type: Number })
    	averageRating: number
    
    	@ApiProperty({ type: Number })
    	categoryId: number
    
    	@ApiProperty({ type: Number })
    	companyId: number
    
    	@ApiProperty({ type: () => Category })
    	category: Category
    
    	@ApiProperty({ type: () => Company })
    	company: Company
    
    	@ApiProperty({ type: Date })
    	createdAt: Date
    
    	@ApiProperty({ type: Date })
    	updatedAt: Date
    }
    // index.ts
    import { Product as _Product } from './product'
    import { Category as _Category } from './category'
    import { Company as _Company } from './company'
    
    export namespace PrismaModel {
    	export class Product extends _Product {}
    	export class Category extends _Category {}
    	export class Company extends _Company {}
    
    	export const extraModels = [Product, Category, Company]
    }

    The reason why classes were grouped into the 'PrismaModel' namespace and distributed in the index.ts file.

    1. First, generated classes can overlap with the model types generated by Prisma, causing confusion.
    2. when using Swagger in Nest.JS, you can use this array data in Bootstrap code to scan classes into @nestjs/swagger without having to list them.

    There is a reference code for this below.

    // main.ts in Nest.JS application
    import { PrismaModel } from './_gen/prisma-class'
    
    const document = SwaggerModule.createDocument(app, options, {
    	extraModels: [...PrismaModel.extraModels],
    })

    You can also disable it through the makeIndexFile option.

Supported options

  • dryRun
    • Decide whether to write file or just print result. default value is true
      • if you finished check result via terminal, then you should this options to false
  • output
    • sets output path. default is '../src/_gen/prisma-class'
  • useSwagger
    • generates swggger decorator. default value is true
  • makeIndexFile
    • makes index file, default value is true
  • separateRelationFields
    • puts relational fields into different file for each model. This way the class will match the object returned by a Prisma query, default value is false
  • clientImportPath
    • set prisma client import path manually, default value is @prisma/client
  • useNonNullableAssertions
    • Apply a ! after non-optional class fields to avoid strict mode warnings (Property has no initializer and is not definitely assigned in the constructor.)
  • preserveDefaultNullable
    • Determines how null fields are handled. When set to false (default), it turns all null fields to undefined. Otherwise, it follows Prisma generation and adds null to the type.

How it works?

Prima internally defines metadata as a dmmf object.

prisma-class-generator can automate class definition using this dmmf.

It is defined as an additional generator in the schema.prisma file and will operate in the prisma generate process.

Feature

  • generate Classes from prisma model definition
  • Support Basic Type and Relation
  • Support option to generate Swagger Decorator
  • Format generated Classes with prettier, using the user's prettier config file if present

Future Plan

  • Considers all class-based things that are not limited to Nest.JS
  • Support all types in prisma.schema
  • Support TypeGraphQL
  • Support DTO
  • Support custom path, case or name per each model

FAQ

1. Is it CRUD Generator?

No. It will not provide functions such as "nestjs CRUD generate". I think it is outside the scope of this library. Instead, it will only serve as a bridge connecting the Prisma model and (entity)class.

It will focus on defining classes and then give the developer responsibility on how to use them.

This is because if too much is provided, the library becomes less adaptable accordingly.

2. Is only works with NestJS?

No, but of course, it goes well with NestJS. I'm also planning to support the library related to NestJS.

But even if you don't use NestJS, this library will be useful for you if you use class decorator based on reflect-metadata to develop web services.

prisma-class-generator's People

Contributors

ashenm avatar bennet-esyoil avatar dvmoomoodv avatar etnol avatar jad31 avatar jannis6023 avatar janpio avatar joao-moonward avatar kimjbstar avatar nmate980829 avatar othmanemadrhino avatar rtroberts avatar strlns avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

prisma-class-generator's Issues

Cannot access 'User' before initialization

I got Cannot access 'User' before initialization because of a relation? Circular import, or what?
A relation is pretty basic in sql, how to solve this?

schema.prisma:

generator client {
  provider = "prisma-client-js"
}

generator prismaClassGenerator {
  provider = "prisma-class-generator"
  output   = "../src/_gen/prisma-class"
  dryRun   = "false"
  // separateRelationFields = "false"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

Generated output:

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { User } from './user';

export class Post {
	@ApiProperty({ type: Number })
	id: number;

	@ApiProperty({ type: String })
	title: string;

	@ApiPropertyOptional({ type: String })
	content?: string;

	@ApiPropertyOptional({ type: Boolean })
	published?: boolean;

	@ApiPropertyOptional({ type: () => User })
	author?: User;

	@ApiPropertyOptional({ type: Number })
	authorId?: number;
}

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Post } from './post';

export class User {
	@ApiProperty({ type: Number })
	id: number;

	@ApiProperty({ type: String })
	email: string;

	@ApiPropertyOptional({ type: String })
	name?: string;

	@ApiProperty({ isArray: true, type: () => Post })
	posts: Post[];
}

Error: spawn prisma-class-generator ENOENT

Expected Behavior

Actual Behavior

Steps to Reproduce the Problem

1.npx prisma generate
Error: spawn prisma-class-generator ENOENT

Specificatios

prisma : 5.14.0
@prisma/client : 5.14.0
Computed binaryTarget : windows
Operating System : win32
Architecture : x64
Node.js : v18.18.2

No Files Generated

Expected Behavior

class files generated to "./../src/backplane/generated"

Actual Behavior

Classes generated but only printed in standard output, so I had to manually create the class files via copy and paste.

Steps to Reproduce the Problem

  1. Install the generator
  2. Run "npx prisma generate"

Specifications

  • Version: latest
  • Prisma Version: lastest
  • Platform: MacOS Ventura 13.4.1

Fails to generate class with default Date

Expected Behavior

@ApiProperty({type: Date})
 metadataLastCheckedAt: Date = new Date(2000-01-01T01:00:00+00:00);

Actual Behavior

SyntaxError: ';' expected. (16:42)
  14 | 
  15 |  @ApiProperty({type: Date})
> 16 |  metadataLastCheckedAt: Date = 2000-01-01T01:00:00+00:00
     |                                          ^

Steps to Reproduce the Problem

  1. Create a Prisma schema with a default date, for example
model App {
  id        Int       @id @default(autoincrement())
  metadataLastCheckedAt        DateTime              @default("2000-01-01T01:00:00.00Z")
}
  1. Run prisma generate
  2. See error

Specifications

  • Version: 0.2.6
  • Prisma Version: 4.14.0
  • Platform: ARM

Relational models: class names are incorrect.

Expected Behavior

import { License_types } from './license_types'
import { Media_type } from '@prisma/client'

export class Media {
	type?: Media_type = Media_type.other

	name?: string = undefined

	url?: string = undefined

	license_types: License_types[] = undefined
}

Actual Behavior

import { LicenseTypes } from './license_types'
import { Media_type } from '@prisma/client'

export class Media {
	type?: Media_type = Media_type.other

	name?: string = undefined

	url?: string = undefined

	license_types: License_types[] = undefined
}

Steps to Reproduce the Problem

  1. Create 2 Prisma models with underscore: "some_table_name".
  2. Add relational field in one of the models. Dosen't matter what kind.
  3. Run npx prisma generate

Specifications

  • Version: 0.2.6
  • Prisma Version: 4.13.0
  • Platform: aarch64 (darwin)

Classes are not generated

Expected Behavior

Classes are generated

Actual Behavior

No classes are generated

Steps to Reproduce the Problem

  1. use this scheme file:
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

generator prismaClassGenerator {
  provider   = "prisma-class-generator"
  useSwagger = true
  output     = "../src/_gen/prisma"
}

model User {
  id                Int                    @id @unique @default(autoincrement())
  username          String                 @unique
  firstName         String
  lastName          String
  shortName         String                 @unique
  mailAddress       String?
  admin             Boolean                @default(false)
  lawCases          LawCase[]
  mailFooter        MailFooter[]
  todoListRelations UserTodoListRelation[]
}

...

enum DocumentImportType {
  bea
  local
}
  1. run prisma generate
  2. see, that prisma generatesays, that classes should be generated at output directory
  3. Output directory is empty - no matter if I leave default or not

Specifications

  • Version: 0.2.6
  • Prisma Version: 4.14.0
  • Platform: MacOS Ventura, M2 Macbook Pro

Annotations in the field documentation

I want to hide fields in the swagger and exclude with class-transformer serialization. For example:

model User {
  id       Int    @id @default(autoincrement())
  username String
  /// @hide @exclude Password hash
  password String
  /// @hide For example, only hide a field in swagger
  email    String
  /// @exclude For example, only exclude a field in response
  name     String
}

will generate:

export class User {
  @ApiProperty({ type: Number })
  id: number;

  @ApiProperty({ type: String })
  username: string;

  // @ApiHideProperty() can be used
  @Exclude()
  password: string;

  // @ApiHideProperty() can be used
  email: string;

  @ApiProperty({ type: String, description: 'For example, only exclude a field in response' })
  @Exclude()
  name: string;
}

The idea is taken from the https://www.npmjs.com/package/@vegardit/prisma-generator-nestjs-dto

Optional properties in generated classes don't match Prisma generated types

Hi, I'm running into a couple of errors due to type mismatch between prisma-class-generator classes and Prisma generated types. I'm using Typescript with strictNullChecks activated and null and undefined are not equivalent.

Actual behavior

When you declare a prisma model like this:

model Document {
  id       String           @id @default(uuid())
  name     String
  url      String?

The resulting class is generated like this:

export class Document {
  @ApiProperty({ type: String })
  id: string;

  @ApiProperty({ type: String })
  name: string;

  @ApiProperty({ type: String })
  url?: string;

Expected behavior

To properly match Prisma generated typings for all optional properties in models, the resulting class should be generated like this:

export class Document {
  @ApiProperty({ type: String })
  id: string;

  @ApiProperty({ type: String })
  name: string;

  @ApiProperty({ type: String })
  url: string | null;

Decimal types are generated as number

Expected Behavior

Perhaps we could add a new setting called 'preserveDecimal' to the library, which would allow users to choose how Decimal values are generated. By default, this setting would be set to false.

Example of output when it set to true:

@ApiProperty({ type: Number })
landSize: Prisma.Decimal;

I am proposing a solution to make all my DTO payloads type-safe by following Prisma includes. In the end it helps me to better document my APIs.

class UserDto extends IntersectionType(
    PrismaModel.User,
    PickType(PrismaModel.UserRelations, ['address','documents']),
  )
  implements
    Prisma.UserGetPayload<{
      include: typeof UserDto.include;
    }>{


 static get include() {
    return Prisma.validator<Prisma.UserInclude>()({
      address: true,
      documents: true,
    })
 }
}

The Decimal type is generating as a number, which causes type incompatibilities. The temporary solution I have found so far is to ignore it:

  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore: Unreachable code error

If I find the time, I can work on this and suggest a solution.

Actual Behavior

The output is in number type:

@ApiProperty({ type: Number })
landSize: number;

Class fields generated from the schema should be nullable instead of optional

Expected Behavior

When a model inside the Prisma schema has a field that is defined as nullable (marked with the ?, that field inside the generated class should also be nullable.

Actual Behavior

The generator marks these nullable fields as optional (can be undefined) instead of nullable.

Steps to Reproduce the Problem

  1. Create a model within the schema.prisma file with a field that is nullable, e.g. model Foo { bar String? }
  2. Run npx prisma generate
  3. Check the resulting class file. For the example, it should look like this: export class Foo { bar?: string } and I'd expect it to be export class Foo { bar: string | null }

Is this just me or what's the idea behind this?

Enum Generation

Expected Behavior

It should import enums from @prisma/client

Actual Behavior

It is trying to import from a file that is not generated:
import { ProductType } from './product_type'

Steps to Reproduce the Problem

We can use the example in the repository:

  1. npm run generate:mysql

Specifications

  • Version: 0.2.8
  • Prisma Version: 4.12.0
  • Platform: Mac

Suggestion

We could implement tests to check if the change doesn't break anything.

After some investigation

The break seems to come from the #49 PR.

if (this.prismaClass.types) {

This library is broken for my use case; I had to rollback to version 0.2.7

[Bug] BigInt type with default value

Hello.

I'm using MS-SQL.
I got an error for type BigInt with default value.

error:
error TS2322: Type 'number' is not assignable to type 'BigInt'.

image

If I change the generated code to
AGROUP_NO: BigInt = BigInt(1);

then error is disappeared

Specifications

  • Version:
  • Prisma Version: 4.3.1
  • Platform: NestJs, MS-SQL

registerEnumType placed outside the class

With version 0.2.1 the generated registerEnumType is placed outside the class, which causes issues with compilation.

Additionally, I think this should be based on a flag, since it isn't needed unless using graphql. Thoughts?

Feature: generate validation decorators

Expected Behavior

Validation decorators from class-validator and class-transformer are generated.

Actual Behavior

No validation decorators are generated.

It would be nice if this package apart from Swagger decorators adds validation decorators from class-validator and class-transformer so we can use it with the ValidationPipe from NestJS.

Specifications

  • Version: 0.2.7
  • Prisma Version: 4.15.0

Add an option of adding `!` after generated class properties name

Expected Behavior

The generated class works well with compilerOptions.strict: true.

Actual Behavior

After set compilerOptions.strict: true in tsconfig, all required fileds will get an error:

Property 'usage' has no initializer and is not definitely assigned in the constructor.

This can be fixed by adding an ! to the end of property name. Like:

export class Example {
  id!: number;
  usage!: number;
  description?: string;
}

Maybe a new genarate option can solve this?

Steps to Reproduce the Problem

  1. set compilerOptions.strict: true in tsconfig
  2. generate the class from prisma schema
  3. open generated class file

Specifications

  • Version:
  • Prisma Version:
  • Platform:

Prisma version limit

hi ๏ผŒ
Prisma version limit๏ผŒwhen i use prisma 3.2.1 Latest๏ผŒ it can not create _gen folder and related files .tks

Imports not generated

First things first, this is an awesome and very useful package ๐Ÿ™Œ

I have experienced problems with models that have relations to themselves while using the separateRelationFields flag. First, the school_relation class is generated, and afterward the actual school class. This results in school_relation.ts missing imports from school.ts which I need to add manually later. Not a huge deal but it gets tedious on a large-scale project. Maybe this can be solved by reverting the order so that we first generate school.ts and then school_relation.ts?

Expected Behavior

Imports are also generated.

Actual Behavior

Imports are not generated.

Steps to Reproduce the Problem

define a model in schema.prisma

model School {
  id      String
  School  School  @relation()
}

define a generator

generator prismaClassGenerator {
  ...
  separateRelationFields = "true"
  ...
}

run prisma generate

Specifications

  • Version: 0.2.6
  • Prisma Version: 4.15.0

The folder _gen isn't created

Expected Behavior

The folder _gen is created

Actual Behavior

The folder _gen isn't created

Steps to Reproduce the Problem

  1. Install it
  2. Configure prisma.schema
  3. Execute npx prisma generate

Specifications

  • Version: 0.1.10
  • Prisma Version: 3.6.0
  • Platform: Linux

Missed import class for self one to one relation with separateRelationFields

Expected Behavior

comment_relations.ts

import { Post } from './post';
import { User } from './user';
import { Tag } from './tag';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Comment } from './comment';

export class CommentRelations {
  @ApiProperty({ type: () => Post })
  post: Post;

  @ApiProperty({ type: () => User })
  user: User;

  @ApiPropertyOptional({ type: () => Comment })
  replyTo?: Comment;

  @ApiProperty({ isArray: true, type: () => Comment })
  replyComments: Comment[];

  @ApiProperty({ isArray: true, type: () => Tag })
  tags: Tag[];

  @ApiProperty({ isArray: true, type: () => User })
  likedUsers: User[];

  @ApiProperty({ isArray: true, type: () => User })
  mentionedUsers: User[];
}

Actual Behavior

comment_relations.ts

import { Post } from './post';
import { User } from './user';
import { Tag } from './tag';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class CommentRelations {
  @ApiProperty({ type: () => Post })
  post: Post;

  @ApiProperty({ type: () => User })
  user: User;

  @ApiPropertyOptional({ type: () => Comment })
  replyTo?: Comment;

  @ApiProperty({ isArray: true, type: () => Comment })
  replyComments: Comment[];

  @ApiProperty({ isArray: true, type: () => Tag })
  tags: Tag[];

  @ApiProperty({ isArray: true, type: () => User })
  likedUsers: User[];

  @ApiProperty({ isArray: true, type: () => User })
  mentionedUsers: User[];
}

Steps to Reproduce the Problem

 generator prismaClassGenerator {
  provider               = "prisma-class-generator"
  output                 = "../src/prisma/prisma-class"
  dryRun                 = false
  separateRelationFields = true
}
model Comment {
  id             Int       @id @default(autoincrement())
  postId         Int
  post           Post      @relation(fields: [postId], references: [id])
  userId         Int
  user           User      @relation(fields: [userId], references: [id])
  replyToId      Int?
  replyTo        Comment?  @relation(fields: [replyToId], references: [id], name: "_ReplyComments")
  replyComments  Comment[] @relation(name: "_ReplyComments")
  message        String
  tags           Tag[]
  likedUsers     User[]    @relation(name: "_CommentsLikedUsers")
  mentionedUsers User[]    @relation(name: "_CommentsMentionedUsers")
  createdAt      DateTime  @default(now())
  updatedAt      DateTime  @default(now()) @updatedAt
}

Missed import class Comment in comment_relations.ts file for self one to one relation with separateRelationFields param

Specifications

  • Version: 0.2.6
  • Prisma Version: 4.15.0
  • Platform: windows

reference to non existing ModelType

Expected Behavior

Here using a simple model named Node with a parent/children tree relation.

schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator prismaClassGenerator {
  provider = "prisma-class-generator"
  dryRun   = false
}

model Node {
  id Int @id @default(autoincrement())

  parentId Int?
  parent   Node?  @relation("NodeToNodeParent", fields: [parentId], references: [id], onDelete: Restrict)
  children Node[] @relation("NodeToNodeParent")
}

generated src/_gen/prisma-class/node.ts

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'

export class Node {
	@ApiProperty({ type: Number })
	id: number

	@ApiPropertyOptional({ type: Number })
	parentId?: number

	@ApiPropertyOptional({ type: () => Node })
	parent?: Node

	@ApiProperty({ isArray: true, type: () => Node })
	children: Node[]
}

Actual Behavior

generated src/_gen/prisma-class/node.ts

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'

export class Node {
	@ApiProperty({ type: Number })
	id: number

	@ApiPropertyOptional({ type: Number })
	parentId?: number

	@ApiPropertyOptional({ type: () => Node })
	parent?: NodeType

	@ApiProperty({ isArray: true, type: () => Node })
	children: NodeType[]
}

Steps to Reproduce the Problem

Not actually sure what triggers this problem.
On my project with a larger database model it tries to import from ./model_type and there is no such file in the generated folder.
On the example using simply Node model it doesn't try to import NodeType but yet the problem appears as it uses it in the class.

import { Edge } from './edge';
import { FeedData } from './feed_data';
// following imports points to non existing files
import { EdgeType } from './edge_type';
import { FeedDataType } from './feeddata_type';

Specifications

  • Version: 0.2.8
  • Prisma Version: 5.4.2
  • Platform: linux
  • Node: v18.17.1

Feature Request: Support for @ApiHideProperty Decorator

The nestjs-swagger library provides the @ApiHideProperty decorator, which is used to hide properties in the Swagger UI and exclude them from the API documentation. However, when using prisma-class-generator to generate classes based on a Prisma schema, this decorator is not available.

Specifically, it would be beneficial to use @ApiHideProperty to exclude sensitive or unnecessary fields such as "passwordHash", "updatedBy", and "createdBy" from the generated documentation.

I propose that prisma-class-generator should support the @ApiHideProperty decorator. This would allow developers to annotate fields in the Prisma schema which should be hidden from the API documentation.

extraModels: [...PrismaModel.extraModels] does not work

I have:

import { User } from '@prisma/client';
import { User as UserClass } from './_gen/prisma-class/user';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('/users')
  async getAll(): Promise<User[]> {
    return (await this.appService.getAll()) as User[];
  }

  @Get('/users2')
  async getAll2(): Promise<UserClass[]> {
    return await this.appService.getAll();
  }
}

And in main.ts:

const options = new DocumentBuilder()
   .setTitle('nest example')
   .setDescription('My nest API description')
   .setVersion('1.0')
   .addTag('myTag')
   .build();

 const document = SwaggerModule.createDocument(app, options, {
   extraModels: [...PrismaModel.extraModels],
 });

 SwaggerModule.setup('api', app, document);

Expected Behavior

I expected swagger will display description response schema for both /users and /users2

Actual Behavior

result_user

result_user2
swagger works only for the explicitly imported generated class.

Steps to Reproduce the Problem

Clone This Repo and see localhost:300/api.

Specifications

  • "prisma-class-generator": "^0.2.6"
  • "@nestjs/swagger": "^6.3.0"
  • Prisma Version: "prisma": "^4.11.0"
  • Platform: mac m1

Typo regarding useNonNullableAssertions in the documentation

Expected Behavior

Actual Behavior

Steps to Reproduce the Problem

  1. Add the generator to the prisma file.
  2. Set the useNonNullAssertions flag to true.
  3. Generated classes files are not affected.

Steps to Solve the Problem

  1. Update the README.md to use the correct name for the flag which is useNonNullableAssertions

Specifications

  • Version: 0.2.7
  • Prisma Version: 5.0
  • Platform: MacOS

Json type generates a field with object type instead of Prisma.JsonValue

Expected Behavior

Field must have Prisma.JsonValue type

Actual Behavior

Field has object type

Steps to Reproduce the Problem

  1. Create a table with Json type
  2. Run npx prisma generate
  3. Verify the generated file for this model

Example:

model AnyModel {
  id       Int @id @default(autoincrement())
  anyField Json     @default("{}")
}

Specifications

  • Version: 0.2.6
  • Prisma Version: 4.15.0
  • Platform: Windows 10 Version 22H2 (19045.3155)

how to build dist folder?

i want change the template file, but When I the execute yarn dev generator dist file , prompt prisma:info [Prisma Class Generator]:Handler Registered.

Error: spawn prisma-class-generator ENOENT

file schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator prismaClassGenerator {
  provider = "prisma-class-generator"
}

model Company {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  name      String   @unique
  cnpj      String   @unique
  status    EnumStatus   @default(ACTIVE)
  phone     String?
  Products      Products[]
}

model Products {
  id        Int      @id @default(autoincrement())
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
  productName     String
  company   Company  @relation(fields: [companyId], references: [id])
  status    EnumStatus   @default(ACTIVE)
  companyId Int

  @@unique([productName, companyId], name: "productName_companyId_unique_constraint")
}

enum EnumStatus {
  ACTIVE
  INACTIVE
}

Steps to Reproduce the Problem

  1. Run the
    prisma generate
  2. Error
    Error: spawn prisma-class-generator ENOENT

Specifications

  • Version: 0.1.10
  • Prisma Version: 3.3.0
  • Platform: Windows

No output

The generate function runs successfully, but there is no output file....

Version:
"prisma-class-generator": "^0.2.9",

schema.prisma:

generator client {
  provider = "prisma-client-js"
}

generator prismaClassGenerator {
  provider = "prisma-class-generator"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

npx prisma generate output:

Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
prisma:info [Prisma Class Generator]:Handler Registered.
prisma:info [Prisma Class Generator]:[dryRun] Generate C:\Users\Noel\Documents\source\vesta-new\vesta-nestjs\src\_gen\prisma-class\user.ts
import { Post } from './post';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class User {
        @ApiProperty({ type: Number })
        id: number;

        @ApiProperty({ type: String })
        email: string;

        @ApiPropertyOptional({ type: String })
        name?: string;

        @ApiProperty({ isArray: true, type: () => Post })
        posts: Post[];
}

prisma:info [Prisma Class Generator]:[dryRun] Generate C:\Users\Noel\Documents\source\vesta-new\vesta-nestjs\src\_gen\prisma-class\post.ts
import { User } from './user';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class Post {
        @ApiProperty({ type: Number })
        id: number;

        @ApiProperty({ type: String })
        title: string;

        @ApiPropertyOptional({ type: String })
        content?: string;

        @ApiPropertyOptional({ type: Boolean })
        published?: boolean;

        @ApiPropertyOptional({ type: () => User })
        author?: User;

        @ApiPropertyOptional({ type: Number })
        authorId?: number;
}

prisma:info [Prisma Class Generator]:[dryRun] Generate C:\Users\Noel\Documents\source\vesta-new\vesta-nestjs\src\_gen\prisma-class\index.ts
import { User as _User } from './user';
import { Post as _Post } from './post';

export namespace PrismaModel {
        export class User extends _User {}
        export class Post extends _Post {}

        export const extraModels = [User, Post];
}


โœ” Generated Prisma Client (v5.10.2) to .\node_modules\@prisma\client in 67ms

โœ” Generated Prisma Class Generator to .\src\_gen\prisma-class in 80ms

Generator doesn't recognize scalar lists (arrays of strings)

Expected Behavior

Expected a prisma model field
methods String[] @default([])

to generate

  @ApiProperty({ isArray: true, type: String })
  permittedMethods: string[];

Actual Behavior

prisma model field
methods String[] @default([])

instead generates

  @ApiProperty({type: String })
  permittedMethods: string;

This causes issues because the class defined no longer matches the Prisma schema, which makes it impossible to assign the class to the returned value from a call to prisma (or requires workarounds)

Steps to Reproduce the Problem

  1. Create a model with a scalar list (array) like above
  2. Run the generator
  3. Observe the generated type

Specifications

  • Version: 0.2.0
  • Prisma Version: 4.5.0

class generate with "Declarations with initializers cannot also have definite assignment assertions." error

Expected Behavior

Generate the class without annoying error "Declarations with initializers cannot also have definite assignment assertions." and for number type generate a default value as Date.

Actual Behavior

Actualy when I generate a class, when a property in the schema has a default value, the generator create a class with error

Steps to Reproduce the Problem

With this schema

generator client {
  provider = "prisma-client-js"
  output   = env("PRISMA_CLIENT_PATH")
}

generator prismaClassGenerator {
  provider                 = "prisma-class-generator"
  dryRun                   = false
  useSwagger               = false
  makeIndexFile            = false
  separateRelationFields   = false
  useNonNullableAssertions = true
  output                   = "./models"
}

datasource db {
  provider = "sqlite"
  url      = env("PRISMA_DATABASE_URL")
}

model test{
  id                 String  @id
  description  String? 
  value            Int    @default(1)
} 

The generator create this class

export class item {
  id!: string;   // here for me is correct

  description?: string; 

  value!: number = new Date('1');;  // <- this is the problem, the ! and type of value (Date instead of number)

}

Specifications

  • Version: 0.2.9
  • Prisma Version: 5.3.0
  • Platform: windows10

Build with default `undefined`

Expected Behavior

export class Dealer {
  @ApiProperty({ type: String })
  id: string;

  @ApiProperty({ type: Date })
  createdAt: Date;

  @ApiProperty({ type: Date })
  modifiedAt: Date;

  @ApiProperty({ type: String })
  name: string;

  @ApiProperty({ type: String })
  slug: string;

  @ApiProperty()
  address: Address;

  @ApiProperty({ isArray: true, type: () => Offer })
  Offer: Offer[];
}

Actual Behavior

export class Dealer {
  @ApiProperty({ type: String })
  id: string = undefined;

  @ApiPropertyOptional({ type: Date })
  createdAt: Date = undefined;

  @ApiProperty({ type: Date })
  modifiedAt: Date = undefined;

  @ApiProperty({ type: String })
  name: string = undefined;

  @ApiProperty({ type: String })
  slug: string = undefined;

  @ApiProperty()
  address: Address = undefined;

  @ApiProperty({ isArray: true, type: () => Offer })
  Offer: Offer[] = undefined;
}

Steps to Reproduce the Problem

Schema:

generator prismaClassGenerator {
  provider   = "prisma-class-generator"
  useSwagger = true
  dryRun     = false
}

model Dealer {
  id         String    @id @default(auto()) @map("_id") @db.ObjectId
  createdAt  DateTime? @default(now())
  modifiedAt DateTime  @updatedAt
  name       String
  slug       String    @unique
  address    Address
  Offer      Offer[]

  @@map("dealers")
}

Specifications

  • Version: "prisma-class-generator": "^0.2.4"
  • Prisma Version: "@prisma/client": "^4.7.1"
  • Platform: linux

please guide me if I did something wrong here ^^

Relational imports not given proper snakecased file names that match generated files

Expected Behavior

I am receiving numerous typescript errors because the file import declarations are incorrect. What I should be seeing:

import { OrderEntity } from 'order_entity';
import { CurrencyCode, CheckoutTransportationMethod } from '@prisma/client';
import { Money } from './money';
import { MailingAddress } from './mailing_address';

Actual Behavior

import { OrderEntity } from 'orderentity';
import { CurrencyCode, CheckoutTransportationMethod } from '@prisma/client';
import { Money } from './money';
import { MailingAddress } from './mailingaddress';

The filenames for the types that were actually generated are order_entity.ts and mailing_address.ts, so the mismatch is problematic here.

Steps to Reproduce the Problem

  1. Create Prisma schema with pascal-cased model names
  2. Generate types with PrismaClassGenerator definition:
generator prismaClassGenerator {
  provider = "prisma-class-generator"
  output  = "../src/@generated/prisma-class"
  useSwagger = false
  dryRun = false
}
  1. Done

Specifications

  • Version: 0.2.9
  • Prisma Version: 5.7.0
  • Platform: macOS

Option makeIndexFile = false is not respected when set in Prisma schema

Expected Behavior

No index file is generated when setting makeIndexFile = false in Prisma schema

Actual Behavior

File is generated anyway, the merged config object contains string "false" instead of boolean

Steps to Reproduce the Problem

  1. config generator in prisma schema
generator prismaClassGenerator {
  provider = "prisma-class-generator"
  makeIndexFile = false
  1. run prisma generate
  2. index file is generated

Specifications

  • Version: latest
  • Prisma Version: 3.14
  • Platform: node 16 on Linux

How to handle deeper relations

Hi,
just a question concerning usage and best practice using this generator.

I am using NestJS and Swagger - that's the reason I am using this generator for.
As the project grows, I have deeper relations, controlled by the include property in Prisma's find methods. How can I replicate them without having to have multiple classes with TypeIntersects and so on?

Is there a best practice I haven't read about?

Thanks in advance for any help!

Best regards

Prisma type and enum are not generated

Unfortunately types and enums are not generated. This unfortunately makes the use of the generator completely useless.

TSError: โจฏ Unable to compile TypeScript: [0] src/data/gen/user.ts(26,20): error TS2304: Cannot find name 'DeliveryAddress'.

generator client {
  provider = "prisma-client-js"
}

generator prismaClassGenerator {
  provider               = "prisma-class-generator"
  dryRun                 = false
  separateRelationFields = false
  output                 = "./gen"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model User {
  id                String           @id @default(auto()) @map("_id") @db.ObjectId
  email             String           @unique @map("_email")
  deliveryAddress   DeliveryAddress?
  state             UserState?
}

enum UserState {
  QUEUE
  ACTIVE
}

type DeliveryAddress {
  firstName             String
  lastName              String
  streetName            String
  streetNumber          String
  postalCode            String
  city                  String
  countryId             Int
  phone                 String
  additionalInformation String
}

Invalid import path generation with pnpm

Expected Behavior

import { Role } from '../../node_modules/.pnpm/@[email protected][email protected]/node_modules/@prisma/client';

or

import { Role } from '..\\..\\node_modules\\.pnpm\\@[email protected][email protected]\\node_modules\\@prisma\\client';

Actual Behavior

import { Role } from '....\node_modules.pnpm@[email protected][email protected]\node_modules@prismaclient';

Steps to Reproduce the Problem

I'm doing this on Windows and cannot get it to reproduce minimally on CodeSandbox (which I'd assume is Linux).

  1. Clone the prisma-class-generator repository on a Windows machine.
  2. Install dependencies.
  3. Run yarn generate:postgresql.
  4. See invalid import in generated product.ts.

Specifications

  • Version: v0.2.5
  • Prisma Version: v4.9.0
  • Platform: Windows/Node.js

Solution

I don't think this should be too bad of a fix, I think the easiest would be to add something like

importRow.from = importRow.from.replaceAll('\\', '/')

right above

return importRow

I'm not sure how well this would play with other operating systems, so maybe something like

importRow.from = importRow.from.replaceAll('\\', '\\\\')

to replace with a double slash. If either of these would work, I'd be happy to make a PR.

Upcoming rename of `@prisma/sdk` to `@prisma/internals` with Prisma 4

Hey,

Jan from Prisma Engineering here.

Quick heads up that we will soon rename our @prisma/sdk package to @prisma/internals with Prisma 4, which we plan to release on June 28th (soon!).

The @prisma/sdk package was meant as an Prisma internal package only, but somehow it leaked out over time and is now used across all kinds of tools - including yours of course ๐Ÿ˜„

With the rename of the Npm package we want to make it clearer that we can not give any API guarantees for @prisma/internals, might need to introduce breaking changes to the API from time to time and will not follow semantic versioning (breaking changes only in major upgrade) with it. We think that it is better communicated with internals than with sdk.
With Prisma 4, besides the package name nothing should change though.

Additionally it would be super helpful if you could help us gain an understanding where, how and why you are using @prisma/sdk (soon @prisma/internals, remember ๐Ÿ˜€) to achieve, what exactly. We want to cleanup that package and your feedback will be valuable to us to define a better API.

Looking forward to your feedback.

Best
Jan & your friends at Prisma

PS: Are you using Prisma.dmmf from import { Prisma } from '@prisma/client' in your code somewhere by chance? That will also change soon and not include the Prisma.dmmf.schema sub property. Instead you can use getDmmf from @prisma/internals moving forward.

[Feature-Request] Support for `type`

In MongoDB we use the Composite-Types type-Declaration (https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#defining-composite-types), which enables us to use nested-documents.

These are currently not being transformed into Classes, which means that classes which use them break.

Expected Behavior

Also generate a class for the types - and import them in the entity.

Actual Behavior

Does not generate classes, which leads to missing imports and breaks building.

Example Schema-File:

model Dealer {
  id         String    @id @default(auto()) @map("_id") @db.ObjectId
  createdAt  DateTime? @default(now())
  modifiedAt DateTime  @updatedAt
  name       String
  slug       String    @unique
  address    Address
  Offer      Offer[]

  @@map("dealers")
}

type Address {
  city         String
  postalCode   String
  street       String
  streetNumber String
}

Build result would be:

import { Offer } from './offer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class Dealer {
  @ApiProperty({ type: String })
  id: string = undefined;

  @ApiPropertyOptional({ type: Date })
  createdAt?: Date = undefined;

  @ApiProperty({ type: Date })
  modifiedAt: Date = undefined;

  @ApiProperty({ type: String })
  name: string = undefined;

  @ApiProperty({ type: String })
  slug: string = undefined;

  @ApiProperty()
  address: Address = undefined;

  @ApiProperty({ isArray: true, type: () => Offer })
  Offer: Offer[] = undefined;
}

Specifications

  • Version: "prisma-class-generator": "^0.2.4"
  • Prisma Version: "@prisma/client": "^4.7.1"
  • Platform: linux

Invalid prisma client import path

Expected Behavior

import { PermissionAction } from '@prisma/client'

Actual Behavior

import { PermissionAction } from '../../.prisma/client'

Steps to Reproduce the Problem

  1. Set custom prisma client path
generator client {
  provider = "prisma-client-js"
  output   = "../../../node_modules/.prisma/client"
}
  1. Set prisma class generator
generator prismaClassGenerator {
  provider   = "prisma-class-generator"
  dryRun     = false
  output     = "../src/generated"
}
  1. Run generate command
$ npx prisma generate --schema=libs/models/prisma/schema.prisma

Specifications

  • Version: 0.2.5
  • Prisma Version: 4.11.0
  • Platform: MacOs

Solution

I am using prisma-class-generator with Nx monorepo and my prisma schema is existing
on the path libs/models/prisma/schema.prisma.

Maybe it is nice to have generator argument like clientImportPath to set custom prisma client import path

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.