# Ts.ED Prisma client

Premium sponsors

Ts.ED Prisma client is only available for premium sponsors (opens new window).

Then contact the Ts.ED team (opens new window) on Slack so that we add it to the private repository.

# Why should I paid for the package

Prisma Client generate only TypeScript interfaces based on the Prisma schema. Because, interfaces have no consistency in JavaScript, isn't possible to infer a Json Schema and therefore generate the Swagger documentation or perform validation on the models (without manually writing code).

The Ts.ED Prisma will generates classes and enums compatible with Ts.ED decorators like Returns but also, but it will also generate the PrismaService (connection to the database) but also the repositories for each model of your Prisma schema.

# Install the package from Github

Ask Ts.ED team on Slack (opens new window) to get a unique personal GH_TOKEN.

Then add on your project (or on profile level) a .npmrc file with the following content:

@tsedio:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=GH_TOKEN
1
2

Replace the GH_TOKEN by your token or by ${GH_TOKEN} if you want to use env variable.

If you use yarn (v1), you can also add a .yarnrc with the following content:

"@tsedio:registry" "https://npm.pkg.github.com/tsedio"
1

Then add the package to you package.json:

{
  "name": "@project/server",
  "version": "1.0.0",
  "description": "A Server based on Ts.ED",
  "main": "index.js",
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@tsedio/prisma": "1.0.3"
  }
}
1
2
3
4
5
6
7
8
9
10
11

Furthermore, @tsedio/prisma requires Prisma 2 to work properly, so please install Prisma dependencies if you don't have it already installed:

npm i -D prisma
npm i @prisma/client
1
2

WARNING

Be aware that @tsedio/prisma is designed to work with a selected version of prisma.

Please make sure you use prisma and @prisma/client with version matching ~2.22.0. Otherwise, the runtime check will report an error when you run the generator.

# Configuration

After installation, you need to update your schema.prisma file and then add a new generator section below the client one:

generator client {
  // ...
}

generator tsed {
  provider = "tsed-prisma"
}
1
2
3
4
5
6
7

Then after running npx prisma generate, this will emit the generated Ts.ED classes and Enums to @tsedio/prisma/.schema in node_modules folder.

You can also configure the default output folder, e.g.:

generator tsed {
  provider = "tsed-prisma"
  output   = "../prisma/generated/tsed"
}
1
2
3
4

By default, when the output path contains node_modules, the generated code is transpiled - containing *.js and *.d.ts files that are ready to use (import) in your code. However, if you explicitly choose an other folder in output config, the generated code will be emitted as raw TS files which you can use and import as your other source code files.

You can overwrite that by explicitly setting emitTranspiledCode config option:

generator tsed {
  provider           = "tsed-prisma"
  output             = "../prisma/generated/tsed"
  emitTranspiledCode = true
}
1
2
3
4
5

# Usage

Given that you have this part of datamodel definitions:

model User {
  /// @TsED.Groups("!creation")
  /// Comment
  id          Int      @id @default(autoincrement())
  createdAt   DateTime @default(now())
  /// @TsED.Email()
  /// @TsED.Description("User email. This email must be unique!")
  email       String   @unique
  weight      Float?
  is18        Boolean?
  name        String?
  successorId Int?
  successor   User?    @relation("BlogOwnerHistory", fields: [successorId], references: [id])
  predecessor User?    @relation("BlogOwnerHistory")
  role        Role     @default(USER)
  posts       Post[]
  keywords    String[]
  biography   Json
  /// @TsED.Ignore(ctx.endpoint === true)
  ignored    String
}

model Post {
  id     Int   @id @default(autoincrement())
  user   User? @relation(fields: [userId], references: [id])
  userId Int?
}

enum Role {
  USER
  ADMIN
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

it will generate the following UserModel:

import { User } from "../client";
import { Integer, Required, Property, Groups, Format, Email, Description, Allow, Enum, CollectionOf } from "@tsed/schema";
import { Role } from "../enums";
import { PostModel } from "./PostModel";

export class UserModel implements User {
  @Property(Number)
  @Integer()
  @Required()
  @Groups("!creation")
  id: number;

  @Property(Date)
  @Format("date-time")
  @Required()
  createdAt: Date;

