🎃
Laravel から Nuxtに移行してprismaに嵌った話
TL;DR
「Laravel Eloquent の甘い蜜に慣れていた自分が、Nuxt + Prisma の世界に飛び込み、Timezone や deletedAt で苦しんだ話。そして Eloquent 風の ORM ヘルパーを OSS として作った記録。」
はじめに
私は長年 Laravel(PHP)でアプリケーションを開発してきました。
特に Eloquent ORM のシンプルさと、直感的にチェーンできるクエリビルダーに魅了されていました。
しかし、新しい現場へ入り Nuxt と Prisma(TypeScript ORM)に移行したことで、思わぬ壁に次々と直面することになったのです。
Prisma で最初に感じた「カルチャーショック」
- Timezone の罠
Laravel では Carbon(DateTime) が自動でアプリのタイムゾーンを適用してくれるため、ユーザーの表示用の時間は常に JST(Asia/Tokyo)で扱えました。
しかし Prisma では:
DB(UTC) ↔ Prisma(UTC) ↔ フロントエンド(UTC)
アプリケーション側で意識的にタイムゾーン変換をしないとすべて UTC。
これにより、画面表示がすべて9時間ズレたタイムスタンプになってしまいました。
→ 結局 dayjs や date-fns-tz を導入し、手動で変換する羽目に。
- deletedAt(ソフトデリート)の扱い
Laravel Eloquent の場合:
User::where('active', true)->get(); // 自動的に deleted_at 除外
Prisma では除外されない。
await prisma.user.findMany({ where: { active: true } }); // 削除済みも出てくる
そのため、毎クエリに:
where: { deletedAt: null }
を明示的に書かなければならない。
→ ソフトデリートの文化が違う
- クエリビルダーの不自由さ
Eloquent のように:
User::where('active', true)->with('profile')
->orderBy('created_at', 'desc')->get();
これが Prisma では型の壁と構文の制限で毎回書き直し。
チェーンビルダーは存在しないので、ついに独自でラッパー(ヘルパー)を作り始めた。
OSS「Prisma Relation Helper Generator」を開発
Prisma の制約を乗り越えるため、以下のような Laravel Eloquent 風のクエリビルダーを自動生成する OSS を作成。
注記:下記は未実装ですが、次回バージョンにて展開予定
const user = await UserHelper
.where({ name: "Taro" })
.with('profile')
.orderBy('id', 'desc')
.first();
自動生成なので、Prisma スキーマを書き換えればヘルパーも再生成可能。
GitHub
目標
- Prisma に Eloquent チェーンの書き心地を導入
- Nuxt + Prisma でも Laravel ライクな開発体験を実現
結論
- Prisma は型安全・速度・フロントエンド親和性は素晴らしいが 学習コストと文化の違いが大きい。
- Laravel の甘やかしに慣れていると最初は絶望する。
- しかし自分でラッパーを書く自由度があるのも Prisma の魅力。
- 今後も Laravel の良いところを Prisma 世界に持ち込んでいきたい。
Discussion