🏔️

Prismaのスキーマを複数ファイルに分割するprisma-import

2023/02/19に公開

概要

PrismaはNodejs環境で使えるORMです。Prismaについての詳しい説明は以下のリンクか解説している記事がたくさんあるのでそちらをを見てください🙏
https://www.prisma.io/docs/concepts/overview/what-is-prisma

この記事ではPrismaのスキーマの定義ファイル(schema.prisma)を分割して定義できるprisma-importを紹介します。2023年2月18日現在スキーマファイルを分割する方法は公式ではサポートされておらず、こちらのissueで議論されていますが機能が本体に追加されるとしてもまだまだ先になりそうです。
https://github.com/prisma/prisma/issues/2377

schema.prismaを分割したい

公式ではスキーマの分割がサポートされてないとはいえ、1ファイルで全てを管理するのはスキーマが増えてくるにつれて厳しくなってくると思います。そのため非公式ではありますがスキーマの分割をサポートしてくれるprisma-importというソフトウェアがあるのでこちらを使います。つくってくれた方に感謝です🙏
https://github.com/ajmnz/prisma-import

prisma-importは複数のファイルにスキーマを分割して定義し、npx prisma-importコマンドを使うことで最終的にマージしたスキーマの生成をしてくれます。コマンドを打つだけなので使い方自体はとても簡単です。

Getting started

1. VSCode拡張機能のインストール

まずシンタックスハイライトやコード補完のためにprisma-importのvscode拡張機能をインストールします。もしPrisma公式の拡張機能を入れている場合、機能が競合してしまうので公式の方は無効にしておきます。
https://marketplace.visualstudio.com/items?itemName=ajmnz.prisma-import

2. Prismaのセットアップ

通常通りPrismaプロジェクトのセットアップをします。

% mkdir hello-prisma 
% cd hello-prisma
% npm init -y
% npm install typescript ts-node @types/node --save-dev
% npx tsc --init 
% npm install prisma --save-dev
% npx prisma init --datasource-provider sqlite

https://www.prisma.io/docs/getting-started/quickstart

3. スキーマ定義

スキーマの定義は一旦以下のように分割し/models配下に配置します。

  • base.prisma: generatordatasourceを記述しておくファイル
  • user.prisma: userのスキーマ
  • post.prisma: postのスキーマ
base.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
user.prisma
import { Post, Comment } from "./post"

model User {
  id        Int       @id @default(autoincrement())
  firstName String
  lastName  String
  email     String    @unique
  password  String
  posts     Post[]
  comments  Comment[]
}
post.prisma
import { User } from "./user"

model Post {
  id          Int       @id @default(autoincrement())
  title       String
  description String
  content     String
  user        User      @relation(fields: [userId], references: [id])
  userId      Int
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
  comments    Comment[]
}

model Comment {
  id        Int      @id @default(autoincrement())
  user      User     @relation(fields: [userId], references: [id])
  userId    Int
  post      Post     @relation(fields: [postId], references: [id])
  postId    Int
  message   String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

4. npx prisma-importでマージ

npx prisma-importで分割して定義したスキーマをマージすることができます。ただその前にスキーマ生成する際に必要なschemasoutputパラメータをpackage.jsonに記述します。これを記述することでどのファイルを参照してどこにマージしたファイルを出力するかを決められます。またコマンド実行時に--schemas--outputで値を渡すことでも実行できます。

package.json
{
  "name": "prisma-multiple-schema",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  // 必要なパラメータ
  "prisma": {
    "import": {
      "schemas": "./models/*.prisma",
      "output": "./prisma/schema.prisma"
    }
  },
  ...
}

実行後のファイル

出力されるファイルは以下になります。あとはこのファイルを使ってnpx prisma migrate dev --name initでマイグレーションなどをするだけです。

schema.prisma
//
// Autogenerated by `prisma-import`
// Any modifications will be overwritten on subsequent runs.
//

//
// base.prisma
//

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

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

//
// post.prisma
//

model Post {
  id          Int       @id @default(autoincrement())
  title       String
  description String
  content     String
  user        User      @relation(fields: [userId], references: [id])
  userId      Int
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
  comments    Comment[]
}

model Comment {
  id        Int      @id @default(autoincrement())
  user      User     @relation(fields: [userId], references: [id])
  userId    Int
  post      Post     @relation(fields: [postId], references: [id])
  postId    Int
  message   String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

//
// user.prisma
//

model User {
  id        Int       @id @default(autoincrement())
  firstName String
  lastName  String
  email     String    @unique
  password  String
  posts     Post[]
  comments  Comment[]
}

おわり

1ファイルでスキーマ管理はつらみがありますが、prisma-import使えばコマンドを打つだけなので割と便利に使えるかなと思います。いつかPrisma側のほうでなんとかしてもらいたい気持ちがありますが、とりあえずこれでも凌げそうです。

Discussion