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

イントロスペクション

Prisma CLIを使用してデータベースをイントロスペクションし、データモデルPrismaスキーマに生成できます。データモデルは、Prisma Clientを生成するために必要です。

イントロスペクションは、既存のプロジェクトにPrisma ORMを追加する際に、データモデルの初期バージョンを生成するためによく使用されます。

ただし、アプリケーションで繰り返し使用することもできます。これは、Prisma Migrateを使用せずに、プレーンSQLまたは別の移行ツールを使用してスキーマ移行を実行する場合に最も一般的です。その場合、データベースを再度イントロスペクションし、続いてPrisma Clientを再生成して、Prisma Client APIのスキーマ変更を反映させる必要もあります。

イントロスペクションは何をしますか?

イントロスペクションには、1つの主な機能があります。それは、現在のデータベーススキーマを反映するデータモデルをPrismaスキーマに入力することです。

Introspect your database with Prisma

SQLデータベースでの主な機能の概要を以下に示します。

  • データベース内のテーブルPrismaモデルにマッピングする
  • データベース内のカラムをPrismaモデルのフィールドにマッピングする
  • データベース内のインデックスをPrismaスキーマのインデックスにマッピングする
  • データベースの制約をPrismaスキーマの属性または型修飾子にマッピングする

MongoDBでは、主な機能は次のとおりです。

  • データベース内のコレクションPrismaモデルにマッピングする。MongoDBのコレクションには事前定義された構造がないため、Prisma ORMはコレクション内のドキュメントサンプリングし、それに応じてモデル構造を導き出します(つまり、ドキュメントのフィールドをPrismaモデルのフィールドにマッピングします)。埋め込み型がコレクション内で検出された場合、これらはPrismaスキーマの複合型にマッピングされます。
  • コレクションにインデックスに含まれるフィールドを含むドキュメントが少なくとも1つ含まれている場合、データベース内のインデックスをPrismaスキーマのインデックスにマッピングする

Prisma ORMがデータベースからPrismaスキーマで利用可能な型に型をマッピングする方法の詳細については、データソースコネクタのそれぞれのドキュメントページを参照してください。

prisma db pullコマンド

Prisma CLIprisma db pullコマンドを使用してデータベースをイントロスペクションできます。このコマンドを使用するには、Prismaスキーマのdatasource接続URLを設定する必要があることに注意してください。

prisma db pullが内部的に実行するステップの概要を以下に示します。

  1. Prismaスキーマのdatasource構成から接続URLを読み取る
  2. データベースへの接続を開く
  3. データベーススキーマをイントロスペクションする(つまり、テーブル、カラム、その他の構造を読み取る...)
  4. データベーススキーマをPrismaスキーマデータモデルに変換する
  5. データモデルをPrismaスキーマに書き込むか、既存のスキーマを更新する

イントロスペクションワークフロー

Prisma Migrateを使用せず、代わりにプレーンSQLまたは別の移行ツールを使用するプロジェクトの典型的なワークフローは次のとおりです。

  1. データベーススキーマを変更する(例:プレーンSQLを使用)
  2. prisma db pullを実行してPrismaスキーマを更新する
  3. prisma generateを実行してPrisma Clientを更新する
  4. 更新されたPrisma Clientをアプリケーションで使用する

アプリケーションを進化させるにつれて、このプロセスを無期限に繰り返すことができることに注意してください。

Introspect workflow

ルールと慣例

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
表示CLI結果
$ 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スキーマでモデルとしてレンダリングされます(したがって、明示的な多対多のリレーションになります)。

このトピックは、リレーションに関するドキュメントページで広範囲にカバーされています。

リレーションの曖昧さ回避

Prisma ORMは、通常、@relation属性でname引数が不要な場合は省略します。前のセクションのUserPostの例を考えてみましょう。@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のラベル付き)で確認できます。

サポートされていない機能に関するイントロスペクション警告の回避策

リレーショナルデータベースを使用しており、前のセクションにリストされている上記の機能のいずれかを使用している場合

  1. ドラフト移行を作成する
    npx prisma migrate dev --create-only
  2. 警告で表面化された機能を追加するSQLを追加します。
  3. ドラフト移行をデータベースに適用する
    npx prisma migrate dev