イントロスペクション
Prisma CLIを使用してデータベースをイントロスペクションし、データモデルをPrismaスキーマに生成できます。データモデルは、Prisma Clientを生成するために必要です。
イントロスペクションは、既存のプロジェクトにPrisma ORMを追加する際に、データモデルの初期バージョンを生成するためによく使用されます。
ただし、アプリケーションで繰り返し使用することもできます。これは、Prisma Migrateを使用せずに、プレーンSQLまたは別の移行ツールを使用してスキーマ移行を実行する場合に最も一般的です。その場合、データベースを再度イントロスペクションし、続いてPrisma Clientを再生成して、Prisma Client APIのスキーマ変更を反映させる必要もあります。
イントロスペクションは何をしますか?
イントロスペクションには、1つの主な機能があります。それは、現在のデータベーススキーマを反映するデータモデルをPrismaスキーマに入力することです。
SQLデータベースでの主な機能の概要を以下に示します。
- データベース内のテーブルをPrismaモデルにマッピングする
- データベース内のカラムをPrismaモデルのフィールドにマッピングする
- データベース内のインデックスをPrismaスキーマのインデックスにマッピングする
- データベースの制約をPrismaスキーマの属性または型修飾子にマッピングする
MongoDBでは、主な機能は次のとおりです。
- データベース内のコレクションをPrismaモデルにマッピングする。MongoDBのコレクションには事前定義された構造がないため、Prisma ORMはコレクション内のドキュメントをサンプリングし、それに応じてモデル構造を導き出します(つまり、ドキュメントのフィールドをPrismaモデルのフィールドにマッピングします)。埋め込み型がコレクション内で検出された場合、これらはPrismaスキーマの複合型にマッピングされます。
- コレクションにインデックスに含まれるフィールドを含むドキュメントが少なくとも1つ含まれている場合、データベース内のインデックスをPrismaスキーマのインデックスにマッピングする
Prisma ORMがデータベースからPrismaスキーマで利用可能な型に型をマッピングする方法の詳細については、データソースコネクタのそれぞれのドキュメントページを参照してください。
prisma db pull
コマンド
Prisma CLIのprisma db pull
コマンドを使用してデータベースをイントロスペクションできます。このコマンドを使用するには、Prismaスキーマのdatasource
に接続URLを設定する必要があることに注意してください。
prisma db pull
が内部的に実行するステップの概要を以下に示します。
- Prismaスキーマの
datasource
構成から接続URLを読み取る - データベースへの接続を開く
- データベーススキーマをイントロスペクションする(つまり、テーブル、カラム、その他の構造を読み取る...)
- データベーススキーマをPrismaスキーマデータモデルに変換する
- データモデルをPrismaスキーマに書き込むか、既存のスキーマを更新する
イントロスペクションワークフロー
Prisma Migrateを使用せず、代わりにプレーンSQLまたは別の移行ツールを使用するプロジェクトの典型的なワークフローは次のとおりです。
- データベーススキーマを変更する(例:プレーンSQLを使用)
prisma db pull
を実行してPrismaスキーマを更新するprisma generate
を実行してPrisma Clientを更新する- 更新されたPrisma Clientをアプリケーションで使用する
アプリケーションを進化させるにつれて、このプロセスを無期限に繰り返すことができることに注意してください。
ルールと慣例
Prisma ORMは、データベーススキーマをPrismaスキーマのデータモデルに変換するために、いくつかの慣例を採用しています。
モデル、フィールド、およびenum名
フィールド、モデル、およびenum名(識別子)は、文字で始まり、通常はアンダースコア、文字、および数字のみを含む必要があります。これらの識別子の命名規則と慣例は、それぞれのドキュメントページで確認できます。
識別子の一般的なルールは、次の正規表現に従う必要があるということです。
[A-Za-z][A-Za-z0-9_]*
無効な文字のサニタイズ
無効な文字はイントロスペクション中にサニタイズされます。
- 識別子内の文字より前に現れる場合、それらは削除されます。
- 最初の文字より後に現れる場合、それらはアンダースコアに置き換えられます。
さらに、変換された名前は、元の名前を保持するために@map
または@@map
を使用してデータベースにマッピングされます。
例として次のテーブルを考えてみましょう。
CREATE TABLE "42User" (
_id SERIAL PRIMARY KEY,
_name VARCHAR(255),
two$two INTEGER
);
テーブル名の先頭の42
と、カラムの先頭のアンダースコアと$
はPrisma ORMで禁止されているため、イントロスペクションは@map
および@@map
属性を追加して、これらの名前がPrisma ORMの命名規則に従うようにします。
model User {
id Int @id @default(autoincrement()) @map("_id")
name String? @map("_name")
two_two Int? @map("two$two")
@@map("42User")
}
サニタイズ後の重複した識別子
サニタイズによって重複した識別子が発生した場合、即時のエラー処理は行われません。後でエラーが発生し、手動で修正できます。
次の2つのテーブルのケースを考えてみましょう。
CREATE TABLE "42User" (
_id SERIAL PRIMARY KEY
);
CREATE TABLE "24User" (
_id SERIAL PRIMARY KEY
);
これにより、次のイントロスペクション結果が得られます。
model User {
id Int @id @default(autoincrement()) @map("_id")
@@map("42User")
}
model User {
id Int @id @default(autoincrement()) @map("_id")
@@map("24User")
}
prisma generate
でPrisma Clientを生成しようとすると、次のエラーが発生します。
npx prisma generate
$ npx prisma generate
Error: Schema parsing
error: The model "User" cannot be defined because a model with that name already exists.
--> schema.prisma:17
|
16 | }
17 | model User {
|
Validation Error Count: 1
この場合、重複するモデル名はPrismaスキーマで許可されていないため、生成された2つのUser
モデルのいずれかの名前を手動で変更する必要があります。
フィールドの順序
イントロスペクションは、モデルフィールドをデータベース内の対応するテーブルカラムと同じ順序でリストします。
属性の順序
イントロスペクションは、次の順序で属性を追加します(この順序はprisma format
によって反映されます)。
- ブロックレベル:
@@id
、@@unique
、@@index
、@@map
- フィールドレベル:
@id
、@unique
、@default
、@updatedAt
、@map
、@relation
リレーション
Prisma ORMは、データベーステーブルで定義されている外部キーをリレーションに変換します。
1対1のリレーション
Prisma ORMは、テーブルの外部キーにUNIQUE
制約がある場合、1対1のリレーションをデータモデルに追加します。例:
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Profile" (
id SERIAL PRIMARY KEY,
"user" integer NOT NULL UNIQUE,
FOREIGN KEY ("user") REFERENCES "User"(id)
);
Prisma ORMはこれを次のデータモデルに変換します。
model User {
id Int @id @default(autoincrement())
Profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user Int @unique
User User @relation(fields: [user], references: [id])
}
1対多のリレーション
デフォルトでは、Prisma ORMは、データベーススキーマで見つかった外部キーに対して、1対多のリレーションをデータモデルに追加します。
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"author" integer NOT NULL,
FOREIGN KEY ("author") REFERENCES "User"(id)
);
これらのテーブルは、次のモデルに変換されます。
model User {
id Int @id @default(autoincrement())
Post Post[]
}
model Post {
id Int @id @default(autoincrement())
author Int
User User @relation(fields: [author], references: [id])
}
多対多のリレーション
多対多のリレーションは、通常、リレーショナルデータベースではリレーションテーブルとして表現されます。
Prisma ORMは、Prismaスキーマで多対多のリレーションを定義する2つの方法をサポートしています。
- 暗黙的な多対多のリレーション(Prisma ORMが内部でリレーションテーブルを管理します)
- 明示的な多対多のリレーション(リレーションテーブルはモデルとして存在します)
暗黙的な多対多のリレーションは、Prisma ORMのリレーションテーブルの慣例に従っている場合に認識されます。それ以外の場合、リレーションテーブルはPrismaスキーマでモデルとしてレンダリングされます(したがって、明示的な多対多のリレーションになります)。
このトピックは、リレーションに関するドキュメントページで広範囲にカバーされています。
リレーションの曖昧さ回避
Prisma ORMは、通常、@relation
属性でname
引数が不要な場合は省略します。前のセクションのUser
↔ Post
の例を考えてみましょう。@relation
属性にはreferences
引数のみがあり、この場合は不要であるため、name
は省略されています。
model Post {
id Int @id @default(autoincrement())
author Int
User User @relation(fields: [author], references: [id])
}
Post
テーブルに2つの外部キーが定義されている場合は必要になります。
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"author" integer NOT NULL,
"favoritedBy" INTEGER,
FOREIGN KEY ("author") REFERENCES "User"(id),
FOREIGN KEY ("favoritedBy") REFERENCES "User"(id)
);
この場合、Prisma ORMは、専用のリレーション名を使用してリレーションを曖昧にする必要があります。
model Post {
id Int @id @default(autoincrement())
author Int
favoritedBy Int?
User_Post_authorToUser User @relation("Post_authorToUser", fields: [author], references: [id])
User_Post_favoritedByToUser User? @relation("Post_favoritedByToUser", fields: [favoritedBy], references: [id])
}
model User {
id Int @id @default(autoincrement())
Post_Post_authorToUser Post[] @relation("Post_authorToUser")
Post_Post_favoritedByToUser Post[] @relation("Post_favoritedByToUser")
}
Prisma-ORMレベルのリレーションフィールドの名前を、生成されたPrisma Client APIでよりフレンドリーに見えるように、好きなように変更できることに注意してください。
既存のスキーマでのイントロスペクション
リレーショナルデータベースに対して既存のPrismaスキーマでprisma db pull
を実行すると、スキーマへの手動による変更とデータベースで行われた変更がマージされます。(この機能はバージョン2.6.0で初めて追加されました。)MongoDBの場合、イントロスペクションは当面の間、最初のデータモデルに対して1回だけ実行することを意図しています。繰り返し実行すると、以下に示すようなカスタム変更が失われます。
リレーショナルデータベースのイントロスペクションは、次の手動による変更を維持します。
model
ブロックの順序enum
ブロックの順序- コメント
@map
および@@map
属性@updatedAt
@default(cuid())
(cuid()
はPrisma-ORMレベルの関数です)@default(uuid())
(uuid()
はPrisma-ORMレベルの関数です)- カスタム
@relation
名
注意:データベースレベルのモデル間のリレーションのみが検出されます。これは、外部キーが設定されている必要があることを意味します。
スキーマの次のプロパティはデータベースによって決定されます。
model
ブロック内のフィールドの順序enum
ブロック内の値の順序
注意:すべての
enum
ブロックはmodel
ブロックの下にリストされます。
強制上書き
手動による変更を上書きし、イントロスペクションされたデータベースのみに基づいてスキーマを生成し、既存のPrismaスキーマを無視するには、db pull
コマンドに--force
フラグを追加します。
npx prisma db pull --force
ユースケースには以下が含まれます。
- 基盤となるデータベースから生成されたスキーマで最初からやり直したい場合
- スキーマが無効で、イントロスペクションを成功させるために
--force
を使用する必要がある場合
データベーススキーマのサブセットのみをイントロスペクションする
データベーススキーマのサブセットのみをイントロスペクションすることは、Prisma ORMではまだ公式にはサポートされていません。
ただし、Prismaスキーマで表現したいテーブルへのアクセス権のみを持つ新しいデータベースユーザーを作成し、そのユーザーを使用してイントロスペクションを実行することで、これを実現できます。イントロスペクションには、新しいユーザーがアクセスできるテーブルのみが含まれます。
モデルをPrisma Clientの生成から除外することが目標の場合は、Prismaスキーマのモデル定義に@@ignore
属性を追加できます。無視されたモデルは、生成されたPrisma Clientから除外されます。
サポートされていない機能に関するイントロスペクション警告
Prisma Schema Language(PSL)は、Prisma ORMがサポートするターゲットデータベースのほとんどのデータベース機能を表現できます。ただし、Prisma Schema Languageでまだ表現する必要がある機能と機能があります。
これらの機能について、Prisma CLIはデータベースでの機能の使用状況を検出し、警告を返します。Prisma CLIは、機能が使用されているモデルとフィールドにコメントも追加します。警告には、回避策の提案も含まれます。
prisma db pull
コマンドは、次のサポートされていない機能を表面化します。
サポートする予定の機能のリストは、GitHub(topic:database-functionality
のラベル付き)で確認できます。
サポートされていない機能に関するイントロスペクション警告の回避策
リレーショナルデータベースを使用しており、前のセクションにリストされている上記の機能のいずれかを使用している場合
- ドラフト移行を作成する
npx prisma migrate dev --create-only
- 警告で表面化された機能を追加するSQLを追加します。
- ドラフト移行をデータベースに適用する
npx prisma migrate dev