メインコンテンツへスキップ

Prisma ORMレイヤーのアップグレード (MySQL)

概要

このページでは、アップグレードプロセスの最初のステップである、Prisma 1の構成をPrisma ORM 2にアップグレードする方法について説明します。具体的には、以下の方法を学びます。

  1. Prisma ORM 2 CLIを開発依存関係として追加する
  2. Prisma ORM 2スキーマを作成する
  3. 接続URLを決定し、データベースに接続する
  4. データベースをイントロスペクトする(これまではPrisma 1で管理されていました)
  5. 新しいPrisma ORM 2データモデルにおけるスキーマの非互換性を解決するために、Prisma 1アップグレードCLIを使用する
  6. Prisma Clientをインストールして生成する

これらのステップが完了したら、次のガイドに進み、Prisma Clientを使用してデータベースクエリを実行するためにアプリケーションレイヤーをアップグレードする方法を学ぶことができます。

:アップグレードプロセス中に、データベースのグラフィカルビューを取得すると役立つ場合があります。そのため、TablePlusPosticoなどのグラフィカルなデータベースクライアントを使用してデータベースに接続することをお勧めします。

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
// 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"の値を定義する必要があります。

コードブロックのタブを切り替えて、両方の例をご覧ください。

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

providerフィールドが設定されたら、.envファイル内で接続URLを設定できます。

Prisma ORMサーバーのデプロイに使用したDocker Composeファイルのデータベース設定が次のようになっているとします。

docker-compose.yml
PRISMA_CONFIG: |
port: 4466
databases:
default:
connector: mysql
host: mysql
port: 3306
user: root
password: randompassword

また、prisma.ymlendpointが次のように構成されているとします。

prisma.yml
endpoint: http://:4466/myproject/dev

これらの接続詳細に基づいて、.envファイル内のDATABASE_URL環境変数を次のように構成する必要があります。

.env
DATABASE_URL="mysql://root:randompassword@localhost:3306/myproject@dev"

接続URLのデータベース名は通常、サービス名サービスステージprisma.ymlendpointの一部)を@文字で区切ったもので構成されることに注意してください。

prisma.ymlにサービス名とステージが指定されていない場合があります。

prisma.yml
endpoint: http://:4466/

その場合、データベース名は次のように指定する必要があります。

.env
DATABASE_URL="mysql://root:randompassword@localhost:3306/default@default"

接続URLページで詳細をご覧ください。

4. データベースをイントロスペクトする

このガイドの目的のため、次のPrisma 1データモデルを使用します(データモデルがSQLでどのようにマッピングされるかを見るには、下の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
}

このデータモデルには、3つのリレーションがあることに注意してください。

  • 1対1: UserProfile
  • 1対多: UserPost (_PostToUserリレーションテーブルを介して維持される)
  • 多対多: PostCategory (_CategoryToPostリレーションテーブルを介して維持される)

これで、次のコマンドを使用してPrisma ORMのイントロスペクションをデータベースに対して実行できます。

npx prisma db pull

db pullが呼び出されたときに何が起こるかを示すグラフィカルな図です。

Introspect your database

上記のPrisma 1データモデルの場合、これにより次のPrisma ORM 2スキーマが生成されます(モデルはPrisma 1データモデルの初期順序と一致するように並べ替えられていることに注意してください)。

schema.prisma
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の同等のものであったいくつかの機能が不足しています。

  • PostcreatedAtフィールドとupdatedAtフィールドに自動生成された日付値がない
  • Userroleフィールドにデフォルト値がない
  • Postpublishedフィールドにデフォルト値がない

さらに、Prisma Client APIが非イディオマティック/非人間工学的になる原因となる、いくつかの不整合があります。

  • UserProfileは1対1ではなく1対多のリレーションである
  • UserPostは1対多ではなく多対多のリレーションである
  • リレーションフィールドが大文字になっている(例:UserProfilePost
  • UserjsonDataフィールドがJsonではなくString型になっている
  • Userroleフィールドが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つのフェーズで動作します。

  1. プレーンSQLを介してデータベーススキーマを修正する
  2. 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データモデルを更新できることに注意してください。

Fixing the schema incompatibilities

アップグレード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;

今すぐこれらのステートメントをデータベースに対して実行してください。

Altering columns to use ENUM with SQL

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ステートメントをデータベースに対して実行できます。

TablePlus 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 `User` CHANGE `jsonData` `jsonData` JSON ;

これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。

TablePlus 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 `Post` CHANGE `createdAt` `createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;

これで、コマンドラインクライアントまたはTablePlusのようなGUIを使用して、これらのSQLステートメントをデータベースに対して実行できます。

5.1.5. UNIQUE制約を追加して1対1リレーションを修正する

これで、このツールは、データベースの外部キー列user(Prisma 1データモデルのリレーションフィールドにちなんで名付けられたもの)にUNIQUE制約を追加することで、UserProfile間の現在の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対多リレーションであるべきUserPostリレーションがこれに該当します。

これを修正するには、次の移行を実行する必要があります。

  1. Postに新しい外部キー列を作成し、Userテーブルに直接リンクする。
  2. リレーションテーブルから新しい外部キー列(Post上)に外部キー値を移行する。
  3. リレーションテーブルを削除する。

これらの指示が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ステートメントを実行する必要があります。

  1. 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`);
  2. _PostToUserリレーションテーブルからすべての行を読み取り、各行に対して次の処理を行うSQLクエリを記述します。
    1. Aの値を使用して、対応するPostレコードを検索する
    2. Bの値を、そのPostレコードのauthorIdの値として挿入する
    UPDATE `Post`, `_PostToUser` SET `Post`.`authorId` = `_PostToUser`.B where `_PostToUser`.A = `Post`.`id`;
  3. _PostToUserリレーションテーブルを削除する
    DROP TABLE `_PostToUser`;

