Prisma:下一代 ORM 框架
ORM:对象关系映射(Object Relational Mapping,简称ORM),主要实现程序对象到关系数据库数据的映射
package.json
{
"name": "server",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"dev": "concurrently \"npx prisma studio\" \"nodemon src/index.ts\""
},
"dependencies": {
"@prisma/client": "4.11.0",
"express": "4.18.2"
},
"devDependencies": {
"@types/express": "4.17.17",
"@types/node": "18.14.4",
"concurrently": "^7.6.0",
"prisma": "4.11.0"
},
"prisma": {
"seed": "nodemon prisma/seed.ts"
}
}
之后运行 yarn install
或 npm install
即可。
启动服务使用 yarn dev
或者 npm run dev
会自动启动服务并打开可视化图形
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = "file:./dev.db"
}
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
}
这样我们成功创建了 Prisma schema,但是目前还没有创建数据库,所以我们需要运行以下命令去创建 User
和 Post
表
npx prisma migrate dev --name init
// prisma/seed.ts
import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient()
const userData: Prisma.UserCreateInput[] = []
async function main() {
// 书写 Prisma Client queries
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
记得使用此命令
ts-node prisma/seed.ts
添加字段
async function main() {
const user = await prisma.user.create({
data: {
name: 'xjj',
emial: '3434909403@qq.com'
}
})
console.log(user)
}
检索所有字段
async function main() {
const users = await prisma.user.findMany()
console.log(users)
}
检索特定字段
async function main() {
const usersWithPosts = await prisma.user.findMany({
include: {
posts: true
}
})
}
使用此命令,我们可以打开可视化界面,查看和修改表的内容
npx prisma studio
create
创建单个
const user = await prisma.user.create({
data: {
email: 'xj@example.com',
name: 'xj'
}
})
// output: 创建的对象
createMany
创建多个
const usersCreatedNums = await prisma.user.create.createMany({
data: [
{ name: 'xj', email: 'xj@example.com' },
{ name: 'sx', email: 'sx@example.com' },
{ name: 'xm', email: 'xm@example.com' },
{ name: 'yq', email: 'yq@example.com' },
]
})
// output: { count: 4 }
findUnique
查找单个
// By Email
const user01 = await prisma.user.findUnique({
where: {
email: 'xj@example.com'
}
})
// By ID
const user02 = await prisma.user.findUnique({
where: {
id: 99
}
})
findMany
查找全部
const users = await prisma.user.findMany()
update
更新单个
const updateUser = await prisma.user.update({
where: {
email: 'xj@example.com'
},
data: {
name: 'xjj'
}
})
// output: 更新的用户字段数据
updateMany
更新多个
const updateUsers = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io'
}
},
data: {
role: 'ADMIN'
}
})
// output: { count: xxx }
delete
删除单个
const deleteUser = await prisma.user.delete({
where: {
email: 'xj@example.com'
}
})
deleteMany
删除多个
const deleteUsers = await prisma.user.deleteMany({
where: {
email: {
contains: 'example.com'
}
}
})
// 清空操作
await prisma.user.deleteMany({})
Prisma 可以查询对象之间的映射关系,这里演示的是上述表字段的数据:
// prisma/schema.prisma
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
}
可以看到 User(id:1) <-> Post(N)
include
const user = await prisma.user.findUnique({
where: {
id: 1
},
include: {
posts: true
}
})
返回结果:
当我们把 posts
设置为 false
时,
include: {
posts: false
}
返回结果:
有时候某个关系映射可能在三个甚至更多个对象之间,这时我们可以通过嵌套来查询
include: {
posts: {
include: {
categories: true,
}
}
}
select
用法与 include
一致,不再赘述。需要注意的是,select
不可以和 include
在同一级使用,例如下面的是错误的:
await prisma.user.findUnique({
where: {
id: 1
},
select: {
posts: true
},
include: {
posts: {
include: {
categories: false
}
}
}
})
但是 select
和 include
可以在不同级中使用,例如下面是正确的:
await prisma.user.findUnique({
include: {
name: true,
posts: {
select: {
categories: false
}
}
}
})
当我们想要创建(create)一个字段数据时,可以给与之关联的字段添加数据:
const createUserAndPost = await prisma.user.create({
data: {
email: 'xj@example.com',
name: 'xj',
posts: {
create: [
{ title: 'xj的blog' },
{ title: 'bulabula' }
]
}
}
})
当然还有另一种写法:
await prisma.user.create({
data: {
email: 'xj@example.com',
name: 'xj',
posts: {
createMany({
data: [
{ title: 'xj的blog' },
{ title: 'bulabula' }
]
})
}
}
})
当我们添加数据时,可以关联到某一张表上
const user = await prisma.user.create({
data: {
email: 'jjjj@example.com'
posts: {
connect: {
id: 2
}
}
}
})
也可以关联多张表:
connect: [{ id: 1 }, { id: 2 }, { id: 2 }]
当然也可以在 update
更新时,更新关联
const user = await prisma.user.update({
where: {
id: 1
},
data: {
posts: {
connect: {
id: 2
},
create: {
title: 'My new post title' // 这里又创建了一个 post
}
}
}
})
当我们 connect
的表不存在时,创建并关联一个表
const queryEmail = 'gxj@example.com'
const createPost = await prisma.post.create({
data: {
title: 'connect or create a record',
author: {
connectOrCreate: {
where: {
email: queryEmail
},
create: {
email: queryEmail
}
}
}
}
})
取消特定关联
const updatePost = await prisma.user.update({
where: {
id: 1
},
data: {
posts: {
disconnect: [{ id: 1 }, { id: 2 }]
}
}
})
取消所有关联,如下代码,可以取消一对多的关联。
const updateUser = await prisma.user.update({
where: {
id: 2
},
data: {
posts: {
set: []
}
}
})
删除所有:不是取消关联,而是取消关联并将关联的表删除(其实都删除了,还哪来的关联)
const update = await prisma.user.update({
where: {
id: 1
},
data: {
posts: {
deleteMany: {}
}
}
})
也可以指定删除对应表
根据 published
字段删除
const update = await prisma.user.update({
where: {
id: 1
},
data: {
posts: {
deleteMany: {
published: false
}
}
}
})
根据 id
指定删除
const update = await prisma.user.update({
where: {
id: 1
},
data: {
posts: {
deleteMany: [{ id: 2 }]
}
}
})
updateMany
更新多个
const update = prisma.user.update({
where: {
id: 2
},
data: {
posts: {
updateMany: {
where: {
published: false
},
data: {
published: true
}
}
}
}
})
也可以指定特定 id
更新
const update = prisma.user.update({
where: {
id: 1
},
data: {
posts: {
updateMany({
where: {
id: 2
},
data: {
title: 'jjgiegie'
}
})
}
}
})
以下代码表明:如果 post
表中 id=2
的字段存在,那么就会更新对应 author
表中的 email
和 name
字段
const email = 'bob@example.com'
const update = await prisma.post.update({
where: {
id: 2
},
data: {
author: {
upsert: {
create: {
email,
name: 'Bob the New User'
},
update: {
email,
name: 'Bob the existing user'
}
}
}
}
})
我们可以在 update
API 里使用 create
或者 createMany
去创建对应关联表的内容
const user = await prisma.user.update({
where: {
id: 2
},
data: {
posts: {
createMany: {
data: [{ title: 'My First Post' }, { title: 'My Second Post' }]
}
}
}
})
根据关联表字段过滤
示例1
posts
关联表的 views
字段值**不是(none)**大于(gt) 100posts
关联表的 likes
字段值不多于(lte) 100const users = await prisma.user.findMany({
where: {
posts: {
none: {
views: {
gt: 100 // greater than
}
}
},
every: {
likes: {
lte: 50 // less than equal
}
}
}
})
示例2
author
表 name
字段值不是(isNot) Bobauthor
表 age
字段值**大于(gt)**40const users = awiat prisma.post.findMany({
where: {
author: {
isNot: {
name: 'Bob'
},
is: {
age: {
gt: 40
}
}
}
}
})
示例3
posts
const userWithZeroPosts = await prisma.user.findMany({
where: {
posts: {
none: {}
}
}
})
示例4
posts
const useWithSomePosts = await prisma.user.findMany({
where: {
posts: {
some: {}
}
}
})
获得 user
表中 email
字段值为 alice@prisma.io 的 posts()
表内容
const postByUser: Post[] = await prisma.user.findUnique({
where: {
email: 'alice@prisma.io'
}
}).posts()
当然,这对于 findMany
是不允许的,因为 findMany
返回值并不是单个对象
// 非法操作
const posts = await prisma.user.findMany().posts()
参考地址:Prisma Client API (Reference)
以下表明:
prisma.io
结尾(endsWith)published
为 true
的 post
User
字段Post
表中 pushlished
字段值为 true
的内容(where:{published:true})const result = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io'
},
posts: {
some: {
published: true
}
}
},
includes: {
posts: {
where: {
published: true
}
}
}
})
equals
返回**字段值为 xxx **的数据
await prisma.user.findMany({
where: {
name: {
equals: 'xj'
}
}
})
也可以使用下面简单的方法:
await prisma.user.findMany({
where: {
name: 'xj'
}
})
not
返回字段值不是 xxx 的所有数据
await prisma.user.findMany({
where: {
name: {
not: 'xj'
}
}
})
in
& notIn
id
字段值为 1、2、3、5
的数据await prisma.user.findMany({
where: {
id: {
in: [1, 2, 3, 5]
}
}
})
name
不为 [‘xj’, ‘sx’, ‘yq’]
的数据await prisma.user.findMany({
where: {
name: {
notIn: ['xj', 'sx', 'yq']
}
}
})
或者使用组合方式 in
+ NOT
实现:
await prisma.user.findMany({
where: {
NOT: {
name: {
in: ['xj', 'sx', 'yq']
}
}
}
})
:wink: 字段值为
null
的数据是不计入in
和notIn
等算法里的。例如你使用组合in
+NOT
返回name
字段值不在某个列表中的数据,name
为null
的值是不会返回的。
lt
& lte
lt
: less than;lte
:less than or equal to
Post
表中 likes
字段值小于 9 的数据await prisma.post.findMany({
where: {
likes: {
lt: 9
}
}
})
Post
表中 likes
字段值小于等于 9 的数据await prisma.post.findMany({
where:{
likes: {
lte: 9
}
}
})
gt
& gte
gt
:greater than;gte
:greater than or equal to
与 lt
和 lte
基本一致,这里不再赘述
contains
字段值是否**包含(contains)**xxx
post
表中的 content
字段值包含 ‘Plumbiu’
的数据await prisma.post.findMany({
where: {
content: {
contains: 'Plumbiu'
}
}
})
post
表中 content
字段值不包含 hate
的数据await prisma.post.findMany({
where: {
NOT: {
content: {
contains: 'hate'
}
}
}
})
search
在字符串字段中使用全文搜索(Full-Text Search)
目前版本(4.11.0),Full-Text Search
处于预览版本,并且仅支持 PostgreSQL
和 MySQL
。
使用 fullTextSearch
需要一些额外的配置
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearch"]
}
post
表中 title
字段值包含 cat
或 dog
的数据await prisma.post.findMany({
where: {
title: {
search: 'cat | dog'
}
}
})
post
表中 title
字段值包含 cat
和 dog
的数据await prisma.post.findMany({
where: {
title: {
search: 'cat & dog'
}
}
})
post
表中 title
字段值不包含 cat
数据await prisma.post.findMany({
where: {
title: {
search: '!cat'
}
}
})
mode
:wink: 仅支持
PostgreSQL
和MongoDB
获取 post
表中 title
字段中包含 prisma
字段,以一种不敏感的方式(不区分大小写)
await prisma.post.findMany({
where: {
title: {
contains: 'prisma',
mode: 'insentitive'
}
}
})
startsWith
& endWith
post
表中以 'Pr'
为开头的 title
字段值数据await prisma.post.findMany({
where: {
title: {
startWith: 'Pr'
}
}
})
post
表中以 'prisma.io'
为结尾的 title
字段值数据await prisma.post.findMany({
where: {
title: {
endsWith: 'prisma.io'
}
}
})
AND
获取 post
表中 content
字段值包含 ‘Prisma’
并且 publish
字段值为 false
的数据
await prisma.post.findMany({
where: {
AND: [
{
content: {
contains: 'Prisma'
}
},
{
published: {
equals: false
}
}
]
}
})
以下代码也能实现上面的逻辑
await prisma.post.findMany({
where: {
content: {
contains: 'Prisma'
},
published: false
}
})
OR
获取 post
表中 title
包含 Prisma
或者 databases
的数据
await prisma.post.findMany({
where: {
OR: [{
title: {
contains: 'Prisma'
}
}, {
title: {
contains: 'Prisma'
}
}
]
}
})
NOT
获取 post
表中 title
包含 Prisma
或者 databases
,但是不包含 SQL
的数据
await prisma.post.findMany({
where: {
OR: [{
title: {
contains: 'Prisma'
}
}, {
title: {
contains: 'databases'
}
}
],
NOT: {
title: {
contains: 'SQL'
}
}
}
})
关于关联表的过滤 API
some
获取满足条件的关联表的至少一个数据。
例:获取 user
关联表 post
至少一个(some) content
字段值包含 ‘Prisma’
的数据
await prisma.user.findMany({
where: {
post: {
some: {
content: {
contains: 'Prisma'
}
}
}
}
})
every
获取所有满足条件的关联表的数据
例:获取 user
关联表 post
至少一个(some) content
字段值包含 ‘Prisma’
的数据且**每一条(everu)**数据均满足 published: true
await prisma.post.findMany({
where: {
every: {
published: true
},
content: {
contains: 'Prisma'
}
}
})
none
获取所有满足条件(相反)的关联表的数据
post
的数据await prisma.user.findMany({
where: {
post: {
none: {}
}
}
})
post
中 published
字段值不为(none) true
的数据await prisma.user.findMany({
where: {
post: {
none: {
published: true
}
}
}
})
is
& isNot
is
:获取关联表某一字段具有某个值的数据
isNot
:获取关联表某一字段不具有某个值的字段
返回 post
关联表 user
中 name
字段值为 ‘Bob’
的值
await prisma.post.findMany({
where: {
user: {
is: {
name: 'Bob'
}
}
}
})
isNot
同理,不再赘述
Scalar list filters 允许我们对 list / array
字段进行过滤
:sunglasses: 支持以下版本
- PostgreSQL >= 2.15.0
- CockroachDB >= 3.9.0
- MongoDB >= 3.11.0
:cry: Scalar list / array 会忽视字段值为
null
的数据
has
返回 post
表中 tags
字段值包含 ‘database’
的数据
await prisma.post.findMnay({
where: {
tags: {
has: 'databases'
}
}
})
NOT
+ has
:返回 post
表中 tags
字段值不包含 ‘database’
的数据
await prisma.post.findMany({
where: {
NOT: {
tags: {
has: 'databases'
}
}
}
})
hasEvery
相当于多个 has
,多个约束条件都要满足
返回 post
表中 tags
字段值同时含有 ‘database’
和 ‘typescript’
的值
await prisma.post.findMany({
where: {
tags: {
hasEvery: ['database', 'typescript']
}
}
})
hasSome
相当于多个 has
,至少一个约束条件要满足
返回 post
表中 tags
字段值同时含有 ‘database’
或 ‘typescript’
的值
await prisma.post.findMany({
where: {
tags: {
hasSome: ['database', 'typescript']
}
}
})
isEmpty
返回 Post
表中没有 tags
的数据
await prisma.post.findMany({
where: {
tags: {
isEmpty: true
}
}
})
isSet
:heart_eyes: 适用于 MongoDB >= 3.11.1
参考:Prisma Client API (Reference)
equals
相当于多个 has
,字段值要与约束条件的字段相同
返回 post
表中 tags
字段值同时仅含有 ‘database’
和 ‘typescript’
的值
await prisma.post.findMany({
where: {
tags: {
equals: ['databases', 'typescript'],
},
},
})
名字 | 描述 |
---|---|
asc | 升序排序(A → Z) |
desc | 降序排序(Z → A) |
获取 user
表中以 role
和 name
字段排序的数据,其中返回的数据包括其关联表 posts
,posts
中的数据按照 title
字段排序
await prisma.user.findMany({
orderBy: [
{ tole: 'desc' },
{ name: 'desc' }
],
include: {
posts: {
orderBy: {
title: 'desc'
},
select: {
title: true
}
}
}
})
获取 post
的数据,数据以关联表 author
以 email
字段顺序排序
await prisma.post.findMany({
orderBy: {
author: {
email: 'asc'
}
}
})
:kissing: Need Prisma >= 2.19.0
根据 user
的关联表 posts
的数量排序
await prisma.user.findMany({
orderBy: {
posts: {
_count: 'desc'
}
}
})
decimal
:adj.十进制的,小数的;n.小数
Prisma
指的是小数,同时这里使用的依赖为 Decimal.js
await prisma.sample.create({
data: {
cost: new Prisma.Decimal(24.454545)
}
})
BigInt
依赖于 NodeJS10.4.0+ 中的 BigInt
类型
await prisma.sample.create({
data: {
revenue: BigInt(114514191)
}
})
Bytes
依赖于 Nodejs 中的 Buffer
类型
await prisma.sample.create({
data: {
myField: Buffer.from([1, 2, 3, 4]),
},
})
Working with scalar lists / arrays
在 typescript 中,我们可以这样声明变量:
let str: string = 'xxx'
添加了类型注解,是的变量更加的安全,也使得代码更加语义化,在 Prisma 中,当我们创建了一个 model
,便会有其对应的类型
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
profile Profile?
}
之前我们已经介绍了 select
和 include
方法,即筛选返回的数据应包含什么字段,其对应的类型为 UserSelect
、UserInclude
即在 User
后加 Select
、Include
,具体使用如下
import { Prisma } from '@prisma/client'
const userEmail: Prisma.UserSelect = {
email: false,
id: true
}
const usersWithoutEmail = prisma.user.findMany({
select: userEmail
})
返回的数据格式
应用场景:返回指定数据
中间件相当于生命周期钩子,允许你处理某个请求时,在之前和之后进行一定的处理。
使用 prisma.$use
API 去添加中间件,如下:
const prisma = new PrismaClient()
// Middleware 1
prisma.$use(async (params, next) => {
// 操作一下参数
const result = await next(params)
// 将 result 返回
return result
})
// Middleware 2
prisma.$use(async (params, next) => {
// 操作一下参数
const result = await next(params)
// 将 result 返回
return result
})
// 处理请求
prisma
的中间件的使用很像 koa2 的洋葱模型,见以下示例:
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
console.log(params.args.data.title)
console.log('1')
const result = await next(params)
console.log('6')
return result
})
prisma.$use(async (params, next) => {
console.log('2')
const result = await next(params)
console.log('5')
return result
})
prisma.$use(async (params, next) => {
console.log('3')
const result = await next(params)
console.log('4')
return result
})
const create = await prisma.post.create({
data: {
title: 'Welcome to Prisma Day 2020',
},
})
const create2 = await prisma.post.create({
data: {
title: 'How to Prisma!',
},
})
输出结果:
Welcome to Prisma Day 2020
1
2
3
4
5
6
How to Prisma!
1
2
3
4
5
6
params
是一个关于请求的一些参数,我们可以设置它来更改一些 API (例如 findMany
、deleteMany
)的参数,甚至是 API 请求本身,例如我们可以通过判断 action
将 deleteMany
改为 updateMany
从而实现软删除,具体见下:
参数 | 描述 |
---|---|
action | 请求方法 - 例如:create 或者 findMany |
args | 请求中的一些参数,例如:where 、data 或者 orderBy |
dataPath | 如果你使用 fluent API,可以用来增添数据 |
model | model 的类型 - 例如:Post 或者 User |
runInTransaction | 如果请求在 transaction 中,那么返回 true |
以下是 params
的一个示例
prisma.$use(async (params, next) => {
console.log(params)
const result = await next(params)
return result
})
app.get('/use', async (req, res) => {
const users = await prisma.user.findMany({
select: {
email: true
}
})
res.json(users)
})
打印结果:
将字符 xj
替换为 **
prisma.$use(async (params, next) => {
const result = await next(params)
const newResult = result.map((item: any) => {
return item.email.indexOf('xj') === -1 ? item : { ...item, email: item.email.replace('xj', '**')}
})
return newResult
})
app.get('/illegal', async (req, res) => {
const users = await prisma.user.findMany({
select: {
email: true
}
})
res.json(users)
})
// prisma/schema.prisma
model Post {
+ deleted Boolean @default(false)
}
prisma.$use(async (params, next) => {
if(params.model === 'Post') {
if(params.action === 'delete') {
params.action = 'update'
params.args['data'] = { deleted: true }
} else if(params.action === 'deleteMany') {
params.action = 'updateMany'
if(params.args.data !== undefined) {
params.args.data['deleted'] = true
} else {
params.args['data'] = { deleted: true }
}
}
}
return next(params)
})
app.get('/softdelete', async (req, res) => {
const users = await prisma.post.deleteMany({
where: {
published: false
}
})
res.json(users)
})
打印 api 请求并响应后的时间
prisma.$use(async (params, next) => {
const before = Date.now()
const result = await next(params)
const after = Date.now()
console.log(`api dutation is ${after - before}ms`)
return result
})
app.get('/duration', async (req, res) => {
const users = await prisma.user.findMany({
select: {
email: true
}
})
res.json(users)
})
分页功能
偏移分页使用 skip
和 take
两个参数去跳过前几个结果,选择用户指定数量的一些文章
await prisma.post.findMany({
skip: 3,
take: 4
})
指针型分页,返回指针指向数据后面的指定数量的数据
const secondQueryResults = await prisma.post.findMany({
take: 4,
skip: 1, // Skip the cursor
cursor: {
id: myCursor,
}
})
const lastPostInResults = secondQueryResults[3] // Remember: zero-based index! :)
const myCursor = lastPostInResults.id // Example: 52
Prisma Client
允许我们使用 aggregate
方法在一些数量字段(例如 Int
、Float
)获取一些数据,如下获取用户的平均年龄
const averAge = await prisma.user.aggregate({
_avg: {
age: true
}
})
console.log('Average age:' + averAge._avg.age)
当然,aggregate
方法还包括其他参数(不赘述 where
、orderBy
等参数)
参数名 | 描述 |
---|---|
_count | 返回符合条件描述并且值不为 null 的个数 |
_avg | 返回指定字段的平均值 |
_sum | 返回指定字段的总和 |
_min | 返回指定字段的最小值 |
_max | 返回指定字段的最大值 |
当然,参数之间还可以组合使用:
await prisma.user.aggregate({
_avg: {
age: true
},
_count: {
age: true
}
})
otuput:
{
_avg: {
age: 18
},
_count: {
age: 9
}
}
groupBy
方法运行我们组合表的字段返回数据
await prisma.user.groupBy({
by: ['country'],
_sum: {
profileViews: true
}
})
output:
[
{ country: 'Germany', _sum: { profileViews: 126 } },
{ country: 'Sweden', _sun: { profileViews: 0 } }
]
groupBy
方法的参数,与 Aggregation
基本一致
参数名 | 描述 |
---|---|
_count | 返回符合条件描述并且值不为 null 的个数 |
_avg | 返回指定字段的平均值 |
_sum | 返回指定字段的总和 |
_min | 返回指定字段的最小值 |
_max | 返回指定字段的最大值 |
count
方法返回对应表中的数据数量
const userCount = await prisma.user.count()
count
方法的参数
参数名 | 描述 |
---|---|
where | 略 |
cursor | 指针,指向某一个数据,一般将 使用 id 充当 cursor 的值 |
skip | 略 |
take | 略 |
orderBy | 略 |
select | 略 |
有时候我们需要验证用户输入的字段格式是否正确,这一般是前端来解决的。
这里的例子使用的是 Superstruct 去验证字段数据是否正确
import { PrismaClient, Prisma, User } from '@prisma/client'
import { assert, object, string, size, refine } from 'superstruct'
import isEmail from 'isemail'
const prisma = new PrismaClient()
const Signup = object({
email: refine(string(), 'email', (v) => isEmail.validate(v)), // email 应该是长字符,使用 isemail 添加验证规则
password: size(string(), 7, 30), // pasword 应该是长字符型,字符数量在 7-30 之间
firstName: size(string(), 2, 50),
lastName: size(string(), 2, 50),
})
type Signup = Omit<Prisma.UserCreateArgs['data'], 'id'>
async function signup(input: Signup): Promise<User> {
assert(input, Signup)
return prisma.user.create({
data: input.user,
})
}
Prisma Client
是区分 null
和 undefined
的:
null
is a valueundefined
means do nothingNote:
null
和undefined
的区分对于GraphQL
十分重要,因为GraphQL
中两者是可交换的
const update = await prisma.user.update({
where: {
id: 1,
},
data: {
name: "Petunia",
email: emailInput === null ? undefined : emailInput, // If null, don't include in update!
},
});
将某个字段设置为 undefined
,与不包括这个字段是相同的:
await prisma.user.update({
where: {
id: 1
},
data: {
name: 'xjj',
// no email
}
})
与下面 data
参数设置一致:
data: {
name: 'xjj',
email: undefined
}