Prisma ORMレイヤーのアップグレード (MySQL)
概要
このページでは、アップグレードプロセスの最初のステップである、Prisma 1の構成をPrisma ORM 2にアップグレードする方法について説明します。具体的には、以下の方法を学びます。
- Prisma ORM 2 CLIを開発依存関係として追加する
- Prisma ORM 2スキーマを作成する
- 接続URLを決定し、データベースに接続する
- データベースをイントロスペクトする(これまではPrisma 1で管理されていました)
- 新しいPrisma ORM 2データモデルにおけるスキーマの非互換性を解決するために、Prisma 1アップグレードCLIを使用する
- Prisma Clientをインストールして生成する
これらのステップが完了したら、次のガイドに進み、Prisma Clientを使用してデータベースクエリを実行するためにアプリケーションレイヤーをアップグレードする方法を学ぶことができます。
注:アップグレードプロセス中に、データベースのグラフィカルビューを取得すると役立つ場合があります。そのため、TablePlusやPosticoなどのグラフィカルなデータベースクライアントを使用してデータベースに接続することをお勧めします。
1. Prisma ORM 2 CLIのインストール
Prisma ORM 2 CLIはnpmのprisma
パッケージとして利用可能で、prisma
コマンドを介して呼び出されます。
Prisma 1の以前のprisma
コマンドはprisma1
に名前が変更されました。詳細については、こちらをご覧ください。
Node.jsプロジェクトにPrisma ORM 2 CLIを以下のようにインストールできます(package.json
があるディレクトリでこのコマンドを実行してください)
npm install prisma --save-dev
注:Prisma 1では、CLIをグローバルにインストールすることが通常推奨されていました。現在は、バージョン競合を防ぐためにPrisma CLIをローカルにインストールすることを推奨しています。
これで、npx
をプレフィックスとして付けて、ローカルにインストールしたprisma
CLIを使用できます。
npx prisma
プロジェクト全体を一括でアップグレードする場合は、Prisma 1 CLIをアンインストールすることもできます(そうでない場合は以下を展開してください)
# remove global installation
npm uninstall -g prisma1
# remove local installation
npm uninstall prisma1
Prisma 1 CLIを並行して使い続けたい場合は展開してください
Prisma 1 CLIを使い続けたい場合は、グローバルインストールを削除し、prisma1
CLIを開発依存関係として追加することをお勧めします。
# installs v1.34 of the Prisma 1 CLI
npm uninstall -g prisma
npm install prisma1 --save-dev
これで、次のように呼び出すことができます。
npx prisma1
CLIバージョンが1.34より小さいもの(例:1.30)が必要な場合は、次のようにインストールできることに注意してください。
# installs v1.30 of the Prisma 1 CLI
npm uninstall -g prisma@1.30
npm install prisma@1.30 --save-dev
これで、次のように呼び出すことができます。
npx prisma
2. Prisma ORM 2スキーマの作成
このガイドでは、まずprisma init
コマンドを使用して新しいPrismaスキーマを作成し、次にイントロスペクションを使用してデータモデルを「埋めます」。
次のコマンドを実行してPrismaスキーマを作成します(すでにprisma
というフォルダがある場合はエラーが発生しますので注意してください)
npx prisma init
次のエラーが表示される場合、現在のprisma
ディレクトリの名前を変更する必要があります。
ERROR A folder called prisma already exists in your project.
Please try again in a project that is not yet using Prisma.
現在のprisma
ディレクトリをprisma1
に名前を変更すると、これが以前のPrisma 1の構成を保持していることが明確になります。
mv prisma prisma1
これでinit
を実行でき、成功します。
npx prisma init
次の出力が表示されるはずです。
✔ Your Prisma schema was created at prisma/schema.prisma.
You can now open it in your favorite editor.
Next steps:
1. Set the `DATABASE_URL` in the `.env` file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the `provider` of your `datasource` block in `schema.prisma` to match your database: `postgresql`, `mysql` or `sqlite`.
3. Run `prisma db pull` to turn your database schema into a Prisma data model.
4. Run `prisma generate` to install Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
このコマンドは、prisma
という新しいフォルダと2つのファイルを作成しました。
prisma/schema.prisma
: データソース、ジェネレーター、データモデルを指定するPrismaスキーマ(データモデルはまだ存在せず、イントロスペクションによって生成されることに注意してください)。.env
: データベースの接続URLを構成するためのdotenvファイル。
最初のPrismaスキーマは次のようになります。
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
Prisma 1では、prisma.yml
でPrisma Clientのどの言語バリアントを使用するかを指定していました。Prisma ORM 2では、この情報はgenerator
ブロックを介してPrismaスキーマ内で指定されるようになりました。
注:Prisma 1とは異なり、Prisma Client 2.0のTypeScriptおよびJavaScriptバリアントは、同じジェネレーター(
prisma-client-js
)を使用します。index.d.ts
で生成される型は、プレーンなJavaScriptプロジェクトでも常に含まれます。これにより、TypeScriptを使用していない場合でも、VS Codeでのオートコンプリートなどの機能が有効になります。
3. 接続URLを決定し、データベースに接続する
Prisma 1では、データベース接続はPrisma ORMサーバーを起動するために使用されるDocker Composeファイルで構成されます。Prisma ORMサーバーは、Prisma ClientアプリケーションコードからのすべてのデータベースリクエストをプロキシするGraphQLエンドポイント(HTTP経由)を公開します。そのHTTPエンドポイントは、prisma.yml
で指定されます。
Prisma ORM 2では、HTTPレイヤーはもはや公開されず、Prisma Client 2.0はデータベースに対して「直接」リクエストを実行するように構成されています(つまり、リクエストはPrisma ORMのクエリエンジンによってプロキシされますが、追加のサーバーはもうありません)。
したがって、次のステップとして、Prisma ORM 2にどの種類のデータベースを使用しているか(MySQLまたはPostgreSQL)、そしてどこにそれが存在するかを伝える必要があります。
まず、schema.prisma
内のdatasource
ブロックにあるprovider
フィールドが、正しいデータベースを使用するように構成されていることを確認する必要があります。
- PostgreSQLを使用している場合は、
provider
フィールドに"postgresql"
の値を定義する必要があります。 - MySQLを使用している場合は、
provider
フィールドに"mysql"
の値を定義する必要があります。
コードブロックのタブを切り替えて、両方の例をご覧ください。
- PostgreSQL
- MySQL
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
provider
フィールドが設定されたら、.env
ファイル内で接続URLを設定できます。
Prisma ORMサーバーのデプロイに使用したDocker Composeファイルのデータベース設定が次のようになっているとします。
PRISMA_CONFIG: |
port: 4466
databases:
default:
connector: mysql
host: mysql
port: 3306
user: root
password: randompassword
また、prisma.yml
のendpoint
が次のように構成されているとします。
endpoint: http://:4466/myproject/dev
これらの接続詳細に基づいて、.env
ファイル内のDATABASE_URL
環境変数を次のように構成する必要があります。
DATABASE_URL="mysql://root:randompassword@localhost:3306/myproject@dev"
接続URLのデータベース名は通常、サービス名とサービスステージ(prisma.yml
のendpoint
の一部)を@
文字で区切ったもので構成されることに注意してください。
prisma.yml
にサービス名とステージが指定されていない場合があります。
endpoint: http://:4466/
その場合、データベース名は次のように指定する必要があります。
DATABASE_URL="mysql://root:randompassword@localhost:3306/default@default"
接続URLページで詳細をご覧ください。
4. データベースをイントロスペクトする
このガイドの目的のため、次のPrisma 1データモデルを使用します(データモデルがSQLでどのようにマッピングされるかを見るには、下のSQLタブを選択してください)
- Prisma 1データモデル
- SQL
type User {
id: ID! @id
email: String @unique
name: String!
role: Role! @default(value: CUSTOMER)
jsonData: Json
profile: Profile
posts: [Post!]!
}
type Post {
id: ID! @id
createdAt: DateTime! @createdAt
updatedAt: DateTime! @updatedAt
title: String!
content: String
published: Boolean! @default(value: false)
author: User @relation(link: TABLE)
categories: [Category!]!
}
type Profile {
id: ID! @id
bio: String
user: User! @relation(link: INLINE)
}
type Category {
id: ID! @id
name: String!
posts: [Post!]!
}
enum Role {
ADMIN
CUSTOMER
}
CREATE TABLE"User" (
id character varying(25) PRIMARY KEY,
email text,
name text NOT NULL,
role text NOT NULL,
"jsonData" text
);
CREATE UNIQUE INDEX "User_pkey" ON"User"(id text_ops);
CREATE UNIQUE INDEX "default$default.User.email._UNIQUE" ON"User"(email text_ops);
CREATE TABLE"Post" (
id character varying(25) PRIMARY KEY,
title text NOT NULL,
published boolean NOT NULL,
"createdAt" timestamp(3) without time zone NOT NULL,
"updatedAt" timestamp(3) without time zone NOT NULL,
content text
);
CREATE UNIQUE INDEX "Post_pkey" ON"Post"(id text_ops);
CREATE TABLE"Profile" (
id character varying(25) PRIMARY KEY,
bio text,
user character varying(25) REFERENCES"User"(id) ON DELETE SET NULL
);
CREATE UNIQUE INDEX "Profile_pkey" ON"Profile"(id text_ops);
CREATE TABLE"Category" (
id character varying(25) PRIMARY KEY,
name text NOT NULL
);
CREATE UNIQUE INDEX "Category_pkey" ON"Category"(id text_ops);
CREATE TABLE"_PostToUser" (
"A" character varying(25) NOT NULL REFERENCES"Post"(id) ON DELETE CASCADE,
"B" character varying(25) NOT NULL REFERENCES"User"(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX "_PostToUser_AB_unique" ON"_PostToUser"("A" text_ops,"B" text_ops);
CREATE INDEX "_PostToUser_B" ON"_PostToUser"("B" text_ops);
CREATE TABLE"_CategoryToPost" (
"A" character varying(25) NOT NULL REFERENCES"Category"(id) ON DELETE CASCADE,
"B" character varying(25) NOT NULL REFERENCES"Post"(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON"_CategoryToPost"("A" text_ops,"B" text_ops);
CREATE INDEX "_CategoryToPost_B" ON"_CategoryToPost"("B" text_ops);
このデータモデルには、3つのリレーションがあることに注意してください。
- 1対1:
User
↔Profile
- 1対多:
User
↔Post
(_PostToUser
リレーションテーブルを介して維持される) - 多対多:
Post
↔Category
(_CategoryToPost
リレーションテーブルを介して維持される)
これで、次のコマンドを使用してPrisma ORMのイントロスペクションをデータベースに対して実行できます。
npx prisma db pull
db pull
が呼び出されたときに何が起こるかを示すグラフィカルな図です。
上記のPrisma 1データモデルの場合、これにより次のPrisma ORM 2スキーマが生成されます(モデルはPrisma 1データモデルの初期順序と一致するように並べ替えられていることに注意してください)。
model User {
id String @id @default(cuid())
email String? @unique
name String
role String
jsonData String?
Profile Profile[]
Post Post[]
}
model Post {
id String @id @default(cuid())
createdAt DateTime
updatedAt DateTime
title String
content String?
published Boolean
Category Category[]
User User[]
}
model Profile {
id String @id @default(cuid())
bio String?
user String? @unique
User User? @relation(fields: [user], references: [id])
}
model Category {
id String @id @default(cuid())
name String
Post Post[]
}
これはすでに有効なPrisma ORM 2スキーマですが、Prisma 1の同等のものであったいくつかの機能が不足しています。
Post
のcreatedAt
フィールドとupdatedAt
フィールドに自動生成された日付値がないUser
のrole
フィールドにデフォルト値がないPost
のpublished
フィールドにデフォルト値がない
さらに、Prisma Client APIが非イディオマティック/非人間工学的になる原因となる、いくつかの不整合があります。
User
↔Profile
は1対1ではなく1対多のリレーションであるUser
↔Post
は1対多ではなく多対多のリレーションである- リレーションフィールドが大文字になっている(例:
User
のProfile
とPost
) User
のjsonData
フィールドがJson
ではなくString
型になっているUser
のrole
フィールドがRole
ではなくString
型になっている、ロールのenum
定義が完全に欠落している
これらの不整合は、実際にPrisma Client APIで利用できる「機能セット」に影響を与えるわけではありませんが、以前に存在していた特定の制約や保証が失われることになります。
たとえば、Prisma ORMは、イントロスペクション中にテーブル間のリレーションが1対多として認識されたため、1つのUser
が最大で1つのProfile
に接続されていることを保証しなくなります。そのため、1つのUser
レコードが複数のProfile
レコードに接続される可能性があります。
もう一つの問題は、jsonData
フィールドとrole
フィールドに、有効なJSONであるかRole
enumの値であるかに関わらず、任意のテキストを保存できてしまうことです。
これらの不整合の詳細については、スキーマの非互換性ページをご覧ください。
以下では、これらの非互換性をPrismaスキーマアップグレードCLIを使用して1つずつ修正していきます。
5. スキーマの非互換性を解決するためにPrismaスキーマアップグレードCLIを使用する
Prisma 1アップグレードCLIは、Prismaスキーマをアップグレードし、上記の不整合のほとんどを解消するのに役立つ対話型ツールです。
Prisma 1アップグレードCLIは、主に2つのフェーズで動作します。
- プレーンSQLを介してデータベーススキーマを修正する
- Prisma ORM 2スキーマに不足している属性とその他のスキーマ修正を追加する
最初のフェーズでは、データベーススキーマを調整するためにデータベースに対して実行すべきSQLステートメントが生成・表示されます。すべてのステートメントを実行するか、一部のみを実行してから2番目のフェーズに進むことができます。
2番目のフェーズでは、手動で何かをする必要はありません。アップグレードCLIは、特定のPrisma ORMレベルの属性(@default(cuid))
や@updatedAt
など)を追加したり、リレーションフィールドの名前をPrisma 1データモデルのものと一致するように調整したり、Prisma 1データモデルで両側で必須であった1対1のリレーションがPrisma ORM 2スキーマでも必須であることを確認したりすることで、Prismaスキーマに変更を加えます。
プロセスの途中いつでもやり直すことができ、2番目のフェーズから最初のフェーズに戻ることができることに注意してください。
この図では、緑色の領域が最初のフェーズ、青色の領域が2番目のフェーズを示しています。オプションで、フェーズ間にprisma db pull
を実行してPrisma ORMデータモデルを更新できることに注意してください。
アップグレードCLIを使用するには、プロジェクトにローカルでインストールするか、またはここで示されているようにnpx
を使用して一度だけインストールせずに呼び出すことができます。
npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma
CLIは次のメッセージを表示します。
◮ Welcome to the interactive Prisma Upgrade CLI that helps with the
upgrade process from Prisma 1 to Prisma ORM 2.
Please read the docs to learn more about the upgrade process:
https://pris.ly/d/how-to-upgrade
➤ Goal
The Upgrade CLI helps you resolve the schema incompatibilities
between Prisma 1 and Prisma ORM 2. Learn more in the docs:
https://pris.ly/d/schema-incompatibilities
➤ How it works
Throughout the process, you'll need to adjust your database schema by sending
SQL statements to it. The SQL statements are provided by the Upgrade CLI.
Note that the Upgrade CLI never makes changes to your database,
you are in full control over any operations that are executed against it.
You can stop and re-run the Upgrade CLI at any time.
These are the different steps of the upgrade process:
1. The Upgrade CLI generates SQL commands for you to run on your database.
2. You run the SQL commands against your database.
3. You run the `npx prisma db pull` command again.
4. You run the `npx prisma-upgrade` command again.
5. The Upgrade CLI adjusts the Prisma ORM 2 schema by adding missing attributes.
➤ Note
It is recommended that you make a full backup of your existing data before starting
the upgrade process. If possible, the migration should be performed in a staging
environment before executed against a production environment.
➤ Help
If you have any questions or run into any problems along the way,
please create an issue at:
https://github.com/prisma/prisma1-upgrade/issues/new
Are you ready? [Y/n]
Yボタンを押してから、キーボードのRETURNを押して確定し、続行してください。
確認すると、CLIはデータベースに対して実行すべきSQLステートメントを出力します。
➤ Adjust your database schema
Run the following SQL statements against your database:
Fix columns with ENUM data types
https://pris.ly/d/schema-incompatibilities#enums-are-represented-as-text-in-database
ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL;
Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database
ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL DEFAULT 'CUSTOMER';
ALTER TABLE `Post` CHANGE `published` `published` TINYINT(1) NOT NULL DEFAULT 0;
Fix columns with JSON data types
https://pris.ly/d/schema-incompatibilities#json-type-is-represented-as-text-in-database
ALTER TABLE `User` CHANGE `jsonData` `jsonData` JSON ;
Replicate `@createdAt` behavior in Prisma ORM 2.0
https://pris.ly/d/schema-incompatibilities#createdat-isnt-represented-in-database
ALTER TABLE `Post` CHANGE `createdAt` `createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;
Fix 1-1 relations by adding `UNIQUE` constraints
https://pris.ly/d/schema-incompatibilities#inline-1-1-relations-are-recognized-as-1-n-missing-unique-constraint
ALTER TABLE `Profile` ADD UNIQUE (`user`);
Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `Category` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Post` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `user` `user` char(30) CHARACTER SET utf8 ;
ALTER TABLE `User` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
SET FOREIGN_KEY_CHECKS=1;
➤ Breaking changes detected
In order to fully optimize your database schema, you'll need to run a few SQL
statements that can break your Prisma 1 setup. Note that these changes are optional
and if you are upgrading gradually and running Prisma 1 and Prisma ORM 2 side-by-side,
you should not perform these changes yet. Instead, you can perform them whenever
you are ready to completely remove Prisma 1 from your project.
If you are upgrading all at once, you can safely perform these changes now.
Learn more in the docs:
https://pris.ly/d/how-to-upgrade'
注:破壊的変更に関する注記が表示されている場合、現時点では無視して構いません。後で説明します。
表示されるSQLステートメントは、特定のスキーマの非互換性を解決することを目的とした、いくつかの「バケット」に分類されています。
- ENUMデータ型の列を修正する
- データベースに不足している
DEFAULT
制約を追加する - JSONデータ型の列を修正する
- Prisma 2で
@createdAt
の動作を再現する UNIQUE
制約を追加して1対1リレーションを修正する
次のステップとして、データベースにSQLステートメントを送信し始めることができます。これらの変更はすべて破壊的ではないため、Prisma ORM 2と並行してPrisma 1を使い続けることができます。
次のセクションでは、データベースに個別に送信されるさまざまな種類のSQLステートメントについて説明します。
5.1. プレーンSQLによるデータベーススキーマの修正(非破壊的)
このセクションでは、表示されたSQLステートメントを一つずつ確認し、データベースに対して実行します。
5.1.1. ENUMデータ型の列を修正する
このツールが最初に行うのは、Prisma 1データモデルのenum
定義が基盤となるデータベースで実際のENUM
型として表現されるようにすることです。現状では、それらはプレーンな文字列(例:MySQLではMEDIUMTEXT
)として表現されています。
CLIは現在、次の出力を表示しています。
Fix columns with ENUM data types
https://pris.ly/d/schema-incompatibilities#enums-are-represented-as-text-in-database
ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL;
今すぐこれらのステートメントをデータベースに対して実行してください。
5.1.2. データベースに不足しているDEFAULT
制約を追加する
次に、アップグレードCLIは、データベースにデフォルト値が表現されていないという問題を、対応するDEFAULT
制約をデータベースに直接追加するSQLステートメントを生成することで解決するのに役立ちます。
この場合、ツールによって2つのDEFAULT
制約が不足していることが示唆されています。
Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database
ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL DEFAULT 'CUSTOMER';
ALTER TABLE `Post` CHANGE `published` `published` TINYINT(1) NOT NULL DEFAULT 0;
これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。
5.1.3. JSONデータ型の列を修正する
次に、このツールは、Prisma 1データモデルのJson
フィールドが基盤となるデータベースでJSON
列として表現されるようにします。現状では、それらはプレーンな文字列(例:MySQLではMEDIUMTEXT
)として表現されています。
列の型をJSON
に変更すると、Prisma ORM 2のイントロスペクション中にそのフィールドがJson
として適切に認識されるようになります。
CLIは現在、次の出力を表示しています。
Fix columns with JSON data types
https://pris.ly/d/schema-incompatibilities#json-type-is-represented-as-text-in-database
ALTER TABLE `User` CHANGE `jsonData` `jsonData` JSON ;
これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。
5.1.4. Prisma ORM 2で@createdAt
の動作を再現する
次に、このツールは、データベースで@createdAt
の動作が表現されていないという問題を解決するのに役立ちます。
CLIは現在、次の出力を表示しています。
Replicate `@createdAt` behavior in Prisma ORM 2.0
https://pris.ly/d/schema-incompatibilities#createdat-isnt-represented-in-database
ALTER TABLE `Post` CHANGE `createdAt` `createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;
これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。
5.1.5. UNIQUE
制約を追加して1対1リレーションを修正する
これで、このツールは、データベースの外部キー列user
(Prisma 1データモデルのリレーションフィールドにちなんで名付けられたもの)にUNIQUE
制約を追加することで、User
↔ Profile
間の現在の1対多リレーションを1対1リレーションに戻すのに役立ちます。
CLIは現在、次の出力を表示しています。
Fix 1-1 relations by adding `UNIQUE` constraints
https://pris.ly/d/schema-incompatibilities#inline-1-1-relations-are-recognized-as-1-n-missing-unique-constraint
ALTER TABLE `Profile` ADD UNIQUE (`user`);
これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。
5.1.6. CUID長の不一致を修正する
注:これらのSQLステートメントは、基盤となるデータベースで列の型を変更した後でも、アップグレードCLIに表示され続けます。これは現在、アップグレードCLIの制限です。
最後に、このツールは、データベースの外部キー列user
(Prisma 1データモデルのリレーションフィールドにちなんで名付けられたもの)にUNIQUE
制約を追加することで、現在のID列の型VARCHAR(25)
をVARCHAR(30)
に変更するのに役立ちます。
CLIは現在、次の出力を表示しています。
Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `Category` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Post` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `user` `user` char(30) CHARACTER SET utf8 ;
ALTER TABLE `User` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
SET FOREIGN_KEY_CHECKS=1;
これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。
5.1.7. 破壊的変更が検出されました
アップグレードCLIが破壊的変更に関する注記を表示した場合、データベーススキーマを完全に最適化するためには、Prisma 1との互換性を損なう調整が必要になります。
破壊的変更が検出されなかった場合は、セクション5.2に進むことができます。
お使いのアップグレード戦略によっては、これらの変更を今すぐ実行するか、アップグレードCLIの次のフェーズにスキップすることができます。
- 段階的な並行アップグレード戦略に従っている場合は、Prisma 1のセットアップが壊れるため、これらの変更はまだ実行しないでください。その場合は、nと入力し、RETURNを押してアップグレードCLIの次のフェーズに進むことができます。
- 一括アップグレード戦略に従っている場合は、これらの変更を今すぐ実行できます。その場合は、Yと入力し、RETURNを押して続行してください。
5.2. プレーンSQLによるデータベーススキーマの修正(破壊的)
このセクションでは、Prisma 1のセットアップを壊しているスキーマの非互換性を解決します。プロジェクトでまだPrisma 1を実行している場合は、これらの変更を実行しないでください!
5.2.1. 不適切な多対多リレーションを修正する
これで、アップグレードCLIは、Prisma 1がリレーションテーブルで表現し、新しいPrisma ORM 2スキーマでは現在多対多リレーションとしてのみ存在するすべての1対1および1対多リレーションを修正するのに役立ちます。具体的には、現在多対多として定義されているが、本来は1対多リレーションであるべきUser
↔ Post
リレーションがこれに該当します。
これを修正するには、次の移行を実行する必要があります。
Post
に新しい外部キー列を作成し、User
テーブルに直接リンクする。- リレーションテーブルから新しい外部キー列(
Post
上)に外部キー値を移行する。 - リレーションテーブルを削除する。
これらの指示がCLIによって出力されます。
➤ Adjust your database schema
Run the following SQL statements against your database:
Fix one-to-many table relations
https://pris.ly/d/schema-incompatibilities#all-non-inline-relations-are-recognized-as-m-n
ALTER TABLE `Post` ADD COLUMN `authorId` char(25) CHARACTER SET utf8 ;
ALTER TABLE `Post` ADD CONSTRAINT author FOREIGN KEY (`authorId`) REFERENCES `User`(`id`);
UPDATE `Post`, `_PostToUser` SET `Post`.`authorId` = `_PostToUser`.B where `_PostToUser`.A = `Post`.`id`;
DROP TABLE `_PostToUser`;
➤ Next Steps
After you executed one or more of the above SQL statements against your database,
please run the following two commands to refresh your Prisma ORM 2 Schema and check
the changes.
1. Run `npx prisma db pull` again to refresh your Prisma ORM 2 schema.
2. Run `npx prisma-upgrade` again.
If you can't or don't want to execute the remaining SQL statements right now, you can
skip to the last step where the Upgrade CLI adds missing attributes to your Prisma ORM 2
schema that are not picked up by introspection.
Skip to the last step? [Y/n]?
この修正には、3つのSQLステートメントを実行する必要があります。
Post
テーブルに新しい列authorId
を作成します。この列は、User
テーブルのid
フィールドを参照する外部キーである必要があります。ALTER TABLE `Post` ADD COLUMN `authorId` char(25) CHARACTER SET utf8 ;
ALTER TABLE `Post` ADD CONSTRAINT author FOREIGN KEY (`authorId`) REFERENCES `User`(`id`);_PostToUser
リレーションテーブルからすべての行を読み取り、各行に対して次の処理を行うSQLクエリを記述します。- 列
A
の値を使用して、対応するPost
レコードを検索する - 列
B
の値を、そのPost
レコードのauthorId
の値として挿入する
UPDATE `Post`, `_PostToUser` SET `Post`.`authorId` = `_PostToUser`.B where `_PostToUser`.A = `Post`.`id`;
- 列
_PostToUser
リレーションテーブルを削除するDROP TABLE `_PostToUser`;
これらのコマンドの後、リレーションテーブルの列B
からのレコードのユーザーID値は、新しいauthorId
列に移行されます。
5.2. データベースを再イントロスペクトしてPrismaスキーマを更新する
この時点で、アップグレードCLIでスキーマの非互換性を解決しました。ここで、nと入力し、RETURNを押して、アップグレードCLIを終了できます。
このセクションでは、別のイントロスペクションラウンドでPrismaスキーマを更新します。今回は、データベーススキーマが調整されたため、Prismaスキーマの以前の欠陥が解決されます。
npx prisma db pull
今回は、結果のPrismaスキーマは次のようになります。
model User {
id String @id
name String
email String? @unique
jsonData Json?
role Role @default(CUSTOMER)
Post Post[]
Profile Profile?
}
model Post {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime
title String
content String?
published Boolean @default(false)
authorId String?
User User? @relation(fields: [authorId], references: [id])
Category Category[] @relation(references: [id])
}
model Category {
id String @id
name String
Post Post[] @relation(references: [id])
}
model Profile {
bio String?
id String @id
user String? @unique
User User? @relation(fields: [user], references: [id])
}
enum Role {
ADMIN
CUSTOMER
}
このスキーマはほとんどの問題が解決されていますが、以下の点がまだ不足しています。
5.2. Prisma 2スキーマに不足している属性とその他のスキーマ修正を追加する
CLIは次の出力を表示します。
➤ What happens next
As a last step, some final adjustments will be made to your Prisma ORM 2 schema
to carry over some Prisma ORM-level attributes that aren't picked up by introspection.
As a last step, some final adjustments will be made to your Prisma ORM 2.0
schema to carry over some Prisma ORM-level attributes that aren't picked
up by introspection.
Warning
Your current Prisma ORM 2.0 schema will be overwritten, so please
make sure you have a backup!
Are you ready? [Y/n]
この時点で、CLIによって出力されたSQLステートメントをすべて実行したか、一部をスキップしたかのどちらかです。いずれにせよ、最後のステップに進み、アップグレードCLIに不足しているPrisma ORM 2属性を追加させることができます。通常、これらは次のとおりです。
@id
フィールドの@default(cuid())
- Prisma 1でこの属性を使用していたフィールドの
@updatedAt
- Prisma 1の
@db
と@@db
の代替としての@map
と@@map
このステップで、アップグレードCLIはPrisma ORM 2への移行で発生したその他の問題も修正します。
- Prisma 1で両側で必須であった1対1リレーションが、Prisma ORM 2スキーマでも必須であることを確認する
- リレーションフィールドをPrisma 1データモデルと同じ名前に変更する(近日公開)
これらの変更を適用するには、アップグレードCLIを再実行できます。
npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma
すべてのスキーマの非互換性を解決しなかった場合、アップグレードCLIは残りのSQLステートメント(およびID移行用のもの)を出力します。この時点ではそれらを無視して、プロンプトが表示されたときにYを連続して入力し、RETURNを押すことで最後のステップに進むことができます。
すべてのスキーマの非互換性を解決した場合、SQLステートメントは何も出力されず、アップグレードCLIは次のもののみを出力します。
$ npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma
➤ Next Steps
After you executed one or more of the previous SQL statements against your database,
please run the following two commands to refresh your Prisma ORM 2 schema and check
the changes.
1. Run `npx prisma db pull` again to refresh your Prisma ORM 2 schema.
2. Run `npx prisma-upgrade` again.
If you can't or don't want to execute the remaining SQL statements right now, you can
skip to the last step where the Upgrade CLI adds missing attributes to your Prisma ORM 2
schema that are not picked up by introspection.
Skip to the last step? [Y/n]?
もう一度、Yと入力し、RETURNを押して確認してください。
アップグレードCLIの最後のプロンプトで、Prismaスキーマに対して行われる上記の変更を確認するよう求められます。
➤ What happens next
As a last step, some final adjustments will be made to your Prisma ORM 2 schema
to carry over some Prisma ORM-level attributes that aren't picked up by introspection.
As a last step, some final adjustments will be made to your Prisma ORM 2.0
schema to carry over some Prisma ORM-level attributes that aren't picked
up by introspection.
Warning
Your current Prisma ORM 2.0 schema will be overwritten, so please
make sure you have a backup!
Are you ready? [Y/n]
最後にもう一度、Yと入力し、RETURNを押して確認してください。
これがアップグレードCLIの最終出力です。
Updating prisma/schema.prisma...
Done updating prisma/schema.prisma!
✔ Congratulations, you're all set!
➤ Note
If you didn't execute all generated SQL commands against your database,
you can re-run the Upgrade CLI at any time.
Note that the Upgrade CLI doesn't resolve all of the schema incompatibilities
between Prisma 1 and Prisma ORM 2. If you want to resolve the remaining ones,
you can do so manually by following this guide:
https://pris.ly/d/upgrading-the-prisma-layer
➤ Next steps
Otherwise you can continue your upgrade process by installing Prisma Client 2:
npm install @prisma/client
You can find guides for different upgrade scenarios in the docs:
https://pris.ly/d/upgrade-from-prisma-1
5.3. 最終結果
Prismaスキーマの最終バージョンは次のようになるはずです。
model User {
id String @id @default(cuid())
name String
email String? @unique
jsonData Json?
role Role @default(CUSTOMER)
Post Post[]
Profile Profile?
}
model Post {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
content String?
published Boolean @default(false)
authorId String?
User User? @relation(fields: [authorId], references: [id])
Category Category[] @relation(references: [id])
}
model Profile {
id String @id @default(cuid())
bio String?
user String? @unique
User User? @relation(fields: [user], references: [id])
}
model Category {
id String @id @default(cuid())
name String
Post Post[] @relation(references: [id])
}
enum Role {
ADMIN
CUSTOMER
}
5.4. リレーションフィールドの名前を変更する
このバージョンのPrisma ORM 2スキーマで気づくことの1つは、すべてのリレーションフィールドがそれぞれのモデルにちなんで名付けられていることです(例:)。
model User {
Post Post[]
Profile Profile?
}
model Post {
User User? @relation(fields: [authorId], references: [id])
Category Category[] @relation(references: [id])
}
model Profile {
User User? @relation(fields: [user], references: [id])
}
model Category {
Post Post[] @relation(references: [id])
}
これは理想的ではなく、実際にはそれらすべてを以前のバージョンに手動で名前変更できます!
すべてのリレーションフィールドは仮想であり、データベースに現れないため、好きなように名前を付けることができます。この場合、すべてのリレーションフィールドは小文字になり、場合によっては複数形になります。
名前変更後の状態は次のとおりです。
model User {
posts Post[]
profile Profile?
}
model Post {
author User? @relation(fields: [authorId], references: [id])
categories Category[] @relation(references: [id])
}
model Profile {
user String? @unique
owner User? @relation(fields: [user], references: [id])
}
model Category {
posts Post[] @relation(references: [id])
}
注:
User
とProfile
間の1対1リレーションでは、リレーションフィールドに古い名前user
を設定することはできませんでした。これは、すでに存在する外部キーを保持するリレーションスカラーフィールドと名前の衝突が発生するためです。その場合、別の名前を選択するか、SQLを介してデータベース内で直接外部キー列の名前を変更することもできます。
5.5. 残りのスキーマの非互換性を解決する
アップグレードCLIではまだ解決されていないスキーマの非互換性がいくつかあります。この時点では、スカラーリストはまだ修正されていません。これらやその他の推奨される回避策については、スキーマの非互換性ページをご覧ください。
6. Prisma Clientをインストールして生成する
Prisma ORM 2スキーマの準備ができたので、次のコマンドでPrisma Clientをインストールできます。
npm install @prisma/client
7. 次のステップ
おめでとうございます、Prisma ORMレイヤーをPrisma ORM 2にアップグレードしました!ここから、以下のいずれかのガイドを使用してアプリケーションコードの更新に進むことができます。
- 旧Nexusから新Nexusへ: 現在Prisma 1をGraphQL Nexusで実行している場合は、このガイドを選択してください。
- prisma-bindingからNexusへ: 現在Prisma 1を
prisma-binding
で実行しており、Nexus(およびTypeScript)にアップグレードしたい場合は、このガイドを選択してください。 - prisma-bindingからSDL-firstへ: 現在Prisma 1を
prisma-binding
で実行しており、SDL-first GraphQLサーバーにアップグレードしたい場合は、このガイドを選択してください。 - REST API: 現在Prisma Client 1を使用してPrisma 1を実行しており、REST APIを構築している場合は、このガイドを選択してください。
ボーナス: Prisma Client APIの比較
このセクションには、Prisma 1とPrisma ORM 2のPrisma Client APIの概要と並行比較が含まれています。新しいPrisma Client APIの詳細については、Prisma Clientドキュメントをご覧ください。
単一レコードの読み取り
const user = await prisma.user({ id: 1 })
await prisma.user.findUnique({
where: { id: 1 },
})
レコードリストの読み取り
const user = await prisma.users()
await prisma.user.findMany()
リストのフィルタリング
const users = await prisma.users({
where: {
name: 'Alice',
},
})
await prisma.user.findMany({
where: {
name: 'Alice',
},
})
リストのページネーション
const posts = await prisma.posts({
skip: 5,
first: 10,
})
await prisma.user.findMany({
skip: 5,
take: 10,
})
注:新しいページネーションAPIの詳細については、それぞれのリリースノートまたはドキュメントのページネーションページで確認できます。
リストのソート
await prisma.posts({
orderBy: 'title_ASC',
})
await prisma.posts({
orderBy: {
title: 'asc',
},
})
レコードの作成
await prisma.createUser({
name: 'Alice',
})
await prisma.user.create({
data: {
name: 'Alice',
},
})
レコードの更新
await prisma.updateUser({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})
await prisma.user.update({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})
レコードの削除
await prisma.deleteUser({ id: 1 })
await prisma.user.delete({
where: { id: 1 },
})
フィールドの選択とリレーションの読み込み
Prisma 1では、特定のフィールドを選択したり、オブジェクトのリレーションを読み込んだりする唯一の方法は、文字列ベースの$fragment
関数と$graphql
関数を使用することでした。Prisma ORM 2では、これはselect
とinclude
を使用して、クリーンで型安全な方法で行われるようになりました。
このアプローチのもう一つの利点は、select
とinclude
をあらゆるPrisma Clientクエリ、例えばfindUnique
、findMany
、create
、update
、delete
などに使用できることです。
await prisma.user({ id: 1 }).$fragment(`
fragment NameAndEmail on User { id email }`
`)
await prisma.user.findUnique({
where: { id: 1 },
select: {
id: true,
email: true,
},
})
例えば、Prisma 1では新しいレコードを作成し、返されるオブジェクトでid
のみを取得することはできませんでした。Prisma ORM 2では、これを次のように実現できます。
await prisma.user.create({
data: {
name: 'Alice',
},
select: {
id: true,
},
})