Fixing incorrect m-n relations with SQL

これらのコマンドの後、リレーションテーブルの列BからのレコードのユーザーID値は、新しいauthorId列に移行されます。

5.2. データベースを再イントロスペクトしてPrismaスキーマを更新する

この時点で、アップグレードCLIでスキーマの非互換性を解決しました。ここで、nと入力し、RETURNを押して、アップグレードCLIを終了できます。

このセクションでは、別のイントロスペクションラウンドでPrismaスキーマを更新します。今回は、データベーススキーマが調整されたため、Prismaスキーマの以前の欠陥が解決されます。

npx prisma db pull

今回は、結果のPrismaスキーマは次のようになります。

schema.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スキーマの最終バージョンは次のようになるはずです。

schema.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つは、すべてのリレーションフィールドがそれぞれのモデルにちなんで名付けられていることです(例:)。

schema.prisma
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])
}

これは理想的ではなく、実際にはそれらすべてを以前のバージョンに手動で名前変更できます!

すべてのリレーションフィールドは仮想であり、データベースに現れないため、好きなように名前を付けることができます。この場合、すべてのリレーションフィールドは小文字になり、場合によっては複数形になります。

名前変更後の状態は次のとおりです。

schema.prisma
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])
}

UserProfile間の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ドキュメントをご覧ください。

単一レコードの読み取り

Prisma Client (v1)
const user = await prisma.user({ id: 1 })
Prisma Client (v2)
await prisma.user.findUnique({
where: { id: 1 },
})

レコードリストの読み取り

Prisma Client (v1)
const user = await prisma.users()
Prisma Client (v2)
await prisma.user.findMany()

リストのフィルタリング

Prisma Client (v1)
const users = await prisma.users({
where: {
name: 'Alice',
},
})
Prisma Client (v2)
await prisma.user.findMany({
where: {
name: 'Alice',
},
})

リストのページネーション

Prisma Client (v1)
const posts = await prisma.posts({
skip: 5,
first: 10,
})
Prisma Client (v2)
await prisma.user.findMany({
skip: 5,
take: 10,
})

:新しいページネーションAPIの詳細については、それぞれのリリースノートまたはドキュメントのページネーションページで確認できます。

リストのソート

Prisma Client (v1)
await prisma.posts({
orderBy: 'title_ASC',
})
Prisma Client (v2)
await prisma.posts({
orderBy: {
title: 'asc',
},
})

レコードの作成

Prisma Client (v1)
await prisma.createUser({
name: 'Alice',
})
Prisma Client (v2)
await prisma.user.create({
data: {
name: 'Alice',
},
})

レコードの更新

Prisma Client (v1)
await prisma.updateUser({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})
Prisma Client (v2)
await prisma.user.update({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})

レコードの削除

Prisma Client (v1)
await prisma.deleteUser({ id: 1 })
Prisma Client (v2)
await prisma.user.delete({
where: { id: 1 },
})

フィールドの選択とリレーションの読み込み

Prisma 1では、特定のフィールドを選択したり、オブジェクトのリレーションを読み込んだりする唯一の方法は、文字列ベースの$fragment関数と$graphql関数を使用することでした。Prisma ORM 2では、これはselectincludeを使用して、クリーンで型安全な方法で行われるようになりました。

このアプローチのもう一つの利点は、selectincludeあらゆるPrisma Clientクエリ、例えばfindUniquefindManycreateupdatedeleteなどに使用できることです。

Prisma Client (v1)
await prisma.user({ id: 1 }).$fragment(`
fragment NameAndEmail on User { id email }`
`)
Prisma Client (v2)
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,
},
})
© . All rights reserved.