mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 15:20:54 +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:
parent
57afd3d979
commit
9f3af59250
69
orm/db.go
69
orm/db.go
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user