TypeScriptプロジェクトにおけるPostgreSQLのイントロスペクション
Prisma ORMでデータベースをイントロスペクトする
このガイドでは、3つのテーブルを持つデモSQLスキーマを使用します。
CREATE TABLE "public"."User" (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255),
email VARCHAR(255) UNIQUE NOT NULL
);
CREATE TABLE "public"."Post" (
id SERIAL PRIMARY KEY NOT NULL,
title VARCHAR(255) NOT NULL,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
content TEXT,
published BOOLEAN NOT NULL DEFAULT false,
"authorId" INTEGER NOT NULL,
FOREIGN KEY ("authorId") REFERENCES "public"."User"(id)
);
CREATE TABLE "public"."Profile" (
id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
"userId" INTEGER UNIQUE NOT NULL,
FOREIGN KEY ("userId") REFERENCES "public"."User"(id)
);
注: PostgreSQLで適切な大文字/小文字が使用されるように、いくつかのフィールドは二重引用符で囲まれています。二重引用符を使用しない場合、PostgreSQLはすべてを小文字として読み取ります。
テーブルのグラフィカルな概要を展開
User
列名 | 型 | 主キー | 外部キー | 必須 | デフォルト |
---|---|---|---|---|---|
id | SERIAL | ✔️ | いいえ | ✔️ | 自動インクリメント |
name | VARCHAR(255) | いいえ | いいえ | いいえ | - |
email | VARCHAR(255) | いいえ | いいえ | ✔️ | - |
Post
列名 | 型 | 主キー | 外部キー | 必須 | デフォルト |
---|---|---|---|---|---|
id | SERIAL | ✔️ | いいえ | ✔️ | 自動インクリメント |
createdAt | TIMESTAMP | いいえ | いいえ | ✔️ | now() |
title | VARCHAR(255) | いいえ | いいえ | ✔️ | - |
content | TEXT | いいえ | いいえ | いいえ | - |
published | BOOLEAN | いいえ | いいえ | ✔️ | false |
authorId | INTEGER | いいえ | ✔️ | ✔️ | - |
Profile
列名 | 型 | 主キー | 外部キー | 必須 | デフォルト |
---|---|---|---|---|---|
id | SERIAL | ✔️ | いいえ | ✔️ | 自動インクリメント |
bio | TEXT | いいえ | いいえ | いいえ | - |
userId | INTEGER | いいえ | ✔️ | ✔️ | - |
次のステップとして、データベースをイントロスペクトします。イントロスペクションの結果は、Prismaスキーマ内のデータモデルになります。
データベースをイントロスペクトするには、以下のコマンドを実行します。
npx prisma db pull
このコマンドは、.env
で定義されているDATABASE_URL
環境変数を読み取り、データベースに接続します。接続が確立されると、データベースをイントロスペクトします(つまり、データベーススキーマを読み取ります)。その後、データベーススキーマをSQLからPrismaスキーマのデータモデルに変換します。
イントロスペクションが完了すると、Prismaスキーマが更新されます
データモデルは現在、次のようになっています(モデルのフィールドは読みやすさのために並べ替えられています)。
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
createdAt DateTime @default(now()) @db.Timestamp(6)
content String?
published Boolean @default(false)
authorId Int
User User @relation(fields: [authorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
}
model Profile {
id Int @id @default(autoincrement())
bio String?
userId Int @unique
User User @relation(fields: [userId], references: [id], onDelete: NoAction, onUpdate: NoAction)
}
model User {
id Int @id @default(autoincrement())
name String? @db.VarChar(255)
email String @unique @db.VarChar(255)
Post Post[]
Profile Profile?
}
Prisma ORMのデータモデルは、データベーススキーマの宣言的な表現であり、生成されるPrisma Clientライブラリの基盤となります。Prisma Clientインスタンスは、これらのモデルに合わせて調整されたクエリを公開します。
現在、データモデルにはいくつかの小さな「問題」があります。
User
のリレーションフィールドが大文字になっており、Prismaの命名規則に準拠していません。より「セマンティクス」を表現するために、このフィールドをauthor
と呼んで、User
とPost
の関係をよりよく記述することも良いでしょう。User
上のPost
とProfile
リレーションフィールド、およびProfile
上のUser
リレーションフィールドはすべて大文字になっています。Prismaの命名規則に準拠するため、両方のフィールドを小文字のpost
、profile
、user
にする必要があります。- 小文字化された後も、
User
のpost
フィールドはわずかに名前が間違っています。これは、実際には投稿のリストを指しているため、より良い名前は複数形のposts
です。
これらの変更は、生成されたPrisma Client APIにおいて重要です。小文字のリレーションフィールドauthor
、posts
、profile
、user
を使用すると、JavaScript/TypeScript開発者にとってより自然で慣用的に感じられるでしょう。そのため、Prisma Client APIを構成できます。
リレーションフィールドは仮想的(つまり、データベースに直接現れない)であるため、データベースに触れることなくPrismaスキーマで手動で名前を変更できます。
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
createdAt DateTime @default(now()) @db.Timestamp(6)
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
}
model Profile {
id Int @id @default(autoincrement())
bio String?
userId Int @unique
user User @relation(fields: [userId], references: [id], onDelete: NoAction, onUpdate: NoAction)
}
model User {
id Int @id @default(autoincrement())
name String? @db.VarChar(255)
email String @unique @db.VarChar(255)
posts Post[]
profile Profile?
}
この例では、データベーススキーマはPrisma ORMモデルの命名規則に従っていました(イントロスペクションから生成された仮想リレーションフィールドのみがそれらに準拠しておらず、調整が必要でした)。これにより、生成されたPrisma Client APIのエルゴノミクスが最適化されます。
カスタムモデルとフィールド名の使用
しかし、Prisma Client APIで公開されるカラム名やテーブル名にさらに変更を加えたい場合があります。一般的な例は、データベーススキーマでよく使用されるsnake_case表記を、JavaScript/TypeScript開発者にとってより自然に感じられるPascalCaseやcamelCase表記に変換することです。
snake_case表記に基づいた以下のモデルをイントロスペクションから取得したとします。
model my_user {
user_id Int @id @default(autoincrement())
first_name String?
last_name String @unique
}
このモデルのPrisma Client APIを生成した場合、APIではsnake_case表記が採用されます。
const user = await prisma.my_user.create({
data: {
first_name: 'Alice',
last_name: 'Smith',
},
})
Prisma Client APIでデータベースのテーブル名やカラム名を使用したくない場合は、@map
と@@map
で設定できます。
model MyUser {
userId Int @id @default(autoincrement()) @map("user_id")
firstName String? @map("first_name")
lastName String @unique @map("last_name")
@@map("my_user")
}
このアプローチでは、モデルとそのフィールドを好きなように命名し、@map
(フィールド名用)と@@map
(モデル名用)を使用して、基になるテーブルとカラムを指すことができます。Prisma Client APIは次のようになります。
const user = await prisma.myUser.create({
data: {
firstName: 'Alice',
lastName: 'Smith',
},
})
これについては、Prisma Client APIの構成ページで詳しく学ぶことができます。