Exec support conversion data (#1970)

Fix #1803

Reviewed-on: https://gitea.com/xorm/xorm/pulls/1970
This commit is contained in:
Lunny Xiao 2023-08-07 10:54:57 +00:00
parent 94882e39df
commit ac84217e14
3 changed files with 76 additions and 2 deletions

View File

@ -16,11 +16,21 @@ import (
"time" "time"
) )
// ConversionFrom is an inteface to allow retrieve data from database
type ConversionFrom interface {
FromDB([]byte) error
}
// ConversionTo is an interface to allow store data to database
type ConversionTo interface {
ToDB() ([]byte, error)
}
// Conversion is an interface. A type implements Conversion will according // Conversion is an interface. A type implements Conversion will according
// the custom method to fill into database and retrieve from database. // the custom method to fill into database and retrieve from database.
type Conversion interface { type Conversion interface {
FromDB([]byte) error ConversionFrom
ToDB() ([]byte, error) ConversionTo
} }
// ErrNilPtr represents an error // ErrNilPtr represents an error

View File

@ -644,6 +644,23 @@ func (statement *Statement) convertSQLOrArgs(sqlOrArgs ...interface{}) (string,
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05")) newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05"))
} else if v, ok := arg.(*time.Time); ok && v != nil { } else if v, ok := arg.(*time.Time); ok && v != nil {
newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05")) 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)
}
} else {
newArgs = append(newArgs, nil)
}
} else { } else {
newArgs = append(newArgs, arg) newArgs = append(newArgs, arg)
} }

View File

@ -9,6 +9,8 @@ import (
"testing" "testing"
"time" "time"
"xorm.io/xorm/convert"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -65,3 +67,48 @@ func TestExecTime(t *testing.T) {
assert.True(t, has) assert.True(t, has)
assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), uet.Created.Format("2006-01-02 15:04:05")) assert.EqualValues(t, now.In(testEngine.GetTZLocation()).Format("2006-01-02 15:04:05"), uet.Created.Format("2006-01-02 15:04:05"))
} }
type ConversionData struct {
MyData string
}
var _ convert.Conversion = new(ConversionData)
func (c ConversionData) ToDB() ([]byte, error) {
return []byte(c.MyData), nil
}
func (c *ConversionData) FromDB(bs []byte) error {
if bs != nil {
c.MyData = string(bs)
}
return nil
}
func TestExecCustomTypes(t *testing.T) {
assert.NoError(t, PrepareEngine())
type UserinfoExec struct {
Uid int
Name string
Data string
}
assert.NoError(t, testEngine.Sync2(new(UserinfoExec)))
res, err := testEngine.Exec("INSERT INTO "+testEngine.TableName("`userinfo_exec`", true)+" (uid, name,data) VALUES (?, ?, ?)",
1, "user", ConversionData{"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"])
}