GORM で PostgreSQL を利用する場合の小ネタです。
執筆時点 (2024/04/06) での GORM のバージョンは v1.25.9、GORM PostgreSQL Driver のバージョンは v1.5.7 です。将来のバージョンでは挙動が変わる可能性があるのでご了承ください。
先にまとめ
- GORM + PostgreSQL でモデルの
float64
型のフィールドにgorm:"type:double precision"
を指定すると、AutoMigrate
実行時に余計なALTER TABLE
が発生してしまうことがある gorm:"type:float8"
を指定することでこの問題を回避できそう
準備
以下のような compose.yaml ファイルを用意して、Docker Compose で PostgreSQL を起動できるようにしておきます。
# compose.yaml
services:
postgres:
image: postgres:16.2
container_name: postgres
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=example
- POSTGRES_INITDB_ARGS=--encoding=UTF-8
- LANG=C
- TZ=Asia/Tokyo
- PGTZ=Asia/Tokyo
ports:
- "127.0.0.1:5432:5432"
restart: always
本題
GORM で float64
型のフィールドを持つモデルを定義して AutoMigrate
すると、PostgreSQL 上では decimal
(numeric
) 型のカラムを持ったテーブルが作成されます。
// main.go
package main
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
const (
DSN = "host=localhost port=5432 user=postgres password=password dbname=example sslmode=disable TimeZone=Asia/Tokyo"
)
type Sample struct {
Column float64
}
func main() {
db, err := gorm.Open(postgres.Open(DSN))
if err != nil {
panic("failed to connect database")
}
// デバッグモードを有効にして AutoMigrate を実行
if err := db.Debug().AutoMigrate(&Sample{}); err != nil {
panic("failed to migrate database")
}
}
実行してみます。
$ docker compose up -d
$ go run main.go
ログを見ると、確かに decimal
型のカラムを持ったテーブルが作成されていることがわかります。
[7.177ms] [rows:0] CREATE TABLE "samples" ("column" decimal)
しかし、場合によっては decimal
ではなく PostgreSQL の倍精度浮動小数点データ型 (double precision
) で格納したいこともあると思います。
そこで、gorm:"type:double precision"
を指定してみます。
// main.go
// ...
type Sample struct {
Column float64 `gorm:"type:double precision"`
}
// ...
$ docker compose down
$ docker compose up -d
$ go run main.go
ログを見ると、今度は double precision
型のカラムを持ったテーブルが作成されていることがわかります。
[3.314ms] [rows:0] CREATE TABLE "samples" ("column" double precision)
しかし、この状態でもう一度 AutoMigrate
を実行してログを見てみると、ALTER TABLE
が実行されてしまっていることがわかります。
$ go run main.go
[1.418ms] [rows:0] ALTER TABLE "samples" ALTER COLUMN "column" TYPE double precision USING "column"::double precision
この不要な ALTER TABLE
は、double precision
の別名である float8
を用いることで回避できます。
// main.go
// ...
type Sample struct {
Column float64 `gorm:"type:float8"`
}
// ...
$ docker compose down
$ docker compose up -d
$ go run main.go
$ go run main.go
この場合は二度目の AutoMigrate
で不要な ALTER TABLE
が発生しません。
また、単精度浮動小数点データ型 (real
) の場合も float4
を指定することで同様の問題を回避できるようです。
余談
最近月曜日はリモートワークにしていたのですが、4/1 には新入社員の方々が入社されるということでオフィスに出社したところ、よりにもよってコーヒーポットをひっくり返してしまいました。ごめんなさい。
初出社日にコーヒー(ポット)をひっくり返してしまった全国の新入社員の皆さん、あまり落ち込みすぎないで頑張ってください。
会津ラボはそれでもコーヒーが好きなコーヒー大好き人類を募集しています。