Motivation
- できるだけ gorm 標準の
gorm.Model
に準拠させた形にして、gorm の恩恵を受けたい
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string
Price uint
}
// → このままだと PK が uint / auto_increment フィールドになる
結論
以下のサンプルコードをご覧ください。
type UUIDBaseModel struct {
// UUID が主キーになり、UUID は Postgres が勝手に生成する
ID string `gorm:"primaryKey;size:255;default:uuid_generate_v4()"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
type Product struct {
// UUIDBaseModel を含む struct は全て UUID が主キーになる
UUIDBaseModel
Code string
Price uint
}
func migrate() {
dsn := "host=localhost user=user password=password dbname=dbname port=5432 sslmode=disable TimeZone=Asia/Tokyo"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
// 追加: PostgreSQL に拡張機能 "uuid-ossp" を追加する
db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)
// マイグレーションを行なう
err = db.AutoMigrate(&Product{})
if err != nil {
panic(err)
}
}
ポイントは以下の3点です。
-
マイグレーションを行なう前に、SQL句
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
を実行する
go ではなく実際に SQL のコンソールに入って実行しても構いませんが、go で実行することをおすすめします。db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)
-
UUID が主キーになるようなモデルをつくる
この構造体が埋め込まれた構造体はすべてで、Primary Key が UUID になります。type UUIDBaseModel struct { // UUID が主キーになり、UUID は Postgres が勝手に生成する ID string `gorm:"primaryKey;size:255;default:uuid_generate_v4()"` CreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` }
-
実際にマイグレートするモデルの構造体にはすべて
UUIDBaseModel
を含めるtype Product struct { // UUIDBaseModel を含む struct は全て UUID が主キーになる UUIDBaseModel Code string Price uint }
Docker の postgres
公式イメージを使用している場合
マイグレーションを行なう前に、SQL句 CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
を実行する方法以外に、環境変数で拡張機能 uuid-ossp
を追加することができます。
これにより、 db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)
の追記が不要になります。
環境変数 POSTGRES_EXTENSIONS=uuid-ossp
を追記して下さい。
Dockerfile
FROM postgres:9.6.23
USER root
# 以下を追記
ENV POSTGRES_EXTENSIONS=uuid-ossp
docker-compose.yml
services:
postgres:
environment:
# 以下を追記
POSTGRES_EXTENSIONS: uuid-ossp