/loader/mysql.go

https://github.com/xo/xo · Go · 151 lines · 136 code · 6 blank · 9 comment · 32 complexity · fa3f95df65c369c2a90057632a80915e MD5 · raw file

  1. package loader
  2. import (
  3. "context"
  4. "regexp"
  5. "strings"
  6. "github.com/xo/xo/models"
  7. xo "github.com/xo/xo/types"
  8. )
  9. func init() {
  10. Register("mysql", Loader{
  11. Mask: "?",
  12. Schema: models.MysqlSchema,
  13. Enums: models.MysqlEnums,
  14. EnumValues: MysqlEnumValues,
  15. Procs: models.MysqlProcs,
  16. ProcParams: models.MysqlProcParams,
  17. Tables: models.MysqlTables,
  18. TableColumns: models.MysqlTableColumns,
  19. TableSequences: models.MysqlTableSequences,
  20. TableForeignKeys: models.MysqlTableForeignKeys,
  21. TableIndexes: models.MysqlTableIndexes,
  22. IndexColumns: models.MysqlIndexColumns,
  23. ViewCreate: models.MysqlViewCreate,
  24. ViewDrop: models.MysqlViewDrop,
  25. })
  26. }
  27. // MysqlGoType parse a mysql type into a Go type based on the column
  28. // definition.
  29. func MysqlGoType(d xo.Type, schema, itype, utype string) (string, string, error) {
  30. var goType, zero string
  31. switch d.Type {
  32. case "bit":
  33. switch {
  34. case d.Prec == 1 && !d.Nullable:
  35. goType, zero = "bool", "false"
  36. case d.Prec == 1 && d.Nullable:
  37. goType, zero = "sql.NullBool", "sql.NullBool{}"
  38. case d.Prec <= 8 && !d.Nullable:
  39. goType, zero = "uint8", "0"
  40. case d.Prec <= 16 && !d.Nullable:
  41. goType, zero = "uint16", "0"
  42. case d.Prec <= 32 && !d.Nullable:
  43. goType, zero = "uint32", "0"
  44. case d.Nullable:
  45. goType, zero = "sql.NullInt64", "sql.NullInt64{}"
  46. default:
  47. goType, zero = "uint64", "0"
  48. }
  49. case "bool", "boolean":
  50. goType, zero = "bool", "false"
  51. if d.Nullable {
  52. goType, zero = "sql.NullBool", "sql.NullBool{}"
  53. }
  54. case "char", "varchar", "tinytext", "text", "mediumtext", "longtext":
  55. goType, zero = "string", `""`
  56. if d.Nullable {
  57. goType, zero = "sql.NullString", "sql.NullString{}"
  58. }
  59. case "tinyint":
  60. switch {
  61. case d.Prec == 1 && !d.Nullable: // force tinyint(1) as bool
  62. goType, zero = "bool", "false"
  63. case d.Prec == 1 && d.Nullable:
  64. goType, zero = "sql.NullBool", "sql.NullBool{}"
  65. case d.Nullable:
  66. goType, zero = "sql.NullInt64", "sql.NullInt64{}"
  67. default:
  68. goType, zero = "int8", "0"
  69. }
  70. case "smallint", "year":
  71. goType, zero = "int16", "0"
  72. if d.Nullable {
  73. goType, zero = "sql.NullInt64", "sql.NullInt64{}"
  74. }
  75. case "mediumint", "int", "integer":
  76. goType, zero = itype, "0"
  77. if d.Nullable {
  78. goType, zero = "sql.NullInt64", "sql.NullInt64{}"
  79. }
  80. case "bigint":
  81. goType, zero = "int64", "0"
  82. if d.Nullable {
  83. goType, zero = "sql.NullInt64", "sql.NullInt64{}"
  84. }
  85. case "float":
  86. goType, zero = "float32", "0.0"
  87. if d.Nullable {
  88. goType, zero = "sql.NullFloat64", "sql.NullFloat64{}"
  89. }
  90. case "decimal", "double":
  91. goType, zero = "float64", "0.0"
  92. if d.Nullable {
  93. goType, zero = "sql.NullFloat64", "sql.NullFloat64{}"
  94. }
  95. case "binary", "blob", "longblob", "mediumblob", "tinyblob", "varbinary":
  96. goType, zero = "[]byte", "nil"
  97. case "json":
  98. goType, zero = "json.RawMessage", "nil"
  99. case "timestamp", "datetime", "date":
  100. goType, zero = "time.Time", "time.Time{}"
  101. if d.Nullable {
  102. goType, zero = "sql.NullTime", "sql.NullTime{}"
  103. }
  104. case "time":
  105. // time is not supported by the MySQL driver. Can parse the string to time.Time in the user code.
  106. goType, zero = "string", `""`
  107. if d.Nullable {
  108. goType, zero = "sql.NullString", "sql.NullString{}"
  109. }
  110. default:
  111. goType, zero = schemaType(d.Type, d.Nullable, schema)
  112. }
  113. // force []byte for SET('a',...)
  114. if setRE.MatchString(d.Type) {
  115. goType, zero = "[]byte", "nil"
  116. }
  117. // if unsigned ...
  118. if intRE.MatchString(goType) && d.Unsigned {
  119. if goType == itype {
  120. goType, zero = utype, "0"
  121. } else {
  122. goType = "u" + goType
  123. }
  124. }
  125. return goType, zero, nil
  126. }
  127. // setRE is the regexp that matches MySQL SET() type definitions.
  128. var setRE = regexp.MustCompile(`(?i)^set\([^)]*\)$`)
  129. // MysqlEnumValues loads the enum values.
  130. func MysqlEnumValues(ctx context.Context, db models.DB, schema string, enum string) ([]*models.EnumValue, error) {
  131. // load enum vals
  132. res, err := models.MysqlEnumValues(ctx, db, schema, enum)
  133. if err != nil {
  134. return nil, err
  135. }
  136. // process enum vals
  137. var values []*models.EnumValue
  138. for i, val := range strings.Split(res.EnumValues[1:len(res.EnumValues)-1], "','") {
  139. values = append(values, &models.EnumValue{
  140. EnumValue: val,
  141. ConstValue: i + 1,
  142. })
  143. }
  144. return values, nil
  145. }