最近在使用xorm,並使用了sql builder來構建sql查詢沒想到升級后原來可以使用的代碼居然報錯了。
0x00 代碼
sql, args, _ := builder.Select("*").
From("user").
Where(builder.Eq{"uid": 1}).
ToSQL()
res, err := orm.QueryString(sql, args...)
0x01 對比
發現xorm在0.6.3 和 0.6.4間做了改動,如圖
0.6.3
0.6.4
原來如此,去掉了第一個參數,改為全部可變參數了,於是機智的把args...,改為了args。
關於可變參數的問題,可以參考我的這篇文章。
0x02 新錯誤
沒想到編譯沒錯,運行時報錯了,提示
sql: converting argument $1 type: unsupported type []interface {}, a slice of interface
即類型錯誤。繼續追蹤代碼,發現session_query.go里有生成sql的函數,代碼如下:
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
if len(sqlorArgs) > 0 {
return sqlorArgs[0].(string), sqlorArgs[1:], nil
}
//省略
}
由於sqlorArgs是slice,而且builder.ToSql的args也是slice,那么sqlorArgs[1:]又創建了一個新的slice,就讓最后返回的slice變成了二元slice了,所以出現了上面的類型錯誤。
0x03 解決辦法
想了一下,其實我覺得上一個版本的函數簽名更好,兩個參數,一個負責接受sql語句,一個負責接收sql變量。給作者提了issue,或許作者有更好的解決方案。
下面是我的臨時解決方法:
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
if len(sqlorArgs) > 0 {
if len(sqlorArgs) == 2 && reflect.TypeOf(sqlorArgs[1]).Kind() == reflect.Slice {
return sqlorArgs[0].(string), sqlorArgs[1].([]interface{}), nil
}
return sqlorArgs[0].(string), sqlorArgs[1:], nil
}
//省略
}
作者已經更新,方法更加巧妙,增加了builder類型
用法,直接傳builder即可