Prismaで型安全なデータベース操作をしよう

## はじめに

バックエンド構築において、色々なORM（オブジェクトリレーショナルマッピング）ツールがありますが、その中でも広く使われている（印象の）Prismaを利用して、型安全にDB操作を行うやり方を備忘的に書いていきたいと思います。

### （宣伝コーナー）
今回はPrisma、ひいてはDB、バックエンドに関する記事ですが、弊社では今回のようなバックエンドの開発や、フロントエンド、モバイルアプリ、などの開発プロジェクトが様々ございます。
* Prismaの使い方やDBの扱いなんか余裕だというあなた
* PrismaのようなFW・ライブラリを利用したモダンな開発環境で開発したいあなた
* とにかく新しい開発にチャレンジしたいあなた
 
上記に当てはまる方、是非下記フォームに回答して、弊社の開発プロジェクトに参加してください！
👉 フォームは[こちら](https://docs.google.com/forms/d/e/1FAIpQLSfY9lckFjAJ_Ddc4rdHDSIFoV4NFHw1q2HriK2aa_jvVhp8QQ/formResponse)

ご回答のほど、お待ちしております！

## Prismaとは？

Prismaは、モダンな開発者向けに設計されたオープンソースのORMツールで、データベースとのやり取りを効率化し、型安全性を提供します。Prismaを使用することで、TypeScriptやJavaScriptと統合された型安全なデータベースクエリを簡単に作成・管理することができます。

### 主な特徴

- **型安全なクエリ:** TypeScriptの型システムを活用し、コンパイル時にクエリのエラーを検出
- **自動生成されたクライアント:** Prisma Clientはスキーマに基づいて自動生成され、直感的なAPIを提供
- **マイグレーションツール:** スキーマの変更を簡単に管理し、データベースに適用
- **複数のデータベースサポート:** PostgreSQL、MySQL、SQLite、SQL Serverなど、様々なデータベースに対応

## 型安全性の重要性

型安全性は、コードの品質と信頼性を高めるために不可欠です。型安全なデータベース操作を行うことで、以下のメリットがあります。

- **コンパイル時エラーの検出:** クエリの構文や型の不一致を事前に検出
- **開発効率の向上:** 自動補完や型チェックにより、コーディングミスを減少
- **リファクタリングの容易さ:** 型情報に基づいた安全なコードの変更が可能
- **バグの削減:** 型安全性により、実行時エラーや不整合を防止

## Prismaの導入方法

Prismaをプロジェクトに導入する手順を順を追って説明します。ここでは、Node.jsとTypeScriptを使用した例を紹介します。

### 1. プロジェクトのセットアップ

まず、新しいプロジェクトディレクトリを作成し、Node.jsプロジェクトを初期化します。

```bash
mkdir prisma-project
cd prisma-project
npm init -y
```

### 2. Prismaのインストール

次に、Prismaと必要なパッケージをインストールします。

```bash
npm install prisma --save-dev
npm install @prisma/client
```

### 3. Prismaの初期化

Prismaを初期化し、基本的な設定ファイルを作成します。

```bash
npx prisma init
```

このコマンドにより、`prisma`ディレクトリと`schema.prisma`ファイルが作成されます。また、`.env`ファイルが生成され、データベース接続情報を設定します。

### 4. データベースの設定

`.env`ファイルを開き、データベースの接続URLを設定します。ここでは、SQLiteを使用した例を示します。

```
DATABASE_URL="file:./dev.db"
```

### 5. Prismaスキーマの定義

`prisma/schema.prisma`ファイルを編集し、データベースのスキーマを定義します。以下は、ユーザーとポストの関係を持つスキーマの例です。

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

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

model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt DateTime @default(now())
}
```

### 6. マイグレーションの実行

スキーマをデータベースに適用するため、マイグレーションを実行します。

```bash
npx prisma migrate dev --name init
```

このコマンドにより、データベースが作成され、スキーマが適用されます。

### 7. Prisma Clientの生成

Prisma Clientを生成し、コードからデータベース操作を行えるようにします。

```bash
npx prisma generate
```

## Prisma Clientを使用した型安全なデータベース操作

Prisma Clientを使用することで、TypeScriptの型安全性を活用したデータベース操作が可能になります。以下に、基本的なCRUD操作の例を示します。

### 1. Prisma Clientのインポートと初期化

```tsx
// src/index.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
  // データベース操作をここに記述
}

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

### 2. データの作成（Create）

```tsx
const newUser = await prisma.user.create({
  data: {
    name: '山田太郎',
    email: 'taro.yamada@example.com',
    posts: {
      create: [
        {
          title: '初めての投稿',
          content: 'これは私の初めての投稿です。',
        },
      ],
    },
  },
});
console.log('新規ユーザー:', newUser);
```

### 3. データの読み取り（Read）

```tsx
const allUsers = await prisma.user.findMany({
  include: {
    posts: true,
  },
});
console.log('全ユーザー:', allUsers);
```

### 4. データの更新（Update）

```tsx
const updatedUser = await prisma.user.update({
  where: { email: 'taro.yamada@example.com' },
  data: { name: '山田太郎（更新済み）' },
});
console.log('更新されたユーザー:', updatedUser);
```

### 5. データの削除（Delete）

```tsx
const deletedUser = await prisma.user.delete({
  where: { email: 'taro.yamada@example.com' },
});
console.log('削除されたユーザー:', deletedUser);
```

