💭
PrismaのモデルからDB上のテーブル名を取り出す方法
後述の アプローチ2 が良かろう。
シチュエーション
型がしっかりしているPrismaといえど、すべてをPrismaモデルだけで扱えない仕事もあるでしょう。
- テーブルを扱うなんかメタなスクリプトだとか。
- 動的なテーブルを扱う複雑なSQL(DML,DDL)をtypescriptコードから呼び出す時とか。
そんなときに prisma.xxx または 型安全な Prisma のモデル文字列 からRDB上のtable名文字列を得たいことがあるでしょう。
アプローチ1: 文字列をゴニョゴニョする系
model/tableの命名規則として、こうやっているプロジェクトが多いのではなかろうか
-
model名: UpperCamelなSingular.
例:
model UserEvent { .... }
-
prisma client オブジェクトに生えているプロパティ名は lowerCamelSingular
例:
prisma.userEvent.findMany(...)
-
RDBのtable名は snake_case な plural
例:
create table user_events
How to do
↑上記のパターンの場合はこうかける
import { Prisma } from "@prisma/client";
import pluralize from "pluralize"
import { snakeCase } from "lodash";
function toTableName(prismaModelName: Prisma.ModelName) {
return pluralize(snakeCase(prismaModelName));
}
// How to use
toTableName(prisma.userEvent) // -> "user_events"
問題
- plural化のところで不可算名詞やperson → people などの不規則変化に関するトラブルがあるかも
- DBのテーブル名 と Prisma Schema のモデル名 が機械的な文字列操作で変換できないケースではこの方式は採用できない
- 例1: model "Post" ↔ table "articles"
- 例2: アプリケーション内の各model/tableごとに名称パターンがカオスな例
model "User" は table "users"
(UpperCamelSingular → snake_case_plural)
なのに
model "UserEvents" は table "user_event"
(UpperCamelPlural → snake_cse_singular)
アプローチ2. 実際のDBをとりだす方法
- これならDBのテーブル名 が Prisma Schema のモデル名と機械的な文字列操作では取り出せないケースでも確実にいける
prisma extension で取り出すコードの例があった。
vitestを使っていると、vPrismaの初期化の都合で$extends(prismaExtension) する方法がみつからなかった。
そこで prisma extension ではない形にしてみた
import { Prisma } from "@prisma/client";
import { prisma } from "<your project's instantiated prisma client>";
type PrismaModel = (typeof prisma)[Uncapitalize<Prisma.ModelName>];
function getTableName(model: PrismaModel):string {
const modelName = Prisma.getExtensionContext(model).$name;
if (!modelName) throw new Error("Model name not found");
return (prisma as any)._runtimeDataModel.models[modelName].dbName;
}
// How to use
getTableName(prisma.user) // -> "users"
その他めも
このコードの type PrismaModel は prisma.xxx を受け取れる型。
import { Prisma } from "@prisma/client";
export type PrismaModel = (typeof prisma)[Uncapitalize<Prisma.ModelName>];
/* === type test cases === */
import { prisma } from "<your project's instantiated prisma client>";
const m1: PrismaModel = prisma.user;
const m2: PrismaModel = prisma.$transaction; // これはコンパイルエラー
Discussion