9wandinavian
logo-prisma.png

【セットアップ編】NestJSとPrisma

Prismaの公式チュートリアルに沿って、Prismaのセットアップを行う。
そのほかに参考にした記事→Zenn - Prismaを使った効率的なバックエンド開発ワークフロー

前提条件

  • Node.js がインストールされている
  • Docker または PostgreSQL がインストールされている
  • プロジェクトを作成済みである(nest new <プロジェクト名>を実行済みである)

最初のディレクトリ構成

プロジェクト名
  ├── node_modules
  ├── src
  │   ├── app.controller.spec.ts
  │   ├── app.controller.ts
  │   ├── app.module.ts
  │   ├── app.service.ts
  │   └── main.ts
  ├── test
  │   ├── app.e2e-spec.ts
  │   └── jest-e2e.json
  ├── README.md
  ├── nest-cli.json
  ├── (使用しているパッケージマネージャのlockファイル)
  ├── package.json
  ├── tsconfig.build.json
  └── tsconfig.json

PostgreSQLのインスタンスを作成する

プロジェクト直下にdocker-compose.ymlを作成する。

# docker-compose.yml
version: '3.8'
services:

  postgres:
    image: postgres:13.5
    restart: always
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_DB=mydb
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - '5432:5432'

volumes:
  postgres:

続いて、

$ docker-compose up -d

を実行し、バックグラウンドでコンテナを起動。

Prismaのセットアップ

次のコマンドでPrismaをインストール。

$ yarn add -D prisma

Prismaの初期化

$ npx prisma init

を実行する。初期化完了後、プロジェクト直下にprismaディレクトリとその中にschema.prismaファイルが作成され、同時に.envも作成される。

プロジェクト名
  ├── node_modules
  ├── prisma
  │   ├──schema.prisma    ←ここ
  ├── src
  │   ├── app.controller.spec.ts
  │   ├── app.controller.ts
  │   ├── app.module.ts
  │   ├── app.service.ts
  │   └── main.ts
  ├── test
  │   ├── app.e2e-spec.ts
  │   └── jest-e2e.json
  ├── .env                ←ここ
  ├── README.md
  ├── nest-cli.json
  ├── (使用しているパッケージマネージャのlockファイル)
  ├── package.json
  ├── tsconfig.build.json
  └── tsconfig.json

Prismaスキーマの定義

Prismaの初期化によって作成されたschema.prismaは、スキーマとPrismaクライアントの連携やDB接続設定、モデル定義を記述するためのファイル。初期状態ではデフォルトスキーマとしてgeneratordatasourceの2つが作成される。

// prisma/schema.prisma

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

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generatorとdatasourceの概要は次の通り。

generator: Prisma Client を生成することを示す。Prisma Clientはデータベースにクエリを送信するために使用される。
datasource: データベース接続の設定パート。上記の構成は、DBとしてPostgreSQL、データベース接続URLとしてDATABASE_URLという環境変数を使用することを示す。

環境変数の設定

.envファイルにDATABASE_URLを設定する。最初にdockerで作成したPostgreSQLのインスタンスを設定する。

DATABASE_URL="postgres://myuser:mypassword@localhost:5432/mydb?schema=public"

データモデルの定義

schema.prismaに、UserモデルとArticleモデルを追加する。ここで定義するモデルはDBのテーブルと対応する。

// prisma/schema.prisma

略

model User {
  id Int @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  email String @unique
  hashedPassword String
  articles Article[]
}

model Article {
  id Int @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  title String
  description String?
  userId Int
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}

デコレータについて
@id:モデルの主キーとして設定する。
@default(autoincrement()):idを自動採番させるよう設定する。
@unique:ユニーク制約を指定する。
@relation:リレーションシップを定義する。

リレーションシップの定義

上記のUserモデルとArticleモデルのリレーションは、

  • UserモデルのarticleフィールドはArticleモデルの配列を持っている。
  • ArticleモデルのuserフィールドはUserモデルを参照している。
  • @Relation()デコレータにより、ArticleモデルのuserIdフィールドとUserモデルのidフィールドを紐づけている。また、onDelete: Cascadeによって、Userが削除された場合はそのUserに紐づくArticleも削除されるように指定している。

DBマイグレーション

Prismaのスキーマ定義が完了したら、次のコマンドでテーブル作成を実行する。なお、--nameオプションをつけずに実行した場合は、Enter a name for the new migration?と聞かれて名前を入力するプロンプトが表示される。

$ npx prisma migrate dev --name "v1"

このコマンドは次の3つの事を行う。

  1. マイグレーションの保存:
    スキーマのスナップショットを作成し、マイグレーションの実行に必要なSQLコマンドを組み立てる。マイグレーションの初回実行時は、新たにPrisma/migrationsフォルダを作成し、そのフォルダ中にスナップショットのフォルダとSQLファイルを保存する。
プロジェクト名
  ├── node_modules
  ├── prisma
  │   ├──migrations/
  │   │  └──202304080823816_v1/
  │   │         └──migration.sql
  │   └──schema.prisma
 略
  1. マイグレーションを実行:
    マイグレーションファイルのSQLを実行してテーブルを作成する。
  2. Prisma クライアントの生成:
    最新のスキーマに基づいてPrismaクライアントを生成する。時点でPrismaクライアントライブラリがインストールされていない場合は、自動でインストールする。→ package.jsonファイルの"dependencies"@prisma/client パッケージが追加される。
  "dependencies": {
    "@prisma/client": "4.12.0",
  },

以下が、マイグレーションによって作成されたSQLファイル

-- prisma/migrations/202304080823816_v1/migration.sql

-- CreateTable
CREATE TABLE "User" (
    "id" SERIAL NOT NULL,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMP(3) NOT NULL,
    "email" TEXT NOT NULL,
    "hashedPassword" TEXT NOT NULL,

    CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Article" (
    "id" SERIAL NOT NULL,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMP(3) NOT NULL,
    "title" TEXT NOT NULL,
    "description" TEXT,
    "userId" INTEGER NOT NULL,

    CONSTRAINT "Article_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

-- AddForeignKey
ALTER TABLE "Article" ADD CONSTRAINT "Article_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

(マイグレーションの実行毎にスナップショットのフォルダが作成されるが、そのフォルダ名はprisma/migrations/[タイムスタンプ]_[コマンドで指定した名前]/migration.sqlとなる)

データの確認

$ npx prisma studio

を実行すると、ブラウザが自動でhttp://localhost:5555/へアクセスし、schema.prismaファイルで定義したモデル構造に基づいたテーブルが作成されていることが確認できる。

おまけ

$npx prisma generate

を実行すると、スキーマのモデル構造を解析してTypeScriptで使用できるUserArticleのデータ型を自動生成してくれる。

以上でセットアップは完了。