🐟

TypeScriptのORMはどれが良いのか

2023/04/11に公開

TypeScriptでORMを選定するとき、候補になったのは以下の2つです。
一度はPrismを選択したけども、結果的にはTypeORMで開発し直しています。

Prisma

https://www.prisma.io/
ここ最近勢いあって割と何でもできるORM。独自に定義するスキーマーファイルで、複数DBの接続やモデルの定義ができ、マイグレーションも差分管理してくれるし、コマンドもシンプル。言うことはありませんね。

ただサーバーレス環境からの利用は、Prisma Data Proxyの利用が前提になります。サーバーレス環境だと、短期的にインスタンスが立ち上がり、都度接続を生成しては破棄するといったことを非効率に行うことになります。性能のボトルネックがDB接続にならないためにも、コネクションプールをうまく活用して、クエリを捌いていくことが求められますが、Prismaクライアントを利用するときは、Eege用のクライアントの利用が必要です。ただそのときに求められるDBのURLがprisma://スキーマーになるため、Data Proxyの利用が必須になります。

- @prisma/client
+ @prisma/client/edge
const prisma = new PrismaClient({
  datasources: {
    db: {
-      url: "postgresql://postgres:postgres@localhost:5432/my-db?schema=public",
+      url: "prisma://<リージョン>.prisma-data.com/?api_key=<APIキー>"
    }
  }
})

コネクションプール関係の課題をも解決するプロダクトですが、以下の理由で選定を辞めました。

Alternative Prisma Data Proxy

https://github.com/aiji42/prisma-data-proxy-alt

試してはいませんが、このプロジェクトを活用すると、ローカル環境や日本ロケーション含めて自由にセルフホストできるようです。

https://zenn.dev/aiji42/articles/ba7767e66fb439

公式のData Proxyよりも早い結果が出ているようです。

TypeORM

こちらも有名どころだと思いますが、こちらも割と何でもできる系のORMです。独自ファイルで定義するのではなく、モデルやマイグレーションはTypeScriptのコードで表現されます。

https://github.com/typeorm/typeorm

https://orkhan.gitbook.io/typeorm/

コネクションプールについては、同様にサーバーレス環境であれば懸念があるので、PostgreSQLであれば PgBouncer あたりを使うのがいいのではと思います。

ドキュメント他、色々情報がネット上にもあるので、Prisma同様に作っていく上で困ることはなさそうですが、ハマったところがあるので、いくつか紹介します。

typeormの実態

公式が作るプロジェクトのひな形やネット上の情報も、package.jsonscriptstypeormを作ってマイグレーションなどを行うようになっています。

"typeorm": "typeorm-ts-node-commonjs"

ただcommonjsではないESMなプロジェクトについては、typeorm-ts-node-esmがありますので、指定に注意が必要です。

https://orkhan.gitbook.io/typeorm/docs/migrations#running-and-reverting-migrations

データソースに指定するエンティティ

typeorm init --name FirstProject --database mysql を使うと、プロジェクトのひな形が生成されますが、データソースの定義は以下のようにTypeScriptで行います。
適切なデータベースのタイプ(MySQL等)や接続情報を追記する必要がありますが、ここでentitiesに渡せるのは、インポートしたエンティティかエンティティが存在するパスのどちらかになります。このようにUserをそのまま指定できる環境もあれば、エンティティのパスを指定しないと、エンティティが存在しないといった警告を受けて、マイグレーションデータが生成されないことがあります。

import "reflect-metadata"
import { DataSource } from "typeorm"
import { User } from "./entity/User"

export const AppDataSource = new DataSource({

    synchronize: true,
    logging: false,
    entities: [User],
    migrations: [],
    subscribers: [],
})

私の場合は、パスの指定で生成できました。

entities: ["./db/entity/*.ts"],

最後に

ORMは他にもあるようなので、ニーズにあった選択が出来ればと思います。

以下沢山掲載ありました。
https://scrapbox.io/uki00a/Node.jsのORMについて

Discussion