Prisma の Seeding 機能を使ってみた

Prisma には DB への Seeding の機能が搭載されています。

この機能を用いて、Docker コンテナで動作する MySQL に初期データの投入作業を行ってみたので、備忘録としてブログに残します。

環境

  • node 20.11.1
  • prisma 5.10.2
  • @prisma/client 5.10.2
  • docker compose 2.22.0-desktop.2

MySQL コンテナ

Docker compose を用いて、MySQL コンテナを構築します。今回は MySQL 8.0 のイメージを使用します。

volumes:
  db:

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: example
    command: mysqld
    volumes:
      - type: volume
        source: db
        target: /var/lib/mysql
    ports:
      - 127.0.0.1:3306:3306
docker compose up

Prisma スキーマ

単純なスキーマを作成します。model が2つほどあれば十分でしょう。

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = "mysql://root:password@localhost:3306/example" // 本来ハードコーディングするべきではない⚠️
}

model User {
  id         Int      @id @default(autoincrement())
  name       String
  tasks      Task[]
  created_at DateTime @default(now())
  updated_at DateTime @default(now())
}

model Task {
  id         Int        @id @default(autoincrement())
  user       User       @relation(fields: [userId], references: [id])
  userId     Int
  status     TaskStatus
  createdAt DateTime   @default(now())
  updatedAt DateTime   @default(now())
}

enum TaskStatus {
  TODO
  IN_PROGRESS
  DONE
}

Prisma スキーマMySQL スキーマを同期します。

npx prisma db push

テーブルの作成を確認します。テーブル名、カラム名はスネークケースが好みですが、今回は一旦見逃しています。

% docker compose exec db sh
sh-4.4# mysql -uroot -p
(snip)
mysql> use example;
(snip)
mysql> show tables;
+-------------------+
| Tables_in_example |
+-------------------+
| Task              |
| User              |
+-------------------+
2 rows in set (0.00 sec)

Seed スクリプト

User と Task を1件ずつ作成するスクリプトを作成します。@prisma/client を使用するために、クライアントコードの生成コマンドも実行しておきます。

npx prisma generate
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient({
  log: ["query"],
});

async function main() {
  await prisma.user.create({
    data: {
      name: "Alice",
      tasks: {
        create: {
          status: "TODO",
        },
      },
    },
  });
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });

package.jsonprisma.seed のフィールドを追加します。

(snip)
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  },
(snip)

実際に試してはいませんが、Next.js のプロジェクトである場合はスクリプト実行コマンドにコンパイルオプションが必要であるようです。

ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts

Seeding 実行

コマンドを打って Seeding を実行します。

 % npx prisma db seed
Environment variables loaded from .env
Running seed command `ts-node prisma/seed.ts` ...
prisma:query BEGIN
prisma:query INSERT INTO `example`.`User` (`id`,`name`,`created_at`,`updated_at`) VALUES (?,?,?,?)
prisma:query INSERT INTO `example`.`Task` (`id`,`userId`,`status`,`created_at`,`updated_at`) VALUES (?,?,?,?,?)
prisma:query SELECT `example`.`User`.`id`, `example`.`User`.`name`, `example`.`User`.`created_at`, `example`.`User`.`updated_at` FROM `example`.`User` WHERE `example`.`User`.`id` = ? LIMIT ? OFFSET ?
prisma:query COMMIT

🌱  The seed command has been executed.

テーブルを確認します。

% docker compose exec db sh
sh-4.4# mysql -uroot -p
(snip)
mysql> use example;
(snip)
mysql> select * from User;
+----+-------+-------------------------+-------------------------+
| id | name  | created_at              | updated_at              |
+----+-------+-------------------------+-------------------------+
|  1 | Alice | 2024-03-09 13:19:02.744 | 2024-03-09 13:19:02.744 |
+----+-------+-------------------------+-------------------------+
1 row in set (0.00 sec)

mysql> select * from Task;
+----+--------+--------+-------------------------+-------------------------+
| id | userId | status | created_at              | updated_at              |
+----+--------+--------+-------------------------+-------------------------+
|  1 |      1 | TODO   | 2024-03-09 13:19:02.744 | 2024-03-09 13:19:02.744 |
+----+--------+--------+-------------------------+-------------------------+
1 row in set (0.00 sec)

まとめ

Prisma の Seeding 機能を使ってみました。

やってみて途中で気がついたのですが、npm スクリプトでも同じことできるような気がします。Prisma の機能を使うことで実現可能な便利オプションとかあるのでしょうか。

最近 Prisma に入門して SQL でテストデータ作るの面倒だなと思っていたところなので、ひとまずその課題が解消できそうなので良かったなと思います。