Prisma で始める

タイプセーフな ORM 生活

Prisma とは?

Node.js の

タイプセーフな ORM

最近話題な JavaScript の

フルスタックフレームワークでも

デフォルトとして採用されている

ORM とは?

オブジェクト関係マッピング

のことで

「リレーショナルデータベース設計」と

「オブジェクト指向設計」の差分を吸収する技法

1. オブジェクトを用意する

2. クエリを叩いてレコードを取得する

3. オブジェクトにデータをマッピングする

ORM を使わない場合

+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | Tanaka |  22 |
|  2 | Yamada |  30 |
|  3 | Sato   |  27 |
+----+--------+-----+
const users = new Users()

connection.query('SELECT * from userdata', (err, rows) => {
    for(const { id, name } of rows) {
      const user = new User(id, name)
      users.add(user)
    }
})

console.log(users.users)
/*
[
  { id: 1, name: 'Tanaka', age: 22 },
  { id: 2, name: 'Yamada', age: 30 },
  { id: 3, name: 'Sato', age: 27 }
]
*/

1. オブジェクトのメソッドを叩く

ORM を使う場合

+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | Tanaka |  22 |
|  2 | Yamada |  30 |
|  3 | Sato   |  27 |
+----+--------+-----+
const users = model.user.findAll()

console.log(users)
/*
[
  { id: 1, name: 'Tanaka', age: 22 },
  { id: 2, name: 'Yamada', age: 30 },
  { id: 3, name: 'Sato', age: 27 }
]
*/
  • 簡単に分かりやすく書ける

  • クエリの間違いが減る

  • データベースが疎結合になる

タイプセーフとは?

スキーマを元に

型が用意される

スキーマとは?

データベースにおける構造

CREATE TABLE "public"."User" (
  id SERIAL PRIMARY KEY NOT NULL,
  name VARCHAR(255),
  age INTEGER NOT NULL
);

今回の場合は

Prisma スキーマのことを指します

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

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

model User {
  id   Int      @id @default(autoincrement())
  name String?
  age  Int
}
  • イントロスペクション:
    データベースに接続して
    Prisma スキーマにデータモデルを生成
     

  • マイグレーション:
    Prisma スキーマのデータモデルから
    データベースにマッピング
    ※ まだプレビュー版

prisma.user.create({
  data: {
    name: 'Suzuki',
    gender: 'male' // 性別は存在しないプロパティなので怒られる
  }
})  
      
model User {
  id   Int      @id @default(autoincrement())
  name String?
  age  Int
}

新しくユーザを作成する場合

先程とおなじ以下のデータモデルがあるとして

  • 間違いが減る

  • サジェストが効く

簡単な実装をしてみる

$ npm init -y  # npm の初期化
$ npm i @prisma/cli @prisma/client # prisma のインストール
$ npx prisma init # prisma の初期化
$ npm i -D typescript # typescript のインストール
$ npx tsc --init # typescript の初期化
{
  "target": "ESNEXT",
  "moduleResolution": "node"
}

tsconfig.json の設定

プロジェクトの初期化

$ touch docker-compose.yml # dcoker-compose ファイルの作成
version: '3'
services:
  db:
    image: postgres:12.2-alpine
    container_name: db-container
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=mysecretpassword1234
      - POSTGRES_DB=testdb
      - DATABASE_HOST=localhost
    volumes:
      - ./docker/db/init:/docker-entrypoint-initdb.d

docker-compose.yml の設定

データベースの作成

$ docker-compose up # DB の構築&起動
DATABASE_URL="postgresql://postgres:mysecretpassword1234@localhost:5432/testdb?schema=public"

.env の設定

Prisma スキーマの作成

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

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

model User {
  id   Int      @id @default(autoincrement())
  name String?
  age  Int
}

prisma/schema.prisma の設定

$ npx prisma migrate dev --preview-feature # マイグレーション
$ npx prisma generate

Prisma スキーマから

クライアントライブラリを生成

クエリ​の作成と実行

import { PrismaClient } from "@prisma/client"

const prisma = new PrismaClient()

async function main() {
  // データベースからすべてのユーザーレコードを読み取り出力
  const allUsers = await prisma.user.findMany()
  console.log(allUsers)
}

main()
  .catch(e => {
    throw e
  })
  .finally(async () => {
    await prisma.$disconnect()
  })

index.ts の設定

$ touch index.ts
$ npx ts-node index.ts

公式ドキュメントのセットアップ例

今回の DEMO

GraphQL での DEMO

END

Prisma で始めるタイプセーフな ORM 生活

By Syuji Higa

Prisma で始めるタイプセーフな ORM 生活

  • 331