## ベストプラクティス

### 1. スキーマの設計を慎重に行う

Prismaスキーマは、データベースの構造を明確に定義します。エンティティ間の関係やフィールドの制約を慎重に設計し、将来的な拡張性を考慮しましょう。

### 2. Prisma Migrateを活用する

Prisma Migrateを使用することで、スキーマの変更を安全かつ一貫してデータベースに適用できます。マイグレーションの履歴を管理し、チーム全体で共有することが重要です。

### 3. 型安全性を最大限に活用する

Prisma Clientは、TypeScriptの型システムと連携し、型安全なデータ操作を提供します。エディタの自動補完や型チェックを活用し、バグの発生を防ぎましょう。

### 4. エラーハンドリングを徹底する

データベース操作中に発生する可能性のあるエラーに対して、適切なハンドリングを実装しましょう。例外をキャッチし、ユーザーに有用なフィードバックを提供するとともに、ログに記録することが重要です。

```tsx
try {
  const user = await prisma.user.findUnique({
    where: { email: 'nonexistent@example.com' },
  });
  if (!user) {
    throw new Error('ユーザーが見つかりませんでした。');
  }
} catch (error) {
  console.error(error);
  // ユーザーにエラーメッセージを表示
}
```

### 5. セキュリティ対策を実施する

データベースのセキュリティを確保するために、以下の対策を講じましょう。

- **環境変数の管理:** データベースの接続情報やシークレットは、環境変数として管理し、コードベースに含めないでください！
- **アクセス制御:** データベースユーザーには最小限の権限を付与し、不必要な権限を避けましょう！
- **データの暗号化:** センシティブなデータは、暗号化を忘れずにしてください！（パスワードなど当前）

### 6. Prisma Studioを活用する

Prisma Studioは、ブラウザベースのGUIツールで、データベースのデータを視覚的に管理・操作できます。開発中のデータの確認やテストに活用しましょう。

```bash
npx prisma studio
```

## 具体的な使用例

### 1. リレーションの管理

Prismaを使用すると、エンティティ間のリレーションを簡単に管理できます。以下は、ユーザーとポストの一対多の関係を定義した例です。

```tsx
// ユーザーに紐づくポストを取得
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true },
});
console.log('ユーザーとそのポスト:', userWithPosts);
```

### 2. トランザクションの利用

複数のデータベース操作を一つのトランザクションとして実行することで、一貫性のあるデータ操作が可能です。

```tsx
const [user, post] = await prisma.$transaction([
  prisma.user.create({
    data: {
      name: '佐藤花子',
      email: 'hanako.sato@example.com',
    },
  }),
  prisma.post.create({
    data: {
      title: 'トランザクションの例',
      content: 'これはトランザクション内で作成されたポストです。',
      authorId: 2,
    },
  }),
]);

console.log('トランザクション内で作成されたユーザーとポスト:', user, post);
```

### 3. フィルタリングとソート

Prismaを使用すると、複雑なフィルタリングやソートを簡単に実装できます。

```tsx
const publishedPosts = await prisma.post.findMany({
  where: { published: true },
  orderBy: { createdAt: 'desc' },
});
console.log('公開されたポスト:', publishedPosts);
```

## Prismaのツールとリソース

### 1. Prisma Studio

Prisma Studioは、データベースのデータをブラウザ上で視覚的に管理できるツールです。データの確認や編集が直感的に行えます。

```bash
npx prisma studio
```

### 2. Prisma Migrate

Prisma Migrateは、スキーマの変更をデータベースに適用するためのマイグレーションツールです。バージョン管理されたマイグレーションファイルを使用して、スキーマの変更履歴を管理します。

```bash
npx prisma migrate dev --name add-new-field
```

## まとめ

Prismaは、型安全なデータベース操作を実現するための強力なORMツールです。TypeScriptと統合されているので、開発者はコンパイル時にエラーを検出し、より信頼性の高いコードを書くことができます。以下のポイントをまとめましたので、これらを踏まえてPrismaを活用した型安全なデータベース操作を実現しましょう！

- **スキーマ設計:** データベースの構造を明確に定義し、リレーションを適切に設定
- **Prisma Clientの活用:** 型安全なクエリを生成し、直感的なデータ操作を実施
- **エラーハンドリング:** 発生する可能性のあるエラーを適切にキャッチし、処理
- **マイグレーション管理:** Prisma Migrateを使用して、スキーマの変更を安全にデータベースに適用
- **セキュリティ対策:** 環境変数の管理やアクセス制御を徹底し、データの安全性を確保
- **ツールの活用:** Prisma StudioやPrisma Migrateなどのツールを活用し、効率的な開発・管理を行う

この記事を参考に、バックエンドのDB周りの開発がより効率的になれれば幸いです！
**お問い合わせやご意見がありましたら、お気軽にご連絡ください！**

## おわりに
繰り返しになりますが、弊社では、フリーランスエンジニアの方を募集しております！

熱意を持って新しいプロジェクトに挑戦したい方、様々な大規模開発プロジェクトに興味のある方は、下記フォームにてあなたの経歴をご回答ください！

👉 フォームは[こちら](https://docs.google.com/forms/d/e/1FAIpQLSfY9lckFjAJ_Ddc4rdHDSIFoV4NFHw1q2HriK2aa_jvVhp8QQ/formResponse)

たくさんのご応募、お待ちしております！