Move value2interface from session to statement package
This commit is contained in:
parent
3617ee736f
commit
5bfaa7c843
|
@ -0,0 +1,151 @@
|
||||||
|
// Copyright 2017 The Xorm Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package statements
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"xorm.io/xorm/convert"
|
||||||
|
"xorm.io/xorm/dialects"
|
||||||
|
"xorm.io/xorm/internal/json"
|
||||||
|
"xorm.io/xorm/schemas"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
nullFloatType = reflect.TypeOf(sql.NullFloat64{})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Value2Interface convert a field value of a struct to interface for puting into database
|
||||||
|
func (statement *Statement) Value2Interface(col *schemas.Column, fieldValue reflect.Value) (interface{}, error) {
|
||||||
|
if fieldValue.CanAddr() {
|
||||||
|
if fieldConvert, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
||||||
|
data, err := fieldConvert.ToDB()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if col.SQLType.IsBlob() {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
||||||
|
data, err := fieldConvert.ToDB()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if col.SQLType.IsBlob() {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldType := fieldValue.Type()
|
||||||
|
k := fieldType.Kind()
|
||||||
|
if k == reflect.Ptr {
|
||||||
|
if fieldValue.IsNil() {
|
||||||
|
return nil, nil
|
||||||
|
} else if !fieldValue.IsValid() {
|
||||||
|
return nil, nil
|
||||||
|
} else {
|
||||||
|
// !nashtsai! deference pointer type to instance type
|
||||||
|
fieldValue = fieldValue.Elem()
|
||||||
|
fieldType = fieldValue.Type()
|
||||||
|
k = fieldType.Kind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k {
|
||||||
|
case reflect.Bool:
|
||||||
|
return fieldValue.Bool(), nil
|
||||||
|
case reflect.String:
|
||||||
|
return fieldValue.String(), nil
|
||||||
|
case reflect.Struct:
|
||||||
|
if fieldType.ConvertibleTo(schemas.TimeType) {
|
||||||
|
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
|
||||||
|
tf := dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
|
||||||
|
return tf, nil
|
||||||
|
} else if fieldType.ConvertibleTo(nullFloatType) {
|
||||||
|
t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
|
||||||
|
if !t.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return t.Float64, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !col.SQLType.IsJson() {
|
||||||
|
// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
|
||||||
|
if v, ok := fieldValue.Interface().(driver.Valuer); ok {
|
||||||
|
return v.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldTable, err := statement.tagParser.ParseWithCache(fieldValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(fieldTable.PrimaryKeys) == 1 {
|
||||||
|
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
|
||||||
|
return pkField.Interface(), nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no primary key for col %v", col.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if col.SQLType.IsText() {
|
||||||
|
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
} else if col.SQLType.IsBlob() {
|
||||||
|
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
|
||||||
|
case reflect.Complex64, reflect.Complex128:
|
||||||
|
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
case reflect.Array, reflect.Slice, reflect.Map:
|
||||||
|
if !fieldValue.IsValid() {
|
||||||
|
return fieldValue.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if col.SQLType.IsText() {
|
||||||
|
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
} else if col.SQLType.IsBlob() {
|
||||||
|
var bytes []byte
|
||||||
|
var err error
|
||||||
|
if (k == reflect.Slice) &&
|
||||||
|
(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
|
||||||
|
bytes = fieldValue.Bytes()
|
||||||
|
} else {
|
||||||
|
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
return nil, ErrUnSupportedType
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return int64(fieldValue.Uint()), nil
|
||||||
|
default:
|
||||||
|
return fieldValue.Interface(), nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"xorm.io/xorm/convert"
|
"xorm.io/xorm/convert"
|
||||||
"xorm.io/xorm/dialects"
|
|
||||||
"xorm.io/xorm/internal/json"
|
"xorm.io/xorm/internal/json"
|
||||||
"xorm.io/xorm/internal/utils"
|
"xorm.io/xorm/internal/utils"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
|
@ -88,10 +86,6 @@ func (session *Session) byte2Time(col *schemas.Column, data []byte) (outTime tim
|
||||||
return session.str2Time(col, string(data))
|
return session.str2Time(col, string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
nullFloatType = reflect.TypeOf(sql.NullFloat64{})
|
|
||||||
)
|
|
||||||
|
|
||||||
// convert a db data([]byte) to a field value
|
// convert a db data([]byte) to a field value
|
||||||
func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Value, data []byte) error {
|
func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Value, data []byte) error {
|
||||||
if structConvert, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
if structConvert, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
||||||
|
@ -533,133 +527,3 @@ func (session *Session) bytes2Value(col *schemas.Column, fieldValue *reflect.Val
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert a field value of a struct to interface for put into db
|
|
||||||
func (session *Session) value2Interface(col *schemas.Column, fieldValue reflect.Value) (interface{}, error) {
|
|
||||||
if fieldValue.CanAddr() {
|
|
||||||
if fieldConvert, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
|
|
||||||
data, err := fieldConvert.ToDB()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if col.SQLType.IsBlob() {
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if fieldConvert, ok := fieldValue.Interface().(convert.Conversion); ok {
|
|
||||||
data, err := fieldConvert.ToDB()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if col.SQLType.IsBlob() {
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldType := fieldValue.Type()
|
|
||||||
k := fieldType.Kind()
|
|
||||||
if k == reflect.Ptr {
|
|
||||||
if fieldValue.IsNil() {
|
|
||||||
return nil, nil
|
|
||||||
} else if !fieldValue.IsValid() {
|
|
||||||
session.engine.logger.Warnf("the field [%s] is invalid", col.FieldName)
|
|
||||||
return nil, nil
|
|
||||||
} else {
|
|
||||||
// !nashtsai! deference pointer type to instance type
|
|
||||||
fieldValue = fieldValue.Elem()
|
|
||||||
fieldType = fieldValue.Type()
|
|
||||||
k = fieldType.Kind()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch k {
|
|
||||||
case reflect.Bool:
|
|
||||||
return fieldValue.Bool(), nil
|
|
||||||
case reflect.String:
|
|
||||||
return fieldValue.String(), nil
|
|
||||||
case reflect.Struct:
|
|
||||||
if fieldType.ConvertibleTo(schemas.TimeType) {
|
|
||||||
t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
|
|
||||||
tf := dialects.FormatColumnTime(session.engine.dialect, session.engine.DatabaseTZ, col, t)
|
|
||||||
return tf, nil
|
|
||||||
} else if fieldType.ConvertibleTo(nullFloatType) {
|
|
||||||
t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
|
|
||||||
if !t.Valid {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return t.Float64, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !col.SQLType.IsJson() {
|
|
||||||
// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
|
|
||||||
if v, ok := fieldValue.Interface().(driver.Valuer); ok {
|
|
||||||
return v.Value()
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldTable, err := session.engine.tagParser.ParseWithCache(fieldValue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(fieldTable.PrimaryKeys) == 1 {
|
|
||||||
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
|
|
||||||
return pkField.Interface(), nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("no primary key for col %v", col.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if col.SQLType.IsText() {
|
|
||||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return string(bytes), nil
|
|
||||||
} else if col.SQLType.IsBlob() {
|
|
||||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return bytes, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return string(bytes), nil
|
|
||||||
case reflect.Array, reflect.Slice, reflect.Map:
|
|
||||||
if !fieldValue.IsValid() {
|
|
||||||
return fieldValue.Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if col.SQLType.IsText() {
|
|
||||||
bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return string(bytes), nil
|
|
||||||
} else if col.SQLType.IsBlob() {
|
|
||||||
var bytes []byte
|
|
||||||
var err error
|
|
||||||
if (k == reflect.Slice) &&
|
|
||||||
(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
|
|
||||||
bytes = fieldValue.Bytes()
|
|
||||||
} else {
|
|
||||||
bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes, nil
|
|
||||||
}
|
|
||||||
return nil, ErrUnSupportedType
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
|
||||||
return int64(fieldValue.Uint()), nil
|
|
||||||
default:
|
|
||||||
return fieldValue.Interface(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
setColumnInt(bean, col, 1)
|
setColumnInt(bean, col, 1)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
arg, err := session.value2Interface(col, fieldValue)
|
arg, err := session.statement.Value2Interface(col, fieldValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
setColumnInt(bean, col, 1)
|
setColumnInt(bean, col, 1)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
arg, err := session.value2Interface(col, fieldValue)
|
arg, err := session.statement.Value2Interface(col, fieldValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -567,25 +567,8 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
|
||||||
}
|
}
|
||||||
fieldValue := *fieldValuePtr
|
fieldValue := *fieldValuePtr
|
||||||
|
|
||||||
if col.IsAutoIncrement {
|
if col.IsAutoIncrement && fieldValue.IsZero() {
|
||||||
switch fieldValue.Type().Kind() {
|
continue
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
|
||||||
if fieldValue.Int() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
|
||||||
if fieldValue.Uint() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
if len(fieldValue.String()) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
|
||||||
if fieldValue.Pointer() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
|
||||||
|
@ -609,7 +592,7 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
|
||||||
} else if col.IsVersion && session.statement.CheckVersion {
|
} else if col.IsVersion && session.statement.CheckVersion {
|
||||||
args = append(args, 1)
|
args = append(args, 1)
|
||||||
} else {
|
} else {
|
||||||
arg, err := session.value2Interface(col, fieldValue)
|
arg, err := session.statement.Value2Interface(col, fieldValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return colNames, args, err
|
return colNames, args, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -473,25 +473,8 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
|
||||||
}
|
}
|
||||||
fieldValue := *fieldValuePtr
|
fieldValue := *fieldValuePtr
|
||||||
|
|
||||||
if col.IsAutoIncrement {
|
if col.IsAutoIncrement && fieldValue.IsZero() {
|
||||||
switch fieldValue.Type().Kind() {
|
continue
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
|
|
||||||
if fieldValue.Int() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
|
|
||||||
if fieldValue.Uint() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
if len(fieldValue.String()) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
|
||||||
if fieldValue.Pointer() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (col.IsDeleted && !session.statement.GetUnscoped()) || col.IsCreated {
|
if (col.IsDeleted && !session.statement.GetUnscoped()) || col.IsCreated {
|
||||||
|
@ -532,7 +515,7 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
|
||||||
} else if col.IsVersion && session.statement.CheckVersion {
|
} else if col.IsVersion && session.statement.CheckVersion {
|
||||||
args = append(args, 1)
|
args = append(args, 1)
|
||||||
} else {
|
} else {
|
||||||
arg, err := session.value2Interface(col, fieldValue)
|
arg, err := session.statement.Value2Interface(col, fieldValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return colNames, args, err
|
return colNames, args, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue