github.com/astaxie/beego@v1.12.3/orm/models_utils.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package orm 16 17 import ( 18 "database/sql" 19 "fmt" 20 "reflect" 21 "strings" 22 "time" 23 ) 24 25 // 1 is attr 26 // 2 is tag 27 var supportTag = map[string]int{ 28 "-": 1, 29 "null": 1, 30 "index": 1, 31 "unique": 1, 32 "pk": 1, 33 "auto": 1, 34 "auto_now": 1, 35 "auto_now_add": 1, 36 "size": 2, 37 "column": 2, 38 "default": 2, 39 "rel": 2, 40 "reverse": 2, 41 "rel_table": 2, 42 "rel_through": 2, 43 "digits": 2, 44 "decimals": 2, 45 "on_delete": 2, 46 "type": 2, 47 "description": 2, 48 } 49 50 // get reflect.Type name with package path. 51 func getFullName(typ reflect.Type) string { 52 return typ.PkgPath() + "." + typ.Name() 53 } 54 55 // getTableName get struct table name. 56 // If the struct implement the TableName, then get the result as tablename 57 // else use the struct name which will apply snakeString. 58 func getTableName(val reflect.Value) string { 59 if fun := val.MethodByName("TableName"); fun.IsValid() { 60 vals := fun.Call([]reflect.Value{}) 61 // has return and the first val is string 62 if len(vals) > 0 && vals[0].Kind() == reflect.String { 63 return vals[0].String() 64 } 65 } 66 return snakeString(reflect.Indirect(val).Type().Name()) 67 } 68 69 // get table engine, myisam or innodb. 70 func getTableEngine(val reflect.Value) string { 71 fun := val.MethodByName("TableEngine") 72 if fun.IsValid() { 73 vals := fun.Call([]reflect.Value{}) 74 if len(vals) > 0 && vals[0].Kind() == reflect.String { 75 return vals[0].String() 76 } 77 } 78 return "" 79 } 80 81 // get table index from method. 82 func getTableIndex(val reflect.Value) [][]string { 83 fun := val.MethodByName("TableIndex") 84 if fun.IsValid() { 85 vals := fun.Call([]reflect.Value{}) 86 if len(vals) > 0 && vals[0].CanInterface() { 87 if d, ok := vals[0].Interface().([][]string); ok { 88 return d 89 } 90 } 91 } 92 return nil 93 } 94 95 // get table unique from method 96 func getTableUnique(val reflect.Value) [][]string { 97 fun := val.MethodByName("TableUnique") 98 if fun.IsValid() { 99 vals := fun.Call([]reflect.Value{}) 100 if len(vals) > 0 && vals[0].CanInterface() { 101 if d, ok := vals[0].Interface().([][]string); ok { 102 return d 103 } 104 } 105 } 106 return nil 107 } 108 109 // get snaked column name 110 func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string { 111 column := col 112 if col == "" { 113 column = nameStrategyMap[nameStrategy](sf.Name) 114 } 115 switch ft { 116 case RelForeignKey, RelOneToOne: 117 if len(col) == 0 { 118 column = column + "_id" 119 } 120 case RelManyToMany, RelReverseMany, RelReverseOne: 121 column = sf.Name 122 } 123 return column 124 } 125 126 // return field type as type constant from reflect.Value 127 func getFieldType(val reflect.Value) (ft int, err error) { 128 switch val.Type() { 129 case reflect.TypeOf(new(int8)): 130 ft = TypeBitField 131 case reflect.TypeOf(new(int16)): 132 ft = TypeSmallIntegerField 133 case reflect.TypeOf(new(int32)), 134 reflect.TypeOf(new(int)): 135 ft = TypeIntegerField 136 case reflect.TypeOf(new(int64)): 137 ft = TypeBigIntegerField 138 case reflect.TypeOf(new(uint8)): 139 ft = TypePositiveBitField 140 case reflect.TypeOf(new(uint16)): 141 ft = TypePositiveSmallIntegerField 142 case reflect.TypeOf(new(uint32)), 143 reflect.TypeOf(new(uint)): 144 ft = TypePositiveIntegerField 145 case reflect.TypeOf(new(uint64)): 146 ft = TypePositiveBigIntegerField 147 case reflect.TypeOf(new(float32)), 148 reflect.TypeOf(new(float64)): 149 ft = TypeFloatField 150 case reflect.TypeOf(new(bool)): 151 ft = TypeBooleanField 152 case reflect.TypeOf(new(string)): 153 ft = TypeVarCharField 154 case reflect.TypeOf(new(time.Time)): 155 ft = TypeDateTimeField 156 default: 157 elm := reflect.Indirect(val) 158 switch elm.Kind() { 159 case reflect.Int8: 160 ft = TypeBitField 161 case reflect.Int16: 162 ft = TypeSmallIntegerField 163 case reflect.Int32, reflect.Int: 164 ft = TypeIntegerField 165 case reflect.Int64: 166 ft = TypeBigIntegerField 167 case reflect.Uint8: 168 ft = TypePositiveBitField 169 case reflect.Uint16: 170 ft = TypePositiveSmallIntegerField 171 case reflect.Uint32, reflect.Uint: 172 ft = TypePositiveIntegerField 173 case reflect.Uint64: 174 ft = TypePositiveBigIntegerField 175 case reflect.Float32, reflect.Float64: 176 ft = TypeFloatField 177 case reflect.Bool: 178 ft = TypeBooleanField 179 case reflect.String: 180 ft = TypeVarCharField 181 default: 182 if elm.Interface() == nil { 183 panic(fmt.Errorf("%s is nil pointer, may be miss setting tag", val)) 184 } 185 switch elm.Interface().(type) { 186 case sql.NullInt64: 187 ft = TypeBigIntegerField 188 case sql.NullFloat64: 189 ft = TypeFloatField 190 case sql.NullBool: 191 ft = TypeBooleanField 192 case sql.NullString: 193 ft = TypeVarCharField 194 case time.Time: 195 ft = TypeDateTimeField 196 } 197 } 198 } 199 if ft&IsFieldType == 0 { 200 err = fmt.Errorf("unsupport field type %s, may be miss setting tag", val) 201 } 202 return 203 } 204 205 // parse struct tag string 206 func parseStructTag(data string) (attrs map[string]bool, tags map[string]string) { 207 attrs = make(map[string]bool) 208 tags = make(map[string]string) 209 for _, v := range strings.Split(data, defaultStructTagDelim) { 210 if v == "" { 211 continue 212 } 213 v = strings.TrimSpace(v) 214 if t := strings.ToLower(v); supportTag[t] == 1 { 215 attrs[t] = true 216 } else if i := strings.Index(v, "("); i > 0 && strings.Index(v, ")") == len(v)-1 { 217 name := t[:i] 218 if supportTag[name] == 2 { 219 v = v[i+1 : len(v)-1] 220 tags[name] = v 221 } 222 } else { 223 DebugLog.Println("unsupport orm tag", v) 224 } 225 } 226 return 227 }