table2struct.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package sqlmodel
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "text/template"
  8. util2 "github.com/tal-tech/go-zero/tools/modelctl/util"
  9. )
  10. var (
  11. commonMysqlDataTypeMap = map[string]string{
  12. "tinyint": "int64",
  13. "smallint": "int64",
  14. "mediumint": "int64",
  15. "int": "int64",
  16. "integer": "int64",
  17. "bigint": "int64",
  18. "float": "float64",
  19. "double": "float64",
  20. "decimal": "float64",
  21. "date": "time.Time",
  22. "time": "string",
  23. "year": "int64",
  24. "datetime": "time.Time",
  25. "timestamp": "time.Time",
  26. "char": "string",
  27. "varchar": "string",
  28. "tinyblob": "string",
  29. "tinytext": "string",
  30. "blob": "string",
  31. "text": "string",
  32. "mediumblob": "string",
  33. "mediumtext": "string",
  34. "longblob": "string",
  35. "longtext": "string",
  36. }
  37. )
  38. var modelTemplate = `
  39. type (
  40. {{.ModelCamelWithUpperStart}}Model struct {
  41. table string
  42. conn sqlx.SqlConn
  43. }
  44. {{.ModelCamelWithUpperStart}} struct {
  45. {{.Fields}}
  46. }
  47. )
  48. func New{{.ModelCamelWithUpperStart}}Model(table string, conn sqlx.SqlConn) *{{.ModelCamelWithUpperStart}}Model {
  49. return &{{.ModelCamelWithUpperStart}}Model{table: table, conn: conn}
  50. }
  51. `
  52. const (
  53. fieldTemplateText = "{{.NameCamelWithUpperStart}} {{.DataType}} `db:\"{{.NameWithUnderline}}\"` {{.Comment}}"
  54. )
  55. type (
  56. Template struct {
  57. ModelCamelWithUpperStart string
  58. Fields string
  59. }
  60. StructField struct {
  61. // 字段名称,下划线
  62. NameWithUnderline string
  63. // 字段名称,驼峰式,大写开头
  64. NameCamelWithUpperStart string
  65. // 字段名称,驼峰式,小写开头
  66. NameCamelWithLowerStart string
  67. // 字段数据类型
  68. DataType string
  69. // 字段注释
  70. Comment string
  71. }
  72. GenStruct struct {
  73. // 表对应的struct
  74. TableStruct string `json:"tableStruct"`
  75. // 表对应生成的model信息,参考模板${modelTemplate}
  76. TableModel string `json:"tableModel"`
  77. // 主键
  78. PrimaryKey string `json:"primaryKey"`
  79. }
  80. )
  81. func generateTypeModel(table string, fields []*Column) (*GenStruct, error) {
  82. var resp GenStruct
  83. structString, fieldsString, err := convertStruct(table, fields)
  84. if err != nil {
  85. return nil, err
  86. }
  87. templateStruct := Template{
  88. ModelCamelWithUpperStart: util2.FmtUnderLine2Camel(table, true),
  89. Fields: fieldsString,
  90. }
  91. tl, err := template.New("").Parse(modelTemplate)
  92. if err != nil {
  93. return nil, err
  94. }
  95. var resultBuffer = bytes.NewBufferString("")
  96. err = tl.Execute(resultBuffer, templateStruct)
  97. if err != nil {
  98. return nil, err
  99. }
  100. resp.TableStruct = structString
  101. resp.TableModel = resultBuffer.String()
  102. return &resp, nil
  103. }
  104. // returns struct、fields、error
  105. func convertStruct(table string, columns []*Column) (string, string, error) {
  106. var structBuffer, fieldsBuffer bytes.Buffer
  107. structBuffer.WriteString("package model \n\n")
  108. structBuffer.WriteString("type " + fmtUnderLine2Camel(table, true) + " struct {\n")
  109. for index, item := range columns {
  110. goType, ok := commonMysqlDataTypeMap[item.DataType]
  111. if !ok {
  112. return "", "", errors.New(fmt.Sprintf("table: %s,the data type %s of %s does not match", table, item.DataType, item.Name))
  113. }
  114. out, err := convertField(&StructField{
  115. NameWithUnderline: item.Name,
  116. NameCamelWithUpperStart: fmtUnderLine2Camel(item.Name, true),
  117. NameCamelWithLowerStart: fmtUnderLine2Camel(item.Name, false),
  118. DataType: goType,
  119. Comment: item.Comment,
  120. })
  121. if err != nil {
  122. return "", "", err
  123. }
  124. structBuffer.WriteString("\t" + out)
  125. structBuffer.WriteString("\n")
  126. if index == 0 {
  127. fieldsBuffer.WriteString(out)
  128. } else {
  129. fieldsBuffer.WriteString("\t\t" + out)
  130. }
  131. if index < len(columns)-1 {
  132. fieldsBuffer.WriteString("\n")
  133. }
  134. }
  135. structBuffer.WriteString("}")
  136. return structBuffer.String(), fieldsBuffer.String(), nil
  137. }
  138. // column转换成struct field
  139. func convertField(field *StructField) (string, error) {
  140. if strings.TrimSpace(field.Comment) != "" {
  141. field.Comment = "// " + field.Comment
  142. }
  143. tl, err := template.New("").Parse(fieldTemplateText)
  144. if err != nil {
  145. return "", err
  146. }
  147. buf := bytes.NewBufferString("")
  148. err = tl.Execute(buf, field)
  149. if err != nil {
  150. return "", err
  151. }
  152. return buf.String(), nil
  153. }
  154. // 简单的下划线转驼峰格式
  155. func fmtUnderLine2Camel(in string, upperStart bool) string {
  156. if strings.TrimSpace(in) == "" {
  157. return ""
  158. }
  159. var words []string
  160. if strings.Contains(in, "_") {
  161. words = strings.Split(in, "_")
  162. if len(words) == 0 {
  163. return ""
  164. }
  165. }
  166. if len(words) == 0 {
  167. if !upperStart {
  168. bts := []byte(in)
  169. r := bytes.ToLower([]byte{bts[0]})
  170. bts[0] = r[0]
  171. return string(bts)
  172. } else {
  173. return strings.Title(in)
  174. }
  175. }
  176. var buffer bytes.Buffer
  177. for index, word := range words {
  178. if strings.TrimSpace(word) == "" {
  179. continue
  180. }
  181. bts := []byte(word)
  182. if index == 0 && !upperStart {
  183. bts[0] = bytes.ToLower([]byte{bts[0]})[0]
  184. buffer.Write(bts)
  185. continue
  186. }
  187. bts = bytes.Title(bts)
  188. buffer.Write(bts)
  189. }
  190. return buffer.String()
  191. }