RM-BLOG

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

Prisma Getting Startedの記録+α

はじめに

話題の(?)ORM、Prismaをちょっとだけ触ってみたので記録を載せる

prisma init

Postgresqlで作る場合のコマンドは以下。--datasource-providerオプションにpostgresqlを指定する

$ npx prisma init --datasource-provider postgresql

DATABASE_URL with specific schema

?schemaパラメータつければスキーマ指定して繋がるらしいのでやってみる。localhostで5432ポートで立ち上げてるポスグレのtestスキーマを指定

DATABASE_URL="postgresql://postgres:@localhost:5432/postgres?schema=test"

Model設定

scheme.prismaの最下部に以下を追記。モデル定義は適当。ただし以下が自動的に満たせるようにしてみたかったのでその実験を含む。

  • UUIDを自動採番
  • システムカラム(作成日時と更新日時)を自動設定
model Test {
id String @id @default(uuid())
name String
created_at DateTime @default(now())
updated_at DateTime @default(now())
}

migration

以下コマンドで実行。ちょっと時間かかった。事前に prisma-client を入れてればもう少し速かった?かも。--nameパラメータはよくわからんが必須らしい。できあがるmigrationファイルのファイル名の後方にprefixとしてくっつく。タイムスタンプはこの--nameパラメータの指定とは別に自動でつく。

npx prisma migrate dev --name test-init

migration結果観察

migration実行時点でスキーマが存在しなければ、npx prisma migrateで一緒にスキーマも作ってくれるみたい。

データ操作

今回つくったTestテーブルに1件データを挿入する。以下のコードをつくって実行してみる

async function main() {
    const user = await prisma.test.create({
        data: {
        name: 'test-1',
    },
    });
    console.log(user);
}

データ入った&見れた。

deployに伴うmigrateの反映

これをstagingやproductionなどの環境に反映する、例えばHerokuのリリースフェーズなどでこのmigrateする場合にはどうすればいいのか?を考える。個々のmigrateの反映は npx prisma migrate dev でいいが、ローカルでは既にこれを実施済みのはず。つまり「プロジェクト資産内にmigrationファイルはあるがそれの適用状態がローカルとstaging/productionで異なる」という状態が生まれる。で、コマンド探すとどうやらnpx yarn prisma migrate deployというのがある。これを使えばよいらしい。例として、HerokuのProcfileでは

release: npx prisma migrate deploy
web: yarn start

とかで書けばよい。
ちなみにちょっと前の情報だが、 Prismaがmigrateするときに一時的なDatabaseを作成するので、その権限がないとmigrateの段階でエラーになる」 っていうのがある。例えばこのStackoverflowとか。しかし2023年3月時点で試した限りでは、このようなエラーは発生しなかったので、知らない間に改善された?のかもしれない。

スキーマ指定したうえでHeroku Postgresqlと一緒に使う

Prismaスキーマを指定する場合、DATABASE_URLの末尾に"?schema=hogehoge"のようにパラメータをつけて指定する。つまり"postgres://postgres:@localhost:5432/postgres?schema=hogehoge"みたいな感じだ。
一方で、Heroku PostgresqlのDATABASE_URLには?schema=hogehogeの部分が含まれていない。このため、prisma.schemaurl = env("DATABASE_URL")のように指定してしまうと、スキーマを指定することができない。固定の文字列書いてもいいが、それだといくらなんでもイケてない。Herokuが管理するDatabaseの接続文字列DATABASE_URLを基準に、特定のSCHEMAを対象に付け加えてprismaで扱えないか?
結論から言うと、以下の方法で出来る(できた)。ちょっと手間だが。

  • prisma.schemaのurlの設定もと記述をenv("DATABASE_URL_WITH_SCHEMA")にする
  • アプリのルートに/.profile.d/ディレクトリを掘って、ここにDATABASE_URL_WITH_SCHEMA環境変数を設定するshellスクリプトを用意する
  • Herokuのアプリに別途SCHEMA環境変数を設定する

これでいける。/.profile.d/配下のスクリプトのサンプルは以下のような感じ

#!/bin/sh

echo "`date -u` start configure-database-schema"
echo "DATABASE_URL=$DATABASE_URL"
export DATABASE_URL_WITH_SCHEMA=${DATABASE_URL}"?schema="${SCHEMA}
echo "DATABASE_URL_WITH_SCHEMA=$DATABASE_URL_WITH_SCHEMA"
echo "`date -u` e n d configure-database-schema"

Herokuの/.profile.d/配下のshellスクリプトは、順序的に言えばreleaseフェーズよりも先に動くので、事前にこうやって環境変数を補足してやることで(もともとそういう目的のためにshellを用意できるための仕組みだ)、スキーマを指定したうえでprismaでmigrateができる。
余談だが、最初は別々の環境変数prisma.schema上で文字列結合みたいに指示できるのかと思ったんだが(url = env("DATABASE_URL") + "?" + env("SCHEMA"))、やってみたらわかるがこれは普通にprismaの構文に反していてエラーになる。というかprisma公式docでも、スキーマ指定するなら、Herokuのこの仕組みのように、スキーマ文字列を付け加えたDATABASE_URLに相当する別の環境変数を用意して、それをprisma.schemaで指定しなさいと書いてある。(下記参考)
これに関しては非常に簡素なサンプルアプリのリポを別途用意したので、興味ある方は参考にしてください。