`result`: クエリ結果にカスタムフィールドとメソッドを追加する
Prisma Client拡張機能はバージョン4.16.0以降で一般提供されています。これらはバージョン4.7.0でプレビュー導入されました。4.16.0より前のバージョンを実行している場合は、必ずclientExtensions
プレビュー機能フラグを有効にしてください。
result
Prisma Client拡張機能コンポーネントタイプを使用して、クエリ結果にカスタムフィールドとメソッドを追加できます。
$extends
クライアントレベルメソッドを使用して、拡張クライアントを作成します。拡張クライアントは、1つ以上の拡張機能でラップされた標準のPrisma Clientのバリアントです。
カスタムフィールドまたはメソッドをクエリ結果に追加するには、次の構造を使用します。この例では、user
モデルクエリの結果にカスタムフィールドmyComputedField
を追加します。
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() { ... }
},
},
},
});
パラメータは次のとおりです
name
: (オプション) エラーログに表示される拡張機能の名前を指定します。result
: クエリ結果への新しいフィールドとメソッドを定義します。needs
: 結果フィールドの依存関係を記述するオブジェクト。compute
: 仮想フィールドがアクセスされたときにどのように計算されるかを定義するメソッド。
クエリ結果にカスタムフィールドを追加する
result
拡張機能コンポーネントを使用して、クエリ結果にフィールドを追加できます。これらのフィールドは実行時に計算され、タイプセーフです。
次の例では、fullName
という名前の新しい仮想フィールドをuser
モデルに追加します。
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
は、needs
で指定されているため、string
型です。needs
で指定されていない場合、アクセスできません。
計算フィールドを別の計算フィールドで再利用する
次の例では、ユーザーの敬称とフルネームをタイプセーフな方法で計算します。titleFullName
は、fullName
計算フィールドを再利用する計算フィールドです。
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})`
},
},
},
},
})
フィールドに関する考慮事項
-
パフォーマンス上の理由から、Prisma Clientは取得時ではなく、アクセス時に結果を計算します。
-
スカラーフィールドに基づいて計算フィールドを作成することのみが可能です。
-
計算フィールドは
select
でのみ使用でき、集計することはできません。例:const user = await prisma.user.findFirst({
select: { email: true },
})
console.log(user.fullName) // undefined
結果オブジェクトにカスタムメソッドを追加する
result
コンポーネントを使用して、クエリ結果にメソッドを追加できます。次の例では、新しいメソッドsave
を結果オブジェクトに追加します。
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
クエリオプションを使用する
omit
(プレビュー) オプションをカスタムフィールドおよびカスタムフィールドに必要なフィールドで使用できます。
クエリ結果からカスタムフィールドに必要なフィールドをomit
する
カスタムフィールドの依存関係であるフィールドをomit
した場合でも、クエリ結果には含まれませんが、データベースから読み取られます。
次の例では、カスタムフィールドsanitizedPassword
の依存関係であるpassword
フィールドを省略します
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
カスタムフィールドの依存関係であるため、データベースからクエリされます。
クエリ結果からカスタムフィールドと依存関係をomit
する
省略されたフィールドがデータベースからまったくクエリされないようにするには、カスタムフィールドとその依存関係の両方を省略する必要があります。
次の例では、カスタムフィールドsanitizedPassword
と依存関係のあるpassword
フィールドの両方を省略します
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
フィールドがデータベースから読み取られるのを防ぎます。
制限事項
現在のところ、Prisma Clientの結果拡張機能コンポーネントはリレーションフィールドをサポートしていません。これは、リレーショナルリレーションシップ(例:user.posts、post.author)の関連モデルまたはフィールドに基づいてカスタムフィールドまたはメソッドを作成できないことを意味します。needsパラメータは、同じモデル内のスカラーフィールドのみを参照できます。GitHubのissue #20091に従ってください。
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
},
},
},
},
})