Prisma ORM 4へのアップグレード
Prisma ORM 4では、以前のPrisma ORMバージョンからアップグレードする際に、いくつかの破壊的変更が導入されます。このガイドでは、このアップグレードがアプリケーションにどのように影響するかを説明し、変更への対処方法に関する指示を提供します。
破壊的変更
このセクションでは、Prisma ORM 4における破壊的変更の概要を、Prisma SchemaとPrisma Clientの両方に影響する一般的な変更、Schemaの変更、Clientの変更に分けて説明します。
まず、Prisma スキーマの検証エラーに対処し、次にデータベースをプルして新しい Prisma スキーマ機能を反映させ、最後にPrisma Clientの型エラーを修正し、テストスイートを実行して検証することをお勧めします。
Prisma Schemaをアップグレードする
- 変更点のリストを注意深く確認し、破壊的変更の影響を受けているかどうかを確認してください。
- Prisma スキーマの検証エラー(`npx prisma validate` を実行するか、Prisma VS Code 拡張機能を使用)を確認してください。
- 検証エラーがない場合は、手順3に進みます。
- 検証エラーがある場合
- 検証エラーを以下のリストの変更点にマッピングして、どの変更が不正なPrismaスキーマを引き起こしたのかを理解し、アップグレード方法に関するリンクされた指示を読んでください。これは以下に起因します。
- 1:1 リレーションの明示的なユニーク制約
- 暗黙的な多対多リレーションにおける `references` の使用サポートが削除されました
- MySQL および MongoDB の1対1および多対1リレーションで、`references` 引数における参照フィールドの一意性が強制されるようになりました
- `type` エイリアスの非公式サポートの削除
- SQLite URL から `sqlite` プロトコルの削除
- 文字列リテラルのより厳密な文法
- 検証エラーを以下のリストの変更点にマッピングして、どの変更が不正なPrismaスキーマを引き起こしたのかを理解し、アップグレード方法に関するリンクされた指示を読んでください。これは以下に起因します。
- Prisma スキーマが有効になるまで繰り返します。
- `npx prisma db pull` を実行して、Prisma スキーマをすべての新しい機能(例: `extendedIndexes`)にアップグレードします。
- Prisma スキーマの変更点を確認し、有効性を検証します。
- Prisma Client の手順に進みます。
Prisma Clientの使用をアップグレードする
- 変更点のリストを注意深く確認し、破壊的変更の影響を受けているかどうかを理解してください。
- はいの場合、詳細なアップグレード手順を読んでください。
- いいえの場合、2に進みます。
- Prisma Client の一部のAPI変更はランタイムの挙動に影響を与えるため、テストスイートを実行してください。
Prisma ORM 4をお楽しみください!
一般的な変更
このセクションには、Prisma Schema と Prisma Client の両方に影響する変更が含まれます。
Node.js の最小バージョン変更
Prisma ORM バージョン4.0.0より、サポートされるNode.jsの最小バージョンは14.17.xです。それ以前のNode.jsバージョンを使用している場合は、更新する必要があります。
すべての最小バージョン要件については、システム要件を参照してください。
スキーマの変更
このセクションには、Prisma Schema に影響する変更が含まれます。
インデックス設定
Prisma ORM 4では、`extendedIndexes` プレビュー機能が正式に利用可能になります。これには、以下のインデックス設定オプションが含まれます。
- MySQL のインデックス、ユニーク制約、プライマリキー制約の長さ設定(バージョン3.5.0以降でプレビュー提供)
- インデックス、ユニーク制約、プライマリキー制約のソート順設定(バージョン3.5.0以降でプレビュー提供)
- PostgreSQL の新しいインデックスタイプ: Hash(バージョン3.6.0以降でプレビュー提供)、GIN、GiST、SP-GiST、BRIN(バージョン3.14.0以降でプレビュー提供)
- SQL Server のインデックスクラスタリング(バージョン3.13.0以降でプレビュー提供)
これらの機能の詳細については、インデックス設定に関するドキュメントを参照してください。
アップグレードパス
これらの設定を以前にデータベースレベルで構成していた場合、これらはすべて破壊的変更となる可能性があります。この場合、以下の手順を実行する必要があります。
- これらの手順に従って、新しいPrisma ORM 4パッケージにアップグレードします。
- その後、`npx prisma db pull` を実行して、既存のインデックスおよび制約の設定を取得します。これは、`npx prisma db push` または `npx prisma migrate dev` コマンドを実行する前に行う必要があります。さもなければ、データベースで定義されていても以前はPrismaスキーマに表現されていなかった設定が失われる可能性があります。
詳細については、インデックス設定ドキュメントの以前のバージョンからのアップグレードセクションを参照してください。
スカラリストのデフォルト値
スカラリストをサポートするデータベースコネクタ(PostgreSQL、CockroachDB、MongoDB)の場合、Prisma ORM 4 では `@default` 属性を使用してPrismaスキーマにデフォルト値を設定できるようになりました。
- リレーショナルデータベース
- MongoDB
model User {
id Int @id @default(autoincrement())
posts Post[]
favoriteColors String[] @default(["red", "yellow", "purple"])
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
posts Post[]
favoriteColors String[] @default(["red", "yellow", "purple"])
}
アップグレードパス
以前にスカラリストのデフォルト値をデータベースレベルで定義していた場合、これは破壊的変更です。この場合、以下の手順を実行する必要があります。
- これらの手順に従って、新しいPrisma ORM 4パッケージにアップグレードします。
- その後、`npx prisma db pull` を実行して、既存のインデックスおよび制約の設定を取得します。これは、`npx prisma db push` または `npx prisma migrate dev` コマンドを実行する前に行う必要があります。さもなければ、データベースで定義されていても以前はPrismaスキーマに表現されていなかったデフォルト値が失われる可能性があります。
1対1リレーションにおける明示的な `@unique` 制約
Prisma ORM 4で1対1リレーションを使用する場合、リレーションスカラフィールドに `@unique` 属性を明示的に追加する必要があります。例えば、`User` モデルと `Profile` モデル間のこの1対1リレーションでは、`profileId` フィールドに `@unique` 属性を追加する必要があります。
- リレーショナルデータベース
- MongoDB
model User {
id Int @id @default(autoincrement())
profile Profile? @relation(fields: [profileId], references: [id])
profileId Int? @unique // <-- include this explicitly
}
model Profile {
id Int @id @default(autoincrement())
user User?
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
profile Profile? @relation(fields: [profileId], references: [id])
profileId String? @unique @db.ObjectId // <-- include this explicitly
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
user User?
}
アップグレードパス
Prisma ORM 4にアップグレードした後、リレーションスカラに `@unique` 属性がない1対1リレーションは検証エラーを引き起こします。アップグレードするには、以下の手順を実行する必要があります。
-
これらの手順に従って、新しいPrisma ORM 4パッケージにアップグレードします。
-
データモデルに明示的な `@unique` または `@id` 属性を追加して、Prisma スキーマの検証エラーを手動で修正します。
-
MongoDBの場合は `prisma db push`、MySQLの場合は `prisma migrate dev` を使用して、変更をデータベースにプッシュします。
1対1および多対1リレーションにおける `@unique` または `@id` 属性の使用の強制(MySQLおよびMongoDB)
Prisma ORM 4で1対1および多対1リレーションを使用する場合、リレーションの単一側が1つのレコードのみを持つことを保証するために、リレーションフィールドに `@unique` 属性を使用する必要があります。これはMySQLとMongoDBで強制されるようになり、他のコネクタとの整合性が取れました。`@unique` 属性が不足している場合、検証エラーが発生します。
`User` モデルと `Post` モデル間の多対1リレーションの次の例では、`email` フィールドに `@unique` 属性を追加する必要があります。
- リレーショナルデータベース
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique // <-- we enforce this attribute
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
authorEmail String
author User @relation(fields: [authorEmail], references: [email])
}
model User {
id Int @id @default(auto()) @map("_id") @db.ObjectId
email String @unique // <-- we enforce this attribute
posts Post[]
}
model Post {
id Int @id @default(auto()) @map("_id") @db.ObjectId
authorEmail String
author User @relation(fields: [authorEmail], references: [email])
}
`User` モデルと `Profile` モデル間の1対1リレーションの次の例では、`email` フィールドに `@unique` 属性を追加する必要があります。
- リレーショナルデータベース
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique // <- we enforce this unique attribute
profile Profile @relation(fields: [profileId], references: [id])
profileId Int
}
model Profile {
id Int @id @default(autoincrement())
userEmail String? @unique
user User?
}
model User {
id Int @id @default(auto()) @map("_id") @db.ObjectId
email String @unique // <- we enforce this unique attribute
profile Profile @relation(fields: [profileId], references: [id])
profileId Int @db.ObjectId
}
model Profile {
id Int @id @default(auto()) @map("_id") @db.ObjectId
userEmail String? @unique
user User? @relation(fields: [userEmail], references: [email])
}
アップグレードパス
Prisma ORM 4にアップグレードした後、リレーションフィールドに `@unique` または `@id` 属性がない1対1または多対1リレーションは検証エラーを引き起こします。アップグレードするには、以下の手順を実行する必要があります。
- これらの手順に従って、新しいPrisma ORM 4パッケージにアップグレードします。
- Prisma スキーマの検証エラーを手動で修正します。あるいは、最新のライブデータベースがある場合は、`npx prisma db pull` を実行すると、`@unique` 属性が自動的に追加されます。
暗黙的な多対多リレーションにおける `references` 構文の禁止
Prisma ORM 4で暗黙的な多対多リレーションを使用する場合、以前はオプションであった `references` 引数を使用できなくなります。例えば、以下のリレーションは現在、検証エラーを引き起こします。
model Post {
id Int @id @default(autoincrement())
categories Category[] @relation("my-relation", references: [id]) // <-- validation error
}
model Category {
id Int @id @default(autoincrement())
posts Post[] @relation("my-relation", references: [id]) // <-- validation error
}
代わりに、次のように記述できます。
model Post {
id Int @id @default(autoincrement())
categories Category[] @relation("my-relation")
}
model Category {
id Int @id @default(autoincrement())
posts Post[] @relation("my-relation")
}
これは、`references` の唯一の有効な値が `id` であったためであり、この引数を削除することで、変更できるものとできないものがより明確になります。
アップグレードパス
Prisma ORM 4にアップグレードした後、`references` 引数を持つ暗黙的な多対多リレーションは検証エラーを引き起こします。アップグレードするには、以下の手順を実行する必要があります。
- これらの手順に従って、新しいPrisma ORM 4パッケージにアップグレードします。
- Prisma スキーマの検証エラーを手動で修正します。あるいは、最新のライブデータベースがある場合は、`npx prisma db pull` を実行すると、`references` 引数が自動的に削除されます。
文字列リテラルのより厳密な文法
Prisma Schemaの文字列リテラルは、JSONの文字列と同じルールに従う必要があります。これは主に、一部の特殊文字のエスケープを変更します。詳細については、JSON仕様またはJSONウェブサイトを参照してください。
アップグレードパス
これは、既存の一部のスキーマにとって破壊的変更です。Prisma ORM 4にアップグレードした後、不適切にエスケープされた文字は検証エラーを引き起こします。アップグレードするには、以下の手順を実行する必要があります。
- これらの手順に従って、新しいPrisma ORM 4パッケージにアップグレードします。
- Prisma スキーマの検証エラーを手動で修正します。
Clientの変更
このセクションには、Prisma Client に影響する変更が含まれます。
生クエリの型マッピング: スカラ値が正しいJavaScript型としてデシリアライズされるようになりました
バージョン3.14.xおよび3.15.xでは、`improvedQueryRaw` プレビュー機能により生クエリの型マッピングが利用可能でした。バージョン4.0.0では、生クエリの型マッピングが正式に利用可能になりました。バージョン4.0.0以降では、この機能を利用するために `improvedQueryRaw` を使用する必要はありません。
生クエリは、スカラ値を対応するJavaScript型にデシリアライズするようになりました。Prisma ORM は、値自体から型を推論し、Prisma Schema の型からは推論しないことに注意してください。
クエリとレスポンスの例
const res =
await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`
console.log(res) // [{ bigint: BigInt("123"), bytes: Buffer.from([1, 2]), decimal: new Prisma.Decimal("12.34"), date: Date("<some_date>") }]
アップグレードパス
バージョン4.0.0以降、`queryRaw` または `queryRawUnsafe` によって返される一部のデータ型は、次のように異なります。
データ型 | バージョン4.0.0以前 | バージョン4.0.0以降 |
---|---|---|
DateTime | `String` として返されます | `Date` として返されます |
Numeric | `Float` として返されます | `Decimal` として返されます |
Bytes | `String` として返されます | `Buffer` として返されます |
Int64 | `Integer` として返されます | `BigInt` として返されます |
上記のデータ型のいずれかを返すために `queryRaw` または `queryRawUnsafe` を使用している場合、新しい型を処理するようにコードを変更する必要があります。
例えば、`DateTime` データを返す場合、以下を考慮する必要があります。
- 返されたデータに対して `DateTime` オブジェクトを手動でインスタンス化する必要はなくなりました。
- 現在、コードが返された `String` データを使用している場合、`DateTime` オブジェクトを `String` に変換する必要があります。
上記の表にある他のデータ型についても、同等のコード変更を行う必要があります。
生クエリマッピング: PostgreSQL 型キャスト
バージョン3.14.xおよび3.15.xでは、`improvedQueryRaw` プレビュー機能により生クエリの型マッピングが利用可能でした。バージョン4.0.0では、生クエリの型マッピングが正式に利用可能になりました。バージョン4.0.0以降では、この機能を利用するために `improvedQueryRaw` を使用する必要はありません。
バージョン4.0.0以前では、多くのPostgreSQL型キャストが機能しませんでした。型強制ルールを厳格化したため、すべての型キャストが機能するようになりました。結果として、一部の暗黙的なキャストが失敗するようになりました。
アップグレードパス
`$queryRaw` の使用を再テストし、生クエリに渡す型がPostgreSQLが期待する型と一致することを確認することをお勧めします。
例えば、バージョン4.0.0では、以下のクエリは失敗します。
await prisma.$queryRaw`select length(${42});`
// ERROR: function length(integer) does not exist
// HINT: No function matches the given name and argument types. You might need to add explicit type casts.
これは、PostgreSQLの `length` 関数が入力として `text` を期待するためです。以前のPrisma ORMは `42` を暗黙的に `text` に型強制していましたが、バージョン4.0.0ではこれを行いません。これを修正するには、次のように `42` を明示的に `text` にキャストします。
await prisma.$queryRaw`select length(${42}::text);`
生クエリマッピング: PostgreSQLとJavaScriptの整数
バージョン3.14.xおよび3.15.xでは、`improvedQueryRaw` プレビュー機能により生クエリの型マッピングが利用可能でした。バージョン4.0.0では、生クエリの型マッピングが正式に利用可能になりました。バージョン4.0.0以降では、この機能を利用するために `improvedQueryRaw` を使用する必要はありません。
Prisma ORM はJavaScriptの整数を `INT8` としてPostgreSQLに送信します。これは、`INT4` のみを入力として受け入れるユーザー定義関数と競合する可能性があります。
アップグレードパス
PostgreSQLデータベースで `$queryRaw` またはパラメータ化された `$queryRawUnsafe` クエリを使用している場合、以下のいずれかを実行してください。
- ユーザー定義関数の整数入力型を `INT8` に更新するか、
- クエリパラメータ内の整数を `INT4` にキャストします。
`DbNull`、`JsonNull`、`AnyNull` がオブジェクトになりました
JavaScriptの `null` はJSONカラムに対して曖昧であるため、Prisma ORMはデータベースの `NULL` 値とJSONの `null` 値を区別するために `DbNull`、`JsonNull`、`AnyNull` を使用します。バージョン4.0.0以前は、`DbNull`、`JsonNull`、`AnyNull` は文字列定数でした。バージョン4.0.0以降はオブジェクトです。
詳細については、null値によるフィルタリングを参照してください。
アップグレードパス
-
これらの値をリテラル文字列で指定している場合、以下の名前付き定数に置き換える必要があります。
- `DbNull`: `Prisma.DbNull` に置き換えます
- `JsonNull`: `Prisma.JsonNull` に置き換えます
- `AnyNull`: `Prisma.AnyNull` に置き換えます
すでにこれらの名前付き定数を使用している場合は、何もする必要はありません。
-
JSONフィールドの値として `Prisma.DbNull` を渡したときに型エラーが発生する場合、これはおそらくバージョン4.0.0以前では型が捕捉できなかったコードのバグを示しています。`DbNull` を保存しようとしたフィールドは、スキーマでnullableではない可能性があります。その結果、`NULL` の代わりにリテラル文字列 "DbNull" がデータベースに保存されました。
-
MongoDBで `Prisma.DbNull`、`Prisma.JsonNull`、`Prisma.AnyNull` を使用すると、型エラーまたは実行時検証エラーに遭遇する可能性があります。これは以前から有効ではありませんでしたが、Prisma ORM 4以前では黙って受け入れられていました。データをレビューし、これらのフィールドを `null` に変更する必要があります。
-
Prisma ClientでJSONカラムに動的なJSONを渡す場合(例: `prisma.findMany({where: { jsonColumn: someJson } })`)、`someJson` が文字列 "DBNull"、"JsonNull"、または "AnyNull" でないことを確認する必要があります。これらの値のいずれかである場合、バージョン4.0.0ではクエリが異なる結果を返します。
MongoDBの複合型におけるデフォルトフィールド
バージョン4.0.0以降、以下のすべての条件が真である場合に複合型に対してデータベース読み取りを実行すると、Prisma Client は結果にデフォルト値を挿入します。
条件
- 複合型のフィールドが必須であり、かつ
- このフィールドにデフォルト値があり、かつ
- このフィールドが返されたドキュメントまたは複数のドキュメントに存在しない。
この挙動は、モデルフィールドの挙動と一貫するようになりました。
詳細については、複合型の必須フィールドのデフォルト値を参照してください。
アップグレードパス
現在、`null` の戻り値に依存している場合、Prisma ORM 4で返されるようになったデフォルト値を処理するようにコードをリファクタリングする必要があります。
SQLiteにおける大きな数値の丸め誤差
SQLite は、ゆるい型付けのデータベースです。スキーマに `Int` 型のフィールドがある場合、Prisma ORM は整数より大きな値を挿入するのを防ぎます。しかし、データベースが直接より大きな数値を受け入れるのを防ぐものはありません。手動で挿入されたこれらの大きな数値は、クエリ時に丸め誤差を引き起こします。
この問題を回避するため、Prisma ORM バージョン4.0.0以降では、データベースから数値が返される際に、その数値が整数の範囲内に収まるかを確認します。数値が収まらない場合、Prisma ORM はP2023エラーをスローします。例えば、
Inconsistent column data: Conversion failed:
Value 9223372036854775807 does not fit in an INT column,
try migrating the 'int' column type to BIGINT
アップグレードパス
Prisma ORM をSQLiteと組み合わせて使用している場合、`Int` フィールドをクエリするコードを特定し、返される可能性のあるP2023エラーを処理することを確認する必要があります。
Prisma ORM は生成されたPrisma Clientに `Prisma.dmmf.schema` をエクスポートしなくなりました
バージョン4.0.0以降、Prisma ORMは生成されたPrisma Clientに `Prisma.dmmf.schema` をエクスポートしなくなりました。これにより、生成されたPrisma Clientがはるかに効率的になり、Jestとのメモリリークも一部回避されます。
注
- この変更は、Prisma ORM がジェネレーターに渡すDMMFには影響しません。
- `getDmmf()` を `@prisma/internals` から使用して、スキーマプロパティにアクセスできます。
- `Prisma.dmmf.datamodel` は引き続き生成されたPrisma Clientにエクスポートされます。
`prisma` および `@prisma/client` パッケージをバージョン4にアップグレードする
以前のバージョンからPrisma ORM 4にアップグレードするには、`prisma` と `@prisma/client` の両方のパッケージを更新する必要があります。`prisma` と `@prisma/client` の両パッケージは、バージョン番号にキャレット `^` を付けてインストールされます。これにより、マイナーバージョンへのアップグレードは可能ですが、破壊的変更から保護するためにメジャーバージョンへのアップグレードはできません。
キャレット `^` を無視してメジャーバージョンをまたいでアップグレードするには、`npm` または `yarn` でアップグレードする際に `@4` タグを使用します。
アップグレードする前に、各破壊的変更を確認し、アップグレードがアプリケーションにどのように影響するかを調べてください。
- npm
- yarn
npm install prisma@4 @prisma/client@4
yarn up prisma@4 @prisma/client@4
ビデオガイド
アップグレードプロセスとアップグレードシナリオの例のビデオウォークスルーについては、Prisma ORM 4へのアップグレードに関する録画済みライブストリームをご覧ください。