THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

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.

312 lines
7.1KB

  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. ctx.col.DefaultIsEmpty = false
  114. return nil
  115. }
  116. // CreatedTagHandler describes created tag handler
  117. func CreatedTagHandler(ctx *tagContext) error {
  118. ctx.col.IsCreated = true
  119. return nil
  120. }
  121. // VersionTagHandler describes version tag handler
  122. func VersionTagHandler(ctx *tagContext) error {
  123. ctx.col.IsVersion = true
  124. ctx.col.Default = "1"
  125. return nil
  126. }
  127. // UTCTagHandler describes utc tag handler
  128. func UTCTagHandler(ctx *tagContext) error {
  129. ctx.col.TimeZone = time.UTC
  130. return nil
  131. }
  132. // LocalTagHandler describes local tag handler
  133. func LocalTagHandler(ctx *tagContext) error {
  134. if len(ctx.params) == 0 {
  135. ctx.col.TimeZone = time.Local
  136. } else {
  137. var err error
  138. ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
  139. if err != nil {
  140. return err
  141. }
  142. }
  143. return nil
  144. }
  145. // UpdatedTagHandler describes updated tag handler
  146. func UpdatedTagHandler(ctx *tagContext) error {
  147. ctx.col.IsUpdated = true
  148. return nil
  149. }
  150. // DeletedTagHandler describes deleted tag handler
  151. func DeletedTagHandler(ctx *tagContext) error {
  152. ctx.col.IsDeleted = true
  153. return nil
  154. }
  155. // IndexTagHandler describes index tag handler
  156. func IndexTagHandler(ctx *tagContext) error {
  157. if len(ctx.params) > 0 {
  158. ctx.indexNames[ctx.params[0]] = core.IndexType
  159. } else {
  160. ctx.isIndex = true
  161. }
  162. return nil
  163. }
  164. // UniqueTagHandler describes unique tag handler
  165. func UniqueTagHandler(ctx *tagContext) error {
  166. if len(ctx.params) > 0 {
  167. ctx.indexNames[ctx.params[0]] = core.UniqueType
  168. } else {
  169. ctx.isUnique = true
  170. }
  171. return nil
  172. }
  173. // CommentTagHandler add comment to column
  174. func CommentTagHandler(ctx *tagContext) error {
  175. if len(ctx.params) > 0 {
  176. ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
  177. }
  178. return nil
  179. }
  180. // SQLTypeTagHandler describes SQL Type tag handler
  181. func SQLTypeTagHandler(ctx *tagContext) error {
  182. ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
  183. if len(ctx.params) > 0 {
  184. if ctx.tagName == core.Enum {
  185. ctx.col.EnumOptions = make(map[string]int)
  186. for k, v := range ctx.params {
  187. v = strings.TrimSpace(v)
  188. v = strings.Trim(v, "'")
  189. ctx.col.EnumOptions[v] = k
  190. }
  191. } else if ctx.tagName == core.Set {
  192. ctx.col.SetOptions = make(map[string]int)
  193. for k, v := range ctx.params {
  194. v = strings.TrimSpace(v)
  195. v = strings.Trim(v, "'")
  196. ctx.col.SetOptions[v] = k
  197. }
  198. } else {
  199. var err error
  200. if len(ctx.params) == 2 {
  201. ctx.col.Length, err = strconv.Atoi(ctx.params[0])
  202. if err != nil {
  203. return err
  204. }
  205. ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
  206. if err != nil {
  207. return err
  208. }
  209. } else if len(ctx.params) == 1 {
  210. ctx.col.Length, err = strconv.Atoi(ctx.params[0])
  211. if err != nil {
  212. return err
  213. }
  214. }
  215. }
  216. }
  217. return nil
  218. }
  219. // ExtendsTagHandler describes extends tag handler
  220. func ExtendsTagHandler(ctx *tagContext) error {
  221. var fieldValue = ctx.fieldValue
  222. var isPtr = false
  223. switch fieldValue.Kind() {
  224. case reflect.Ptr:
  225. f := fieldValue.Type().Elem()
  226. if f.Kind() == reflect.Struct {
  227. fieldPtr := fieldValue
  228. fieldValue = fieldValue.Elem()
  229. if !fieldValue.IsValid() || fieldPtr.IsNil() {
  230. fieldValue = reflect.New(f).Elem()
  231. }
  232. }
  233. isPtr = true
  234. fallthrough
  235. case reflect.Struct:
  236. parentTable, err := ctx.engine.mapType(fieldValue)
  237. if err != nil {
  238. return err
  239. }
  240. for _, col := range parentTable.Columns() {
  241. col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
  242. var tagPrefix = ctx.col.FieldName
  243. if len(ctx.params) > 0 {
  244. col.Nullable = isPtr
  245. tagPrefix = ctx.params[0]
  246. if col.IsPrimaryKey {
  247. col.Name = ctx.col.FieldName
  248. col.IsPrimaryKey = false
  249. } else {
  250. col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name)
  251. }
  252. }
  253. if col.Nullable {
  254. col.IsAutoIncrement = false
  255. col.IsPrimaryKey = false
  256. }
  257. ctx.table.AddColumn(col)
  258. for indexName, indexType := range col.Indexes {
  259. addIndex(indexName, ctx.table, col, indexType)
  260. }
  261. }
  262. default:
  263. //TODO: warning
  264. }
  265. return nil
  266. }
  267. // CacheTagHandler describes cache tag handler
  268. func CacheTagHandler(ctx *tagContext) error {
  269. if !ctx.hasCacheTag {
  270. ctx.hasCacheTag = true
  271. }
  272. return nil
  273. }
  274. // NoCacheTagHandler describes nocache tag handler
  275. func NoCacheTagHandler(ctx *tagContext) error {
  276. if !ctx.hasNoCacheTag {
  277. ctx.hasNoCacheTag = true
  278. }
  279. return nil
  280. }