command.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package command
  2. import (
  3. "errors"
  4. "path/filepath"
  5. "strings"
  6. "github.com/go-sql-driver/mysql"
  7. "github.com/urfave/cli"
  8. "github.com/zeromicro/go-zero/core/logx"
  9. "github.com/zeromicro/go-zero/core/stores/postgres"
  10. "github.com/zeromicro/go-zero/core/stores/sqlx"
  11. "github.com/zeromicro/go-zero/tools/goctl/config"
  12. "github.com/zeromicro/go-zero/tools/goctl/model/sql/command/migrationnotes"
  13. "github.com/zeromicro/go-zero/tools/goctl/model/sql/gen"
  14. "github.com/zeromicro/go-zero/tools/goctl/model/sql/model"
  15. "github.com/zeromicro/go-zero/tools/goctl/model/sql/util"
  16. file "github.com/zeromicro/go-zero/tools/goctl/util"
  17. "github.com/zeromicro/go-zero/tools/goctl/util/console"
  18. "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
  19. )
  20. const (
  21. flagSrc = "src"
  22. flagDir = "dir"
  23. flagCache = "cache"
  24. flagIdea = "idea"
  25. flagURL = "url"
  26. flagTable = "table"
  27. flagStyle = "style"
  28. flagDatabase = "database"
  29. flagSchema = "schema"
  30. flagHome = "home"
  31. flagRemote = "remote"
  32. flagBranch = "branch"
  33. )
  34. var errNotMatched = errors.New("sql not matched")
  35. // MysqlDDL generates model code from ddl
  36. func MysqlDDL(ctx *cli.Context) error {
  37. migrationnotes.BeforeCommands(ctx)
  38. src := ctx.String(flagSrc)
  39. dir := ctx.String(flagDir)
  40. cache := ctx.Bool(flagCache)
  41. idea := ctx.Bool(flagIdea)
  42. style := ctx.String(flagStyle)
  43. database := ctx.String(flagDatabase)
  44. home := ctx.String(flagHome)
  45. remote := ctx.String(flagRemote)
  46. branch := ctx.String(flagBranch)
  47. if len(remote) > 0 {
  48. repo, _ := file.CloneIntoGitHome(remote, branch)
  49. if len(repo) > 0 {
  50. home = repo
  51. }
  52. }
  53. if len(home) > 0 {
  54. pathx.RegisterGoctlHome(home)
  55. }
  56. cfg, err := config.NewConfig(style)
  57. if err != nil {
  58. return err
  59. }
  60. return fromDDL(src, dir, cfg, cache, idea, database)
  61. }
  62. // MySqlDataSource generates model code from datasource
  63. func MySqlDataSource(ctx *cli.Context) error {
  64. migrationnotes.BeforeCommands(ctx)
  65. url := strings.TrimSpace(ctx.String(flagURL))
  66. dir := strings.TrimSpace(ctx.String(flagDir))
  67. cache := ctx.Bool(flagCache)
  68. idea := ctx.Bool(flagIdea)
  69. style := ctx.String(flagStyle)
  70. home := ctx.String(flagHome)
  71. remote := ctx.String(flagRemote)
  72. branch := ctx.String(flagBranch)
  73. if len(remote) > 0 {
  74. repo, _ := file.CloneIntoGitHome(remote, branch)
  75. if len(repo) > 0 {
  76. home = repo
  77. }
  78. }
  79. if len(home) > 0 {
  80. pathx.RegisterGoctlHome(home)
  81. }
  82. tableValue := ctx.StringSlice(flagTable)
  83. patterns := parseTableList(tableValue)
  84. cfg, err := config.NewConfig(style)
  85. if err != nil {
  86. return err
  87. }
  88. return fromMysqlDataSource(url, dir, patterns, cfg, cache, idea)
  89. }
  90. type pattern map[string]struct{}
  91. func (p pattern) Match(s string) bool {
  92. for v := range p {
  93. match, err := filepath.Match(v, s)
  94. if err != nil {
  95. console.Error("%+v", err)
  96. continue
  97. }
  98. if match {
  99. return true
  100. }
  101. }
  102. return false
  103. }
  104. func (p pattern) list() []string {
  105. var ret []string
  106. for v := range p {
  107. ret = append(ret, v)
  108. }
  109. return ret
  110. }
  111. func parseTableList(tableValue []string) pattern {
  112. tablePattern := make(pattern)
  113. for _, v := range tableValue {
  114. fields := strings.FieldsFunc(v, func(r rune) bool {
  115. return r == ','
  116. })
  117. for _, f := range fields {
  118. tablePattern[f] = struct{}{}
  119. }
  120. }
  121. return tablePattern
  122. }
  123. // PostgreSqlDataSource generates model code from datasource
  124. func PostgreSqlDataSource(ctx *cli.Context) error {
  125. migrationnotes.BeforeCommands(ctx)
  126. url := strings.TrimSpace(ctx.String(flagURL))
  127. dir := strings.TrimSpace(ctx.String(flagDir))
  128. cache := ctx.Bool(flagCache)
  129. idea := ctx.Bool(flagIdea)
  130. style := ctx.String(flagStyle)
  131. schema := ctx.String(flagSchema)
  132. home := ctx.String(flagHome)
  133. remote := ctx.String(flagRemote)
  134. branch := ctx.String(flagBranch)
  135. if len(remote) > 0 {
  136. repo, _ := file.CloneIntoGitHome(remote, branch)
  137. if len(repo) > 0 {
  138. home = repo
  139. }
  140. }
  141. if len(home) > 0 {
  142. pathx.RegisterGoctlHome(home)
  143. }
  144. if len(schema) == 0 {
  145. schema = "public"
  146. }
  147. pattern := strings.TrimSpace(ctx.String(flagTable))
  148. cfg, err := config.NewConfig(style)
  149. if err != nil {
  150. return err
  151. }
  152. return fromPostgreSqlDataSource(url, pattern, dir, schema, cfg, cache, idea)
  153. }
  154. func fromDDL(src, dir string, cfg *config.Config, cache, idea bool, database string) error {
  155. log := console.NewConsole(idea)
  156. src = strings.TrimSpace(src)
  157. if len(src) == 0 {
  158. return errors.New("expected path or path globbing patterns, but nothing found")
  159. }
  160. files, err := util.MatchFiles(src)
  161. if err != nil {
  162. return err
  163. }
  164. if len(files) == 0 {
  165. return errNotMatched
  166. }
  167. generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
  168. if err != nil {
  169. return err
  170. }
  171. for _, file := range files {
  172. err = generator.StartFromDDL(file, cache, database)
  173. if err != nil {
  174. return err
  175. }
  176. }
  177. return nil
  178. }
  179. func fromMysqlDataSource(url, dir string, tablePat pattern, cfg *config.Config, cache, idea bool) error {
  180. log := console.NewConsole(idea)
  181. if len(url) == 0 {
  182. log.Error("%v", "expected data source of mysql, but nothing found")
  183. return nil
  184. }
  185. if len(tablePat) == 0 {
  186. log.Error("%v", "expected table or table globbing patterns, but nothing found")
  187. return nil
  188. }
  189. dsn, err := mysql.ParseDSN(url)
  190. if err != nil {
  191. return err
  192. }
  193. logx.Disable()
  194. databaseSource := strings.TrimSuffix(url, "/"+dsn.DBName) + "/information_schema"
  195. db := sqlx.NewMysql(databaseSource)
  196. im := model.NewInformationSchemaModel(db)
  197. tables, err := im.GetAllTables(dsn.DBName)
  198. if err != nil {
  199. return err
  200. }
  201. matchTables := make(map[string]*model.Table)
  202. for _, item := range tables {
  203. if !tablePat.Match(item) {
  204. continue
  205. }
  206. columnData, err := im.FindColumns(dsn.DBName, item)
  207. if err != nil {
  208. return err
  209. }
  210. table, err := columnData.Convert()
  211. if err != nil {
  212. return err
  213. }
  214. matchTables[item] = table
  215. }
  216. if len(matchTables) == 0 {
  217. return errors.New("no tables matched")
  218. }
  219. generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
  220. if err != nil {
  221. return err
  222. }
  223. return generator.StartFromInformationSchema(matchTables, cache)
  224. }
  225. func fromPostgreSqlDataSource(url, pattern, dir, schema string, cfg *config.Config, cache, idea bool) error {
  226. log := console.NewConsole(idea)
  227. if len(url) == 0 {
  228. log.Error("%v", "expected data source of postgresql, but nothing found")
  229. return nil
  230. }
  231. if len(pattern) == 0 {
  232. log.Error("%v", "expected table or table globbing patterns, but nothing found")
  233. return nil
  234. }
  235. db := postgres.New(url)
  236. im := model.NewPostgreSqlModel(db)
  237. tables, err := im.GetAllTables(schema)
  238. if err != nil {
  239. return err
  240. }
  241. matchTables := make(map[string]*model.Table)
  242. for _, item := range tables {
  243. match, err := filepath.Match(pattern, item)
  244. if err != nil {
  245. return err
  246. }
  247. if !match {
  248. continue
  249. }
  250. columnData, err := im.FindColumns(schema, item)
  251. if err != nil {
  252. return err
  253. }
  254. table, err := columnData.Convert()
  255. if err != nil {
  256. return err
  257. }
  258. matchTables[item] = table
  259. }
  260. if len(matchTables) == 0 {
  261. return errors.New("no tables matched")
  262. }
  263. generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log), gen.WithPostgreSql())
  264. if err != nil {
  265. return err
  266. }
  267. return generator.StartFromInformationSchema(matchTables, cache)
  268. }