9e3ebc88 by slene

Merge pull request #513 from hobeone/develop

add support for sql.Null* types, thx hobeone
2 parents d05270d2 6e00cfb4
...@@ -103,15 +103,36 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val ...@@ -103,15 +103,36 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
103 } else { 103 } else {
104 switch fi.fieldType { 104 switch fi.fieldType {
105 case TypeBooleanField: 105 case TypeBooleanField:
106 value = field.Bool() 106 if nb, ok := field.Interface().(sql.NullBool); ok {
107 value = nil
108 if nb.Valid {
109 value = nb.Bool
110 }
111 } else {
112 value = field.Bool()
113 }
107 case TypeCharField, TypeTextField: 114 case TypeCharField, TypeTextField:
108 value = field.String() 115 if ns, ok := field.Interface().(sql.NullString); ok {
116 value = nil
117 if ns.Valid {
118 value = ns.String
119 }
120 } else {
121 value = field.String()
122 }
109 case TypeFloatField, TypeDecimalField: 123 case TypeFloatField, TypeDecimalField:
110 vu := field.Interface() 124 if nf, ok := field.Interface().(sql.NullFloat64); ok {
111 if _, ok := vu.(float32); ok { 125 value = nil
112 value, _ = StrTo(ToStr(vu)).Float64() 126 if nf.Valid {
127 value = nf.Float64
128 }
113 } else { 129 } else {
114 value = field.Float() 130 vu := field.Interface()
131 if _, ok := vu.(float32); ok {
132 value, _ = StrTo(ToStr(vu)).Float64()
133 } else {
134 value = field.Float()
135 }
115 } 136 }
116 case TypeDateField, TypeDateTimeField: 137 case TypeDateField, TypeDateTimeField:
117 value = field.Interface() 138 value = field.Interface()
...@@ -124,7 +145,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val ...@@ -124,7 +145,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
124 case fi.fieldType&IsPostiveIntegerField > 0: 145 case fi.fieldType&IsPostiveIntegerField > 0:
125 value = field.Uint() 146 value = field.Uint()
126 case fi.fieldType&IsIntegerField > 0: 147 case fi.fieldType&IsIntegerField > 0:
127 value = field.Int() 148 if ni, ok := field.Interface().(sql.NullInt64); ok {
149 value = nil
150 if ni.Valid {
151 value = ni.Int64
152 }
153 } else {
154 value = field.Int()
155 }
128 case fi.fieldType&IsRelField > 0: 156 case fi.fieldType&IsRelField > 0:
129 if field.IsNil() { 157 if field.IsNil() {
130 value = nil 158 value = nil
...@@ -1122,17 +1150,37 @@ setValue: ...@@ -1122,17 +1150,37 @@ setValue:
1122 switch { 1150 switch {
1123 case fieldType == TypeBooleanField: 1151 case fieldType == TypeBooleanField:
1124 if isNative { 1152 if isNative {
1125 if value == nil { 1153 if nb, ok := field.Interface().(sql.NullBool); ok {
1126 value = false 1154 if value == nil {
1155 nb.Valid = false
1156 } else {
1157 nb.Bool = value.(bool)
1158 nb.Valid = true
1159 }
1160 field.Set(reflect.ValueOf(nb))
1161 } else {
1162 if value == nil {
1163 value = false
1164 }
1165 field.SetBool(value.(bool))
1127 } 1166 }
1128 field.SetBool(value.(bool))
1129 } 1167 }
1130 case fieldType == TypeCharField || fieldType == TypeTextField: 1168 case fieldType == TypeCharField || fieldType == TypeTextField:
1131 if isNative { 1169 if isNative {
1132 if value == nil { 1170 if ns, ok := field.Interface().(sql.NullString); ok {
1133 value = "" 1171 if value == nil {
1172 ns.Valid = false
1173 } else {
1174 ns.String = value.(string)
1175 ns.Valid = true
1176 }
1177 field.Set(reflect.ValueOf(ns))
1178 } else {
1179 if value == nil {
1180 value = ""
1181 }
1182 field.SetString(value.(string))
1134 } 1183 }
1135 field.SetString(value.(string))
1136 } 1184 }
1137 case fieldType == TypeDateField || fieldType == TypeDateTimeField: 1185 case fieldType == TypeDateField || fieldType == TypeDateTimeField:
1138 if isNative { 1186 if isNative {
...@@ -1151,18 +1199,39 @@ setValue: ...@@ -1151,18 +1199,39 @@ setValue:
1151 } 1199 }
1152 } else { 1200 } else {
1153 if isNative { 1201 if isNative {
1154 if value == nil { 1202 if ni, ok := field.Interface().(sql.NullInt64); ok {
1155 value = int64(0) 1203 if value == nil {
1204 ni.Valid = false
1205 } else {
1206 ni.Int64 = value.(int64)
1207 ni.Valid = true
1208 }
1209 field.Set(reflect.ValueOf(ni))
1210 } else {
1211 if value == nil {
1212 value = int64(0)
1213 }
1214 field.SetInt(value.(int64))
1156 } 1215 }
1157 field.SetInt(value.(int64))
1158 } 1216 }
1159 } 1217 }
1160 case fieldType == TypeFloatField || fieldType == TypeDecimalField: 1218 case fieldType == TypeFloatField || fieldType == TypeDecimalField:
1161 if isNative { 1219 if isNative {
1162 if value == nil { 1220 if nf, ok := field.Interface().(sql.NullFloat64); ok {
1163 value = float64(0) 1221 if value == nil {
1222 nf.Valid = false
1223 } else {
1224 nf.Float64 = value.(float64)
1225 nf.Valid = true
1226 }
1227 field.Set(reflect.ValueOf(nf))
1228 } else {
1229
1230 if value == nil {
1231 value = float64(0)
1232 }
1233 field.SetFloat(value.(float64))
1164 } 1234 }
1165 field.SetFloat(value.(float64))
1166 } 1235 }
1167 case fieldType&IsRelField > 0: 1236 case fieldType&IsRelField > 0:
1168 if value != nil { 1237 if value != nil {
......
1 package orm 1 package orm
2 2
3 import ( 3 import (
4 "database/sql"
4 "encoding/json" 5 "encoding/json"
5 "fmt" 6 "fmt"
6 "os" 7 "os"
...@@ -116,27 +117,31 @@ type Data struct { ...@@ -116,27 +117,31 @@ type Data struct {
116 } 117 }
117 118
118 type DataNull struct { 119 type DataNull struct {
119 Id int 120 Id int
120 Boolean bool `orm:"null"` 121 Boolean bool `orm:"null"`
121 Char string `orm:"null;size(50)"` 122 Char string `orm:"null;size(50)"`
122 Text string `orm:"null;type(text)"` 123 Text string `orm:"null;type(text)"`
123 Date time.Time `orm:"null;type(date)"` 124 Date time.Time `orm:"null;type(date)"`
124 DateTime time.Time `orm:"null;column(datetime)""` 125 DateTime time.Time `orm:"null;column(datetime)""`
125 Byte byte `orm:"null"` 126 Byte byte `orm:"null"`
126 Rune rune `orm:"null"` 127 Rune rune `orm:"null"`
127 Int int `orm:"null"` 128 Int int `orm:"null"`
128 Int8 int8 `orm:"null"` 129 Int8 int8 `orm:"null"`
129 Int16 int16 `orm:"null"` 130 Int16 int16 `orm:"null"`
130 Int32 int32 `orm:"null"` 131 Int32 int32 `orm:"null"`
131 Int64 int64 `orm:"null"` 132 Int64 int64 `orm:"null"`
132 Uint uint `orm:"null"` 133 Uint uint `orm:"null"`
133 Uint8 uint8 `orm:"null"` 134 Uint8 uint8 `orm:"null"`
134 Uint16 uint16 `orm:"null"` 135 Uint16 uint16 `orm:"null"`
135 Uint32 uint32 `orm:"null"` 136 Uint32 uint32 `orm:"null"`
136 Uint64 uint64 `orm:"null"` 137 Uint64 uint64 `orm:"null"`
137 Float32 float32 `orm:"null"` 138 Float32 float32 `orm:"null"`
138 Float64 float64 `orm:"null"` 139 Float64 float64 `orm:"null"`
139 Decimal float64 `orm:"digits(8);decimals(4);null"` 140 Decimal float64 `orm:"digits(8);decimals(4);null"`
141 NullString sql.NullString `orm:"null"`
142 NullBool sql.NullBool `orm:"null"`
143 NullFloat64 sql.NullFloat64 `orm:"null"`
144 NullInt64 sql.NullInt64 `orm:"null"`
140 } 145 }
141 146
142 // only for mysql 147 // only for mysql
...@@ -303,9 +308,8 @@ go test -v github.com/astaxie/beego/orm ...@@ -303,9 +308,8 @@ go test -v github.com/astaxie/beego/orm
303 308
304 309
305 #### Sqlite3 310 #### Sqlite3
306 touch /path/to/orm_test.db
307 export ORM_DRIVER=sqlite3 311 export ORM_DRIVER=sqlite3
308 export ORM_SOURCE=/path/to/orm_test.db 312 export ORM_SOURCE='file:memory_test?mode=memory'
309 go test -v github.com/astaxie/beego/orm 313 go test -v github.com/astaxie/beego/orm
310 314
311 315
......
1 package orm 1 package orm
2 2
3 import ( 3 import (
4 "database/sql"
4 "fmt" 5 "fmt"
5 "reflect" 6 "reflect"
6 "strings" 7 "strings"
...@@ -98,30 +99,29 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col ...@@ -98,30 +99,29 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col
98 // return field type as type constant from reflect.Value 99 // return field type as type constant from reflect.Value
99 func getFieldType(val reflect.Value) (ft int, err error) { 100 func getFieldType(val reflect.Value) (ft int, err error) {
100 elm := reflect.Indirect(val) 101 elm := reflect.Indirect(val)
101 switch elm.Kind() { 102 switch elm.Interface().(type) {
102 case reflect.Int8: 103 case int8:
103 ft = TypeBitField 104 ft = TypeBitField
104 case reflect.Int16: 105 case int16:
105 ft = TypeSmallIntegerField 106 ft = TypeSmallIntegerField
106 case reflect.Int32, reflect.Int: 107 case int32, int:
107 ft = TypeIntegerField 108 ft = TypeIntegerField
108 case reflect.Int64: 109 case int64, sql.NullInt64:
109 ft = TypeBigIntegerField 110 ft = TypeBigIntegerField
110 case reflect.Uint8: 111 case uint8:
111 ft = TypePositiveBitField 112 ft = TypePositiveBitField
112 case reflect.Uint16: 113 case uint16:
113 ft = TypePositiveSmallIntegerField 114 ft = TypePositiveSmallIntegerField
114 case reflect.Uint32, reflect.Uint: 115 case uint32, uint:
115 ft = TypePositiveIntegerField 116 ft = TypePositiveIntegerField
116 case reflect.Uint64: 117 case uint64:
117 ft = TypePositiveBigIntegerField 118 ft = TypePositiveBigIntegerField
118 case reflect.Float32, reflect.Float64: 119 case float32, float64, sql.NullFloat64:
119 ft = TypeFloatField 120 ft = TypeFloatField
120 case reflect.Bool: 121 case bool, sql.NullBool:
121 ft = TypeBooleanField 122 ft = TypeBooleanField
122 case reflect.String: 123 case string, sql.NullString:
123 ft = TypeCharField 124 ft = TypeCharField
124 case reflect.Invalid:
125 default: 125 default:
126 if elm.CanInterface() { 126 if elm.CanInterface() {
127 if _, ok := elm.Interface().(time.Time); ok { 127 if _, ok := elm.Interface().(time.Time); ok {
......
...@@ -2,6 +2,7 @@ package orm ...@@ -2,6 +2,7 @@ package orm
2 2
3 import ( 3 import (
4 "bytes" 4 "bytes"
5 "database/sql"
5 "fmt" 6 "fmt"
6 "io/ioutil" 7 "io/ioutil"
7 "os" 8 "os"
...@@ -258,12 +259,45 @@ func TestNullDataTypes(t *testing.T) { ...@@ -258,12 +259,45 @@ func TestNullDataTypes(t *testing.T) {
258 err = dORM.Read(&d) 259 err = dORM.Read(&d)
259 throwFail(t, err) 260 throwFail(t, err)
260 261
262 throwFail(t, AssertIs(d.NullBool.Valid, false))
263 throwFail(t, AssertIs(d.NullString.Valid, false))
264 throwFail(t, AssertIs(d.NullInt64.Valid, false))
265 throwFail(t, AssertIs(d.NullFloat64.Valid, false))
266
261 _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec() 267 _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec()
262 throwFail(t, err) 268 throwFail(t, err)
263 269
264 d = DataNull{Id: 2} 270 d = DataNull{Id: 2}
265 err = dORM.Read(&d) 271 err = dORM.Read(&d)
266 throwFail(t, err) 272 throwFail(t, err)
273
274 d = DataNull{
275 DateTime: time.Now(),
276 NullString: sql.NullString{"test", true},
277 NullBool: sql.NullBool{true, true},
278 NullInt64: sql.NullInt64{42, true},
279 NullFloat64: sql.NullFloat64{42.42, true},
280 }
281
282 id, err = dORM.Insert(&d)
283 throwFail(t, err)
284 throwFail(t, AssertIs(id, 3))
285
286 d = DataNull{Id: 3}
287 err = dORM.Read(&d)
288 throwFail(t, err)
289
290 throwFail(t, AssertIs(d.NullBool.Valid, true))
291 throwFail(t, AssertIs(d.NullBool.Bool, true))
292
293 throwFail(t, AssertIs(d.NullString.Valid, true))
294 throwFail(t, AssertIs(d.NullString.String, "test"))
295
296 throwFail(t, AssertIs(d.NullInt64.Valid, true))
297 throwFail(t, AssertIs(d.NullInt64.Int64, 42))
298
299 throwFail(t, AssertIs(d.NullFloat64.Valid, true))
300 throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42))
267 } 301 }
268 302
269 func TestCRUD(t *testing.T) { 303 func TestCRUD(t *testing.T) {
...@@ -1646,10 +1680,10 @@ func TestTransaction(t *testing.T) { ...@@ -1646,10 +1680,10 @@ func TestTransaction(t *testing.T) {
1646 func TestReadOrCreate(t *testing.T) { 1680 func TestReadOrCreate(t *testing.T) {
1647 u := &User{ 1681 u := &User{
1648 UserName: "Kyle", 1682 UserName: "Kyle",
1649 Email: "kylemcc@gmail.com", 1683 Email: "kylemcc@gmail.com",
1650 Password: "other_pass", 1684 Password: "other_pass",
1651 Status: 7, 1685 Status: 7,
1652 IsStaff: false, 1686 IsStaff: false,
1653 IsActive: true, 1687 IsActive: true,
1654 } 1688 }
1655 1689
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!