  @Property(String)
  @Required()
  @Email()
  @Description("User email. This email must be unique!")
  email: string;

  @Property(Number)
  @Allow(null)
  weight: number | null;

  @Property(Boolean)
  @Allow(null)
  is18: boolean | null;

  @Property(String)
  @Allow(null)
  name: string | null;

  @Property(Number)
  @Integer()
  @Allow(null)
  successorId: number | null;

  @Property(() => UserModel)
  @Allow(null)
  predecessor: UserModel | null;

  @Required()
  @Enum(Role)
  role: Role;

  @CollectionOf(() => PostModel)
  @Required()
  posts: PostModel[];

  @CollectionOf(String)
  @Required()
  keywords: string[];

  @Property(Object)
  @Required()
  biography: any;
  
  @TsED.Ignore((value: any, ctx: any) => ctx.endpoint === true)
  ignored: string;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

And, the following repository:

import { isArray } from "@tsed/core";
import { deserialize } from "@tsed/json-mapper";
import { Injectable, Inject } from "@tsed/di";
import { PrismaService } from "../services/PrismaService";
import { Prisma, User } from "../client";
import { UserModel } from "../models";

@Injectable()
export class UsersRepository {
  @Inject()
  protected prisma: PrismaService;

  get collection() {
    return this.prisma.user
  }

  get groupBy() {
    return this.collection.groupBy.bind(this.collection)
  }

  protected deserialize<T>(obj: null | User | User[]): T {
    return deserialize<T>(obj, { type: UserModel, collectionType: isArray(obj) ? Array : undefined })
  }

  async findUnique(args: Prisma.UserFindUniqueArgs): Promise<UserModel | null> {
    const obj = await this.collection.findUnique(args);
    return this.deserialize<UserModel | null>(obj);
  }

  async findFirst(args: Prisma.UserFindFirstArgs): Promise<UserModel | null> {
    const obj = await this.collection.findFirst(args);
    return this.deserialize<UserModel | null>(obj);
  }

  async findMany(args?: Prisma.UserFindManyArgs): Promise<UserModel[]> {
    const obj = await this.collection.findMany(args);
    return this.deserialize<UserModel[]>(obj);
  }

  async create(args: Prisma.UserCreateArgs): Promise<UserModel> {
    const obj = await this.collection.create(args);
    return this.deserialize<UserModel>(obj);
  }

  async update(args: Prisma.UserUpdateArgs): Promise<UserModel> {
    const obj = await this.collection.update(args);
    return this.deserialize<UserModel>(obj);
  }

  async upsert(args: Prisma.UserUpsertArgs): Promise<UserModel> {
    const obj = await this.collection.upsert(args);
    return this.deserialize<UserModel>(obj);
  }

  async delete(args: Prisma.UserDeleteArgs): Promise<UserModel> {
    const obj = await this.collection.delete(args);
    return this.deserialize<UserModel>(obj);
  }

  async deleteMany(args: Prisma.UserDeleteManyArgs) {
    return this.collection.deleteMany(args)
  }

  async updateMany(args: Prisma.UserUpdateManyArgs) {
    return this.collection.updateMany(args)
  }

  async aggregate(args: Prisma.UserAggregateArgs) {
    return this.collection.aggregate(args)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# Add Ts.ED decorator

The generator parse prisma command to find extra Ts.ED decorators. You can use any @tsed/schema decorators from Ts.ED by adding a comment with the following format /// @TsED.Decorator. See example above:

model User {
  /// @TsED.Groups("!creation")
  /// Comment
  id          Int      @id @default(autoincrement())
  createdAt   DateTime @default(now())
  /// @TsED.Email()
  /// @TsED.Description("User email. This email must be unique!")
  email       String   @unique
}
1
2
3
4
5
6
7
8
9

Output:

export class UserModel implements User {
  @Property(Number)
  @Integer()
  @Required()
  @Groups("!creation")
  id: number;

  @Property(String)
  @Required()
  @Email()
  @Description("User email. This email must be unique!")
  email: string;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

Now that the Ts.ED generator is correctly configured, you can go back (or follow) the tutorial to create your first controller

Last Updated: 10/23/2021, 5:14:48 AM

Other topics