gen.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package gen
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "github.com/tal-tech/go-zero/tools/goctl/model/sql/model"
  9. "github.com/tal-tech/go-zero/tools/goctl/model/sql/parser"
  10. "github.com/tal-tech/go-zero/tools/goctl/model/sql/template"
  11. "github.com/tal-tech/go-zero/tools/goctl/util"
  12. "github.com/tal-tech/go-zero/tools/goctl/util/console"
  13. "github.com/tal-tech/go-zero/tools/goctl/util/stringx"
  14. )
  15. const (
  16. pwd = "."
  17. createTableFlag = `(?m)^(?i)CREATE\s+TABLE` // ignore case
  18. NamingLower = "lower"
  19. NamingCamel = "camel"
  20. NamingSnake = "snake"
  21. )
  22. type (
  23. defaultGenerator struct {
  24. //source string
  25. dir string
  26. console.Console
  27. pkg string
  28. namingStyle string
  29. }
  30. Option func(generator *defaultGenerator)
  31. )
  32. func NewDefaultGenerator(dir, namingStyle string, opt ...Option) (*defaultGenerator, error) {
  33. if dir == "" {
  34. dir = pwd
  35. }
  36. dirAbs, err := filepath.Abs(dir)
  37. if err != nil {
  38. return nil, err
  39. }
  40. dir = dirAbs
  41. pkg := filepath.Base(dirAbs)
  42. err = util.MkdirIfNotExist(dir)
  43. if err != nil {
  44. return nil, err
  45. }
  46. generator := &defaultGenerator{dir: dir, namingStyle: namingStyle, pkg: pkg}
  47. var optionList []Option
  48. optionList = append(optionList, newDefaultOption())
  49. optionList = append(optionList, opt...)
  50. for _, fn := range optionList {
  51. fn(generator)
  52. }
  53. return generator, nil
  54. }
  55. func WithConsoleOption(c console.Console) Option {
  56. return func(generator *defaultGenerator) {
  57. generator.Console = c
  58. }
  59. }
  60. func newDefaultOption() Option {
  61. return func(generator *defaultGenerator) {
  62. generator.Console = console.NewColorConsole()
  63. }
  64. }
  65. func (g *defaultGenerator) StartFromDDL(source string, withCache bool) error {
  66. modelList, err := g.genFromDDL(source, withCache)
  67. if err != nil {
  68. return err
  69. }
  70. return g.createFile(modelList)
  71. }
  72. func (g *defaultGenerator) StartFromInformationSchema(db string, columns map[string][]*model.Column, withCache bool) error {
  73. m := make(map[string]string)
  74. for tableName, column := range columns {
  75. table, err := parser.ConvertColumn(db, tableName, column)
  76. if err != nil {
  77. return err
  78. }
  79. code, err := g.genModel(*table, withCache)
  80. if err != nil {
  81. return err
  82. }
  83. m[table.Name.Source()] = code
  84. }
  85. return g.createFile(m)
  86. }
  87. func (g *defaultGenerator) createFile(modelList map[string]string) error {
  88. dirAbs, err := filepath.Abs(g.dir)
  89. if err != nil {
  90. return err
  91. }
  92. g.dir = dirAbs
  93. g.pkg = filepath.Base(dirAbs)
  94. err = util.MkdirIfNotExist(dirAbs)
  95. if err != nil {
  96. return err
  97. }
  98. for tableName, code := range modelList {
  99. tn := stringx.From(tableName)
  100. name := fmt.Sprintf("%smodel.go", strings.ToLower(tn.ToCamel()))
  101. switch g.namingStyle {
  102. case NamingCamel:
  103. name = fmt.Sprintf("%sModel.go", tn.ToCamel())
  104. case NamingSnake:
  105. name = fmt.Sprintf("%s_model.go", tn.ToSnake())
  106. }
  107. filename := filepath.Join(dirAbs, name)
  108. if util.FileExists(filename) {
  109. g.Warning("%s already exists, ignored.", name)
  110. continue
  111. }
  112. err = ioutil.WriteFile(filename, []byte(code), os.ModePerm)
  113. if err != nil {
  114. return err
  115. }
  116. }
  117. // generate error file
  118. filename := filepath.Join(dirAbs, "vars.go")
  119. if g.namingStyle == NamingCamel {
  120. filename = filepath.Join(dirAbs, "Vars.go")
  121. }
  122. text, err := util.LoadTemplate(category, errTemplateFile, template.Error)
  123. if err != nil {
  124. return err
  125. }
  126. err = util.With("vars").Parse(text).SaveTo(map[string]interface{}{
  127. "pkg": g.pkg,
  128. }, filename, false)
  129. if err != nil {
  130. return err
  131. }
  132. g.Success("Done.")
  133. return nil
  134. }
  135. // ret1: key-table name,value-code
  136. func (g *defaultGenerator) genFromDDL(source string, withCache bool) (map[string]string, error) {
  137. ddlList := g.split(source)
  138. m := make(map[string]string)
  139. for _, ddl := range ddlList {
  140. table, err := parser.Parse(ddl)
  141. if err != nil {
  142. return nil, err
  143. }
  144. code, err := g.genModel(*table, withCache)
  145. if err != nil {
  146. return nil, err
  147. }
  148. m[table.Name.Source()] = code
  149. }
  150. return m, nil
  151. }
  152. type (
  153. Table struct {
  154. parser.Table
  155. CacheKey map[string]Key
  156. ContainsUniqueKey bool
  157. }
  158. )
  159. func (g *defaultGenerator) genModel(in parser.Table, withCache bool) (string, error) {
  160. if len(in.PrimaryKey.Name.Source()) == 0 {
  161. return "", fmt.Errorf("table %s: missing primary key", in.Name.Source())
  162. }
  163. text, err := util.LoadTemplate(category, modelTemplateFile, template.Model)
  164. if err != nil {
  165. return "", err
  166. }
  167. t := util.With("model").
  168. Parse(text).
  169. GoFmt(true)
  170. m, err := genCacheKeys(in)
  171. if err != nil {
  172. return "", err
  173. }
  174. importsCode, err := genImports(withCache, in.ContainsTime())
  175. if err != nil {
  176. return "", err
  177. }
  178. var table Table
  179. table.Table = in
  180. table.CacheKey = m
  181. var containsUniqueCache = false
  182. for _, item := range table.Fields {
  183. if item.IsUniqueKey {
  184. containsUniqueCache = true
  185. break
  186. }
  187. }
  188. table.ContainsUniqueKey = containsUniqueCache
  189. varsCode, err := genVars(table, withCache)
  190. if err != nil {
  191. return "", err
  192. }
  193. typesCode, err := genTypes(table, withCache)
  194. if err != nil {
  195. return "", err
  196. }
  197. newCode, err := genNew(table, withCache)
  198. if err != nil {
  199. return "", err
  200. }
  201. insertCode, err := genInsert(table, withCache)
  202. if err != nil {
  203. return "", err
  204. }
  205. var findCode = make([]string, 0)
  206. findOneCode, err := genFindOne(table, withCache)
  207. if err != nil {
  208. return "", err
  209. }
  210. findOneByFieldCode, extraMethod, err := genFindOneByField(table, withCache)
  211. if err != nil {
  212. return "", err
  213. }
  214. findCode = append(findCode, findOneCode, findOneByFieldCode)
  215. updateCode, err := genUpdate(table, withCache)
  216. if err != nil {
  217. return "", err
  218. }
  219. deleteCode, err := genDelete(table, withCache)
  220. if err != nil {
  221. return "", err
  222. }
  223. output, err := t.Execute(map[string]interface{}{
  224. "pkg": g.pkg,
  225. "imports": importsCode,
  226. "vars": varsCode,
  227. "types": typesCode,
  228. "new": newCode,
  229. "insert": insertCode,
  230. "find": strings.Join(findCode, "\n"),
  231. "update": updateCode,
  232. "delete": deleteCode,
  233. "extraMethod": extraMethod,
  234. })
  235. if err != nil {
  236. return "", err
  237. }
  238. return output.String(), nil
  239. }