`result`:添加自定义字段和方法来查询结果
Prisma 客户端扩展从版本 4.16.0 及更高版本开始正式可用。它们是在 4.7.0 版本的预览版中引入的。如果你运行的版本早于 4.16.0,请确保启用 clientExtensions
Preview 功能标志。
¥Prisma Client extensions are Generally Available from versions 4.16.0 and later. They were introduced in Preview in version 4.7.0. Make sure you enable the clientExtensions
Preview feature flag if you are running on a version earlier than 4.16.0.
你可以使用 result
Prisma 客户端扩展 组件类型添加自定义字段和方法来查询结果。
¥You can use the result
Prisma Client extensions component type to add custom fields and methods to query results.
使用 $extends
客户级方法 创建扩展客户端。扩展客户端是标准 Prisma 客户端的一种变体,由一个或多个扩展封装。
¥Use the $extends
client-level method to create an extended client. An extended client is a variant of the standard Prisma Client that is wrapped by one or more extensions.
要将自定义 field 或 method 添加到查询结果,请使用以下结构。在此示例中,我们将自定义字段 myComputedField
添加到 user
模型查询的结果中。
¥To add a custom field or method to query results, use the following structure. In this example, we add the custom field myComputedField
to the result of a user
model query.
const prisma = new PrismaClient().$extends({
name?: 'name',
result?: {
user: { // in this case, we extend the `user` model
myComputedField: { // the name of the new computed field
needs: { ... },
compute() { ... }
},
},
},
});
参数如下:
¥The parameters are as follows:
-
name
:(可选)指定错误日志中显示的扩展名。¥
name
: (optional) specifies a name for the extension that appears in error logs. -
result
:为查询结果定义新的字段和方法。¥
result
: defines new fields and methods to the query results. -
needs
:描述结果字段依赖的对象。¥
needs
: an object which describes the dependencies of the result field. -
compute
:定义访问虚拟字段时如何计算虚拟字段的方法。¥
compute
: a method that defines how the virtual field is computed when it is accessed.
查询结果添加自定义字段
¥Add a custom field to query results
你可以使用 result
扩展组件向查询结果添加字段。这些字段在运行时计算并且是类型安全的。
¥You can use the result
extension component to add fields to query results. These fields are computed at runtime and are type-safe.
在以下示例中,我们将一个名为 fullName
的新虚拟字段添加到 user
模型中。
¥In the following example, we add a new virtual field called fullName
to the user
model.
const prisma = new PrismaClient().$extends({
result: {
user: {
fullName: {
// the dependencies
needs: { firstName: true, lastName: true },
compute(user) {
// the computation logic
return `${user.firstName} ${user.lastName}`
},
},
},
},
})
const user = await prisma.user.findFirst()
// return the user's full name, such as "John Doe"
console.log(user.fullName)
在上面的例子中,compute
的输入 user
是根据 needs
中定义的对象自动键入的。firstName
和 lastName
属于 string
类型,因为它们是在 needs
中指定的。如果 needs
中未指定,则无法访问它们。
¥In above example, the input user
of compute
is automatically typed according to the object defined in needs
. firstName
and lastName
are of type string
, because they are specified in needs
. If they are not specified in needs
, then they cannot be accessed.
在另一个计算字段中重复使用一个计算字段
¥Re-use a computed field in another computed field
以下示例以类型安全的方式计算用户的头衔和全名。titleFullName
是重复使用 fullName
计算字段的计算字段。
¥The following example computes a user's title and full name in a type-safe way. titleFullName
is a computed field that reuses the fullName
computed field.
const prisma = new PrismaClient()
.$extends({
result: {
user: {
fullName: {
needs: { firstName: true, lastName: true },
compute(user) {
return `${user.firstName} ${user.lastName}`
},
},
},
},
})
.$extends({
result: {
user: {
titleFullName: {
needs: { title: true, fullName: true },
compute(user) {
return `${user.title} (${user.fullName})`
},
},
},
},
})
字段注意事项
¥Considerations for fields
-
出于性能原因,Prisma 客户端在访问时计算结果,而不是在检索时计算结果。
¥For performance reasons, Prisma Client computes results on access, not on retrieval.
-
你只能创建基于标量字段的计算字段。
¥You can only create computed fields that are based on scalar fields.
-
你只能将计算字段与
select
一起使用,并且不能聚合它们。例如:¥You can only use computed fields with
select
and you cannot aggregate them. For example:const user = await prisma.user.findFirst({
select: { email: true },
})
console.log(user.fullName) // undefined
向结果对象添加自定义方法
¥Add a custom method to the result object
你可以使用 result
组件添加查询结果的方法。以下示例将一个新方法 save
添加到结果对象。
¥You can use the result
component to add methods to query results. The following example adds a new method, save
to the result object.
const prisma = new PrismaClient().$extends({
result: {
user: {
save: {
needs: { id: true },
compute(user) {
return () =>
prisma.user.update({ where: { id: user.id }, data: user })
},
},
},
},
})
const user = await prisma.user.findUniqueOrThrow({ where: { id: someId } })
user.email = 'mynewmail@mailservice.com'
await user.save()
使用 result
扩展组件的 omit
查询选项
¥Using omit
query option with result
extension component
你可以将 omit
(预览)选项 与 自定义字段 以及自定义字段所需的字段一起使用。
¥You can use the omit
(Preview) option with custom fields and fields needed by custom fields.
查询结果中的自定义字段所需的 omit
字段
¥omit
fields needed by custom fields from query result
如果你 omit
一个自定义字段的依赖,即使它不会包含在查询结果中,它仍将从数据库中读取。
¥If you omit
a field that is a dependency of a custom field, it will still be read from the database even though it will not be included in the query result.
以下示例省略了 password
字段,它是自定义字段 sanitizedPassword
的依赖:
¥The following example omits the password
field, which is a dependency of the custom field sanitizedPassword
:
const xprisma = prisma.$extends({
result: {
user: {
sanitizedPassword: {
needs: { password: true },
compute(user) {
return sanitize(user.password)
},
},
},
},
})
const user = await xprisma.user.findFirstOrThrow({
omit: {
password: true,
},
})
在这种情况下,尽管结果中省略了 password
,但仍会从数据库中查询它,因为它是 sanitizedPassword
自定义字段的依赖。
¥In this case, although password
is omitted from the result, it will still be queried from the database because it is a dependency of the sanitizedPassword
custom field.
查询结果中的 omit
自定义字段和依赖
¥omit
custom field and dependencies from query result
要确保完全不从数据库中查询省略的字段,你必须省略自定义字段及其依赖。
¥To ensure omitted fields are not queried from the database at all, you must omit both the custom field and its dependencies.
以下示例省略了自定义字段 sanitizedPassword
和依赖 password
字段:
¥The following example omits both the custom field sanitizedPassword
and the dependent password
field:
const xprisma = prisma.$extends({
result: {
user: {
sanitizedPassword: {
needs: { password: true },
compute(user) {
return sanitize(user.password)
},
},
},
},
})
const user = await xprisma.user.findFirstOrThrow({
omit: {
sanitizedPassword: true,
password: true,
},
})
在这种情况下,省略 password
和 sanitizedPassword
将从结果中排除两者,并阻止从数据库中读取 password
字段。
¥In this case, omitting both password
and sanitizedPassword
will exclude both from the result as well as prevent the password
field from being read from the database.
限制
¥Limitation
截至目前,Prisma Client 的结果扩展组件不支持关系字段。这意味着你无法基于相关模型或关系关系中的字段创建自定义字段或方法(例如,user.posts、post.author)。needs 参数只能引用同一模型中的标量字段。跟随 GitHub 上的问题 #20091。
¥As of now, Prisma Client's result extension component does not support relation fields. This means that you cannot create custom fields or methods based on related models or fields in a relational relationship (e.g., user.posts, post.author). The needs parameter can only reference scalar fields within the same model. Follow issue #20091 on GitHub.
const prisma = new PrismaClient().$extends({
result: {
user: {
postsCount: {
needs: { posts: true }, // This will not work because posts is a relation field
compute(user) {
return user.posts.length; // Accessing a relation is not allowed
},
},
},
},
})