exec with driver.Valuer #2016

Closed
lunny wants to merge 4 commits from lunny/exec_driver_valuer into master
2 changed files with 71 additions and 25 deletions

View File

@ -637,37 +637,44 @@ func (statement *Statement) ConvertSQLOrArgs(sqlOrArgs ...interface{}) (string,
func (statement *Statement) convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
switch sqlOrArgs[0].(type) {
case string:
if len(sqlOrArgs) > 1 {
newArgs := make([]interface{}, 0, len(sqlOrArgs)-1)
for _, arg := range sqlOrArgs[1:] {
if v, ok := arg.(time.Time); ok {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else if v, ok := arg.(*time.Time); ok && v != nil {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else if v, ok := arg.(convert.ConversionTo); ok {
r, err := v.ToDB()
if err != nil {
return "", nil, err
}
if r != nil {
// for nvarchar column on mssql, bytes have to be converted as ucs-2 external of driver
// for binary column, a string will be converted as bytes directly. So we have to
// convert bytes as string
if statement.dialect.URI().DBType == schemas.MSSQL {
newArgs = append(newArgs, string(r))
} else {
newArgs = append(newArgs, r)
}
if len(sqlOrArgs) <= 1 {
return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
}
newArgs := make([]interface{}, 0, len(sqlOrArgs)-1)
for _, arg := range sqlOrArgs[1:] {
if v, ok := arg.(time.Time); ok {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else if v, ok := arg.(*time.Time); ok && v != nil {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else if v, ok := arg.(convert.ConversionTo); ok {
r, err := v.ToDB()
if err != nil {
return "", nil, err
}
if r != nil {
// for nvarchar column on mssql, bytes have to be converted as ucs-2 external of driver
// for binary column, a string will be converted as bytes directly. So we have to
// convert bytes as string
if statement.dialect.URI().DBType == schemas.MSSQL {
newArgs = append(newArgs, string(r))
} else {
newArgs = append(newArgs, nil)
newArgs = append(newArgs, r)
}
} else {
newArgs = append(newArgs, arg)
newArgs = append(newArgs, nil)
}
} else if v, ok := arg.(driver.Valuer); ok {
vv, err := v.Value()
if err != nil {
return "", nil, err
}
newArgs = append(newArgs, vv)
} else {
newArgs = append(newArgs, arg)
}
return sqlOrArgs[0].(string), newArgs, nil
}
return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
return sqlOrArgs[0].(string), newArgs, nil
case *builder.Builder:
return sqlOrArgs[0].(*builder.Builder).ToSQL()
case builder.Builder:

View File

@ -5,6 +5,7 @@
package tests
import (
"database/sql/driver"
"strconv"
"testing"
"time"
@ -68,6 +69,44 @@ func TestExecTime(t *testing.T) {
assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), uet.Created.Format("2006-01-02 15:04:05"))
}
var _ driver.Valuer = &MyData{}
type MyData struct {
data string
}
func (m *MyData) Value() (driver.Value, error) {
return m.data, nil
}
func TestExecDriverValuer(t *testing.T) {
assert.NoError(t, PrepareEngine())
type UserinfoDriverValuer struct {
Uid int
Name string
Data string
}
assert.NoError(t, testEngine.Sync2(new(UserinfoDriverValuer)))
res, err := testEngine.Exec("INSERT INTO "+testEngine.TableName("`userinfo_driver_valuer`", true)+" (uid, name,data) VALUES (?, ?, ?)",
1, "user", MyData{"data"})
assert.NoError(t, err)
cnt, err := res.RowsAffected()
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
results, err := testEngine.QueryString("select * from " + testEngine.TableName("userinfo_exec", true))
assert.NoError(t, err)
assert.EqualValues(t, 1, len(results))
id, err := strconv.Atoi(results[0]["uid"])
assert.NoError(t, err)
assert.EqualValues(t, 1, id)
assert.Equal(t, "user", results[0]["name"])
assert.EqualValues(t, "data", results[0]["data"])
}
type ConversionData struct {
MyData string
}