123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // Copyright 2014 beego Author. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package orm
- import (
- "database/sql"
- "fmt"
- "reflect"
- "strings"
- "time"
- )
- // 1 is attr
- // 2 is tag
- var supportTag = map[string]int{
- "-": 1,
- "null": 1,
- "index": 1,
- "unique": 1,
- "pk": 1,
- "auto": 1,
- "auto_now": 1,
- "auto_now_add": 1,
- "size": 2,
- "column": 2,
- "default": 2,
- "rel": 2,
- "reverse": 2,
- "rel_table": 2,
- "rel_through": 2,
- "digits": 2,
- "decimals": 2,
- "on_delete": 2,
- "type": 2,
- }
- // get reflect.Type name with package path.
- func getFullName(typ reflect.Type) string {
- return typ.PkgPath() + "." + typ.Name()
- }
- // getTableName get struct table name.
- // If the struct implement the TableName, then get the result as tablename
- // else use the struct name which will apply snakeString.
- func getTableName(val reflect.Value) string {
- if fun := val.MethodByName("TableName"); fun.IsValid() {
- vals := fun.Call([]reflect.Value{})
- // has return and the first val is string
- if len(vals) > 0 && vals[0].Kind() == reflect.String {
- return vals[0].String()
- }
- }
- return snakeString(reflect.Indirect(val).Type().Name())
- }
- // get table engine, mysiam or innodb.
- func getTableEngine(val reflect.Value) string {
- fun := val.MethodByName("TableEngine")
- if fun.IsValid() {
- vals := fun.Call([]reflect.Value{})
- if len(vals) > 0 && vals[0].Kind() == reflect.String {
- return vals[0].String()
- }
- }
- return ""
- }
- // get table index from method.
- func getTableIndex(val reflect.Value) [][]string {
- fun := val.MethodByName("TableIndex")
- if fun.IsValid() {
- vals := fun.Call([]reflect.Value{})
- if len(vals) > 0 && vals[0].CanInterface() {
- if d, ok := vals[0].Interface().([][]string); ok {
- return d
- }
- }
- }
- return nil
- }
- // get table unique from method
- func getTableUnique(val reflect.Value) [][]string {
- fun := val.MethodByName("TableUnique")
- if fun.IsValid() {
- vals := fun.Call([]reflect.Value{})
- if len(vals) > 0 && vals[0].CanInterface() {
- if d, ok := vals[0].Interface().([][]string); ok {
- return d
- }
- }
- }
- return nil
- }
- // get snaked column name
- func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string {
- column := col
- if col == "" {
- column = snakeString(sf.Name)
- }
- switch ft {
- case RelForeignKey, RelOneToOne:
- if len(col) == 0 {
- column = column + "_id"
- }
- case RelManyToMany, RelReverseMany, RelReverseOne:
- column = sf.Name
- }
- return column
- }
- // return field type as type constant from reflect.Value
- func getFieldType(val reflect.Value) (ft int, err error) {
- switch val.Type() {
- case reflect.TypeOf(new(int8)):
- ft = TypeBitField
- case reflect.TypeOf(new(int16)):
- ft = TypeSmallIntegerField
- case reflect.TypeOf(new(int32)),
- reflect.TypeOf(new(int)):
- ft = TypeIntegerField
- case reflect.TypeOf(new(int64)):
- ft = TypeBigIntegerField
- case reflect.TypeOf(new(uint8)):
- ft = TypePositiveBitField
- case reflect.TypeOf(new(uint16)):
- ft = TypePositiveSmallIntegerField
- case reflect.TypeOf(new(uint32)),
- reflect.TypeOf(new(uint)):
- ft = TypePositiveIntegerField
- case reflect.TypeOf(new(uint64)):
- ft = TypePositiveBigIntegerField
- case reflect.TypeOf(new(float32)),
- reflect.TypeOf(new(float64)):
- ft = TypeFloatField
- case reflect.TypeOf(new(bool)):
- ft = TypeBooleanField
- case reflect.TypeOf(new(string)):
- ft = TypeCharField
- case reflect.TypeOf(new(time.Time)):
- ft = TypeDateTimeField
- default:
- elm := reflect.Indirect(val)
- switch elm.Kind() {
- case reflect.Int8:
- ft = TypeBitField
- case reflect.Int16:
- ft = TypeSmallIntegerField
- case reflect.Int32, reflect.Int:
- ft = TypeIntegerField
- case reflect.Int64:
- ft = TypeBigIntegerField
- case reflect.Uint8:
- ft = TypePositiveBitField
- case reflect.Uint16:
- ft = TypePositiveSmallIntegerField
- case reflect.Uint32, reflect.Uint:
- ft = TypePositiveIntegerField
- case reflect.Uint64:
- ft = TypePositiveBigIntegerField
- case reflect.Float32, reflect.Float64:
- ft = TypeFloatField
- case reflect.Bool:
- ft = TypeBooleanField
- case reflect.String:
- ft = TypeCharField
- default:
- if elm.Interface() == nil {
- panic(fmt.Errorf("%s is nil pointer, may be miss setting tag", val))
- }
- switch elm.Interface().(type) {
- case sql.NullInt64:
- ft = TypeBigIntegerField
- case sql.NullFloat64:
- ft = TypeFloatField
- case sql.NullBool:
- ft = TypeBooleanField
- case sql.NullString:
- ft = TypeCharField
- case time.Time:
- ft = TypeDateTimeField
- }
- }
- }
- if ft&IsFieldType == 0 {
- err = fmt.Errorf("unsupport field type %s, may be miss setting tag", val)
- }
- return
- }
- // parse struct tag string
- func parseStructTag(data string) (attrs map[string]bool, tags map[string]string) {
- attrs = make(map[string]bool)
- tags = make(map[string]string)
- for _, v := range strings.Split(data, defaultStructTagDelim) {
- if v == "" {
- continue
- }
- v = strings.TrimSpace(v)
- if t := strings.ToLower(v); supportTag[t] == 1 {
- attrs[t] = true
- } else if i := strings.Index(v, "("); i > 0 && strings.Index(v, ")") == len(v)-1 {
- name := t[:i]
- if supportTag[name] == 2 {
- v = v[i+1 : len(v)-1]
- tags[name] = v
- }
- } else {
- DebugLog.Println("unsupport orm tag", v)
- }
- }
- return
- }
|