tag.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. "github.com/go-xorm/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. }
  52. )
  53. func init() {
  54. for k := range core.SqlTypes {
  55. defaultTagHandlers[k] = SQLTypeTagHandler
  56. }
  57. }
  58. // IgnoreTagHandler describes ignored tag handler
  59. func IgnoreTagHandler(ctx *tagContext) error {
  60. return nil
  61. }
  62. // OnlyFromDBTagHandler describes mapping direction tag handler
  63. func OnlyFromDBTagHandler(ctx *tagContext) error {
  64. ctx.col.MapType = core.ONLYFROMDB
  65. return nil
  66. }
  67. // OnlyToDBTagHandler describes mapping direction tag handler
  68. func OnlyToDBTagHandler(ctx *tagContext) error {
  69. ctx.col.MapType = core.ONLYTODB
  70. return nil
  71. }
  72. // PKTagHandler decribes primary key tag handler
  73. func PKTagHandler(ctx *tagContext) error {
  74. ctx.col.IsPrimaryKey = true
  75. ctx.col.Nullable = false
  76. return nil
  77. }
  78. // NULLTagHandler describes null tag handler
  79. func NULLTagHandler(ctx *tagContext) error {
  80. ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
  81. return nil
  82. }
  83. // NotNullTagHandler describes notnull tag handler
  84. func NotNullTagHandler(ctx *tagContext) error {
  85. ctx.col.Nullable = false
  86. return nil
  87. }
  88. // AutoIncrTagHandler describes autoincr tag handler
  89. func AutoIncrTagHandler(ctx *tagContext) error {
  90. ctx.col.IsAutoIncrement = true
  91. /*
  92. if len(ctx.params) > 0 {
  93. autoStartInt, err := strconv.Atoi(ctx.params[0])
  94. if err != nil {
  95. return err
  96. }
  97. ctx.col.AutoIncrStart = autoStartInt
  98. } else {
  99. ctx.col.AutoIncrStart = 1
  100. }
  101. */
  102. return nil
  103. }
  104. // DefaultTagHandler describes default tag handler
  105. func DefaultTagHandler(ctx *tagContext) error {
  106. if len(ctx.params) > 0 {
  107. ctx.col.Default = ctx.params[0]
  108. } else {
  109. ctx.col.Default = ctx.nextTag
  110. ctx.ignoreNext = true
  111. }
  112. return nil
  113. }
  114. // CreatedTagHandler describes created tag handler
  115. func CreatedTagHandler(ctx *tagContext) error {
  116. ctx.col.IsCreated = true
  117. return nil
  118. }
  119. // VersionTagHandler describes version tag handler
  120. func VersionTagHandler(ctx *tagContext) error {
  121. ctx.col.IsVersion = true
  122. ctx.col.Default = "1"
  123. return nil
  124. }
  125. // UTCTagHandler describes utc tag handler
  126. func UTCTagHandler(ctx *tagContext) error {
  127. ctx.col.TimeZone = time.UTC
  128. return nil
  129. }
  130. // LocalTagHandler describes local tag handler
  131. func LocalTagHandler(ctx *tagContext) error {
  132. if len(ctx.params) == 0 {
  133. ctx.col.TimeZone = time.Local
  134. } else {
  135. var err error
  136. ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
  137. if err != nil {
  138. return err
  139. }
  140. }
  141. return nil
  142. }
  143. // UpdatedTagHandler describes updated tag handler
  144. func UpdatedTagHandler(ctx *tagContext) error {
  145. ctx.col.IsUpdated = true
  146. return nil
  147. }
  148. // DeletedTagHandler describes deleted tag handler
  149. func DeletedTagHandler(ctx *tagContext) error {
  150. ctx.col.IsDeleted = true
  151. return nil
  152. }
  153. // IndexTagHandler describes index tag handler
  154. func IndexTagHandler(ctx *tagContext) error {
  155. if len(ctx.params) > 0 {
  156. ctx.indexNames[ctx.params[0]] = core.IndexType
  157. } else {
  158. ctx.isIndex = true
  159. }
  160. return nil
  161. }
  162. // UniqueTagHandler describes unique tag handler
  163. func UniqueTagHandler(ctx *tagContext) error {
  164. if len(ctx.params) > 0 {
  165. ctx.indexNames[ctx.params[0]] = core.UniqueType
  166. } else {
  167. ctx.isUnique = true
  168. }
  169. return nil
  170. }
  171. // SQLTypeTagHandler describes SQL Type tag handler
  172. func SQLTypeTagHandler(ctx *tagContext) error {
  173. ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
  174. if len(ctx.params) > 0 {
  175. if ctx.tagName == core.Enum {
  176. ctx.col.EnumOptions = make(map[string]int)
  177. for k, v := range ctx.params {
  178. v = strings.TrimSpace(v)
  179. v = strings.Trim(v, "'")
  180. ctx.col.EnumOptions[v] = k
  181. }
  182. } else if ctx.tagName == core.Set {
  183. ctx.col.SetOptions = make(map[string]int)
  184. for k, v := range ctx.params {
  185. v = strings.TrimSpace(v)
  186. v = strings.Trim(v, "'")
  187. ctx.col.SetOptions[v] = k
  188. }
  189. } else {
  190. var err error
  191. if len(ctx.params) == 2 {
  192. ctx.col.Length, err = strconv.Atoi(ctx.params[0])
  193. if err != nil {
  194. return err
  195. }
  196. ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
  197. if err != nil {
  198. return err
  199. }
  200. } else if len(ctx.params) == 1 {
  201. ctx.col.Length, err = strconv.Atoi(ctx.params[0])
  202. if err != nil {
  203. return err
  204. }
  205. }
  206. }
  207. }
  208. return nil
  209. }
  210. // ExtendsTagHandler describes extends tag handler
  211. func ExtendsTagHandler(ctx *tagContext) error {
  212. var fieldValue = ctx.fieldValue
  213. switch fieldValue.Kind() {
  214. case reflect.Ptr:
  215. f := fieldValue.Type().Elem()
  216. if f.Kind() == reflect.Struct {
  217. fieldPtr := fieldValue
  218. fieldValue = fieldValue.Elem()
  219. if !fieldValue.IsValid() || fieldPtr.IsNil() {
  220. fieldValue = reflect.New(f).Elem()
  221. }
  222. }
  223. fallthrough
  224. case reflect.Struct:
  225. parentTable, err := ctx.engine.mapType(fieldValue)
  226. if err != nil {
  227. return err
  228. }
  229. for _, col := range parentTable.Columns() {
  230. col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
  231. ctx.table.AddColumn(col)
  232. for indexName, indexType := range col.Indexes {
  233. addIndex(indexName, ctx.table, col, indexType)
  234. }
  235. }
  236. default:
  237. //TODO: warning
  238. }
  239. return nil
  240. }
  241. // CacheTagHandler describes cache tag handler
  242. func CacheTagHandler(ctx *tagContext) error {
  243. if !ctx.hasCacheTag {
  244. ctx.hasCacheTag = true
  245. }
  246. return nil
  247. }
  248. // NoCacheTagHandler describes nocache tag handler
  249. func NoCacheTagHandler(ctx *tagContext) error {
  250. if !ctx.hasNoCacheTag {
  251. ctx.hasNoCacheTag = true
  252. }
  253. return nil
  254. }