Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle https://xorm.io
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

311 lines
7.1 KiB

  1. // Copyright 2017 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package xorm
  5. import (
  6. "fmt"
  7. "reflect"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "xorm.io/core"
  12. )
  13. type tagContext struct {
  14. tagName string
  15. params []string
  16. preTag, nextTag string
  17. table *core.Table
  18. col *core.Column
  19. fieldValue reflect.Value
  20. isIndex bool
  21. isUnique bool
  22. indexNames map[string]int
  23. engine *Engine
  24. hasCacheTag bool
  25. hasNoCacheTag bool
  26. ignoreNext bool
  27. }
  28. // tagHandler describes tag handler for XORM
  29. type tagHandler func(ctx *tagContext) error
  30. var (
  31. // defaultTagHandlers enumerates all the default tag handler
  32. defaultTagHandlers = map[string]tagHandler{
  33. "<-": OnlyFromDBTagHandler,
  34. "->": OnlyToDBTagHandler,
  35. "PK": PKTagHandler,
  36. "NULL": NULLTagHandler,
  37. "NOT": IgnoreTagHandler,
  38. "AUTOINCR": AutoIncrTagHandler,
  39. "DEFAULT": DefaultTagHandler,
  40. "CREATED": CreatedTagHandler,
  41. "UPDATED": UpdatedTagHandler,
  42. "DELETED": DeletedTagHandler,
  43. "VERSION": VersionTagHandler,
  44. "UTC": UTCTagHandler,
  45. "LOCAL": LocalTagHandler,
  46. "NOTNULL": NotNullTagHandler,
  47. "INDEX": IndexTagHandler,
  48. "UNIQUE": UniqueTagHandler,
  49. "CACHE": CacheTagHandler,
  50. "NOCACHE": NoCacheTagHandler,
  51. "COMMENT": CommentTagHandler,
  52. }
  53. )
  54. func init() {
  55. for k := range core.SqlTypes {
  56. defaultTagHandlers[k] = SQLTypeTagHandler
  57. }
  58. }
  59. // IgnoreTagHandler describes ignored tag handler
  60. func IgnoreTagHandler(ctx *tagContext) error {
  61. return nil
  62. }
  63. // OnlyFromDBTagHandler describes mapping direction tag handler
  64. func OnlyFromDBTagHandler(ctx *tagContext) error {
  65. ctx.col.MapType = core.ONLYFROMDB
  66. return nil
  67. }
  68. // OnlyToDBTagHandler describes mapping direction tag handler
  69. func OnlyToDBTagHandler(ctx *tagContext) error {
  70. ctx.col.MapType = core.ONLYTODB
  71. return nil
  72. }
  73. // PKTagHandler decribes primary key tag handler
  74. func PKTagHandler(ctx *tagContext) error {
  75. ctx.col.IsPrimaryKey = true
  76. ctx.col.Nullable = false
  77. return nil
  78. }
  79. // NULLTagHandler describes null tag handler
  80. func NULLTagHandler(ctx *tagContext) error {
  81. ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
  82. return nil
  83. }
  84. // NotNullTagHandler describes notnull tag handler
  85. func NotNullTagHandler(ctx *tagContext) error {
  86. ctx.col.Nullable = false
  87. return nil
  88. }
  89. // AutoIncrTagHandler describes autoincr tag handler
  90. func AutoIncrTagHandler(ctx *tagContext) error {
  91. ctx.col.IsAutoIncrement = true
  92. /*
  93. if len(ctx.params) > 0 {
  94. autoStartInt, err := strconv.Atoi(ctx.params[0])
  95. if err != nil {
  96. return err
  97. }
  98. ctx.col.AutoIncrStart = autoStartInt
  99. } else {
  100. ctx.col.AutoIncrStart = 1
  101. }
  102. */
  103. return nil
  104. }
  105. // DefaultTagHandler describes default tag handler
  106. func DefaultTagHandler(ctx *tagContext) error {
  107. if len(ctx.params) > 0 {
  108. ctx.col.Default = ctx.params[0]
  109. } else {
  110. ctx.col.Default = ctx.nextTag
  111. ctx.ignoreNext = true
  112. }
  113. return nil
  114. }
  115. // CreatedTagHandler describes created tag handler
  116. func CreatedTagHandler(ctx *tagContext) error {
  117. ctx.col.IsCreated = true
  118. return nil
  119. }
  120. // VersionTagHandler describes version tag handler
  121. func VersionTagHandler(ctx *tagContext) error {
  122. ctx.col.IsVersion = true
  123. ctx.col.Default = "1"
  124. return nil
  125. }
  126. // UTCTagHandler describes utc tag handler
  127. func UTCTagHandler(ctx *tagContext) error {
  128. ctx.col.TimeZone = time.UTC
  129. return nil
  130. }
  131. // LocalTagHandler describes local tag handler
  132. func LocalTagHandler(ctx *tagContext) error {
  133. if len(ctx.params) == 0 {
  134. ctx.col.TimeZone = time.Local
  135. } else {
  136. var err error
  137. ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
  138. if err != nil {
  139. return err
  140. }
  141. }
  142. return nil
  143. }
  144. // UpdatedTagHandler describes updated tag handler
  145. func UpdatedTagHandler(ctx *tagContext) error {
  146. ctx.col.IsUpdated = true
  147. return nil
  148. }
  149. // DeletedTagHandler describes deleted tag handler
  150. func DeletedTagHandler(ctx *tagContext) error {
  151. ctx.col.IsDeleted = true
  152. return nil
  153. }
  154. // IndexTagHandler describes index tag handler
  155. func IndexTagHandler(ctx *tagContext) error {
  156. if len(ctx.params) > 0 {
  157. ctx.indexNames[ctx.params[0]] = core.IndexType
  158. } else {
  159. ctx.isIndex = true
  160. }
  161. return nil
  162. }
  163. // UniqueTagHandler describes unique tag handler
  164. func UniqueTagHandler(ctx *tagContext) error {
  165. if len(ctx.params) > 0 {
  166. ctx.indexNames[ctx.params[0]] = core.UniqueType
  167. } else {
  168. ctx.isUnique = true
  169. }
  170. return nil
  171. }
  172. // CommentTagHandler add comment to column
  173. func CommentTagHandler(ctx *tagContext) error {
  174. if len(ctx.params) > 0 {
  175. ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
  176. }
  177. return nil
  178. }
  179. // SQLTypeTagHandler describes SQL Type tag handler
  180. func SQLTypeTagHandler(ctx *tagContext) error {
  181. ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
  182. if len(ctx.params) > 0 {
  183. if ctx.tagName == core.Enum {
  184. ctx.col.EnumOptions = make(map[string]int)
  185. for k, v := range ctx.params {
  186. v = strings.TrimSpace(v)
  187. v = strings.Trim(v, "'")
  188. ctx.col.EnumOptions[v] = k
  189. }
  190. } else if ctx.tagName == core.Set {
  191. ctx.col.SetOptions = make(map[string]int)
  192. for k, v := range ctx.params {
  193. v = strings.TrimSpace(v)
  194. v = strings.Trim(v, "'")
  195. ctx.col.SetOptions[v] = k
  196. }
  197. } else {
  198. var err error
  199. if len(ctx.params) == 2 {
  200. ctx.col.Length, err = strconv.Atoi(ctx.params[0])
  201. if err != nil {
  202. return err
  203. }
  204. ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
  205. if err != nil {
  206. return err
  207. }
  208. } else if len(ctx.params) == 1 {
  209. ctx.col.Length, err = strconv.Atoi(ctx.params[0])
  210. if err != nil {
  211. return err
  212. }
  213. }
  214. }
  215. }
  216. return nil
  217. }
  218. // ExtendsTagHandler describes extends tag handler
  219. func ExtendsTagHandler(ctx *tagContext) error {
  220. var fieldValue = ctx.fieldValue
  221. var isPtr = false
  222. switch fieldValue.Kind() {
  223. case reflect.Ptr:
  224. f := fieldValue.Type().Elem()
  225. if f.Kind() == reflect.Struct {
  226. fieldPtr := fieldValue
  227. fieldValue = fieldValue.Elem()
  228. if !fieldValue.IsValid() || fieldPtr.IsNil() {
  229. fieldValue = reflect.New(f).Elem()
  230. }
  231. }
  232. isPtr = true
  233. fallthrough
  234. case reflect.Struct:
  235. parentTable, err := ctx.engine.mapType(fieldValue)
  236. if err != nil {
  237. return err
  238. }
  239. for _, col := range parentTable.Columns() {
  240. col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
  241. var tagPrefix = ctx.col.FieldName
  242. if len(ctx.params) > 0 {
  243. col.Nullable = isPtr
  244. tagPrefix = ctx.params[0]
  245. if col.IsPrimaryKey {
  246. col.Name = ctx.col.FieldName
  247. col.IsPrimaryKey = false
  248. } else {
  249. col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name)
  250. }
  251. }
  252. if col.Nullable {
  253. col.IsAutoIncrement = false
  254. col.IsPrimaryKey = false
  255. }
  256. ctx.table.AddColumn(col)
  257. for indexName, indexType := range col.Indexes {
  258. addIndex(indexName, ctx.table, col, indexType)
  259. }
  260. }
  261. default:
  262. //TODO: warning
  263. }
  264. return nil
  265. }
  266. // CacheTagHandler describes cache tag handler
  267. func CacheTagHandler(ctx *tagContext) error {
  268. if !ctx.hasCacheTag {
  269. ctx.hasCacheTag = true
  270. }
  271. return nil
  272. }
  273. // NoCacheTagHandler describes nocache tag handler
  274. func NoCacheTagHandler(ctx *tagContext) error {
  275. if !ctx.hasNoCacheTag {
  276. ctx.hasNoCacheTag = true
  277. }
  278. return nil
  279. }