拡張機能
Prisma Client拡張機能はバージョン4.16.0以降で一般提供されています。バージョン4.7.0でプレビューとして導入されました。4.16.0より前のバージョンを実行している場合は、clientExtensions
プレビュー機能フラグを有効にしてください。
Prisma Client拡張機能を使用すると、モデル、結果オブジェクト、クエリに機能を追加したり、クライアントレベルのメソッドを追加したりできます。
次のコンポーネントタイプの1つ以上を使用して拡張機能を作成できます
model
: モデルにカスタムメソッドまたはフィールドを追加するclient
: Prisma Clientにクライアントレベルのメソッドを追加するquery
: カスタムPrisma Clientクエリを作成するresult
: クエリ結果にカスタムフィールドを追加する
たとえば、model
およびclient
コンポーネントタイプを使用する拡張機能を作成できます。
Prisma Client拡張機能について
Prisma Client拡張機能を使用すると、拡張クライアントを作成します。拡張クライアントは、1つ以上の拡張機能でラップされた標準Prisma Clientの軽量バリアントです。標準クライアントは変更されません。プロジェクトには、必要な数の拡張クライアントを追加できます。拡張クライアントの詳細はこちら。
単一の拡張機能、または複数の拡張機能を拡張クライアントに関連付けることができます。複数の拡張機能の詳細はこちら。
Prisma Client拡張機能を他のPrisma ORMユーザーと共有したり、他のユーザーが開発したPrisma Client拡張機能をPrisma ORMプロジェクトにインポートしたりできます。
拡張クライアント
拡張クライアントは、相互に、および標準クライアントと次のように対話します
- 各拡張クライアントは、分離されたインスタンス内で独立して動作します。
- 拡張クライアントは、相互に、または標準クライアントと競合することはありません。
- すべての拡張クライアントと標準クライアントは、同じPrisma ORMクエリエンジンと通信します。
- すべての拡張クライアントと標準クライアントは、同じ接続プールを共有します。
注: 拡張機能の作成者は、拡張機能の一部として任意のコードを実行できるため、この動作を変更できます。たとえば、拡張機能は、実際には完全に新しい
PrismaClient
インスタンス(独自のクエリエンジンと接続プールを含む)を作成する可能性があります。使用している拡張機能のドキュメントを必ず確認して、実装されている可能性のある特定の動作について学習してください。
拡張クライアントのユースケース例
拡張クライアントは分離されたインスタンスで動作するため、たとえば、次のことを行うのに適しています。
- 行レベルセキュリティ(RLS)を実装します。各HTTPリクエストには、セッションデータでカスタマイズされた独自のRLS拡張機能を備えた独自のクライアントがあります。これにより、各ユーザーを完全に分離し、それぞれを個別のクライアントにすることができます。
- 現在ログインしているユーザーを取得するために、
User
モデルにuser.current()
メソッドを追加します。 - デバッグクッキーが設定されている場合、リクエストのより詳細なロギングを有効にします。
- 後で関連付けることができるように、たとえば、Prisma Clientが実行する操作の分析に役立つように、すべてログに一意のリクエストIDをアタッチします。
- アプリケーションが管理者エンドポイントを呼び出し、ユーザーが必要な権限を持っている場合を除き、モデルから
delete
メソッドを削除します。
Prisma Clientに拡張機能を追加する
主に2つの方法で拡張機能を作成できます
-
クライアントレベルの
$extends
メソッドを使用するconst prisma = new PrismaClient().$extends({
name: 'signUp', // Optional: name appears in error logs
model: { // This is a `model` component
user: { ... } // The extension logic for the `user` model goes inside the curly braces
},
}) -
Prisma.defineExtension
メソッドを使用して拡張機能を定義して変数に割り当て、その拡張機能をクライアントレベルの$extends
メソッドに渡しますimport { Prisma } from '@prisma/client'
// Define the extension
const myExtension = Prisma.defineExtension({
name: 'signUp', // Optional: name appears in error logs
model: { // This is a `model` component
user: { ... } // The extension logic for the `user` model goes inside the curly braces
},
})
// Pass the extension to a Prisma Client instance
const prisma = new PrismaClient().$extends(myExtension)ヒントこのパターンは、プロジェクト内の複数のファイルまたはディレクトリに拡張機能を分離したい場合に役立ちます。
上記の例では、model
拡張機能コンポーネントを使用してUser
モデルを拡張しています。
$extends
メソッドでは、適切な拡張機能コンポーネント(model
、client
、result
、またはquery
)を使用します。
エラーログの拡張機能に名前を付ける
エラーログで拡張機能を識別しやすくするために、拡張機能に名前を付けることができます。そのためには、オプションのフィールドname
を使用します。例:
const prisma = new PrismaClient().$extends({
name: `signUp`, // (Optional) Extension name
model: {
user: { ... }
},
})
複数の拡張機能
拡張機能を拡張クライアントに関連付けるには、次の2つの方法があります
- 拡張機能を拡張クライアントに単独で関連付けるか、または
- 拡張機能を他の拡張機能と組み合わせて、これらのすべての拡張機能を拡張クライアントに関連付けることができます。これらの組み合わせた拡張機能からの機能は、同じ拡張クライアントに適用されます。注: 組み合わせた拡張機能は競合する可能性があります。
上記の2つのアプローチを組み合わせることができます。たとえば、1つの拡張機能を独自の拡張クライアントに関連付け、他の2つの拡張機能を別の拡張クライアントに関連付けることができます。クライアントインスタンスがどのように相互作用するかについての詳細はこちら。
複数の拡張機能を拡張クライアントに適用する
次の例では、extensionA
とextensionB
の2つの拡張機能があるとします。これらを組み合わせるには2つの方法があります。
オプション1: 1行で新しいクライアントを宣言する
このオプションを使用すると、両方の拡張機能を1行のコードで新しいクライアントに適用します。
// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient()
// Declare an extended client that has an extensionA and extensionB
const prismaAB = prisma.$extends(extensionA).$extends(extensionB)
その後、コード内でprismaAB
を参照できます(例: prismaAB.myExtensionMethod()
)。
オプション2: 複数の拡張クライアントを宣言する
このオプションの利点は、拡張クライアントを個別に呼び出すことができることです。
// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient()
// Declare an extended client that has extensionA applied
const prismaA = prisma.$extends(extensionA)
// Declare an extended client that has extensionB applied
const prismaB = prisma.$extends(extensionB)
// Declare an extended client that is a combination of clientA and clientB
const prismaAB = prismaA.$extends(extensionB)
コード内で、これらのクライアントを個別に呼び出すことができます(例: prismaA.myExtensionMethod()
、prismaB.myExtensionMethod()
、またはprismaAB.myExtensionMethod()
)。
組み合わせた拡張機能の競合
2つ以上の拡張機能を単一の拡張クライアントに組み合わせると、宣言した最後の拡張機能が競合で優先されます。上記のオプション1の例では、extensionA
で定義されたmyExtensionMethod()
というメソッドと、extensionB
で定義されたmyExtensionMethod()
というメソッドがあるとします。prismaAB.myExtensionMethod()
を呼び出すと、Prisma ClientはextensionB
で定義されているmyExtensionMethod()
を使用します。
拡張クライアントの型
typeof
ユーティリティを使用して、拡張Prisma Clientインスタンスの型を推測できます。以下に示すように
const extendedPrismaClient = new PrismaClient().$extends({
/** extension */
})
type ExtendedPrismaClient = typeof extendedPrismaClient
Prisma Clientをシングルトンとして使用している場合は、typeof
およびReturnType
ユーティリティを使用して、拡張Prisma Clientインスタンスの型を取得できます。以下に示すように
function getExtendedClient() {
return new PrismaClient().$extends({
/* extension */
})
}
type ExtendedPrismaClient = ReturnType<typeof getExtendedClient>
Prisma.Result
でモデル型を拡張する
Prisma.Result
型ユーティリティを使用して、クライアント拡張機能を通じて追加されたプロパティを含めるようにモデル型を拡張できます。これにより、拡張プロパティを含む拡張モデルの型を推測できます。
例
次の例は、Prisma.Result
を使用して、クライアント拡張機能を通じて追加された__typename
プロパティを含めるようにUser
モデル型を拡張する方法を示しています。
import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient().$extends({
result: {
user: {
__typename: {
needs: {},
compute() {
return 'User'
},
},
},
},
})
type ExtendedUser = Prisma.Result<typeof prisma.user, { select: { id: true } }, 'findFirstOrThrow'>
async function main() {
const user: ExtendedUser = await prisma.user.findFirstOrThrow({
select: {
id: true,
__typename: true,
},
})
console.log(user.__typename) // Output: 'User'
}
main()
Prisma.Result
型ユーティリティは、クライアント拡張機能を通じて追加された__typename
プロパティを含む、拡張されたUser
モデルの型を推測するために使用されます。
制限事項
拡張クライアントでの$on
と$use
の使用
$on
と$use
は拡張クライアントでは使用できません。これらのクライアントレベルのメソッドを拡張クライアントで引き続き使用する場合は、クライアントを拡張する前にそれらをフックアップする必要があります。
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
console.log('This is middleware!')
return next(params)
})
const xPrisma = prisma.$extends({
name: 'myExtension',
model: {
user: {
async signUp(email: string) {
await prisma.user.create({ data: { email } })
},
},
},
})
詳細については、$on
と$use
に関するドキュメントを参照してください。
拡張クライアントでのクライアントレベルのメソッドの使用
クライアントレベルのメソッドは、拡張クライアントに必ずしも存在するとは限りません。これらのクライアントでは、使用する前に存在を確認する必要があります。
const xPrisma = new PrismaClient().$extends(...);
if (xPrisma.$connect) {
xPrisma.$connect()
}
ネストされた操作での使用
query
拡張機能タイプは、ネストされた読み取りおよび書き込み操作をサポートしていません。