若于Prisma之上构建NestJS之API,汝必感其碍:汝之架构乃真源,然汝之DTO、验证之则、Swagger之元数据,则栖于他处——而其渐离矣。
大抵Prisma之DTO生成器,能解其本(创建/更新/带装饰之实体类)。此诚有益,然汝需特制之输出时—审元数据、GraphQL类型、RBAC规范、汝自之验证者——汝复归手书之粘合码矣。
@tommasomeli/prisma-generator-nestjs-dto乃为彼第二阶段所建之Prisma生成器。其发乎寻常之NestJS DTO,复悄然退避——插件之API,注解驱动之装饰器,复一类型安全配置文件 诚然,棱镜之架构不足。
箱中所得
每有棱镜之模型 User,行 npx prisma generate,则得:
src/generated/nestjs-dto/
user/
user.entity.ts
create-user.dto.ts
update-user.dto.ts
index.ts
index.ts
每文件俱载:
-
class-validator装饰语 (@IsString,@IsOptional,…) -
@nestjs/swagger元数据@ApiProperty,@ApiHideProperty,……) -
自足之输入— 关系数据传输对象,
@DtoOverrideType目标既定,注解之辞亦自明矣。
直接于之配置之schema.prisma:
generator nestjsDto {
provider = "prisma-generator-nestjs-dto"
output = "../src/generated/nestjs-dto"
outputType = "class"
outputStructure = "nestjs"
fileNamingStrategy = "kebab"
reExport = "true"
classValidator = "true"
swaggerDocs = "true"
prettier = "true"
}
安裝:
npm i -D @tommasomeli/prisma-generator-nestjs-dto
注释——无需触碰生成代码,即可控制可见性
模型与字段上方的三斜杠注释(///)驱动内置生成器。无需后处理,无需手动编辑.
model User {
id Int @id @default(autoincrement())
email String @unique
name String
/// @DtoHidden
passwordHash String
/// @DtoReadOnly
createdAt DateTime @default(now())
}
| 注释 | 效 |
|---|---|
@DtoHidden |
隐于四处 |
@DtoReadOnly |
除于创与更之DTO |
@DtoEntityHidden |
隐于实体(API应答) |
@DtoCreateHidden / @DtoUpdateHidden
|
独隐于一DTO |
@DtoOverrideType(MyType) |
覆 TypeScript之型(自引) |
@DtoIgnoreModel |
尽弃此模 |
亦得系汝之自 配置以获验证者与装饰器 — 下文详述之。
插件之制 — 内置数据传输对象不足时
其别在于 extraGenerators:任取类之延 BaseGenerator,则并行于内置于同一流程。
插件所受者:
- 解析之模型图(每字段皆注解)
- 配置已解决(
extraDecorators,extraValidators,extraImports……) - 导入合并辅助工具(
addImport,formatImports,getTemplate)
此乃一简约插件,复用内置渲染器以无class-validator之状发实体:
import { isEntityHidden } from '@tommasomeli/prisma-generator-nestjs-dto';
import { BaseGenerator } from '@tommasomeli/prisma-generator-nestjs-dto';
import type { Field, File, Model } from '@tommasomeli/prisma-generator-nestjs-dto';
export default class EntityDtoGenerator extends BaseGenerator {
filePrefix = '';
fileSuffix = '.entity';
classPrefix = '';
classSuffix = '';
async generate(): Promise<File[]> {
return this.models.map((model) => {
const filteredFields = model.fields.filter((f: Field) => !isEntityHidden(f));
const processedModel: Model = { ...model, fields: filteredFields as Field[] };
const outputPath = this.getPath(model);
return {
path: outputPath,
content: this.getTemplate({ model: processedModel, classValidator: false, outputPath }),
};
});
}
}
生命周期钩子
插件可钩取全程:
-
beforeAll(models)— 在任一生成器运行前,变更共享模型列表(共享预遍历) -
afterAll(files)— 在所有生成器完成后,追加桶、审计报告或聚合索引
TypeScript插件,无需预编译
extraGenerators 指向 .ts 文件,生成器即加载之jiti,無需構建步驟以供汝之插件。
實例:自定義@Auditable註解
此倉庫內含一可運行之例於examples/blog/。
模式 — 以自定義@Auditable名註解模型:
/// @Auditable("user_audit")
model User {
id Int @id @default(autoincrement())
email String @unique
/// @DtoHidden
passwordHash String
posts Post[]
}
/// @Auditable("post_audit")
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id])
authorId Int
}
配置 — 注解与插件之注册:
import { from, type GeneratorConfigFile } from '@tommasomeli/prisma-generator-nestjs-dto';
export default {
extraAnnotations: ['Auditable'],
extraGenerators: from('./generators/audit-generator.ts', ['AuditGenerator']),
} satisfies GeneratorConfigFile;
输出 — 诸般DTO之外,复得模型专有之审计元数据,及聚合索引:
generated/
user/user.audit.ts
post/post.audit.ts
audit-index.ts ← emitted by AuditGenerator#afterAll
— 类型安全之外部配置
Prisma之生成块适于简明标识,然不能表嵌套之物或多行数组。凡较繁者,当用configFile:
generator nestjsDto {
provider = "prisma-generator-nestjs-dto"
output = "../generated"
configFile = "../nestjs-dto.config.ts"
}
"其"from()助者核验路径及命名导出于编译时(此导入闭包永不为运行时所调用)
import { from, fromNamespace, type GeneratorConfigFile } from '@tommasomeli/prisma-generator-nestjs-dto';
export default {
extraValidators: from(() => import('src/common/validators'), ['IsUnique', 'IsStrongPassword']),
extraDecorators: from(() => import('src/common/decorators'), ['Trim', 'Sanitize']),
extraScalars: {
Decimal: { ts: 'Decimal', from: 'decimal.js' },
Json: { ts: 'MyJson', from: 'src/json', apiType: 'Object' },
},
} satisfies GeneratorConfigFile;
乃布注解于架构:
model User {
/// @IsUnique()
email String @unique
/// @IsStrongPassword({ minLength: 10 })
password String
/// @Trim()
name String
}
若定制校验者以名相冲突于内置者(IsBoolean、ApiProperty、…),则尔模块独胜于斯符。
可选之运行时说明书
启用 emitManifest = "true" 以得:
-
manifest.ts—Record<Prisma.ModelName, { primaryKey, entityFields, relations }>为若干构建者、审计中间件、RBAC 字段列表之用 -
model-entity-map.ts— 模型名至实体类之类型映射
当需架构感知之运行时逻辑,而无需自解 Prisma DMMF 时,此尤便
其较之如何
| 此生成器 | 寻常之Prisma NestJS数据传输对象生成器 | |
|---|---|---|
| 创制 / 更新 / 实体数据传输对象 | ✔ | ✅ |
| Swagger(+) + class-validator | ✔ | √ |
| 注解驱动之隐藏 / 只读 / 类型覆盖 | √ | 偏颇 |
| 可插拔之次生成器 | √ | ✅ |
| 插件之定制注解 | √ | ✅ |
| 以名覆内置之导入 | ✔ | ✅ |
类型安全之外configFile
|
✔ | ✅ |
| 可选项运行时清单 | ✅ | ❌ |
试之
npm i -D @tommasomeli/prisma-generator-nestjs-dto
npx prisma generate
- GitHub: github.com/tommasomeli/prisma-generator-nestjs-dto
- npm: @tommasomeli/prisma-generator-nestjs-dto
-
例:
examples/blog/
问题与补丁皆可,依MIT许可。
若此能省君于NestJS与Prisma之栈上时日,于仓中加一⭐(或一)咖啡 ☕其效甚远。























