diff --git a/integrations/session_raw_test.go b/integrations/session_raw_test.go index 36677683..aa1c4410 100644 --- a/integrations/session_raw_test.go +++ b/integrations/session_raw_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "xorm.io/xorm/convert" ) func TestExecAndQuery(t *testing.T) { @@ -65,3 +66,49 @@ func TestExecTime(t *testing.T) { 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")) } + +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"]) +} diff --git a/internal/convert/conversion.go b/internal/convert/conversion.go index 096fcfaf..0a0f8b3e 100644 --- a/internal/convert/conversion.go +++ b/internal/convert/conversion.go @@ -16,11 +16,21 @@ import ( "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 // the custom method to fill into database and retrieve from database. type Conversion interface { - FromDB([]byte) error - ToDB() ([]byte, error) + ConversionFrom + ConversionTo } // ErrNilPtr represents an error diff --git a/internal/statements/statement.go b/internal/statements/statement.go index 8e3c083c..01250c6f 100644 --- a/internal/statements/statement.go +++ b/internal/statements/statement.go @@ -968,6 +968,12 @@ func (statement *Statement) convertSQLOrArgs(sqlOrArgs ...interface{}) (string, newArgs = append(newArgs, v.In(statement.defaultTimeZone).Format("2006-01-02 15:04:05")) } else 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.(convert.ConversionTo); ok { + r, err := v.ToDB() + if err != nil { + return "", nil, err + } + newArgs = append(newArgs, r) } else { newArgs = append(newArgs, arg) }