🎃

2. Prisma Clientを使ってみる Prisma 入門ワークショップ(2021)

2021/06/25に公開
2

ゴール

このレッスンの目的は、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 ウェビナー
https://www.youtube.com/watch?v=80CYmde9z9c

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

Task1: すべての User レコードを返すクエリの作成

少し体を温めるために、データベースから すべての 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())

Task2: 新しい User レコード を作成するクエリの作成

このタスクでは、別の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())

Task3: 既存の User レコードを更新するクエリの作成

このタスクでは、先ほど作成した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())

Task4: データベースに Post テーブルを追加する

もっと面白いPrisma Clientのクエリを探求するために、Prisma Schemaを別のモデルで拡張し、既存のモデルと新しいモデルの間にrelationshipを設定してみましょう。

新しいPostモデルは以下のような形にします。

  • id: データベース内の各ポストを一意に識別するための、自動インクリメントの整数値
  • title: 投稿のタイトル。このフィールドはデータベース内で必須とします。
  • content: 投稿の内容/本文。このフィールドはデータベース内では 任意 になります。
  • published: 投稿が公開されているかどうかを示します。このフィールドはデータベースでは 必須とします。デフォルトでは、作成された投稿はすべて公開されません。
  • authorauthorId: 投稿から、その投稿の著者とみなされるべきユーザーへの 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

Task5: 新しい Post レコードを作成するクエリを書く

このタスクでは、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())

Task6: User レコードと Post レコードを接続するクエリの作成

これで、データベースに複数の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());

Task7: 一意な値を持つ単一の User レコードを取得するクエリの作成

タスク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クエリを再利用することができます。具体的には、返されるすべてのオブジェクトは、idnameのみを含み、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());

Task10: 新しい User レコードと新しい Post レコードを作成する入れ子式の書き込みクエリを作成する

このタスクでは、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

Futa OgawaFuta Ogawa

Task9の答えがTask10の答えになってしまっているようです。

KanasugiKanasugi

コメントありがとうございます!!
Task9の答えを修正致しました。🙇