gendao_structure.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gendao
  7. import (
  8. "bytes"
  9. "context"
  10. "fmt"
  11. "github.com/olekukonko/tablewriter"
  12. "strings"
  13. "github.com/gogf/gf/v2/database/gdb"
  14. "github.com/gogf/gf/v2/frame/g"
  15. "github.com/gogf/gf/v2/text/gregex"
  16. "github.com/gogf/gf/v2/text/gstr"
  17. )
  18. type generateStructDefinitionInput struct {
  19. CGenDaoInternalInput
  20. TableName string // Table name.
  21. StructName string // Struct name.
  22. FieldMap map[string]*gdb.TableField // Table field map.
  23. IsDo bool // Is generating DTO struct.
  24. }
  25. func generateStructDefinition(ctx context.Context, in generateStructDefinitionInput) (string, []string) {
  26. var appendImports []string
  27. buffer := bytes.NewBuffer(nil)
  28. array := make([][]string, len(in.FieldMap))
  29. names := sortFieldKeyForDao(in.FieldMap)
  30. for index, name := range names {
  31. var imports string
  32. field := in.FieldMap[name]
  33. array[index], imports = generateStructFieldDefinition(ctx, field, in)
  34. if imports != "" {
  35. appendImports = append(appendImports, imports)
  36. }
  37. }
  38. tw := tablewriter.NewWriter(buffer)
  39. tw.SetBorder(false)
  40. tw.SetRowLine(false)
  41. tw.SetAutoWrapText(false)
  42. tw.SetColumnSeparator("")
  43. tw.AppendBulk(array)
  44. tw.Render()
  45. stContent := buffer.String()
  46. // Let's do this hack of table writer for indent!
  47. stContent = gstr.Replace(stContent, " #", "")
  48. stContent = gstr.Replace(stContent, "` ", "`")
  49. stContent = gstr.Replace(stContent, "``", "")
  50. buffer.Reset()
  51. buffer.WriteString(fmt.Sprintf("type %s struct {\n", in.StructName))
  52. if in.IsDo {
  53. buffer.WriteString(fmt.Sprintf("g.Meta `orm:\"table:%s, do:true\"`\n", in.TableName))
  54. }
  55. buffer.WriteString(stContent)
  56. buffer.WriteString("}")
  57. return buffer.String(), appendImports
  58. }
  59. // generateStructFieldDefinition generates and returns the attribute definition for specified field.
  60. func generateStructFieldDefinition(
  61. ctx context.Context, field *gdb.TableField, in generateStructDefinitionInput,
  62. ) (attrLines []string, appendImport string) {
  63. var (
  64. err error
  65. typeName string
  66. jsonTag = getJsonTagFromCase(field.Name, in.JsonCase)
  67. )
  68. if in.TypeMapping != nil && len(in.TypeMapping) > 0 {
  69. var (
  70. tryTypeName string
  71. )
  72. tryTypeMatch, _ := gregex.MatchString(`(.+?)\((.+)\)`, field.Type)
  73. if len(tryTypeMatch) == 3 {
  74. tryTypeName = gstr.Trim(tryTypeMatch[1])
  75. } else {
  76. tryTypeName = gstr.Split(field.Type, " ")[0]
  77. }
  78. if tryTypeName != "" {
  79. if typeMapping, ok := in.TypeMapping[strings.ToLower(tryTypeName)]; ok {
  80. typeName = typeMapping.Type
  81. appendImport = typeMapping.Import
  82. }
  83. }
  84. }
  85. if typeName == "" {
  86. typeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
  87. if err != nil {
  88. panic(err)
  89. }
  90. }
  91. switch typeName {
  92. case gdb.LocalTypeDate, gdb.LocalTypeDatetime:
  93. if in.StdTime {
  94. typeName = "time.Time"
  95. } else {
  96. typeName = "*gtime.Time"
  97. }
  98. case gdb.LocalTypeInt64Bytes:
  99. typeName = "int64"
  100. case gdb.LocalTypeUint64Bytes:
  101. typeName = "uint64"
  102. // Special type handle.
  103. case gdb.LocalTypeJson, gdb.LocalTypeJsonb:
  104. if in.GJsonSupport {
  105. typeName = "*gjson.Json"
  106. } else {
  107. typeName = "string"
  108. }
  109. }
  110. var (
  111. tagKey = "`"
  112. descriptionTag = gstr.Replace(formatComment(field.Comment), `"`, `\"`)
  113. )
  114. attrLines = []string{
  115. " #" + gstr.CaseCamel(field.Name),
  116. " #" + typeName,
  117. }
  118. attrLines = append(attrLines, " #"+fmt.Sprintf(tagKey+`json:"%s"`, jsonTag))
  119. attrLines = append(attrLines, " #"+fmt.Sprintf(`description:"%s"`+tagKey, descriptionTag))
  120. attrLines = append(attrLines, " #"+fmt.Sprintf(`// %s`, formatComment(field.Comment)))
  121. for k, v := range attrLines {
  122. if in.NoJsonTag {
  123. v, _ = gregex.ReplaceString(`json:".+"`, ``, v)
  124. }
  125. if !in.DescriptionTag {
  126. v, _ = gregex.ReplaceString(`description:".*"`, ``, v)
  127. }
  128. if in.NoModelComment {
  129. v, _ = gregex.ReplaceString(`//.+`, ``, v)
  130. }
  131. attrLines[k] = v
  132. }
  133. return attrLines, appendImport
  134. }
  135. // formatComment formats the comment string to fit the golang code without any lines.
  136. func formatComment(comment string) string {
  137. comment = gstr.ReplaceByArray(comment, g.SliceStr{
  138. "\n", " ",
  139. "\r", " ",
  140. })
  141. comment = gstr.Replace(comment, `\n`, " ")
  142. comment = gstr.Trim(comment)
  143. return comment
  144. }
  145. // getJsonTagFromCase call gstr.Case* function to convert the s to specified case.
  146. func getJsonTagFromCase(str, caseStr string) string {
  147. switch gstr.ToLower(caseStr) {
  148. case gstr.ToLower("Camel"):
  149. return gstr.CaseCamel(str)
  150. case gstr.ToLower("CamelLower"):
  151. return gstr.CaseCamelLower(str)
  152. case gstr.ToLower("Kebab"):
  153. return gstr.CaseKebab(str)
  154. case gstr.ToLower("KebabScreaming"):
  155. return gstr.CaseKebabScreaming(str)
  156. case gstr.ToLower("Snake"):
  157. return gstr.CaseSnake(str)
  158. case gstr.ToLower("SnakeFirstUpper"):
  159. return gstr.CaseSnakeFirstUpper(str)
  160. case gstr.ToLower("SnakeScreaming"):
  161. return gstr.CaseSnakeScreaming(str)
  162. }
  163. return str
  164. }