column.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // Copyright 2019 Yunion
  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 sqlchemy
  15. import (
  16. "fmt"
  17. "strconv"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/pkg/gotypes"
  20. "yunion.io/x/pkg/utils"
  21. )
  22. // IColumnSpec is an interface that represents a column of a table
  23. type IColumnSpec interface {
  24. // Name returns the name of the column
  25. Name() string
  26. // ColType returns type of the column, e.g. INTEGER, VARCHAR
  27. ColType() string
  28. // Default returns default value of the column, represents in string
  29. Default() string
  30. // IsSupportDefault returns whether this column supports being given a default value
  31. IsSupportDefault() bool
  32. // IsNullable returns whether this column is nullable
  33. IsNullable() bool
  34. // SetNullable sets this column as nullable
  35. SetNullable(on bool)
  36. // IsPrimary returns whether this column is part of the primary keys
  37. IsPrimary() bool
  38. SetPrimary(on bool)
  39. // IsUnique returns whether the value of this column unique for each row
  40. IsUnique() bool
  41. // IsIndex returns whether this column is indexable, if it is true, a index of this column will be automatically created
  42. IsIndex() bool
  43. // ExtraDefs returns some extra column attribute definitions, not covered by the standard fields
  44. ExtraDefs() string
  45. // DefinitionString return the SQL presentation of this column
  46. DefinitionString() string
  47. // IsText returns whether this column is actually a text, such a Datetime column is actually a text
  48. IsText() bool
  49. // IsSearchable returns whether this column is searchable, e.g. a integer column is not searchable, but a text field is searchable
  50. IsSearchable() bool
  51. // IsAscii returns whether this column is an ASCII type text, if true, the column should be compared with a UTF8 string
  52. IsAscii() bool
  53. // IsNumeric returns whether this column is a numeric type column, e.g. integer or float
  54. IsNumeric() bool
  55. GetWidth() int
  56. // ConvertFromString returns the SQL representation of a value in string format for this column
  57. ConvertFromString(str string) interface{}
  58. // ConvertToString(str string) string
  59. // ConvertFromValue returns the SQL representation of a value for this column
  60. ConvertFromValue(val interface{}) interface{}
  61. // ConvertToValue(str interface{}) interface{}
  62. // IsZero is used to determine a value is the zero value for this column
  63. IsZero(val interface{}) bool
  64. // AllowZero returns whether this column allow a zero value
  65. AllowZero() bool
  66. // IsEqual(v1, v2 interface{}) bool
  67. // Tags returns the field tags for this column, which is in the struct definition
  68. Tags() map[string]string
  69. // IsPointer returns whether this column is a pointer type definition, e.g. *int, *bool
  70. IsPointer() bool
  71. // SetDefault sets the default value in the format of string for this column
  72. SetDefault(defStr string)
  73. // IsAutoVersion
  74. IsAutoVersion() bool
  75. // IsUpdatedAt
  76. IsUpdatedAt() bool
  77. // IsCreatedAt
  78. IsCreatedAt() bool
  79. // IsAutoIncrement
  80. IsAutoIncrement() bool
  81. AutoIncrementOffset() int64
  82. SetAutoIncrement(val bool)
  83. SetAutoIncrementOffset(offset int64)
  84. IsString() bool
  85. IsDateTime() bool
  86. // index of column, to preserve the column position
  87. GetColIndex() int
  88. // setter of column index
  89. SetColIndex(idx int)
  90. }
  91. type iColumnInternal interface {
  92. IColumnSpec
  93. Oldname() string
  94. }
  95. // SBaseColumn is the base structure represents a column
  96. type SBaseColumn struct {
  97. name string
  98. dbName string
  99. oldName string
  100. sqlType string
  101. defaultString string
  102. isPointer bool
  103. isNullable bool
  104. isPrimary bool
  105. isUnique bool
  106. isIndex bool
  107. isAllowZero bool
  108. tags map[string]string
  109. colIndex int
  110. }
  111. // IsPointer implementation of SBaseColumn for IColumnSpec
  112. func (c *SBaseColumn) IsPointer() bool {
  113. return c.isPointer
  114. }
  115. // Name implementation of SBaseColumn for IColumnSpec
  116. func (c *SBaseColumn) Name() string {
  117. if len(c.dbName) > 0 {
  118. return c.dbName
  119. }
  120. return c.name
  121. }
  122. // Name implementation of SBaseColumn for IColumnSpec
  123. func (c *SBaseColumn) Oldname() string {
  124. return c.oldName
  125. }
  126. // ColType implementation of SBaseColumn for IColumnSpec
  127. func (c *SBaseColumn) ColType() string {
  128. return c.sqlType
  129. }
  130. // Default implementation of SBaseColumn for IColumnSpec
  131. func (c *SBaseColumn) Default() string {
  132. return c.defaultString
  133. }
  134. // SetDefault implementation of SBaseColumn for IColumnSpec
  135. func (c *SBaseColumn) SetDefault(defStr string) {
  136. c.defaultString = defStr
  137. }
  138. // IsSupportDefault implementation of SBaseColumn for IColumnSpec
  139. func (c *SBaseColumn) IsSupportDefault() bool {
  140. return true
  141. }
  142. // IsNullable implementation of SBaseColumn for IColumnSpec
  143. func (c *SBaseColumn) IsNullable() bool {
  144. return c.isNullable
  145. }
  146. // SetNullable implementation of SBaseColumn for IColumnSpec
  147. func (c *SBaseColumn) SetNullable(on bool) {
  148. c.isNullable = on
  149. }
  150. // IsPrimary implementation of SBaseColumn for IColumnSpec
  151. func (c *SBaseColumn) IsPrimary() bool {
  152. return c.isPrimary
  153. }
  154. func (c *SBaseColumn) SetPrimary(on bool) {
  155. c.isPrimary = on
  156. }
  157. // IsUnique implementation of SBaseColumn for IColumnSpec
  158. func (c *SBaseColumn) IsUnique() bool {
  159. return c.isUnique
  160. }
  161. // IsIndex implementation of SBaseColumn for IColumnSpec
  162. func (c *SBaseColumn) IsIndex() bool {
  163. return c.isIndex
  164. }
  165. // ExtraDefs implementation of SBaseColumn for IColumnSpec
  166. func (c *SBaseColumn) ExtraDefs() string {
  167. return ""
  168. }
  169. // IsText implementation of SBaseColumn for IColumnSpec
  170. func (c *SBaseColumn) IsText() bool {
  171. return false
  172. }
  173. // IsAscii implementation of SBaseColumn for IColumnSpec
  174. func (c *SBaseColumn) IsAscii() bool {
  175. return false
  176. }
  177. // IsSearchable implementation of SBaseColumn for IColumnSpec
  178. func (c *SBaseColumn) IsSearchable() bool {
  179. return false
  180. }
  181. // IsNumeric implementation of SBaseColumn for IColumnSpec
  182. func (c *SBaseColumn) IsNumeric() bool {
  183. return false
  184. }
  185. // AllowZero implementation of SBaseColumn for IColumnSpec
  186. func (c *SBaseColumn) AllowZero() bool {
  187. return c.isAllowZero
  188. }
  189. // ConvertFromString implementation of SBaseColumn for IColumnSpec
  190. //func (c *SBaseColumn) ConvertFromString(str string) interface{} {
  191. // return str
  192. //}
  193. // ConvertFromValue implementation of SBaseColumn for IColumnSpec
  194. func (c *SBaseColumn) ConvertFromValue(val interface{}) interface{} {
  195. return val
  196. }
  197. // Tags implementation of SBaseColumn for IColumnSpec
  198. func (c *SBaseColumn) Tags() map[string]string {
  199. return c.tags
  200. }
  201. func (c *SBaseColumn) IsAutoVersion() bool {
  202. return false
  203. }
  204. func (c *SBaseColumn) IsUpdatedAt() bool {
  205. return false
  206. }
  207. func (c *SBaseColumn) IsCreatedAt() bool {
  208. return false
  209. }
  210. func (c *SBaseColumn) IsAutoIncrement() bool {
  211. return false
  212. }
  213. func (c *SBaseColumn) AutoIncrementOffset() int64 {
  214. return 0
  215. }
  216. func (c *SBaseColumn) SetAutoIncrement(val bool) {
  217. }
  218. func (c *SBaseColumn) SetAutoIncrementOffset(offset int64) {
  219. }
  220. func (c *SBaseColumn) IsString() bool {
  221. return false
  222. }
  223. func (c *SBaseColumn) IsDateTime() bool {
  224. return false
  225. }
  226. func (c *SBaseColumn) GetColIndex() int {
  227. return c.colIndex
  228. }
  229. func (c *SBaseColumn) SetColIndex(idx int) {
  230. c.colIndex = idx
  231. }
  232. func (c *SBaseColumn) GetWidth() int {
  233. return 0
  234. }
  235. // NewBaseColumn returns an instance of SBaseColumn
  236. func NewBaseColumn(name string, sqltype string, tagmap map[string]string, isPointer bool) SBaseColumn {
  237. var val string
  238. var ok bool
  239. dbName := ""
  240. tagmap, val, ok = utils.TagPop(tagmap, TAG_NAME)
  241. if ok {
  242. dbName = val
  243. }
  244. tagmap, val, ok = utils.TagPop(tagmap, TAG_SQL_NAME)
  245. if ok {
  246. dbName = val
  247. }
  248. oldName := ""
  249. tagmap, val, ok = utils.TagPop(tagmap, TAG_OLD_NAME)
  250. if ok {
  251. oldName = val
  252. }
  253. defStr := ""
  254. tagmap, val, ok = utils.TagPop(tagmap, TAG_DEFAULT)
  255. if ok {
  256. defStr = val
  257. }
  258. isNullable := true
  259. tagmap, val, ok = utils.TagPop(tagmap, TAG_NULLABLE)
  260. if ok {
  261. isNullable = utils.ToBool(val)
  262. }
  263. isPrimary := false
  264. tagmap, val, ok = utils.TagPop(tagmap, TAG_PRIMARY)
  265. if ok {
  266. isPrimary = utils.ToBool(val)
  267. }
  268. isUnique := false
  269. tagmap, val, ok = utils.TagPop(tagmap, TAG_UNIQUE)
  270. if ok {
  271. isUnique = utils.ToBool(val)
  272. }
  273. isIndex := false
  274. tagmap, val, ok = utils.TagPop(tagmap, TAG_INDEX)
  275. if ok {
  276. isIndex = utils.ToBool(val)
  277. }
  278. if isPrimary {
  279. isNullable = false
  280. }
  281. isAllowZero := false
  282. tagmap, val, ok = utils.TagPop(tagmap, TAG_ALLOW_ZERO)
  283. if ok {
  284. isAllowZero = utils.ToBool(val)
  285. }
  286. return SBaseColumn{
  287. name: name,
  288. dbName: dbName,
  289. oldName: oldName,
  290. sqlType: sqltype,
  291. defaultString: defStr,
  292. isNullable: isNullable,
  293. isPrimary: isPrimary,
  294. isUnique: isUnique,
  295. isIndex: isIndex,
  296. tags: tagmap,
  297. isPointer: isPointer,
  298. isAllowZero: isAllowZero,
  299. colIndex: -1,
  300. }
  301. }
  302. // SBaseWidthColumn represents a type of column that with width attribute, such as VARCHAR(20), INT(10)
  303. type SBaseWidthColumn struct {
  304. SBaseColumn
  305. width int
  306. }
  307. // ColType implementation of SBaseWidthColumn for IColumnSpec
  308. func (c *SBaseWidthColumn) ColType() string {
  309. if c.width > 0 {
  310. return fmt.Sprintf("%s(%d)", c.sqlType, c.width)
  311. }
  312. return c.sqlType
  313. }
  314. func (c *SBaseWidthColumn) GetWidth() int {
  315. return c.width
  316. }
  317. // NewBaseWidthColumn return an instance of SBaseWidthColumn
  318. func NewBaseWidthColumn(name string, sqltype string, tagmap map[string]string, isPointer bool) SBaseWidthColumn {
  319. width := 0
  320. tagmap, v, ok := utils.TagPop(tagmap, TAG_WIDTH)
  321. if ok {
  322. width, _ = strconv.Atoi(v)
  323. }
  324. wc := SBaseWidthColumn{
  325. SBaseColumn: NewBaseColumn(name, sqltype, tagmap, isPointer),
  326. width: width,
  327. }
  328. return wc
  329. }
  330. type SBaseCompoundColumn struct{}
  331. // ConvertFromString implementation of CompoundColumn for IColumnSpec
  332. func (c *SBaseCompoundColumn) ConvertFromString(str string) interface{} {
  333. json, err := jsonutils.ParseString(str)
  334. if err != nil {
  335. json = jsonutils.JSONNull
  336. }
  337. return json.String()
  338. }
  339. // ConvertFromValue implementation of CompoundColumn for IColumnSpec
  340. func (c *SBaseCompoundColumn) ConvertFromValue(val interface{}) interface{} {
  341. bVal, ok := val.(gotypes.ISerializable)
  342. if ok && bVal != nil {
  343. return bVal.String()
  344. }
  345. if _, ok := val.(string); ok {
  346. return val
  347. }
  348. return jsonutils.Marshal(val).String()
  349. }