SQLboiler で SQLite の日付フィールドを扱うポイント
はじめに
Go でデータベースを操作するライブラリの一つに SQLboiler があります。
SQLboiler は database first と呼ばれる ORM ジェネレーターで、データ構造から自動的に ORM を生成できます。
本記事では、SQLite で SQLboiler を利用して ORM を生成する際の日付フィールドの扱いについて、ハマったポイントと対処方法を説明します。
SQLite で日付フィールドを扱う上での SQLboiler の注意点
SQLite には日付型を扱うフィールドはありません。
そのため日付データは TEXT 型として扱い、 Date And Time Functions を利用して定義します。
例えば created_at TEXT NOT NULL DEFAULT (DATETIME('now','localtime'))
のように記述します。
さて、上記のようにテーブルのフィールドを定義したデータベースから SQLboiler で ORM を生成すると、created_at や updated_at フィールドはデータベースと同じ string 型で変換されます。
一方 SQLboiler では created_at や updated_at というフィールド名の場合はデフォルトでは time.Now() で自動で timestamp を行う ORM が生成されます。
If your generated SQLBoiler models package can find columns with the names created_at or updated_at it will automatically set them to time.Now() in your database, and update your object appropriately.
https://github.com/volatiletech/sqlboiler/blob/master/README.md#automatic-createdatupdatedat
この時、生成された ORM では created_at や updated_at を time.Time 型として扱ってしまいます。
そのため、型の不整合でコンパイルエラーになってしまいます。
- 生成されるコードの例
...
currTime := time.Now().In(boil.GetLocation())
// o.CreatedAt が string 型なのでコンパイルエラーになる
if queries.MustTime(o.CreatedAt).IsZero() {
queries.SetScanner(&o.CreatedAt, currTime)
}
...
SQLite の created_at や updated_at を SQLboiler で扱う方法
型の不整合をどう扱うかについて、対応策を紹介します。
対応策1: auto timestamp を無効化する
--no-auto-timestamps
オプションを使用して auto timestamp を無効化することができます。
ORM で created_at や updated_at フィールドを time.Time 型として扱わないようになるので、型の不整合によるエラーがなくなります。
没案: カスタムフィールドを定義する
カスタムフィールドを定義する方法ではエラーになりました。
SQLboiler の設定でドライバーが定義する型を上書きすることで、created_at や updated_at フィールドの型を time.Time に変更することができます。
例えば sqlboiler.toml に以下のように記述します。
...
[[types]]
[types.match]
name = "created_at"
[types.replace]
type = "time.Time"
...
これで ORM の生成はうまくいくのですが、実際にデータベースと接続する際にエラーになりました。
sql driver 上は string として扱うため、ORM 上の 構造体を time.Time としたとしてもうまくいかないようでした。
- 実際に発生したエラー
db: failed to execute a one query for repositories: failed to bind pointers to obj: sql: Scan error on column index 2, name \"created_at\": unsupported Scan, storing driver.Value type string into type *time.Time
まとめ
SQLboilerはデータベースのスキーマからコードを自動生成できる便利なツールですが、SQLiteを利用する場合は日付データの扱いに注意が必要です。
本記事では、SQLiteでSQLboilerを利用してORMを生成する際の注意点と対応策について説明しました。
Discussion