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