1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-25 20:00:55 +00:00

add support for sql.Null* types

Change instructions for sqlite3 tests to use in memory db for much faster
This commit is contained in:
Daniel Hobe 2014-02-27 19:53:35 -08:00
parent d05270d2ec
commit 6e00cfb464
4 changed files with 167 additions and 60 deletions

View File

@ -103,16 +103,37 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
} else { } else {
switch fi.fieldType { switch fi.fieldType {
case TypeBooleanField: case TypeBooleanField:
if nb, ok := field.Interface().(sql.NullBool); ok {
value = nil
if nb.Valid {
value = nb.Bool
}
} else {
value = field.Bool() value = field.Bool()
}
case TypeCharField, TypeTextField: case TypeCharField, TypeTextField:
if ns, ok := field.Interface().(sql.NullString); ok {
value = nil
if ns.Valid {
value = ns.String
}
} else {
value = field.String() value = field.String()
}
case TypeFloatField, TypeDecimalField: case TypeFloatField, TypeDecimalField:
if nf, ok := field.Interface().(sql.NullFloat64); ok {
value = nil
if nf.Valid {
value = nf.Float64
}
} else {
vu := field.Interface() vu := field.Interface()
if _, ok := vu.(float32); ok { if _, ok := vu.(float32); ok {
value, _ = StrTo(ToStr(vu)).Float64() value, _ = StrTo(ToStr(vu)).Float64()
} else { } else {
value = field.Float() value = field.Float()
} }
}
case TypeDateField, TypeDateTimeField: case TypeDateField, TypeDateTimeField:
value = field.Interface() value = field.Interface()
if t, ok := value.(time.Time); ok { if t, ok := value.(time.Time); ok {
@ -124,7 +145,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
case fi.fieldType&IsPostiveIntegerField > 0: case fi.fieldType&IsPostiveIntegerField > 0:
value = field.Uint() value = field.Uint()
case fi.fieldType&IsIntegerField > 0: case fi.fieldType&IsIntegerField > 0:
if ni, ok := field.Interface().(sql.NullInt64); ok {
value = nil
if ni.Valid {
value = ni.Int64
}
} else {
value = field.Int() value = field.Int()
}
case fi.fieldType&IsRelField > 0: case fi.fieldType&IsRelField > 0:
if field.IsNil() { if field.IsNil() {
value = nil value = nil
@ -1122,18 +1150,38 @@ setValue:
switch { switch {
case fieldType == TypeBooleanField: case fieldType == TypeBooleanField:
if isNative { if isNative {
if nb, ok := field.Interface().(sql.NullBool); ok {
if value == nil {
nb.Valid = false
} else {
nb.Bool = value.(bool)
nb.Valid = true
}
field.Set(reflect.ValueOf(nb))
} else {
if value == nil { if value == nil {
value = false value = false
} }
field.SetBool(value.(bool)) field.SetBool(value.(bool))
} }
}
case fieldType == TypeCharField || fieldType == TypeTextField: case fieldType == TypeCharField || fieldType == TypeTextField:
if isNative { if isNative {
if ns, ok := field.Interface().(sql.NullString); ok {
if value == nil {
ns.Valid = false
} else {
ns.String = value.(string)
ns.Valid = true
}
field.Set(reflect.ValueOf(ns))
} else {
if value == nil { if value == nil {
value = "" value = ""
} }
field.SetString(value.(string)) field.SetString(value.(string))
} }
}
case fieldType == TypeDateField || fieldType == TypeDateTimeField: case fieldType == TypeDateField || fieldType == TypeDateTimeField:
if isNative { if isNative {
if value == nil { if value == nil {
@ -1151,19 +1199,40 @@ setValue:
} }
} else { } else {
if isNative { if isNative {
if ni, ok := field.Interface().(sql.NullInt64); ok {
if value == nil {
ni.Valid = false
} else {
ni.Int64 = value.(int64)
ni.Valid = true
}
field.Set(reflect.ValueOf(ni))
} else {
if value == nil { if value == nil {
value = int64(0) value = int64(0)
} }
field.SetInt(value.(int64)) field.SetInt(value.(int64))
} }
} }
}
case fieldType == TypeFloatField || fieldType == TypeDecimalField: case fieldType == TypeFloatField || fieldType == TypeDecimalField:
if isNative { if isNative {
if nf, ok := field.Interface().(sql.NullFloat64); ok {
if value == nil {
nf.Valid = false
} else {
nf.Float64 = value.(float64)
nf.Valid = true
}
field.Set(reflect.ValueOf(nf))
} else {
if value == nil { if value == nil {
value = float64(0) value = float64(0)
} }
field.SetFloat(value.(float64)) field.SetFloat(value.(float64))
} }
}
case fieldType&IsRelField > 0: case fieldType&IsRelField > 0:
if value != nil { if value != nil {
fieldType = fi.relModelInfo.fields.pk.fieldType fieldType = fi.relModelInfo.fields.pk.fieldType

View File

@ -1,6 +1,7 @@
package orm package orm
import ( import (
"database/sql"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@ -137,6 +138,10 @@ type DataNull struct {
Float32 float32 `orm:"null"` Float32 float32 `orm:"null"`
Float64 float64 `orm:"null"` Float64 float64 `orm:"null"`
Decimal float64 `orm:"digits(8);decimals(4);null"` Decimal float64 `orm:"digits(8);decimals(4);null"`
NullString sql.NullString `orm:"null"`
NullBool sql.NullBool `orm:"null"`
NullFloat64 sql.NullFloat64 `orm:"null"`
NullInt64 sql.NullInt64 `orm:"null"`
} }
// only for mysql // only for mysql
@ -303,9 +308,8 @@ go test -v github.com/astaxie/beego/orm
#### Sqlite3 #### Sqlite3
touch /path/to/orm_test.db
export ORM_DRIVER=sqlite3 export ORM_DRIVER=sqlite3
export ORM_SOURCE=/path/to/orm_test.db export ORM_SOURCE='file:memory_test?mode=memory'
go test -v github.com/astaxie/beego/orm go test -v github.com/astaxie/beego/orm

View File

@ -1,6 +1,7 @@
package orm package orm
import ( import (
"database/sql"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -98,30 +99,29 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col
// return field type as type constant from reflect.Value // return field type as type constant from reflect.Value
func getFieldType(val reflect.Value) (ft int, err error) { func getFieldType(val reflect.Value) (ft int, err error) {
elm := reflect.Indirect(val) elm := reflect.Indirect(val)
switch elm.Kind() { switch elm.Interface().(type) {
case reflect.Int8: case int8:
ft = TypeBitField ft = TypeBitField
case reflect.Int16: case int16:
ft = TypeSmallIntegerField ft = TypeSmallIntegerField
case reflect.Int32, reflect.Int: case int32, int:
ft = TypeIntegerField ft = TypeIntegerField
case reflect.Int64: case int64, sql.NullInt64:
ft = TypeBigIntegerField ft = TypeBigIntegerField
case reflect.Uint8: case uint8:
ft = TypePositiveBitField ft = TypePositiveBitField
case reflect.Uint16: case uint16:
ft = TypePositiveSmallIntegerField ft = TypePositiveSmallIntegerField
case reflect.Uint32, reflect.Uint: case uint32, uint:
ft = TypePositiveIntegerField ft = TypePositiveIntegerField
case reflect.Uint64: case uint64:
ft = TypePositiveBigIntegerField ft = TypePositiveBigIntegerField
case reflect.Float32, reflect.Float64: case float32, float64, sql.NullFloat64:
ft = TypeFloatField ft = TypeFloatField
case reflect.Bool: case bool, sql.NullBool:
ft = TypeBooleanField ft = TypeBooleanField
case reflect.String: case string, sql.NullString:
ft = TypeCharField ft = TypeCharField
case reflect.Invalid:
default: default:
if elm.CanInterface() { if elm.CanInterface() {
if _, ok := elm.Interface().(time.Time); ok { if _, ok := elm.Interface().(time.Time); ok {

View File

@ -2,6 +2,7 @@ package orm
import ( import (
"bytes" "bytes"
"database/sql"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -258,12 +259,45 @@ func TestNullDataTypes(t *testing.T) {
err = dORM.Read(&d) err = dORM.Read(&d)
throwFail(t, err) throwFail(t, err)
throwFail(t, AssertIs(d.NullBool.Valid, false))
throwFail(t, AssertIs(d.NullString.Valid, false))
throwFail(t, AssertIs(d.NullInt64.Valid, false))
throwFail(t, AssertIs(d.NullFloat64.Valid, false))
_, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec() _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec()
throwFail(t, err) throwFail(t, err)
d = DataNull{Id: 2} d = DataNull{Id: 2}
err = dORM.Read(&d) err = dORM.Read(&d)
throwFail(t, err) throwFail(t, err)
d = DataNull{
DateTime: time.Now(),
NullString: sql.NullString{"test", true},
NullBool: sql.NullBool{true, true},
NullInt64: sql.NullInt64{42, true},
NullFloat64: sql.NullFloat64{42.42, true},
}
id, err = dORM.Insert(&d)
throwFail(t, err)
throwFail(t, AssertIs(id, 3))
d = DataNull{Id: 3}
err = dORM.Read(&d)
throwFail(t, err)
throwFail(t, AssertIs(d.NullBool.Valid, true))
throwFail(t, AssertIs(d.NullBool.Bool, true))
throwFail(t, AssertIs(d.NullString.Valid, true))
throwFail(t, AssertIs(d.NullString.String, "test"))
throwFail(t, AssertIs(d.NullInt64.Valid, true))
throwFail(t, AssertIs(d.NullInt64.Int64, 42))
throwFail(t, AssertIs(d.NullFloat64.Valid, true))
throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42))
} }
func TestCRUD(t *testing.T) { func TestCRUD(t *testing.T) {