📖

Prisma 基礎

4 min read 1

Prismaのドキュメントを読んでみたので、基本的なことをまとめていきます。

Primsaとは

  • オープンソースのORM(Object-relational mapping)
  • Node上のアプリケーションで直接DBに接続し、クエリー発行が可能
  • RDB周りの処理をより簡単に行えるようにし、開発者の生産性を向上させることを目的に開発
  • Next.jsアプリケーションでDBを扱う際に特に有用
  • Schemaファイルから型情報が生成され、クエリ結果がタイプセーフになる

対応状況

言語

  • JavaScript
  • TypeScript
  • Go (開発途中)

データベース

  • PostgreSQL
  • MySQL
  • SQLite
  • SQL Server (開発途中)

主な構成要素

Prisma Model

アプリケーションで使用するモデルを表現する。
モデル内でテーブルやカラムの定義を行う。
また、Prisma Clientでクエリーを発行するために必要となる。

Prisma schema

メインとなる設定ファイル。
下記の要素を定義し、データベースクライアントやマイグレーションファイルの生成を行う。

  • データソース: データベースへの接続情報
  • ジェネレータ: データモデルを元に生成するデータベースクライアントを指定
  • Prisma Model

Prisma Client

データベースクライアント。
Prisma Modelでの型情報を使用して、クエリーの結果は型安全になる。

Prisma Migrate

Prisma Schemaの情報をベースにマイグレーション周りの処理が可能になる。

Prisma Studio

データベース上のデータを閲覧・編集するGUI。

実際の使用手順

1. Prisma schemaファイルの作成

Prismaを使用する際は必ず作成しなければならない。
独自のデータモデリング言語を使用している。

// データベースの接続情報
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// generateコマンドで生成するものを指定
generator client {
  provider = "prisma-client-js"
}

// アプリケーションで使用するモデル
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields:  [authorId], references: [id])
  authorId  Int?
  @@unique([authorId, title])
  @@index(fields: [title, content], name: "main_index")
}
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
  role    Role     @default(USER)
}

enum Role {
  USER
  ADMIN
}

2. Prisma Clientの生成

@prisma/clientをインストール。

npm install @prisma/client

生成コマンドを叩くことで、Prisma schemaを読み、Prisma Clientコードを自動で作成できる。

prisma generate

モデルなどを変更した際は、生成コマンドを再度叩くことで、Prisma Clientコードを更新できる。

生成されたコードはnode_modules/@prisma/clientに置かれ、使用する際はここからインポートする。

3. クエリーの発行

@prisma/clientからインポートして、Prisma Clientインスタンスを作成し、クエリーを発行する。

import { PrismaClient } from '@prisma/client'

// Fetch all posts (in /pages/index.tsx)
export async function getStaticProps() {
  const prisma = new PrismaClient()
  const posts = await prisma.post.findMany()
  return {
    props : { posts }
  }
}

// Display list of posts (in /pages/index.tsx)
export default ({posts}) =>
  <ul> 
   {posts.map(post => (
     <li key={post.id}>{post.title}</li>
    ))}
  </ul>
);

クエリーの例

  • 全ユーザーの取得
const allUsers = await prisma.user.findMany()
  • 紐づけられた投稿と一緒に、全ユーザー取得
const allUsers = await prisma.user.findMany({
  include: { posts: true },
})
  • 「prisma」を含む全投稿を取得
const filteredPosts = await prisma.post.findMany({
  where: {
    OR: [
      { title: { contains: "prisma" } },
      { content: { contains: "prisma" } },
    ],
  },
})
  • ユーザーと投稿を一緒に作成する
const user = await prisma.user.create({
  data: {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: { title: "Join us for Prisma Day 2020" },
    },
  },
})
  • 条件に合った投稿の更新
const post = await prisma.post.update({
  where: { id: 42 },
  data: { published: true },
})

マイグレーション

マイグレーションの実行

このコマンドを実行することで、下記のようなマイグレーションファイルが生成されると同時に実行される。
先述の通り、SchemaファイルのPrisma Modelより生成される。

prisma migrate dev --preview-feature
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL,
    "name" TEXT NOT NULL,
    PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Post" (
"id" SERIAL,
    "title" TEXT NOT NULL,
    "published" BOOLEAN NOT NULL DEFAULT true,
    "authorId" INTEGER NOT NULL,
    PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Post" ADD FOREIGN KEY("authorId")REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

テーブル構造の変更

テーブル構造を変更する際にも、SchemaファイルのPrisma Modelを更新し、同様のマイグレーションコマンドを実行することで、新たなマイグレーションファイルが生成され、実行される。