gormのアップデートをした話

はじめに

この記事は、仕事で使っているgormのバージョンをv1からv2にアップデートした時の備忘録です。 またgorm v1を使っている人でかつv2にアップデートしたい人向けの記事なので細かいところは省いています。

経緯

仕事で使っているgormのバージョンがv1で特に問題もなく開発できていたんですが、今後の開発で「v2に上げたほうがいいんじゃないか」という話になりアップデートを進めることになりました。 で、ORMのアップデートとかいい経験になりそうだったので手を挙げてみた感じです。

やったこと

v1とv2の差分確認

まずは、ざっと公式のリリースノートを読みながら変更箇所の把握を進めました。

gorm.io

次に、実際にv2へとアップデートした先人の知見などを確認しておおよその変更箇所を確認していきました。

tech.techtouch.jp

qiita.com

future-architect.github.io

zenn.dev

tchssk.hatenablog.com

大体上記の記事を読めば、おおよその変更差分は確認できますね。

使用するパッケージの置き換え

一番最初に進めたのは gorm v1 を使っている箇所をv2に置き換えることでした。

import (
-     "gorm.io/gorm"
+    "github.com/jinzhu/gorm"
)

パッケージを置き換えることでビルドエラーになっているところがはっきりし、そこを随時直していけば手戻りも少なく済みそうだったので。

DBのドライバー置き換え

次にDBのドライバーを置き換えました。

gorm v2ではv1の時とDBへの接続方法が変わっています。

gorm v1では以下のようなコードで接続できます。

import (
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
  db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
  defer db.Close()
}

ただ、v2ではこの辺りの仕様が変わっているので以下のように置き換える必要があります。

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)

func main() {
  // refer https://github.com/go-sql-driver/mysql#dsn-data-source-name for details
  dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}

RecordNotFoundの置き換え

次に、RecordNotFoundエラーの置き換えを進めました。

gorm v1では以下のようにレコードがない場合のエラー処理を行います。

if err := db.Where("name = ?", "jinzhu").First(&user).Error; gorm.IsRecordNotFoundError(err) {
  // record not found
}

この辺りの処理はv2ではerrorsを使ってチェックする方式に変わっています。

errors.Is(err, gorm.ErrRecordNotFound)

サブクエリの置き換え

gorm v1ではサブクエリは以下のようにSubQueryを使っていました。

db.Where("amount > ?", db.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").SubQuery()).Find(&orders)

これがgorm v2ではSubQueryメソッドが廃止され、以下のようにクエリを引数として渡すように変更されています。

subQuery := db.Select("AVG(age)").Where("name LIKE ?", "name%").Table("users")
db.Select("AVG(age) as avgage").Group("name").Having("AVG(age) > (?)", subQuery).Find(&results)

型エラーの修正

gorm v2ではLimit()Offset()が受け取る引数の型がuint64からintに変更されています。

その為、既存の実装を以下のようにキャストして対応しました。

db.Limit(int(limit)).Offset(int(offset))

またCount()が受け取る引数の型もint64に変更されているので以下のようにキャストしてたりします。

var total int64
db.Where("user_id = ?", userID).Count(total)
return uint64(total)

本来であれば元々の引数の型を修正するのが筋がいいんですが、今回は比較的急ぐ必要もあったのでキャストすることで対応しています。 この辺りは今後も改修が必要そうです。

おわりに

基本的にこんな感じの置き換えなどをガガガっと進めたのでアップデートに着手してから大体1か月くらいでリリースまで行けたかな? 変なクエリとか書いて無ければ大体上記に書かれている内容に置き換えていけばすんなりアップデートはできそう。