はじめに
以前の記事でPrisma3系から4系にアップグレードする必要があるケースを書いたが、
その際に発生した問題について。
環境
- Prisma(before): 3.13.0(<= 3.15.2)
- Prisma(after): 4.8.0(>= 4.0.0)
- Provider:MySQL
概要
あるテーブルのレコード件数を$queryRaw
で取得してレコード件数+1をログに出力する場合、一例ではあるが以下のように書くことができる。
const result = await this.prisma.$queryRaw<
{ count: number }[]
>`SELECT COUNT(*) AS count FROM users`
const count = result[0].count
console.log('count + 1 =', count + 1)
仮にusersテーブルに1,000件のレコード数が存在すれば以下のように何の問題もなく出力される。
count + 1 = 1001
しかし、Prisma3系(<= 3.15.2)から4系(>= 4.0.0)にアップグレードすると、
上記の実装はTypeErrorが発生してしまう。
TypeError: Cannot mix BigInt and other types, use explicit conversions
なぜにBigInt?となったがとりあえずcountの値と型を確認してみる。
console.log('count:', count)
console.log('typeof count:', typeof count)
count: 1000n
typeof count: bigint
確かにBigIntになっている。
ということでPrisma4のアップグレードガイドを確認してみると、
queryRawが返却するスカラー値の型に関する仕様変更が明記されていた。
$queryRaw
で取得したスカラー値をJSの対応する型にデシリアライズするように変更された模様。
Int64
の返却型がInteger
からBigInt
になっている。
対応
queryRawのジェネリクスパラメータを{ count: bigint }[]
に変更し、
代入時にNumberコンストラクタでNumber型(数値型)に変換する。
const result = await this.prisma.$queryRaw<
{ count: bigint }[]
>`SELECT COUNT(*) AS count FROM users`
const count = Number(result[0].count)
console.log('count:', count)
console.log('typeof count:', typeof count)
console.log('count + 1 =', count + 1)
count: 1000
typeof count: number
count + 1 = 1001
無事、Prisma3系を使用していた際に期待していた出力結果と同じ出力結果を確認できた。
ただし、当然のことながら$queryRaw
で取得したBigInt型(長整数型)のレコード件数が、
Number型(数値型)で扱える範囲を超えてしまっている場合には精度が落ちるので注意を。
まとめ
Prisma3系(<= 3.15.2)から4系(>= 4.0.0)にアップグレードする際、
$queryRaw
を使用している箇所には注意しましょう。
本記事では単純な加算処理を例に挙げたが、
実際にこの問題に直面したケースではGraphQLのEntityにマッピングする箇所で発生したので、
アプリケーションのアーキテクチャ全体に関わる問題かと思いひやっとした。
参考
関連
Prismaで新規レコード作成時に@default(now())なカラムと@updatedAtなカラムに差異が生じる問題