はじめに
この記事は、仕事で使っているgormのバージョンをv1からv2にアップデートした時の備忘録です。 またgorm v1を使っている人でかつv2にアップデートしたい人向けの記事なので細かいところは省いています。
経緯
仕事で使っているgormのバージョンがv1で特に問題もなく開発できていたんですが、今後の開発で「v2に上げたほうがいいんじゃないか」という話になりアップデートを進めることになりました。 で、ORMのアップデートとかいい経験になりそうだったので手を挙げてみた感じです。
やったこと
v1とv2の差分確認
まずは、ざっと公式のリリースノートを読みながら変更箇所の把握を進めました。
次に、実際にv2へとアップデートした先人の知見などを確認しておおよその変更箇所を確認していきました。
大体上記の記事を読めば、おおよその変更差分は確認できますね。
使用するパッケージの置き換え
一番最初に進めたのは 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か月くらいでリリースまで行けたかな? 変なクエリとか書いて無ければ大体上記に書かれている内容に置き換えていけばすんなりアップデートはできそう。