【Nestjs】 + Prisma 初期設定

NestJS Nestjs

準備

データベース

DockerにPostgresqlコンテナーを作成する

Dockerでも何でも接続できる環境さえあれば良い、ここではDockerを利用します。コンテナーやボリュームなどのみ削除することでパソコンも綺麗になるるクラウドを使った場合の後クリアなど気にしない。

version: '3.8'

services:
  postgres:
    image: postgres:15
    container_name: postgres_svr
    environment:
      POSTGRES_DB: exampledb              # PostgreSQLデータベース名
      POSTGRES_USER: exampleuser          # PostgreSQLユーザー名
      POSTGRES_PASSWORD: examplepass      # PostgreSQLユーザーパスワード
    ports:
      - "5432:5432"  # ホスト:コンテナ (PostgreSQL)
    volumes:
      - type: bind
        source: /Users/twonine/Docker/dbsvr/postgre
        target: /var/lib/postgresql/data
    restart: always

各種バージョン

nodejs: 18.20.2
nestjs: 10.0.0
prisma: 5.22.0
npm: 10.5.0
postgresql: 15

前提

プロジェクトの生成はできた状態からする。簡単に使用コマンドを列挙しておきます。

作成APIのテストはPostmanを利用する。

$ nest new app-name
// npm, typescript, jestを選択
$ cd app-name
$ nest g mo user [--no-spec]
$ nest g co user [--no-spec]
$ nest g service user [--no-spec]

初め

フォルダーとファイルの構成

$ tree -I 'node_modules|dist'         
.
├── README.md
├── nest-cli.json
├── package-lock.json
├── package.json
├── prisma
│   ├── migrations
│   │   ├── 20241116011831_init
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── 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
├── tsconfig.build.json
└── tsconfig.json

Prisma導入

パッケージインストール

$ npm install prisma --save-dev
$ npm install @prisma/client

Prisma初期化

$ npx prisma init
$ tree -I 'node_modules|dist'
.
├── prisma
│   └── schema.prisma
├── src
.
$ cat .env
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"                                                                                                                                             
$ 
Modelを複数ファイルにしたい

Prisma公式では単一ファイルの支援するとしていますがいくつかの方法があるようで一旦関連Linkを共有したいと思います。

Prisma \docs\Tips for multi-file Prisma Schema
Prisma-import

接続文字列設定

Dockerの設定を参考にして接続文字列を更新する。

DATABASE_URL="postgresql://examplduser:examplepass@localhost:5432/exampledb?schema=public"

テーブルのスキマー作成

“npx prisma init”で生成されたschema.prismaにuserテーブル用のmodelを作成、フィルードについての細かい説明は省略します。<Prisma/docs/Models>

model User {
  id    Int     @default(autoincrement()) @id
  email String  @unique 
  name  String?
  created_at DateTime @default(now())
  updated_at DateTime @default(now())
  deleted_at DateTime?
}

テーブルの生成

$ npx prisma migrate dev --name init
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "exampledb", schema "public" at "localhost:5432"

Applying migration `[yyyymmddhhmmdd]_init`

The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ [yyyymmddhhmmdd]_init/
    └─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (v5.22.0) to ./node_modules/@prisma/client in 34ms
$

migrations/[yyyymmddhhmmdd]_init/migration.sqlが生成されDDLが出来ます。

スキマーフォルダー変更

「prisma init」からできる「prisma」変更は不可

「migration」作業時に参照するschema.prismaのフォルダーはpackage.jsonで変更可能、フォルダー名をDB名や環境名などで区別することも良いかもしれません。

$ cat package.json
...
  "prisma": {
    "schema": "./my-db/schema.prisma"
  }
...
$ npx prisma migrate dev --name init
...
$ tree -I 'node_modules|dist'
├── my-db
│   ├── migrations
│   │   ├── [yyyymmddhhmmss]_init
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── schema.prisma
├── prisma
$

アプリケーションから接続

DB接続Serviceを作成

src/database $ touch prisma.service.ts
src/database $ vi prisma.service.ts
import { Injectable, OnModuleInit } from "@nestjs/common";
import { PrismaClient } from "@prisma/client";

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    try {
      await this.$connect();
    } catch(err) {
      console.error(err);
      throw new Error("Method not implemented.");
    }
  }
}

開発では良いと思いますが、productionではConnection Poolを顧慮するべきかと思います。

Prisma/docs Connection Pooling

CRUDの作成

repositoryを作成することもありますがここではuser.service.tsで作成します。<prisma/docs/CRUD>

import { Injectable } from '@nestjs/common';
import { CreateUserDto, UpdateUserDto } from './user.dto';
import { PrismaService } from 'src/database/prisma.service';
import { User, Prisma } from '@prisma/client';

@Injectable()
export class UserService {
  constructor(private readonly prismaService: PrismaService) {}
  ...
  ...
}
Create
 ...
 async create(createUserDto: CreateUserDto): Promise<User>{
    const inputData: Prisma.UserCreateInput = {
      email: createUserDto.email,
      name: createUserDto?.name || undefined
    };
    return this.prismaService.user.create({ data: inputData });
  }
...
Read
...
  async findAll() {
    const res = await this.prismaService.user.findMany();
    return res;
  }
  async findOne(id: number) {
    const where: Prisma.UserWhereUniqueInput = { id };
    const res = await this.prismaService.user.findUnique({
      where 
    });
    return res;
  }
...
Update and Delete
...
  async update(id: number, updateUserDto: UpdateUserDto) {
    const where: Prisma.UserWhereUniqueInput = { id };
    const inputData: Prisma.UserCreateInput = {
      email: updateUserDto?.email || undefined,
      name: updateUserDto?.name || undefined
    };
    const res = await this.prismaService.user.update({
      where: where,
      data: inputData,
    })
    return res;
  }
  async delete(id: number) {
    const where: Prisma.UserWhereUniqueInput = { id };
    const res = await this.prismaService.user.delete({
      where
    });
    return res;
  }
...

公式ページなど

Prisma ドキュメンテーション
Prisma CRUD
Docker compose

タイトルとURLをコピーしました