Prisma ORMレイヤーのアップグレード (PostgreSQL)
概要
このページでは、アップグレードプロセスの最初のステップ、すなわちPrisma 1の設定をPrisma ORM 2にアップグレードする方法について説明します。具体的には、以下の方法を学びます。
- Prisma ORM 2 CLIを開発依存関係として追加する
- Prisma ORM 2スキーマを作成する
- 接続URLを決定し、データベースに接続する
- データベースをイントロスペクトする(これまではPrisma 1で管理されていました)
- Prisma 1 Upgrade CLIを使用して、新しいPrisma ORM 2データモデルにおけるスキーマの非互換性を解決する
- Prisma Clientをインストールして生成する
これらの手順が完了したら、次のガイドに進み、データベースクエリにPrisma Clientを使用するようにアプリケーションレイヤーをアップグレードする方法を学びます。
注意:アップグレードプロセス中、データベースをグラフィカルに表示できると役立つ場合があります。したがって、TablePlusやPosticoのようなグラフィカルデータベースクライアントを使用してデータベースに接続することをお勧めします。
1. Prisma ORM 2 CLIをインストールする
Prisma ORM 2 CLIは、npm上のprisma
パッケージとして利用でき、prisma
コマンドで呼び出されます。
Prisma 1の以前のprisma
コマンドはprisma1
に名前が変更されています。これについてはこちらで詳しく学ぶことができます。
Prisma ORM 2 CLIは、Node.jsプロジェクトに次のようにインストールできます(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 = "postgresql"
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: postgres
host: postgres
port: 5432
user: prisma
password: prisma
また、prisma.yml
のendpoint
が次のように設定されていると仮定します。
endpoint: http://:4466/myproject/dev
これらの接続詳細に基づいて、.env
ファイル内のDATABASE_URL
環境変数を次のように設定する必要があります。
DATABASE_URL="postgresql://janedoe:randompassword@localhost:5432/prisma?schema=myproject$dev"
schema
引数は、通常、サービス名とサービスステージ(prisma.yml
のendpoint
の一部)を$
文字で区切って構成されます。
prisma.yml
にサービス名とステージが指定されていない場合もあります。
endpoint: http://:4466/
その場合、schema
は次のように指定する必要があります。
DATABASE_URL="postgresql://janedoe:randompassword@localhost:5432/prisma?schema=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
型であり、roleのenum
定義が完全に欠落しています
これらの矛盾は、Prisma Client APIで利用できる「機能セット」に実際には影響しませんが、以前に存在していた特定の制約/保証が失われます。
例えば、Prisma ORMは、User
が最大1つのProfile
に接続されていることを保証しなくなります。なぜなら、テーブル間のリレーションはイントロスペクション中に1対多として認識されたため、1つのUser
レコードが複数のProfile
レコードに接続できるようになるからです。
もう1つの問題は、jsonData
およびrole
フィールドに、それが有効なJSONであるか、またはRole
enumの値であるかに関係なく、任意のテキストを保存できることです。
これらの矛盾の詳細については、スキーマの非互換性のページを参照してください。
以下では、これらの非互換性をPrismaスキーマアップグレードCLIを使用して1つずつ修正していきます。
5. PrismaスキーマアップグレードCLIを使用してスキーマの非互換性を解決する
Prisma 1 Upgrade CLIは、Prismaスキーマをアップグレードし、上記に挙げたほとんどの矛盾を解消するのに役立つインタラクティブなツールです。
Prisma 1 Upgrade CLIは、主に2つのフェーズで動作します。
- プレーンSQLを介してデータベーススキーマを修正する
- Prisma ORM 2スキーマに欠落している属性やその他のスキーマの修正を追加する
最初のフェーズでは、データベーススキーマを調整するためにデータベースに対して実行すべきSQLステートメントが生成され、表示されます。2番目のフェーズに進む前に、これらのステートメントのすべてまたは一部を実行できます。
2番目のフェーズでは、手動で何かをする必要はありません。Upgrade CLIは、特定のPrisma ORMレベルの属性(例: @default(cuid))
や@updatedAt
)を追加したり、リレーションフィールドの名前をPrisma 1データモデルのものと一致するように調整したり、Prisma 1データモデルで両側で必須だった1対1リレーションがPrisma ORM 2スキーマでも必須であることを確認したりすることで、Prismaスキーマに変更を加えます。
プロセス中いつでもやり直すことができ、2番目のフェーズから1番目のフェーズに戻ることができることに注意してください。
この図では、緑色の領域が最初のフェーズを、青色の領域が2番目のフェーズを示しています。フェーズ間にオプションでprisma db pull
を実行して、Prisma ORMデータモデルを更新できることに注意してください。
Upgrade 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
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
CREATE TYPE "default$default"."Role" AS ENUM ('ADMIN', 'CUSTOMER');
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DATA TYPE "default$default"."Role" using "role"::"default$default"."Role";
Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DEFAULT 'CUSTOMER';
ALTER TABLE "default$default"."Post" ALTER COLUMN "published" SET DEFAULT false;
Fix columns with JSON data types
https://pris.ly/d/schema-incompatibilities#json-type-is-represented-as-text-in-database
ALTER TABLE "default$default"."User" ALTER COLUMN "jsonData" SET DATA TYPE JSONB USING "jsonData"::TEXT::JSONB;
Replicate `@createdAt` behavior in Prisma ORM 2
https://pris.ly/d/schema-incompatibilities#createdat-isnt-represented-in-database
ALTER TABLE "default$default"."Post" ALTER COLUMN "createdAt" SET 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 "default$default"."Profile" ADD UNIQUE ("user");
Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length
ALTER TABLE "default$default"."Category" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Post" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "user" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."User" ALTER COLUMN "id" SET DATA TYPE character varying(30);
➤ 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 1とPrisma ORM 2を並行して引き続き使用できます。
次のセクションでは、データベースに個別に送信するさまざまな種類の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
CREATE TYPE "default$default"."Role" AS ENUM ('ADMIN', 'CUSTOMER');
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DATA TYPE "default$default"."Role" using "role"::"default$default"."Role";
⚠️ 警告:Prisma 1とPrisma ORM 2を並行して実行している場合、これらのSQLステートメントはPrisma 1のセットアップを破壊します。この点については、ドキュメントが間もなく更新される予定です。
これらのステートメントを今すぐデータベースに対して実行してください。
5.1.2. データベースに欠落しているDEFAULT
制約を追加する
次に、Upgrade 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 "default$default"."User" ALTER COLUMN "role" SET DEFAULT 'CUSTOMER';
ALTER TABLE "default$default"."Post" ALTER COLUMN "published" SET DEFAULT false;
これらのSQLステートメントをコマンドラインクライアントまたはPosticoのようなGUIを使用してデータベースに対して実行できます。
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 "default$default"."User" ALTER COLUMN "jsonData" TYPE JSON USING "jsonData"::json;
⚠️ 警告:Prisma 1とPrisma ORM 2を並行して実行している場合、これらのSQLステートメントはPrisma 1のセットアップを破壊します。この点については、ドキュメントが間もなく更新される予定です。
これらのSQLステートメントをコマンドラインクライアントまたはPosticoのようなGUIを使用してデータベースに対して実行できます。
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 "default$default"."Post" ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP;
これらのSQLステートメントをコマンドラインクライアントまたはPosticoのようなGUIを使用してデータベースに対して実行できます。
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 "default$default"."Profile" ADD UNIQUE ("user");
これらのSQLステートメントをコマンドラインクライアントまたはPosticoのようなGUIを使用してデータベースに対して実行できます。
5.1.6. CUID長の不一致を修正する
注意:これらのSQLステートメントは、基となるデータベースの列タイプを変更した後でも、Upgrade CLIに表示され続けます。これは現在のUpgrade CLIの制限です。
最後に、このツールは、データベースの外部キー列user
(Prisma 1データモデルのリレーションフィールドにちなんで名付けられています)にUNIQUE
制約を追加することで、現在のVARCHAR(25)
型のID列をVARCHAR(30)
型に変更するのに役立ちます。
CLIは現在以下の出力を表示しています。
Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length
ALTER TABLE "default$default"."Category" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Post" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "user" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."User" ALTER COLUMN "id" SET DATA TYPE character varying(30);
これらのSQLステートメントをコマンドラインクライアントまたはPosticoのようなGUIを使用してデータベースに対して実行できます。
5.1.7. 破壊的変更の検出
Upgrade CLIが破壊的変更に関する通知を出力した場合、データベーススキーマを完全に最適化するためには、Prisma 1の互換性を損なう可能性のある調整が必要です。
破壊的変更が検出されなかった場合、セクション5.2をスキップできます。
アップグレード戦略によっては、これらの変更を今すぐ実行するか、Upgrade CLIの次のフェーズにスキップするかを選択できます。
- 段階的な並行アップグレード戦略に従っている場合、これらの変更はPrisma 1のセットアップを破壊するため、まだ実行しないでください。その場合、nを入力してRETURNを押すことで、Upgrade CLIの次のフェーズに進むことができます。
- 一度にすべてアップグレードする戦略に従っている場合、これらの変更を今すぐ実行できます。その場合、Yを入力してRETURNを押して続行してください。
5.2. プレーンSQLによるデータベーススキーマの修正(破壊的)
このセクションでは、Prisma 1のセットアップを破壊するスキーマの非互換性を解決します。プロジェクトでPrisma 1をまだ実行している場合は、これらの変更を実行しないでください!
5.2.1. 不正確な多対多リレーションを修正する
次に、Upgrade 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 "default$default"."Post" ADD COLUMN "authorId" character varying(25) ;
ALTER TABLE "default$default"."Post" ADD CONSTRAINT "author" FOREIGN KEY ("authorId") REFERENCES "default$default"."User"("id");
UPDATE "default$default"."Post" SET "authorId" = "default$default"."_PostToUser"."B" FROM "default$default"."_PostToUser" WHERE "default$default"."_PostToUser"."A" = "default$default"."Post"."id";
DROP TABLE "default$default"."_PostToUser";
➤ 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]?
この修正には、3つのSQLステートメントを実行する必要があります。
Post
テーブルに新しい列authorId
を作成します。この列は、User
テーブルのid
フィールドを参照する外部キーである必要があります。ALTER TABLE `Post` ADD COLUMN `authorId` VARCHAR(25);
ALTER TABLE `Post` ADD FOREIGN KEY (`authorId`) REFERENCES `User` (`id`);_PostToUser
リレーションテーブルからすべての行を読み取り、各行に対して以下の処理を行うSQLクエリを作成します。- 列
A
の値を見て、対応するPost
レコードを見つけます。 - 列
B
の値をそのPost
レコードのauthorId
の値として挿入します。
UPDATE Post, _PostToUser
SET Post.authorId = _PostToUser.B
WHERE Post.id = _PostToUser.A- 列
_PostToUser
リレーションテーブルを削除します。DROP TABLE `_PostToUser`;
これらのコマンドを実行すると、リレーションテーブルの列B
からのレコードのユーザーID値が新しいauthorId
列に移行されます。
5.2. データベースを再イントロスペクトしてPrismaスキーマを更新する
この時点で、Upgrade CLIを使用してスキーマの非互換性を解決しました。これで、nを入力してRETURNを押すことで、一旦Upgrade 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ステートメントを実行したか、またはその一部をスキップしたかのいずれかです。いずれにしても、最後のステップに進み、Upgrade CLIに欠落しているPrisma ORM 2属性を追加させることができます。通常、これらは以下の通りです。
@id
フィールドの@default(cuid())
- Prisma 1でこの属性を使用していたフィールドの
@updatedAt
- Prisma 1の
@db
および@@db
の代替としての@map
および@@map
このステップで、Upgrade CLIはPrisma ORM 2への移行で発生したその他の問題も修正します。
- Prisma 1で両側で必須だった1対1リレーションがPrisma ORM 2スキーマでも必須であることを確認します。
- リレーションフィールドの名前をPrisma 1データモデルと同じ名前に変更します(近日公開予定)。
これらの変更を適用するには、Upgrade CLIを再実行します。
npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma
すべてのスキーマの非互換性を解決しなかった場合、Upgrade CLIは残りのSQLステートメント(およびID移行用のステートメント)を出力します。この時点ではそれらを無視し、プロンプトが表示されたときにYを連続して入力し、RETURNを押すことで最後のステップに進むことができます。
すべてのスキーマの非互換性を解決した場合、SQLステートメントは出力されず、Upgrade 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を押して確認します。
Upgrade 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を押して確認します。
これはUpgrade 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. 残りのスキーマ非互換性の解決
Upgrade 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
を使用して、クリーンで型安全な方法でこれを行うことができます。
このアプローチのもう1つの利点は、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,
},
})
例として、新しいレコードを作成し、返されたオブジェクトでid
のみを取得することはPrisma 1では不可能でした。Prisma ORM 2では、次のようにしてこれを実現できます。
await prisma.user.create({
data: {
name: 'Alice',
},
select: {
id: true,
},
})