command.go 7.6 KB

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