2. Prisma Clientを使ってみる Prisma 入門ワークショップ(2021)
ゴール
このレッスンの目的は、Prisma Client APIを使いこなし、それを使って送信できるデータベース・クエリのいくつかを探ることです。CRUDクエリ、ネストされた書き込みのようなリレーションクエリ、フィルタリング、ページネーションについて学びます。途中、別のマイグレーションを実行して、前に作成した User
モデルに relation した2つ目のモデルを導入してみましょう。
レッスン
0. Prisma 入門ワークショップ(2021)
1. Prismaのセットアップ
2. Prisma Clientを使ってみる←ここ
3. Prisma Clientを使ってREST APIの作成
4. Prisma Clientを使ってGraphQL APIの作成
リソース
Prismaとは?
Node.js & TypeScript向けの完璧なORM
英語のドキュメント
https://www.notion.so/A-Practical-Introduction-to-Prisma-2021-ccf00a066ef4432caeb03da179e38302
Zoom ウェビナー
GitHub。
https://github.com/nikolasburk/prisma-workshop
Setup
lesson1でセットアップしたのと同じ prisma-workshop
プロジェクトで作業を続けることができます。script.ts
ファイルには、スクリプトが実行されるたびに呼び出される main
関数が含まれています。以下のようなことができます。
Hints
自分で入力する、コピー&ペーストはしない
各タスクで自分が何をしているのかを理解するためには、解答をコピー&ペーストするのではなく、自分で解答を入力するようにしてください(たとえ調べなければならない場合でも)。
自動補完
Prisma Clientは、APIを使用してデータベースに送信できる多くのクエリを提供します。これらのクエリについては、documentationで学ぶことができます。また、autocompletionを使用して、エディタで直接APIを調べることもできます。
オートコンプリートを呼び出すには、src/index.ts
を開き、main
関数の内側*に次のように入力します(現在あるコメント // ... your Prisma Client queries will go here
は削除しても構いません)。
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const result = await prisma. // autocompletion will show up if you type this
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.disconnect())
const result = await prisma.
という行をエディタに入力すると、小さなポップアップが表示され、クエリを構成するためのオプションを選択することができます(例えば、クエリを実行したいモデルを選択したり、queryRawやconnectなどの他のトップレベルの関数を使用したりします)。オートコンプリートは、提供したい引数を含む、クエリ全体に対して利用可能です。
自動補完のスクリーンショットを見るにはこちらをクリックしてください。
各タスクで自分が何をしているのかを理解するためには、解答をコピー&ペーストするのではなく、自分で解答を入力するようにしてください(たとえ調べなければならない場合でも)。
Prisma Studio
Prisma Studioは、データベースのGUIで、内部のデータを表示・編集するために使用します。以下のコマンドを実行することで、Prisma Studioを起動することができます。
npx prisma studio
Task
各タスクの最後に、以下のコマンドでスクリプトを実行することができます。
npm run dev
User
レコードを返すクエリの作成
Task1: すべての 少し体を温めるために、データベースから すべての User
レコードを返すクエリを書いてみましょう。 その結果を console.log
を使ってコンソールに出力してみましょう。
答え
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const result = await prisma.user.findMany()
console.log(result)
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect())
User
レコード を作成するクエリの作成
Task2: 新しい このタスクでは、別のUser
レコードを作成します。Prisma Clientのクエリでは、email
には値のみを指定し、name
には値を指定しないようにします。
- email:
"alice@prisma.io"
これを実現するためのクエリを見つけることができますか?
答え
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const result = await prisma.user.create({
data: {
email: "alice@prisma.io"
}
})
console.log(result)
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect())
User
レコードを更新するクエリの作成
Task3: 既存の このタスクでは、先ほど作成したUser
レコードを更新して、name
フィールドに値を追加します。
- name:
"Alice"
.
Prisma Clientで既存のデータベースレコードを更新するにはどうすればよいでしょうか?
答え
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const result = await prisma.user.update({
where: {
email: "alice@prisma.io"
},
data: {
name: "Alice"
}
})
console.log(result)
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect())
Post
テーブルを追加する
Task4: データベースに もっと面白いPrisma Clientのクエリを探求するために、Prisma Schemaを別のモデルで拡張し、既存のモデルと新しいモデルの間にrelationshipを設定してみましょう。
新しいPost
モデルは以下のような形にします。
-
id
: データベース内の各ポストを一意に識別するための、自動インクリメントの整数値 -
title
: 投稿のタイトル。このフィールドはデータベース内で必須とします。 -
content
: 投稿の内容/本文。このフィールドはデータベース内では 任意 になります。 -
published
: 投稿が公開されているかどうかを示します。このフィールドはデータベースでは 必須とします。デフォルトでは、作成された投稿はすべて公開されません。 -
author
とauthorId
: 投稿から、その投稿の著者とみなされるべきユーザーへの relation を構成します。このリレーションは optional であるべきで、投稿には必ずしもデータベース内の著者が必要ではありません。
答え
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
Prismaのスキーマを調整し、2つのモデルを配置したら、マイグレーションを実行して、データベースに対して変更を適用します。
npx prisma migrate dev --name add-post
Post
レコードを作成するクエリを書く。
Task5: 新しい このタスクでは、titleが"Hello World"
という最初のPost
レコードを作成します。
答え
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const result = await prisma.post.create({
data: {
title: "Hello World"
}
})
console.log(result)
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect())
User
レコードと Post
レコードを接続するクエリの作成
Task6: これで、データベースに複数のUser
レコードと、ちょうど1つのPost
レコードができました。これらは、データベースのauthorId
外部キーカラムを介して接続することができます。
Prisma Clientを使用する場合、外部キーを手動で設定する必要はありませんが、Prisma ClientのタイプセーフなAPIを使用してリレーションを設定することができます。どのようにすれば、Post
レコードを更新し、email
フィールドを介して既存のUser
レコードに接続することができるかわかりますか?
エディタのオートコンプリートを使用してクエリについて調べるか、ドキュメントをお読みください。
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.post.update({
where: { id: 1 },
data: {
author: {
connect: { email: "alice@prisma.io" },
},
},
});
console.log(result);
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
User
レコードを取得するクエリの作成
Task7: 一意な値を持つ単一の タスク1では、データベースからレコードのリストを取得する方法を学びました。このタスクでは、Prisma Clientのクエリを使って、単一のUser
レコードをユニークな値で取得する必要があります。
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.user.findUnique({
where: { email: "alice@prisma.io" }
})
console.log(result)
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
Task8: フィールドのサブセットのみを選択するクエリの作成
このタスクでは、タスク1で使用したユーザーに対する同じfindMany
クエリを再利用することができます。具体的には、返されるすべてのオブジェクトは、id
とname
のみを含み、email
フィールドは含まない*ということです。
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.user.findMany({
select: {
id: true,
name: true
}
})
console.log(result)
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
Task9: リレーションを結果に含めるためのネストしたクエリの作成
ここからは、Prisma Clientのリレーションクエリをもっと探ってみましょう! 具体的には、関係をincludeする入れ子の読み方から始めましょう。タスク7のクエリを使って、Post
テーブルへのリレーションを結果に含めてみましょう。
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.user.findUnique({
where: { email: "alice@prisma.io" },
include: { posts: true },
});
console.dir(result, { depth: null })}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
User
レコードと新しい Post
レコードを作成する入れ子式の書き込みクエリを作成する
Task10: 新しい このタスクでは、1つの* Prisma Client (nested write) クエリで、新しい User
レコードと新しい Post
レコードを作成します。オートコンプリート機能を使用して正しいクエリを見つけるか、ドキュメントこちらを参照してください。
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.user.create({
data: {
name: "Nikolas",
email: "burk@prisma.io",
posts: {
create: { title: "A practical introduction to Prisma" },
},
},
});
console.log(result);
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
Task11: 名前が "A "で始まるユーザーをフィルタリングするクエリを作成する
このタスクでは、タスク 1 で使用したユーザーに対する同じ findMany
クエリを再度使用できます。今回は、すべての* User
レコードを返すのではなく、name
が "A"
で始まるものだけを返したいということだけです。この条件を表現できる適切な演算子を見つけることができますか?
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.user.findMany({
where: {
name: {
startsWith: "A",
},
},
});
console.log(result);
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
Task12: ページネーションクエリの作成
Prisma Clientには、オブジェクトのリストをページングする方法がいくつかあります。前述の findMany
クエリを使用して、データベース内の 3番目 と 4番目 の User
レコードのみを返すようにします。
答え
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const result = await prisma.user.findMany({
skip: 2,
take: 2,
});
console.log(result);
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());
次のステップ
ここまでの作業では、PrismaクライアントAPIで可能なことのほんの一部をご紹介しました。もっと多くのクエリを試し、順序付け、アップサート、プレーンSQL、その他の機能を自由に試してみてください。
Discussion
Task9の答えがTask10の答えになってしまっているようです。
コメントありがとうございます!!
Task9の答えを修正致しました。🙇