models_utils.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. package orm
  15. import (
  16. "database/sql"
  17. "fmt"
  18. "reflect"
  19. "strings"
  20. "time"
  21. )
  22. // 1 is attr
  23. // 2 is tag
  24. var supportTag = map[string]int{
  25. "-": 1,
  26. "null": 1,
  27. "index": 1,
  28. "unique": 1,
  29. "pk": 1,
  30. "auto": 1,
  31. "auto_now": 1,
  32. "auto_now_add": 1,
  33. "size": 2,
  34. "column": 2,
  35. "default": 2,
  36. "rel": 2,
  37. "reverse": 2,
  38. "rel_table": 2,
  39. "rel_through": 2,
  40. "digits": 2,
  41. "decimals": 2,
  42. "on_delete": 2,
  43. "type": 2,
  44. }
  45. // get reflect.Type name with package path.
  46. func getFullName(typ reflect.Type) string {
  47. return typ.PkgPath() + "." + typ.Name()
  48. }
  49. // getTableName get struct table name.
  50. // If the struct implement the TableName, then get the result as tablename
  51. // else use the struct name which will apply snakeString.
  52. func getTableName(val reflect.Value) string {
  53. if fun := val.MethodByName("TableName"); fun.IsValid() {
  54. vals := fun.Call([]reflect.Value{})
  55. // has return and the first val is string
  56. if len(vals) > 0 && vals[0].Kind() == reflect.String {
  57. return vals[0].String()
  58. }
  59. }
  60. return snakeString(reflect.Indirect(val).Type().Name())
  61. }
  62. // get table engine, mysiam or innodb.
  63. func getTableEngine(val reflect.Value) string {
  64. fun := val.MethodByName("TableEngine")
  65. if fun.IsValid() {
  66. vals := fun.Call([]reflect.Value{})
  67. if len(vals) > 0 && vals[0].Kind() == reflect.String {
  68. return vals[0].String()
  69. }
  70. }
  71. return ""
  72. }
  73. // get table index from method.
  74. func getTableIndex(val reflect.Value) [][]string {
  75. fun := val.MethodByName("TableIndex")
  76. if fun.IsValid() {
  77. vals := fun.Call([]reflect.Value{})
  78. if len(vals) > 0 && vals[0].CanInterface() {
  79. if d, ok := vals[0].Interface().([][]string); ok {
  80. return d
  81. }
  82. }
  83. }
  84. return nil
  85. }
  86. // get table unique from method
  87. func getTableUnique(val reflect.Value) [][]string {
  88. fun := val.MethodByName("TableUnique")
  89. if fun.IsValid() {
  90. vals := fun.Call([]reflect.Value{})
  91. if len(vals) > 0 && vals[0].CanInterface() {
  92. if d, ok := vals[0].Interface().([][]string); ok {
  93. return d
  94. }
  95. }
  96. }
  97. return nil
  98. }
  99. // get snaked column name
  100. func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string {
  101. column := col
  102. if col == "" {
  103. column = snakeString(sf.Name)
  104. }
  105. switch ft {
  106. case RelForeignKey, RelOneToOne:
  107. if len(col) == 0 {
  108. column = column + "_id"
  109. }
  110. case RelManyToMany, RelReverseMany, RelReverseOne:
  111. column = sf.Name
  112. }
  113. return column
  114. }
  115. // return field type as type constant from reflect.Value
  116. func getFieldType(val reflect.Value) (ft int, err error) {
  117. switch val.Type() {
  118. case reflect.TypeOf(new(int8)):
  119. ft = TypeBitField
  120. case reflect.TypeOf(new(int16)):
  121. ft = TypeSmallIntegerField
  122. case reflect.TypeOf(new(int32)),
  123. reflect.TypeOf(new(int)):
  124. ft = TypeIntegerField
  125. case reflect.TypeOf(new(int64)):
  126. ft = TypeBigIntegerField
  127. case reflect.TypeOf(new(uint8)):
  128. ft = TypePositiveBitField
  129. case reflect.TypeOf(new(uint16)):
  130. ft = TypePositiveSmallIntegerField
  131. case reflect.TypeOf(new(uint32)),
  132. reflect.TypeOf(new(uint)):
  133. ft = TypePositiveIntegerField
  134. case reflect.TypeOf(new(uint64)):
  135. ft = TypePositiveBigIntegerField
  136. case reflect.TypeOf(new(float32)),
  137. reflect.TypeOf(new(float64)):
  138. ft = TypeFloatField
  139. case reflect.TypeOf(new(bool)):
  140. ft = TypeBooleanField
  141. case reflect.TypeOf(new(string)):
  142. ft = TypeCharField
  143. case reflect.TypeOf(new(time.Time)):
  144. ft = TypeDateTimeField
  145. default:
  146. elm := reflect.Indirect(val)
  147. switch elm.Kind() {
  148. case reflect.Int8:
  149. ft = TypeBitField
  150. case reflect.Int16:
  151. ft = TypeSmallIntegerField
  152. case reflect.Int32, reflect.Int:
  153. ft = TypeIntegerField
  154. case reflect.Int64:
  155. ft = TypeBigIntegerField
  156. case reflect.Uint8:
  157. ft = TypePositiveBitField
  158. case reflect.Uint16:
  159. ft = TypePositiveSmallIntegerField
  160. case reflect.Uint32, reflect.Uint:
  161. ft = TypePositiveIntegerField
  162. case reflect.Uint64:
  163. ft = TypePositiveBigIntegerField
  164. case reflect.Float32, reflect.Float64:
  165. ft = TypeFloatField
  166. case reflect.Bool:
  167. ft = TypeBooleanField
  168. case reflect.String:
  169. ft = TypeCharField
  170. default:
  171. if elm.Interface() == nil {
  172. panic(fmt.Errorf("%s is nil pointer, may be miss setting tag", val))
  173. }
  174. switch elm.Interface().(type) {
  175. case sql.NullInt64:
  176. ft = TypeBigIntegerField
  177. case sql.NullFloat64:
  178. ft = TypeFloatField
  179. case sql.NullBool:
  180. ft = TypeBooleanField
  181. case sql.NullString:
  182. ft = TypeCharField
  183. case time.Time:
  184. ft = TypeDateTimeField
  185. }
  186. }
  187. }
  188. if ft&IsFieldType == 0 {
  189. err = fmt.Errorf("unsupport field type %s, may be miss setting tag", val)
  190. }
  191. return
  192. }
  193. // parse struct tag string
  194. func parseStructTag(data string) (attrs map[string]bool, tags map[string]string) {
  195. attrs = make(map[string]bool)
  196. tags = make(map[string]string)
  197. for _, v := range strings.Split(data, defaultStructTagDelim) {
  198. if v == "" {
  199. continue
  200. }
  201. v = strings.TrimSpace(v)
  202. if t := strings.ToLower(v); supportTag[t] == 1 {
  203. attrs[t] = true
  204. } else if i := strings.Index(v, "("); i > 0 && strings.Index(v, ")") == len(v)-1 {
  205. name := t[:i]
  206. if supportTag[name] == 2 {
  207. v = v[i+1 : len(v)-1]
  208. tags[name] = v
  209. }
  210. } else {
  211. DebugLog.Println("unsupport orm tag", v)
  212. }
  213. }
  214. return
  215. }