やる気がストロングZERO

やる気のストロングスタイル

【Go】Gorpで[where in]をいい感じに書く方法

Gorpを使っていて以下のようなqueryを実行したい時がある。

select * from table where id in (1, 2, 4, 8);

"1,2,4,8"は動的に変えたいのでプレースホルダーにしたい。

select * from table where id in ($1, $2, $3, $4);

今回指定したidは4つだったけど、いつもそうとは限らないので渡す数も動的にしたい。

select * from table where id in ($1);

このqueryで以下のように実行してみるとエラーになる。

query := "select * from table where id in ($1);"
dbmap := &gorp.DbMap{
    Db:              db, // コネクション
    Dialect:         gorp.PostgresDialect{},
}
_, err := dbmap.Select(mapper, query, []int{1,2,4,8})

// エラーが出る
// sql: converting argument $1 type: unsupported type []int, a slice of int

方法:ExpandSliceArgsオプションを有効化してmap[string]interface{}型で値を渡す

以下のように書くと意図通りの挙動になる。

query := "select * from table where id in (:ids);"
dbmap := &gorp.DbMap{
    Db:              db,
    Dialect:         gorp.PostgresDialect{},
    ExpandSliceArgs: true, //スライス引数展開オプションを有効化する 

}
_, err := dbmap.Select(mapper, query, map[string]interface{}{"ids": []int{1,2,4,8}})

内部的には、query文字列を

select * from table where id in (:ids0, :ids1, :ids2, :ids3)

と展開して処理してくれている。

gorpのコードを読んでいてこの機能を知った。
この機能を知る前は、where in () の中を予めwhere in ($1, $2, $3, $4) となるように文字列をいじり、argsも[]interface{}型に変換してからdbMap.Select()に渡していたがめんどくさかった。。