RailsでマイグレーションされたDBスキーマをPrismaのschemaに取り込む
RailsでマイグレーションされたDBを、Node.jsからPrismaを使ってアクセスできるようにPrismaのschemaを整えます。
既存のDBはPostgreSQLです。
prisma db pull
する
まずは 既存のDBを取り込む手順がドキュメントにありますので、それに従いschemaを作成します。
- prismaのcliを追加
yarn add -D prisma
- prismaの初期化
npx prisma init
-
.env
にDBの接続設定を設定。 -
prisma db pull
を実行して既存のスキーマをschema.prismaにインポートする
npx prisma db pull
./prisma/schema.prisma
に既存のDBのスキーマが書き込まれました。
このあと npx prisma generate
で型定義も生成できます。
ネーミングルールを合わせる
- modelのルール
-
modelのfieldのルール
- 正規表現:
[A-Za-z][A-Za-z0-9_]*
- 必ず小文字から始まる
- camelCase推奨
- 正規表現:
Node.js(TypeScript)のコードに snake_case
が紛れ込むと、のちのち混乱のもとになりますので、schemaファイルで名前を合わせておきます。
modelの名前のmapping
以下は prisma db pull
を実行した直後の状態です。
model books {
id BigInt @id @default(autoincrement())
}
books
を Book
にするのが推奨される名前です。
model Book {
@@map("books")
id BigInt @id @default(autoincrement())
}
modelのfieldの名前のmapping
fieldの名前も同様にマッピングします。
created_at DateTime @db.Timestamp(6)
updated_at DateTime @db.Timestamp(6)
createdAt DateTime @db.Timestamp(6) @map("created_at")
updatedAt DateTime @db.Timestamp(6) @map("updated_at")
bigintをJSON.strinfigyできない
Railsのデフォルトのidフィールドはbigint型として定義されますが、このままstringifyしようとすると Do not know how to serialize a BigInt
となります。
ワークアラウンドとして JSON.stringify
をカスタマイズする方法が載っています。
また、 fast-json-stringify を使うのもいいかもしれません。こちらはtoStringしてからintegerに変換するようです。(未確認)
fastify ではシリアライザにfast-json-stringifyが使われているので、レスポンスのschema定義をすれば数値として出力されました。
fastify.route({
method: "GET",
url: "/",
handler: async (req, res) => {
const book = await fastify.prisma.book.findFirst();
if (!book) {
return res.code(404);
}
return book;
},
schema: {
response: {
200: {
id: { type: "number" },
},
},
},
});
=> {"id":9}
Railsがデフォルトをbigintにしているのは、後からintをbigintに変えることが大変だからなんだけど、intを超える可能性が限りなくゼロに近いのであれば、prismaの型定義はInt型と定義するでも良いかもしれません。
model Book {
@@map("books")
id Int @id @default(autoincrement()) // 本当はBigInt
}
リレーションシップ
ActiveRecordで設定していた belongs_to
や has_many
などのアソシエーションは、prismaではスキーマ定義で設定します。
belongs_to :user
の場合
model Book {
userId Int @map("user_id")
user User @relation(fields: [userId], references: [id])
has_many :books
の場合
model User {
books Book[]
これで、以下のように型やメソッドが追加されます。
const book = await fastify.prisma.book.findFirst({
include: { user: true },
});
book!.user;
const user = await fastify.prisma.user.findFirst({
include: { books: true },
});
user!.books;
include
を含まない場合、結果の型にuserやbooksが含まれないのが素晴らしいですね。
many-to-many も設定できる。
ポリモーフィック
ActiveRecordのアソシエーションで重宝してよく使われるのが polymorphic
ではないでしょうか。prismaでは、現時点ではActiveRecordと同様の機能が実装される予定はないようです。アプリケーションのロジックで実装を行う必要があります。
カスケード
ActiveRecordのdependentオプションは、prismaのスキーマ定義で設定可能。