Nest 与 Prisma 结合
Prisma 篇
注意
我这里用的 prisma6.16.3 版本
新建一个 Nest 项目
- 具体的参考前面章节
安装 Prisma
- 安装 Prisma CLI
bash
npm install -g prisma初始化 Prisma
bash
npx prisma init修改.env文件
bash
DATABASE_URL='mysql://用户名:密码@地址:端口号/数据库名',- 修改 prisma/schema.prisma 文件
ts
generator client {
provider = "prisma-client-js"
output = "../generated/prisma"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}拉取数据库
bash
npx prisma db pull- 这个时候 你的 prisma/schema.prisma 文件应该会自动生成数据库的表结构
在 package.json 里面添加脚本
ts
"prisma": {
"schema": "prisma/schema"
}多文件处理
- 在根目录下面找到
prisma文件夹
依次按照schema.prisma文件里面的内容,新建对应的文件 类似
ts
prisma
├── schema
│ ├── schema.prisma
│ ├── app.prisma
│ ├── shop.prisma
│ └── erp.prisma- 每一个
prisma文件 对应的就是一张表
把 schema.prisma 放到 prisma 文件夹下
生成 Prisma Client
ts
npx prisma generate最后的结果
ts
prisma
├── generated
├── schema
│ ├── schema.prisma
│ ├── app.prisma
│ ├── shop.prisma
│ └── erp.prismaNest 篇
项目结构
bash
prisma
├── prisma.extension.service.ts // prisma 扩展
├── prisma.module.ts // prisma 模块
├── prisma.service.ts // prisma 暴露出去的服务
├── prisma.provider.ts // 核心prisma 提供创建 一个 Module 和 Service
- 名字任意 我这里起名就是 prisma.module.ts 和 prisma.service.ts
prisma.module.ts
ts
import { PrismadbService } from "./prisma.service"; // 服务
import { Module, Global } from "@nestjs/common";
import { PrismaProvider } from "./prisma.provider"; // 提供
import { PrismaQueryHelperService } from "./prisma.extension.service"; // 扩展
@Global() // Global decorator to make this module available globally
@Module({
imports: [],
controllers: [],
providers: [PrismadbService, PrismaProvider, PrismaQueryHelperService],
exports: [PrismadbService, PrismaProvider, PrismaQueryHelperService],
})
export class PrismadbModule {}prisma.provider.ts
ts
import { Injectable, OnModuleDestroy, OnModuleInit } from "@nestjs/common";
import { PrismaClient } from "../../../prisma/generated/prisma"; // 修改为你自己的
import { PrismaQueryHelperService } from "./prisma.extension.service"; // 扩展
// 读写分离 这样读是一个数据库 写又是另外一个数据库
import { readReplicas } from "@prisma/extension-read-replicas";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class PrismaProvider
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
private static initialized = false;
constructor(
private readonly configService: ConfigService,
private readonly PrismaQueryHelperService: PrismaQueryHelperService
) {
super({
datasourceUrl: `mysql://${configService.get("db").mysql.username}:${
configService.get("db").mysql.password
}@${configService.get("db").mysql.host}:${
configService.get("db").mysql.port
}/${configService.get("db").mysql.database}`,
log: ["info", "query"],
});
}
async onModuleInit() {
if (!PrismaProvider.initialized) {
PrismaProvider.initialized = true;
await this.$connect();
}
}
async onModuleDestroy() {
if (PrismaProvider.initialized) {
PrismaProvider.initialized = false;
await this.$disconnect();
}
}
// 增加扩展 // 读写分离
withExtensions() {
// 读的客户端
const readReplicasClient = new PrismaClient({
datasourceUrl: `mysql://${
this.configService.get("db").mysqlread.username
}:${this.configService.get("db").mysqlread.password}@${
this.configService.get("db").mysqlread.host
}:${this.configService.get("db").mysqlread.port}/${
this.configService.get("db").mysqlread.database
}`,
log: ["info", "query"],
});
return this.$extends(
this.PrismaQueryHelperService.existsExtension
).$extends(
readReplicas({
replicas: [readReplicasClient],
})
);
}
}prisma.extension.service.ts
- 给 prisma 添加一个扩展方法 exists
ts
// query-helper.service.ts
import { Injectable } from "@nestjs/common";
import { Prisma } from "@prisma/client/extension.js";
@Injectable()
export class PrismaQueryHelperService {
//any logic
existsExtension = Prisma.defineExtension({
name: "exists-extension",
model: {
$allModels: {
async exists<T>(
this: T,
where: Prisma.Args<T, "findFirst">["where"]
): Promise<boolean> {
const context = Prisma.getExtensionContext(this);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await (context as any).findFirst({ where });
return result !== null;
},
},
},
});
}prisma.service.ts
ts
import { Inject, Injectable, OnModuleInit, Type } from "@nestjs/common";
import { PrismaProvider } from "./prisma.provider";
const ExtendedPrismaClient = class {
constructor(provider: PrismaProvider) {
return provider.withExtensions();
}
} as Type<ReturnType<PrismaProvider["withExtensions"]>>;
@Injectable()
export class PrismadbService extends ExtendedPrismaClient {
constructor(provider: PrismaProvider) {
super(provider);
}
}使用
- 返回结果就是 true 或者 false
ts
async testextextends() {
// 返回布尔值
const result = await this.prismadbService.emp.exists({ id: { gte: 100 } });
console.log(result);
// 返回查询结果
return result;
}配置文件
bash
# 开发环境配置
app:
prefix: ''
port: 8080
logger:
# 项目日志存储路径,相对路径(相对本项目根目录)或绝对路径
dir: '../logs'
# 文件相关
file:
# 是否为本地文件服务或cos
isLocal: true
# location 文件上传后存储目录,相对路径(相对本项目根目录)或绝对路径
location: '../upload'
# 文件服务器地址,这是开发环境的配置 生产环境请自行配置成可访问域名
domain: 'http://localhost:8080'
# 文件虚拟路径, 必须以 / 开头, 如 http://localhost:8080/profile/****.jpg , 如果不需要则 设置 ''
serveRoot: '/profile'
# 文件大小限制,单位M
maxSize: 10
# 腾讯云cos配置
cos:
secretId: ''
secretKey: ''
bucket: ''
region: ''
domain: ''
location: ''
# 数据库配置
db:
mysql:
host: 'xxxx'
username: 'root'
password: 'xxx'
database: 'manybymany'
port: 3306
charset: 'utf8mb4'
logger: 'file'
logging: true
multipleStatements: true
dropSchema: false
synchronize: true
supportBigNumbers: true
bigNumberStrings: true
mysqlread:
host: 'xxxx'
username: 'root'
password: 'xxxx'
database: 'manybymany'
port: 3306
charset: 'utf8mb4'
logger: 'file'
logging: true
multipleStatements: true
dropSchema: false
synchronize: true
supportBigNumbers: true
bigNumberStrings: true
# redis 配置
redis:
host: 'xxxx'
password: 'redis_n6BSFa'
port: 6379
db: 0
keyPrefix: ''
# jwt 配置
jwt:
secretkey: 'jsopy'
expiresin: '1h'
refreshExpiresIn: '2h'
# 权限 白名单配置
perm:
router:
whiteList:
['/user/login', '/user/register', '/user/refreshToken', '/user/testjwt']
# 不使用全局拦截
noglobalinterceptor:
router:
whiteList: ['/user/yasuo2', '/user/yasuo']
# 用户相关
# 初始密码, 重置密码
user:
initialPassword: '123456'
# 自己写的测试
testconfig:
test: 'dev'