@velopays/prisma-crud-generator
Version:
Generate CRUD operations and tests from Prisma models for NestJS
343 lines (273 loc) • 9.6 kB
Markdown
# Prisma CRUD Generator
一个基于 Prisma 模型自动生成 NestJS CRUD 代码和测试文件的工具。
## 特性
- 🚀 从 Prisma 模型自动生成完整的 CRUD 代码
- 📝 生成 Controller、Service、DTOs 和 Module 文件
- 🧪 自动生成单元测试文件
- 🔧 支持复合主键和索引
- 🎨 支持自定义模板
- 📚 集成 Swagger 文档
- 🔐 内置权限控制支持
- 📦 自动生成通用文件:
- 统一响应格式(ApiResponseDto)
- 高级查询支持(BaseQueryDto 支持过滤、排序、分页、搜索等)
- 认证和权限(Guards、Decorators)
- 拦截器(响应格式化、日志记录)
- 管道和过滤器(验证、异常处理)
- 工具类(Prisma 错误处理、查询构建器)
## 多文件 Schema 支持
- ✅ **支持多文件 Prisma schema 结构**:现在支持从生成的 Prisma 客户端获取 DMMF
- ✅ **自动检测客户端路径**:自动搜索常见的客户端生成路径
- ✅ **自定义客户端路径**:支持通过 `--client-path` 参数指定自定义路径
### 使用多文件 Schema
如果您使用多文件 Prisma schema 结构,请确保:
1. 先运行 `prisma generate` 生成客户端
2. 使用 `--client-path` 参数指定客户端路径(可选)
```bash
# 先生成 Prisma 客户端
npx prisma generate
# 使用生成器(会自动查找客户端)
prisma-crud generate
# 或指定客户端路径
prisma-crud generate --client-path ./generated/prisma
```
## 安装
```bash
npm install -g @ateam/prisma-crud-generator
```
或作为项目依赖:
```bash
npm install --save-dev @ateam/prisma-crud-generator
```
## 使用方法
### CLI 命令
```bash
# 初始化配置文件
prisma-crud init
# 使用配置文件生成(推荐)
prisma-crud generate
# 使用自定义配置文件路径
prisma-crud generate -c ./my-config.json
# 直接指定参数(覆盖配置文件)
prisma-crud generate -s ./prisma/schema.prisma -o ./src/modules
# 覆盖配置文件中的部分选项
prisma-crud generate -p api/v2 --no-swagger
# 使用自定义模板
prisma-crud generate -t ./custom-templates
# 指定 schema 名称
prisma-crud generate -n user
```
### 配置文件
创建 `prisma-crud.config.json`:
```json
{
"schema": "./prisma/schema.prisma",
"output": "./src/modules",
"apiPrefix": "api",
"swaggerEnabled": true,
"customTemplatesPath": "./custom-templates",
"schemaName": "main", // 可选,默认从文件名提取
"clientPath": "./generated/prisma", // 可选,用于多文件 schema 支持
"generateCommonFiles": true, // 可选,是否生成通用文件,默认为 true
"includeRelationsInCreateDto": false, // 可选,是否在创建DTO中包含关系字段
"includeRelationsInQueryDto": false // 可选,是否在查询DTO中包含关系字段
}
```
### 编程式使用
```typescript
import { generateAllCrudFiles, GeneratorConfig } from '@ateam/prisma-crud-generator';
const config: GeneratorConfig = {
prismaSchemaPath: './prisma/schema.prisma',
outputPath: './src/modules',
apiPrefix: 'api',
swaggerEnabled: true,
};
await generateAllCrudFiles(config);
```
## 生成的文件结构
对于每个 Prisma 模型,将生成以下文件结构:
```
src/modules/
├── common/ # 通用文件(generateCommonFiles: true 时生成)
│ ├── dto/
│ │ ├── api-response.dto.ts # 统一响应格式
│ │ ├── base-query.dto.ts # 高级查询基类(支持过滤、排序、分页等)
│ │ ├── base-response.dto.ts # 基础响应 DTO
│ │ └── base.dto.ts # 基础 DTO 工具类型
│ ├── guards/
│ │ ├── jwt-auth.guard.ts # JWT 认证守卫
│ │ └── permission.guard.ts # 权限守卫
│ ├── decorators/
│ │ └── require-permission.decorator.ts # 权限装饰器
│ ├── types/
│ │ └── permission.types.ts # 权限类型定义
│ ├── prisma/
│ │ ├── prisma.service.ts # Prisma 服务
│ │ └── prisma.module.ts # Prisma 模块
│ ├── interceptors/
│ │ ├── response.interceptor.ts # 响应格式化拦截器
│ │ └── logging.interceptor.ts # 日志记录拦截器
│ ├── pipes/
│ │ └── validation.pipe.ts # 验证管道
│ ├── filters/
│ │ └── http-exception.filter.ts # HTTP 异常过滤器
│ ├── services/
│ │ └── query-builder.service.ts # 查询构建服务
│ ├── utils/
│ │ └── prisma-error.util.ts # Prisma 错误处理工具
│ └── common.module.ts # 通用模块
└── [schema-name]/ # 从 Prisma schema 文件名提取的 schema 名称
└── user/
├── controllers/
│ ├── user.controller.ts
│ └── user.controller.spec.ts
├── services/
│ ├── user.service.ts
│ └── user.service.spec.ts
├── dto/
│ ├── create-user.dto.ts
│ ├── update-user.dto.ts
│ ├── query-user.dto.ts
│ └── user-response.dto.ts
└── user.module.ts
```
注意:
- 如果 Prisma schema 文件名为 `user.prisma`,则 schema 名称为 `user`
- 如果文件名为 `schema.prisma`,则默认 schema 名称为 `main`
- 可以通过配置文件中的 `schemaName` 字段自定义 schema 名称
## 支持的功能
### Prisma 模型特性
- ✅ 基本字段类型(String, Int, Float, Boolean, DateTime, Json)
- ✅ 可选字段
- ✅ 默认值
- ✅ 唯一约束
- ✅ 复合主键
- ✅ 关系(一对一、一对多、多对多)
- ✅ 索引
- ✅ 枚举类型
### 生成的代码特性
- 完整的 CRUD 操作(Create, Read, Update, Delete)
- 分页查询支持
- 批量操作(createMany, updateMany, deleteMany)
- 根据唯一字段查询(单字段和复合唯一索引)
- 根据索引字段查询(支持复合索引)
- 关联数据自动加载
- 错误处理(唯一约束、外键约束等)
- 请求验证(class-validator)
- Swagger 文档(包含完整的HTTP状态码定义)
- 权限控制集成
## 自定义模板
您可以通过提供自定义 Handlebars 模板来定制生成的代码:
1. 创建模板目录结构:
```
custom-templates/
├── controller.hbs
├── controller.spec.hbs
├── service.hbs
├── service.spec.hbs
├── module.hbs
└── dto/
├── create.dto.hbs
├── update.dto.hbs
├── query.dto.hbs
└── response.dto.hbs
```
2. 使用自定义模板:
```bash
prisma-crud generate -s ./prisma/schema.prisma -o ./src/modules -t ./custom-templates
```
### 模板变量
模板中可用的变量:
- `name` - 模型名称
- `pascalName` - PascalCase 格式的名称
- `camelName` - camelCase 格式的名称
- `kebabName` - kebab-case 格式的名称
- `pluralName` - 复数形式的名称
- `fields` - 字段数组
- `relations` - 关系数组
- `hasCompositeId` - 是否有复合主键
- `compositeIdFields` - 复合主键字段
- `uniqueFields` - 唯一约束
- `indexes` - 索引
- `apiPrefix` - API 前缀
- `swaggerEnabled` - 是否启用 Swagger
### 模板助手
可用的 Handlebars 助手:
- `isCreateField` - 检查字段是否应包含在创建 DTO 中
- `isUpdateField` - 检查字段是否应包含在更新 DTO 中
- `isQueryField` - 检查字段是否应包含在查询 DTO 中
- `validationDecorators` - 生成验证装饰器
- `swaggerType` - 获取 Swagger 类型
- `compositeIdWhere` - 生成复合主键 where 子句
## 示例
### Prisma 模型
```prisma
model User {
id String @id @default(uuid())
email String @unique
name String?
role UserRole @default(USER)
posts Post[]
profile Profile?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([email])
}
enum UserRole {
USER
ADMIN
}
```
### 生成的 Service
```typescript
@Injectable()
export class UserService {
constructor(private readonly prisma: PrismaService) {}
async create(createUserDto: CreateUserDto) {
try {
const user = await this.prisma.user.create({
data: createUserDto,
include: this.getIncludeOptions(),
});
return user;
} catch (error) {
// 错误处理...
}
}
// 根据唯一字段查询
async findByEmail(email: string) {
const user = await this.prisma.user.findUnique({
where: { email },
include: this.getIncludeOptions(),
});
if (!user) {
throw new NotFoundException(`User with email: ${email} 不存在`);
}
return user;
}
// 根据索引查询(返回数组)
async findByRole(role: string) {
return await this.prisma.user.findMany({
where: { role },
include: this.getIncludeOptions(),
});
}
// 其他 CRUD 方法...
private getIncludeOptions() {
return {
posts: true,
profile: true,
};
}
}
```
### 生成的 Controller 路由
- `GET /api/user` - 获取用户列表(分页)
- `GET /api/user/:id` - 根据ID获取用户
- `GET /api/user/by-email/:email` - 根据邮箱获取用户(唯一索引)
- `GET /api/user/by-username/:username` - 根据用户名获取用户(唯一索引)
- `POST /api/user` - 创建用户
- `PATCH /api/user/:id` - 更新用户
- `DELETE /api/user/:id` - 删除用户
## 许可证
MIT