orm now support custom builtin types as model struct field or query args fix #489
Showing
4 changed files
with
160 additions
and
65 deletions
| ... | @@ -51,9 +51,16 @@ outFor: | ... | @@ -51,9 +51,16 @@ outFor: |
| 51 | continue | 51 | continue |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | switch v := arg.(type) { | 54 | kind := val.Kind() |
| 55 | case []byte: | 55 | if kind == reflect.Ptr { |
| 56 | case string: | 56 | val = val.Elem() |
| 57 | kind = val.Kind() | ||
| 58 | arg = val.Interface() | ||
| 59 | } | ||
| 60 | |||
| 61 | switch kind { | ||
| 62 | case reflect.String: | ||
| 63 | v := val.String() | ||
| 57 | if fi != nil { | 64 | if fi != nil { |
| 58 | if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { | 65 | if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { |
| 59 | var t time.Time | 66 | var t time.Time |
| ... | @@ -78,61 +85,66 @@ outFor: | ... | @@ -78,61 +85,66 @@ outFor: |
| 78 | } | 85 | } |
| 79 | } | 86 | } |
| 80 | arg = v | 87 | arg = v |
| 81 | case time.Time: | 88 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| 82 | if fi != nil && fi.fieldType == TypeDateField { | 89 | arg = val.Int() |
| 83 | arg = v.In(tz).Format(format_Date) | 90 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| 84 | } else { | 91 | arg = val.Uint() |
| 85 | arg = v.In(tz).Format(format_DateTime) | 92 | case reflect.Float32: |
| 93 | arg, _ = StrTo(ToStr(arg)).Float64() | ||
| 94 | case reflect.Float64: | ||
| 95 | arg = val.Float() | ||
| 96 | case reflect.Bool: | ||
| 97 | arg = val.Bool() | ||
| 98 | case reflect.Slice, reflect.Array: | ||
| 99 | if _, ok := arg.([]byte); ok { | ||
| 100 | continue outFor | ||
| 86 | } | 101 | } |
| 87 | default: | ||
| 88 | kind := val.Kind() | ||
| 89 | switch kind { | ||
| 90 | case reflect.Slice, reflect.Array: | ||
| 91 | |||
| 92 | var args []interface{} | ||
| 93 | for i := 0; i < val.Len(); i++ { | ||
| 94 | v := val.Index(i) | ||
| 95 | |||
| 96 | var vu interface{} | ||
| 97 | if v.CanInterface() { | ||
| 98 | vu = v.Interface() | ||
| 99 | } | ||
| 100 | 102 | ||
| 101 | if vu == nil { | 103 | var args []interface{} |
| 102 | continue | 104 | for i := 0; i < val.Len(); i++ { |
| 103 | } | 105 | v := val.Index(i) |
| 104 | 106 | ||
| 105 | args = append(args, vu) | 107 | var vu interface{} |
| 108 | if v.CanInterface() { | ||
| 109 | vu = v.Interface() | ||
| 106 | } | 110 | } |
| 107 | 111 | ||
| 108 | if len(args) > 0 { | 112 | if vu == nil { |
| 109 | p := getFlatParams(fi, args, tz) | 113 | continue |
| 110 | params = append(params, p...) | ||
| 111 | } | 114 | } |
| 112 | continue outFor | ||
| 113 | 115 | ||
| 114 | case reflect.Ptr, reflect.Struct: | 116 | args = append(args, vu) |
| 115 | ind := reflect.Indirect(val) | 117 | } |
| 116 | 118 | ||
| 117 | if ind.Kind() == reflect.Struct { | 119 | if len(args) > 0 { |
| 118 | typ := ind.Type() | 120 | p := getFlatParams(fi, args, tz) |
| 119 | name := getFullName(typ) | 121 | params = append(params, p...) |
| 120 | var value interface{} | 122 | } |
| 121 | if mmi, ok := modelCache.getByFN(name); ok { | 123 | continue outFor |
| 122 | if _, vu, exist := getExistPk(mmi, ind); exist { | 124 | case reflect.Struct: |
| 123 | value = vu | 125 | if v, ok := arg.(time.Time); ok { |
| 124 | } | 126 | if fi != nil && fi.fieldType == TypeDateField { |
| 127 | arg = v.In(tz).Format(format_Date) | ||
| 128 | } else { | ||
| 129 | arg = v.In(tz).Format(format_DateTime) | ||
| 130 | } | ||
| 131 | } else { | ||
| 132 | typ := val.Type() | ||
| 133 | name := getFullName(typ) | ||
| 134 | var value interface{} | ||
| 135 | if mmi, ok := modelCache.getByFN(name); ok { | ||
| 136 | if _, vu, exist := getExistPk(mmi, val); exist { | ||
| 137 | value = vu | ||
| 125 | } | 138 | } |
| 126 | arg = value | 139 | } |
| 140 | arg = value | ||
| 127 | 141 | ||
| 128 | if arg == nil { | 142 | if arg == nil { |
| 129 | panic(fmt.Errorf("need a valid args value, unknown table or value `%s`", name)) | 143 | panic(fmt.Errorf("need a valid args value, unknown table or value `%s`", name)) |
| 130 | } | ||
| 131 | } else { | ||
| 132 | arg = ind.Interface() | ||
| 133 | } | 144 | } |
| 134 | } | 145 | } |
| 135 | } | 146 | } |
| 147 | |||
| 136 | params = append(params, arg) | 148 | params = append(params, arg) |
| 137 | } | 149 | } |
| 138 | return | 150 | return | ... | ... |
| ... | @@ -144,6 +144,45 @@ type DataNull struct { | ... | @@ -144,6 +144,45 @@ type DataNull struct { |
| 144 | NullInt64 sql.NullInt64 `orm:"null"` | 144 | NullInt64 sql.NullInt64 `orm:"null"` |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | type String string | ||
| 148 | type Boolean bool | ||
| 149 | type Byte byte | ||
| 150 | type Rune rune | ||
| 151 | type Int int | ||
| 152 | type Int8 int8 | ||
| 153 | type Int16 int16 | ||
| 154 | type Int32 int32 | ||
| 155 | type Int64 int64 | ||
| 156 | type Uint uint | ||
| 157 | type Uint8 uint8 | ||
| 158 | type Uint16 uint16 | ||
| 159 | type Uint32 uint32 | ||
| 160 | type Uint64 uint64 | ||
| 161 | type Float32 float64 | ||
| 162 | type Float64 float64 | ||
| 163 | |||
| 164 | type DataCustom struct { | ||
| 165 | Id int | ||
| 166 | Boolean Boolean | ||
| 167 | Char string `orm:"size(50)"` | ||
| 168 | Text string `orm:"type(text)"` | ||
| 169 | Byte Byte | ||
| 170 | Rune Rune | ||
| 171 | Int Int | ||
| 172 | Int8 Int8 | ||
| 173 | Int16 Int16 | ||
| 174 | Int32 Int32 | ||
| 175 | Int64 Int64 | ||
| 176 | Uint Uint | ||
| 177 | Uint8 Uint8 | ||
| 178 | Uint16 Uint16 | ||
| 179 | Uint32 Uint32 | ||
| 180 | Uint64 Uint64 | ||
| 181 | Float32 Float32 | ||
| 182 | Float64 Float64 | ||
| 183 | Decimal Float64 `orm:"digits(8);decimals(4)"` | ||
| 184 | } | ||
| 185 | |||
| 147 | // only for mysql | 186 | // only for mysql |
| 148 | type UserBig struct { | 187 | type UserBig struct { |
| 149 | Id uint64 | 188 | Id uint64 | ... | ... |
| ... | @@ -99,34 +99,41 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col | ... | @@ -99,34 +99,41 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col |
| 99 | // return field type as type constant from reflect.Value | 99 | // return field type as type constant from reflect.Value |
| 100 | func getFieldType(val reflect.Value) (ft int, err error) { | 100 | func getFieldType(val reflect.Value) (ft int, err error) { |
| 101 | elm := reflect.Indirect(val) | 101 | elm := reflect.Indirect(val) |
| 102 | switch elm.Interface().(type) { | 102 | switch elm.Kind() { |
| 103 | case int8: | 103 | case reflect.Int8: |
| 104 | ft = TypeBitField | 104 | ft = TypeBitField |
| 105 | case int16: | 105 | case reflect.Int16: |
| 106 | ft = TypeSmallIntegerField | 106 | ft = TypeSmallIntegerField |
| 107 | case int32, int: | 107 | case reflect.Int32, reflect.Int: |
| 108 | ft = TypeIntegerField | 108 | ft = TypeIntegerField |
| 109 | case int64, sql.NullInt64: | 109 | case reflect.Int64: |
| 110 | ft = TypeBigIntegerField | 110 | ft = TypeBigIntegerField |
| 111 | case uint8: | 111 | case reflect.Uint8: |
| 112 | ft = TypePositiveBitField | 112 | ft = TypePositiveBitField |
| 113 | case uint16: | 113 | case reflect.Uint16: |
| 114 | ft = TypePositiveSmallIntegerField | 114 | ft = TypePositiveSmallIntegerField |
| 115 | case uint32, uint: | 115 | case reflect.Uint32, reflect.Uint: |
| 116 | ft = TypePositiveIntegerField | 116 | ft = TypePositiveIntegerField |
| 117 | case uint64: | 117 | case reflect.Uint64: |
| 118 | ft = TypePositiveBigIntegerField | 118 | ft = TypePositiveBigIntegerField |
| 119 | case float32, float64, sql.NullFloat64: | 119 | case reflect.Float32, reflect.Float64: |
| 120 | ft = TypeFloatField | 120 | ft = TypeFloatField |
| 121 | case bool, sql.NullBool: | 121 | case reflect.Bool: |
| 122 | ft = TypeBooleanField | 122 | ft = TypeBooleanField |
| 123 | case string, sql.NullString: | 123 | case reflect.String: |
| 124 | ft = TypeCharField | 124 | ft = TypeCharField |
| 125 | default: | 125 | default: |
| 126 | if elm.CanInterface() { | 126 | switch elm.Interface().(type) { |
| 127 | if _, ok := elm.Interface().(time.Time); ok { | 127 | case sql.NullInt64: |
| 128 | ft = TypeDateTimeField | 128 | ft = TypeBigIntegerField |
| 129 | } | 129 | case sql.NullFloat64: |
| 130 | ft = TypeFloatField | ||
| 131 | case sql.NullBool: | ||
| 132 | ft = TypeBooleanField | ||
| 133 | case sql.NullString: | ||
| 134 | ft = TypeCharField | ||
| 135 | case time.Time: | ||
| 136 | ft = TypeDateTimeField | ||
| 130 | } | 137 | } |
| 131 | } | 138 | } |
| 132 | if ft&IsFieldType == 0 { | 139 | if ft&IsFieldType == 0 { | ... | ... |
| ... | @@ -149,7 +149,7 @@ func TestGetDB(t *testing.T) { | ... | @@ -149,7 +149,7 @@ func TestGetDB(t *testing.T) { |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | func TestSyncDb(t *testing.T) { | 151 | func TestSyncDb(t *testing.T) { |
| 152 | RegisterModel(new(Data), new(DataNull)) | 152 | RegisterModel(new(Data), new(DataNull), new(DataCustom)) |
| 153 | RegisterModel(new(User)) | 153 | RegisterModel(new(User)) |
| 154 | RegisterModel(new(Profile)) | 154 | RegisterModel(new(Profile)) |
| 155 | RegisterModel(new(Post)) | 155 | RegisterModel(new(Post)) |
| ... | @@ -165,7 +165,7 @@ func TestSyncDb(t *testing.T) { | ... | @@ -165,7 +165,7 @@ func TestSyncDb(t *testing.T) { |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | func TestRegisterModels(t *testing.T) { | 167 | func TestRegisterModels(t *testing.T) { |
| 168 | RegisterModel(new(Data), new(DataNull)) | 168 | RegisterModel(new(Data), new(DataNull), new(DataCustom)) |
| 169 | RegisterModel(new(User)) | 169 | RegisterModel(new(User)) |
| 170 | RegisterModel(new(Profile)) | 170 | RegisterModel(new(Profile)) |
| 171 | RegisterModel(new(Post)) | 171 | RegisterModel(new(Post)) |
| ... | @@ -309,6 +309,39 @@ func TestNullDataTypes(t *testing.T) { | ... | @@ -309,6 +309,39 @@ func TestNullDataTypes(t *testing.T) { |
| 309 | throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42)) | 309 | throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42)) |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | func TestDataCustomTypes(t *testing.T) { | ||
| 313 | d := DataCustom{} | ||
| 314 | ind := reflect.Indirect(reflect.ValueOf(&d)) | ||
| 315 | |||
| 316 | for name, value := range Data_Values { | ||
| 317 | e := ind.FieldByName(name) | ||
| 318 | if !e.IsValid() { | ||
| 319 | continue | ||
| 320 | } | ||
| 321 | e.Set(reflect.ValueOf(value).Convert(e.Type())) | ||
| 322 | } | ||
| 323 | |||
| 324 | id, err := dORM.Insert(&d) | ||
| 325 | throwFail(t, err) | ||
| 326 | throwFail(t, AssertIs(id, 1)) | ||
| 327 | |||
| 328 | d = DataCustom{Id: 1} | ||
| 329 | err = dORM.Read(&d) | ||
| 330 | throwFail(t, err) | ||
| 331 | |||
| 332 | ind = reflect.Indirect(reflect.ValueOf(&d)) | ||
| 333 | |||
| 334 | for name, value := range Data_Values { | ||
| 335 | e := ind.FieldByName(name) | ||
| 336 | if !e.IsValid() { | ||
| 337 | continue | ||
| 338 | } | ||
| 339 | vu := e.Interface() | ||
| 340 | value = reflect.ValueOf(value).Convert(e.Type()).Interface() | ||
| 341 | throwFail(t, AssertIs(vu == value, true), value, vu) | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 312 | func TestCRUD(t *testing.T) { | 345 | func TestCRUD(t *testing.T) { |
| 313 | profile := NewProfile() | 346 | profile := NewProfile() |
| 314 | profile.Age = 30 | 347 | profile.Age = 30 |
| ... | @@ -562,6 +595,10 @@ func TestOperators(t *testing.T) { | ... | @@ -562,6 +595,10 @@ func TestOperators(t *testing.T) { |
| 562 | throwFail(t, err) | 595 | throwFail(t, err) |
| 563 | throwFail(t, AssertIs(num, 1)) | 596 | throwFail(t, AssertIs(num, 1)) |
| 564 | 597 | ||
| 598 | num, err = qs.Filter("user_name__exact", String("slene")).Count() | ||
| 599 | throwFail(t, err) | ||
| 600 | throwFail(t, AssertIs(num, 1)) | ||
| 601 | |||
| 565 | num, err = qs.Filter("user_name__exact", "slene").Count() | 602 | num, err = qs.Filter("user_name__exact", "slene").Count() |
| 566 | throwFail(t, err) | 603 | throwFail(t, err) |
| 567 | throwFail(t, AssertIs(num, 1)) | 604 | throwFail(t, AssertIs(num, 1)) |
| ... | @@ -602,11 +639,11 @@ func TestOperators(t *testing.T) { | ... | @@ -602,11 +639,11 @@ func TestOperators(t *testing.T) { |
| 602 | throwFail(t, err) | 639 | throwFail(t, err) |
| 603 | throwFail(t, AssertIs(num, 3)) | 640 | throwFail(t, AssertIs(num, 3)) |
| 604 | 641 | ||
| 605 | num, err = qs.Filter("status__lt", 3).Count() | 642 | num, err = qs.Filter("status__lt", Uint(3)).Count() |
| 606 | throwFail(t, err) | 643 | throwFail(t, err) |
| 607 | throwFail(t, AssertIs(num, 2)) | 644 | throwFail(t, AssertIs(num, 2)) |
| 608 | 645 | ||
| 609 | num, err = qs.Filter("status__lte", 3).Count() | 646 | num, err = qs.Filter("status__lte", Int(3)).Count() |
| 610 | throwFail(t, err) | 647 | throwFail(t, err) |
| 611 | throwFail(t, AssertIs(num, 3)) | 648 | throwFail(t, AssertIs(num, 3)) |
| 612 | 649 | ... | ... |
-
Please register or sign in to post a comment