sqlx/reflectxを触ってて、他のRDBMS関係のライブラリのcreate table部分の実装が気になったので調べてみたメモ

これは自分用のメモです。

github.com

goでRDBMSを触るときに、sqxは機能が小さくて良いのですが、手元で実行例的なコードを書くときに、SQL側のtable定義とgo側のstructの定義を書いたりするのが面倒になることがあります。実運用はともかくとして、ちょっとした実行例を試すときにstructを定義したらおしまいと言う世界観もそう悪くはありません。

加えて、ElasticsearchやAWSのAthenaやBigQueryなど、新しいデータストアを追加で利用したくなった場合にschemaの定義が要求されることはしばしばあります。その種の定義をgoのstructの定義だけでおしまいにできるという利便性が欲しくなることもありそうでした。

sqlx/reflectx

実は、sqlxの中にreflectxというパッケージが存在していたりします。これはちょっとしたstruct定義とtag定義を見るのに地味に便利な機能を持っていたりします。reflect.Typeを渡してあげるといい感じにタグの情報や型の値などを取り出してくれて便利です。

package main

import (
    "fmt"
    "reflect"

    "github.com/jmoiron/sqlx/reflectx"
)

type Person struct {
    Name string `db:"name,unique"`
    Age  int64  `db:"age,default=20"`
}

func main() {
    mapper := reflectx.NewMapper("db")
    tmap := mapper.TypeMap(reflect.TypeOf(Person{}))
    for i, info := range tmap.Index {
        fmt.Printf("%d\t%s\ttags=%+#v\n", i, info.Name, info.Options)
    }
}

このコードを実行すると以下のような出力になります。

$ go run 00reflectx/main.go
0       name    tags=map[string]string{"unique":""}
1       age     tags=map[string]string{"default":"20"}

このreflectxを使ってお遊びでcreate tableやinsertを手軽に書けるようにするコードを書いてみていました。

ここまでが前置きです。そんなことをやっているうちに他のRDBMS用のライブラリの実装がどうなっているかどうか気になったので調べてみました。

対象のライブラリ

ここからが本題。今までの内容はすべて前置きです。

調べてみたライブラリは以下の4つです。独断と偏見でその場で思いついたものの実装を見てみたという感じです。

gorp

結構素直に愚直に実装されていた。

ent

もう一段回キレイにwrapしている感ある(複雑)。gremlinなどにも対応しているせいかもしれない。

gorm

xorm

はい。

ちょっとした感想

RDBMSだけを触ることに限って言えば、それぞれのライブラリが結構真面目に作り込んでいるので、わざわざ自前で実装し直す必要もないかなと思ったというのが正直な感想でした。

一方でかなりRDBMSに寄った実装になっている面もあったりするので、冒頭にあった他のデータストア用のschemaへの対応をと考えると、どれもover killな印象を持ちました。加えて、内部での利用に閉じてしまえば、複数の種類のデータベースに対応する必要はなかったり、利用する型の種類もわずかだったりしそうでもう少し手軽にやれるのかなと思ったりはしました。メモなのでこんな感じで突然おわり。

追記

reflectxはreflectベースの実装ですが、これがgo/typesを使った値を利用する静的解析ベースのものだったらどうだろう?というのは少し考えたりしていました。

デモ程度に動くものは手を動かせば作れそうですが、実は何を読み込ませるか指定するのが地味に面倒で何らかのマーカーが必要になったり引数として渡したりする必要があったり、付加的な情報をどう注入するかが悩ましかったりしそうです。

逆にreflectベースでもbuild tags経由でデフォルトではpackageの対象外にして、go generateでgo runを実行するみたいなことをやれば邪魔にならなかったりします(一方で、静的解析ベースの場合は事前にビルドして置けるのが便利だったりします。余談も余談になってしまうのでこのへんで中断)。

gist