NestJSに最適のORMを考えてみる(Prisma VS TypeORM)
2023/09/03 / 2023/09/04
TypeORMの不具合に絶望したあなたのための記事です。
NestJSにおける最適なORMを考えます。
自分の経験とNestJSのDiscordのスレッド「TypeORM or Prisma ?」の内容をもとに書きます。
結論から書くと私個人の意見としてはPrismaとKeyselyの併用が良いと思いました。
目次
[非表示]
ORMとクエリビルダを羅列してみる
ORM
- TypeORM
- Prisma
- Sequelize
クエリビルダ
- Kysely
- MikroORM
- DrizzleORM
TypeORM vs Prisma(vs Sequelize)
| ORM | よいところ | 微妙なところ |
|---|---|---|
| TypeORM | ・データベースのホットスワップ(例:MySQLからPostgressにスワップするなど)に対応 ・複雑なクエリも作れる | ・安定性が低い |
| Prisma | ・複雑なクエリを作ることができない ・設定ファイル(schema.prisma)が強力 | ・安定性が低い ・ホットスワップ不可 ・複雑なクエリを投げると重い |
私が以前働いていた会社のグループ会社でSequelizeを利用しているチームがあり、運用に耐えられるだけの安定性はあると聞きました。
しかし、書きっぷりは古く、あまり近年は使われていない印象です。
TypeORMを使った感想
トランザクション周りの安定性が貧弱で、ロールバックしたはずなのにデータベースに反映されていたことが過去によくありました🤮
個人的に、コードは読みやすく書きやすく、Prismaより複雑なクエリでも簡単に書けるので、安定性を除けば良いライブラリだと思います。
インターネット上に情報も多いです。
NestJSの公式Discordでは多対多の実装をする時のカーディナリティの設定がダルいという意見がありましたが、その場合は中間テーブルを使って多対多を解消しましょう。
Prismaを使った感想
設定ファイルPrisma.schemaが便利でした。
マイグレーション周りも安定しているし、操作性も気に入ったので、スキーマ管理にはPrismaがおすすめです。
クエリに関してはかなり微妙で、クエリ実行すると初回だけ必ずエラーになったりします。私はこれも絶望してPrismaでクエリを投げるのを諦めました。
また、サブクエリやJOINを書くのも一苦労でした。
ORM vs クエリビルダー vs 生SQL
前見出しで記載した通り、スキーマ管理はPrismaで良いのですが、NodeのORMライブラリはクエリが全然ダメです。
ということでクエリビルダーを使いましょう。
私は、Keyselyしか試していませんが、気に入ったので、これを使います。
複雑なクエリは組めませんが、その場合は、生SQLを書きます。
不安定なORMを使うくらいなら生SQLがよいとおもいます。
KeyselyとPrismaの連携について
この辺りの記事を読むと、Prismaの設定ファイル(prisma.schema)から型ファイル(type.ts)を出力する方法などが書かれています。
PrismaとKyselyの相性もバッチリです👌
Generating types | Kysely
Generating types | Kysely
To work with Kysely, you’re required to provide a database schema type definition to the Kysely constructor.
To work with Kysely, you’re required to provide a database schema type definition to the Kysely constructor.
NestJSにおけるKeyselyのデータベース接続について
NestJSでKeyselyを使ってデータベースを検索する方法などはググっても出てこないかもしれませんが、公式サイトの動的モジュールのところを読めば多分解決できると思います。
Documentation | NestJS – A progressive…
Documentation | NestJS – A progressive…
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, i…
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, i…
本記事の趣旨とズレるため、細かくは解説しませんが以下のようにdatabase.module.tsを作成し、app.module.tsで読み込めばデータベースの接続はできるでしょう。
import { Module, DynamicModule, Global } from '@nestjs/common'
import { db } from 'src/database'
@Global()
@Module({})
export class DatabaseModule {
static forRoot(): DynamicModule {
const providers = [
{
provide: 'KEYSELY_DB',
useValue: db,
},
]
return {
module: DatabaseModule,
providers: providers,
exports: providers,
}
}
}
app.module.tsはこんな感じでしょう。
@Module({
imports: [DatabaseModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
serviceファイルで以下のように注入して利用します。
import { Inject, Injectable } from '@nestjs/common'
import { InsertObject, InsertResult, Kysely } from 'kysely'
import { DB } from 'src/types'
@Injectable()
export class ExchangesRepository {
constructor(@Inject('KEYSELY_DB') private db: Kysely<DB>) {}
async create(hoge: InsertObject<DB, 'hoge'>): Promise<InsertResult> {
try {
return await this.db.insertInto('hoge').values(hoge).executeTakeFirst()
} catch (error) {
throw new Error('Failed to create hoge.')
}
}
}
まとめ
私はPrismaとKeyselyの併用をすることにしました。
スキーマやマイグレーションファイルはPrismaで管理し、クエリの発行はKeyselyで行うイメージです。
複雑なSQLが必要な場合は、迷わず生SQLを書きますが、DBのコネクションはKeyselyを使います。
TypeScriptのORMはまだ安定していて、高機能なものはないようなので、生SQLが最も安定している気がします。
参考
公式Discord:
https://discord.com/invite/nestjs
TypeORM or Prisma ?(Discordのスレッド):
https://discord.com/channels/520622812742811698/1096846405257138226