From db8384355859c9292621de87b0f7955532dbae65 Mon Sep 17 00:00:00 2001 From: Keson Date: Thu, 20 Aug 2020 10:29:18 +0800 Subject: [PATCH] gocctl model v20200819 (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rename snake、came method * new: generate model from data source * add change log md * update model doc * update doc * beauty code --- doc/goctl.md | 9 ++- tools/goctl/goctl.go | 76 ++++++++++++----- tools/goctl/model/sql/CHANGELOG.md | 10 +++ tools/goctl/model/sql/README.MD | 90 +++++++++++++-------- tools/goctl/model/sql/command/command.go | 89 ++++++++++++++++---- tools/goctl/model/sql/example/generator.sh | 7 +- tools/goctl/model/sql/gen/delete.go | 4 +- tools/goctl/model/sql/gen/field.go | 2 +- tools/goctl/model/sql/gen/findone.go | 6 +- tools/goctl/model/sql/gen/fineonebyfield.go | 12 +-- tools/goctl/model/sql/gen/gen.go | 21 +---- tools/goctl/model/sql/gen/insert.go | 6 +- tools/goctl/model/sql/gen/keys.go | 8 +- tools/goctl/model/sql/gen/new.go | 2 +- tools/goctl/model/sql/gen/types.go | 2 +- tools/goctl/model/sql/gen/update.go | 8 +- tools/goctl/model/sql/gen/vars.go | 4 +- tools/goctl/model/sql/model/ddlmodel.go | 33 ++++++++ tools/goctl/model/sql/parser/parser.go | 2 +- tools/goctl/util/console/console.go | 7 ++ tools/goctl/util/stringx/string.go | 22 +---- tools/goctl/util/stringx/string_test.go | 14 ++-- 22 files changed, 295 insertions(+), 139 deletions(-) create mode 100644 tools/goctl/model/sql/CHANGELOG.md create mode 100644 tools/goctl/model/sql/model/ddlmodel.go diff --git a/doc/goctl.md b/doc/goctl.md index 81840576..c5d14214 100644 --- a/doc/goctl.md +++ b/doc/goctl.md @@ -195,6 +195,13 @@ ts需要指定webapi所在目录 goctl api dart -api user/user.api -dir ./src ``` +## 根据mysql ddl或者datasource生成model文件 + +```shell script +$ goctl model mysql -src={filename} -dir={dir} -cache={true|false} +``` +详情参考[model文档](https://github.com/tal-tech/go-zero/blob/master/tools/goctl/model/sql/README.MD) + ## 根据定义好的简单go文件生成mongo代码文件(仅限golang使用) ```shell goctl model mongo -src {{yourDir}}/xiao/service/xhb/user/model/usermodel.go -cache yes @@ -218,7 +225,7 @@ type User struct { o是改字段需要生产的操作函数 可以取得get,find,set 分别表示生成返回单个对象的查询方法,返回多个对象的查询方法,设置该字段方法 生成的目标文件会覆盖该简单go文件 -## goctl rpc生成 +## goctl rpc生成(业务剥离中,暂未开放) 命令 `goctl rpc proto -proto ${proto} -service ${serviceName} -project ${projectName} -dir ${directory} -shared ${shared}` 如: `goctl rpc proto -proto test.proto -service test -project xjy -dir .` diff --git a/tools/goctl/goctl.go b/tools/goctl/goctl.go index 3e3fba75..2ab142fd 100644 --- a/tools/goctl/goctl.go +++ b/tools/goctl/goctl.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "github.com/urfave/cli" + "github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/tools/goctl/api/apigen" "github.com/tal-tech/go-zero/tools/goctl/api/dartgen" @@ -18,7 +20,6 @@ import ( "github.com/tal-tech/go-zero/tools/goctl/docker" "github.com/tal-tech/go-zero/tools/goctl/feature" "github.com/tal-tech/go-zero/tools/goctl/model/sql/command" - "github.com/urfave/cli" ) var ( @@ -191,25 +192,64 @@ var ( { Name: "model", Usage: "generate model code", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "src, s", - Usage: "the file path of the ddl source file", - }, - cli.StringFlag{ - Name: "dir, d", - Usage: "the target dir", - }, - cli.BoolFlag{ - Name: "cache, c", - Usage: "generate code with cache [optional]", - }, - cli.BoolFlag{ - Name: "idea", - Usage: "for idea plugin [optional]", + Subcommands: []cli.Command{ + { + Name: "mysql", + Usage: `generate mysql model"`, + Subcommands: []cli.Command{ + { + Name: "ddl", + Usage: `generate mysql model from ddl"`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "src, s", + Usage: "the file path of the ddl source file", + }, + cli.StringFlag{ + Name: "dir, d", + Usage: "the target dir", + }, + cli.BoolFlag{ + Name: "cache, c", + Usage: "generate code with cache [optional]", + }, + cli.BoolFlag{ + Name: "idea", + Usage: "for idea plugin [optional]", + }, + }, + Action: command.MysqlDDL, + }, + { + Name: "datasource", + Usage: `generate model from datasource"`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "url", + Usage: `the data source of database,like "root:password@tcp(127.0.0.1:3306)/database"`, + }, + cli.StringFlag{ + Name: "table, t", + Usage: `source table,tables separated by commas,like "user,course"`, + }, + cli.BoolFlag{ + Name: "cache, c", + Usage: "generate code with cache [optional]", + }, + cli.StringFlag{ + Name: "dir, d", + Usage: "the target dir", + }, + cli.BoolFlag{ + Name: "idea", + Usage: "for idea plugin [optional]", + }, + }, + Action: command.MyDataSource, + }, + }, }, }, - Action: command.Mysql, }, { Name: "config", diff --git a/tools/goctl/model/sql/CHANGELOG.md b/tools/goctl/model/sql/CHANGELOG.md new file mode 100644 index 00000000..845cee50 --- /dev/null +++ b/tools/goctl/model/sql/CHANGELOG.md @@ -0,0 +1,10 @@ +# Change log + +# 2020-08-20 +* 新增支持通过连接数据库生成model +* 支持数据库多表生成 +* 优化stringx + +# 2020-08-19 +* 重构model代码生成逻辑 +* 实现从ddl解析表信息生成代码 \ No newline at end of file diff --git a/tools/goctl/model/sql/README.MD b/tools/goctl/model/sql/README.MD index e2cbe48c..d525a696 100644 --- a/tools/goctl/model/sql/README.MD +++ b/tools/goctl/model/sql/README.MD @@ -4,21 +4,28 @@ goctl model 为go-zero下的工具模块中的组件之一,目前支持识别m # 快速开始 -``` -$ goctl model -src ./sql/user.sql -dir ./model -c true -``` +* 通过ddl生成 -详情用法请参考[example](https://github.com/tal-tech/go-zero/tools/goctl/model/sql/example) + ```shell script + $ goctl model mysql ddl -src="./sql/user.sql" -dir="./sql/model" -c=true + ``` -执行上述命令后即可快速生成CURD代码。 + 执行上述命令后即可快速生成CURD代码。 -``` -model -│   ├── error.go -│   └── usermodel.go -``` + ``` + model + │   ├── error.go + │   └── usermodel.go + ``` +* 通过datasource生成 + + ```shell script + $ goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2" -dir="./model" + ``` + + +> 详情用法请参考[example](https://github.com/tal-tech/go-zero/tree/master/tools/goctl/model/sql/example) -> 注意:这里的目录结构中有usercoursemodel.go目录,在example中我为了体现带cache与不带cache代码的区别,因此将sql文件分别使用了独立的sql文件(user.sql&course.sql),在实际项目开发中你可以将ddl建表语句放在一个sql文件中,`goctl model`会自动解析并分割,最终按照每个ddl建表语句为单位生成独立的go文件。 * 生成代码示例 @@ -174,22 +181,22 @@ model # 用法 ``` -$ goctl model -h +$ goctl model mysql -h ``` ``` NAME: - goctl model - generate model code + goctl model mysql - generate mysql model" USAGE: - goctl model [command options] [arguments...] + goctl model mysql command [command options] [arguments...] -OPTIONS: - --src value, -s value the file path of the ddl source file - --dir value, -d value the target dir - --cache, -c generate code with cache [optional] - --idea for idea plugin [optional] +COMMANDS: + ddl generate mysql model from ddl" + datasource generate model from datasource" +OPTIONS: + --help, -h show help ``` # 生成规则 @@ -198,22 +205,43 @@ OPTIONS: 我们默认用户在建表时会创建createTime、updateTime字段(忽略大小写、下划线命名风格)且默认值均为`CURRENT_TIMESTAMP`,而updateTime支持`ON UPDATE CURRENT_TIMESTAMP`,对于这两个字段生成`insert`、`update`时会被移除,不在赋值范畴内,当然,如果你不需要这两个字段那也无大碍。 * 带缓存模式 - - ``` - $ goctl model -src {filename} -dir {dir} -cache true - ``` + * ddl + + ```shell script + $ goctl model mysql -src={filename} -dir={dir} -cache=true + ``` + * datasource + + ```shell script + $ goctl model mysql datasource -url={datasource} -table={tables} -dir={dir} -cache=true + ``` 目前仅支持redis缓存,如果选择带缓存模式,即生成的`FindOne(ByXxx)`&`Delete`代码会生成带缓存逻辑的代码,目前仅支持单索引字段(除全文索引外),对于联合索引我们默认认为不需要带缓存,且不属于通用型代码,因此没有放在代码生成行列,如example中user表中的`id`、`name`、`mobile`字段均属于单字段索引。 * 不带缓存模式 - ``` - $ goctl model -src {filename} -dir {dir} - ``` + * ddl + + ```shell script + $ goctl model -src={filename} -dir={dir} + ``` + * datasource + + ```shell script + $ goctl model mysql datasource -url={datasource} -table={tables} -dir={dir} + ``` or - ``` - $ goctl model -src {filename} -dir {dir} -cache false - ``` + * ddl + + ```shell script + $ goctl model -src={filename} -dir={dir} -cache=false + ``` + * datasource + + ```shell script + $ goctl model mysql datasource -url={datasource} -table={tables} -dir={dir} -cache=false + ``` + 生成代码仅基本的CURD结构。 # 缓存 @@ -238,10 +266,6 @@ OPTIONS: # QA -* goctl model支持根据数据库连接后选择表生成代码吗? - - 目前暂时不支持,在后面会向这个方向扩展。 - * goctl model除了命令行模式,支持插件模式吗? 很快支持idea插件。 diff --git a/tools/goctl/model/sql/command/command.go b/tools/goctl/model/sql/command/command.go index 7604699c..eb823d39 100644 --- a/tools/goctl/model/sql/command/command.go +++ b/tools/goctl/model/sql/command/command.go @@ -1,24 +1,85 @@ package command import ( + "io/ioutil" + "path/filepath" + "strings" + + "github.com/urfave/cli" + + "github.com/tal-tech/go-zero/core/collection" + "github.com/tal-tech/go-zero/core/logx" + "github.com/tal-tech/go-zero/core/stores/sqlx" "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen" + "github.com/tal-tech/go-zero/tools/goctl/model/sql/model" "github.com/tal-tech/go-zero/tools/goctl/util/console" - "github.com/urfave/cli" ) -func Mysql(ctx *cli.Context) error { - src := ctx.String("src") - dir := ctx.String("dir") - cache := ctx.Bool("cache") - idea := ctx.Bool("idea") - var log console.Console - if idea { - log = console.NewIdeaConsole() - } else { - log = console.NewColorConsole() - } - generator := gen.NewDefaultGenerator(src, dir, gen.WithConsoleOption(log)) - err := generator.Start(cache) +const ( + flagSrc = "src" + flagDir = "dir" + flagCache = "cache" + flagIdea = "idea" + flagUrl = "url" + flagTable = "table" +) + +func MysqlDDL(ctx *cli.Context) error { + src := ctx.String(flagSrc) + dir := ctx.String(flagDir) + cache := ctx.Bool(flagCache) + idea := ctx.Bool(flagIdea) + log := console.NewConsole(idea) + fileSrc, err := filepath.Abs(src) + if err != nil { + return err + } + data, err := ioutil.ReadFile(fileSrc) + if err != nil { + return err + } + source := string(data) + generator := gen.NewDefaultGenerator(source, dir, gen.WithConsoleOption(log)) + err = generator.Start(cache) + if err != nil { + log.Error("%v", err) + } + return nil +} + +func MyDataSource(ctx *cli.Context) error { + url := strings.TrimSpace(ctx.String(flagUrl)) + dir := strings.TrimSpace(ctx.String(flagDir)) + cache := ctx.Bool(flagCache) + idea := ctx.Bool(flagIdea) + table := strings.TrimSpace(ctx.String(flagTable)) + log := console.NewConsole(idea) + if len(url) == 0 { + log.Error("%v", "expected data source of mysql, but is empty") + return nil + } + if len(table) == 0 { + log.Error("%v", "expected table(s), but nothing found") + return nil + } + logx.Disable() + conn := sqlx.NewMysql(url) + m := model.NewDDLModel(conn) + tables := collection.NewSet() + for _, item := range strings.Split(table, ",") { + item = strings.TrimSpace(item) + if len(item) == 0 { + continue + } + tables.AddStr(item) + } + ddl, err := m.ShowDDL(tables.KeysStr()...) + if err != nil { + log.Error("%v", err) + return nil + } + generator := gen.NewDefaultGenerator(strings.Join(ddl, "\n"), dir, gen.WithConsoleOption(log)) + err = generator.Start(cache) if err != nil { log.Error("%v", err) } diff --git a/tools/goctl/model/sql/example/generator.sh b/tools/goctl/model/sql/example/generator.sh index 4a44d5e1..2e121423 100644 --- a/tools/goctl/model/sql/example/generator.sh +++ b/tools/goctl/model/sql/example/generator.sh @@ -1,4 +1,7 @@ #!/bin/bash -# generate usermodel with cache -goctl model -src ./sql/user.sql -dir ./model -c true +# generate model with cache from ddl + goctl model mysql ddl -src="./sql/user.sql" -dir="./sql/model" -c=true + +# generate model with cache from data source + goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2" -dir="./model" \ No newline at end of file diff --git a/tools/goctl/model/sql/gen/delete.go b/tools/goctl/model/sql/gen/delete.go index 71abbd79..0d89d606 100644 --- a/tools/goctl/model/sql/gen/delete.go +++ b/tools/goctl/model/sql/gen/delete.go @@ -27,14 +27,14 @@ func genDelete(table Table, withCache bool) (string, error) { break } } - camel := table.Name.Snake2Camel() + camel := table.Name.ToCamel() output, err := templatex.With("delete"). Parse(template.Delete). Execute(map[string]interface{}{ "upperStartCamelObject": camel, "withCache": withCache, "containsIndexCache": containsIndexCache, - "lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.Snake2Camel()).LowerStart(), + "lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(), "dataType": table.PrimaryKey.DataType, "keys": strings.Join(keySet.KeysStr(), "\n"), "originalPrimaryKey": table.PrimaryKey.Name.Source(), diff --git a/tools/goctl/model/sql/gen/field.go b/tools/goctl/model/sql/gen/field.go index 125800db..817a5ebd 100644 --- a/tools/goctl/model/sql/gen/field.go +++ b/tools/goctl/model/sql/gen/field.go @@ -28,7 +28,7 @@ func genField(field parser.Field) (string, error) { output, err := templatex.With("types"). Parse(template.Field). Execute(map[string]interface{}{ - "name": field.Name.Snake2Camel(), + "name": field.Name.ToCamel(), "type": field.DataType, "tag": tag, "hasComment": field.Comment != "", diff --git a/tools/goctl/model/sql/gen/findone.go b/tools/goctl/model/sql/gen/findone.go index b7b1a1b5..e89e9277 100644 --- a/tools/goctl/model/sql/gen/findone.go +++ b/tools/goctl/model/sql/gen/findone.go @@ -7,15 +7,15 @@ import ( ) func genFindOne(table Table, withCache bool) (string, error) { - camel := table.Name.Snake2Camel() + camel := table.Name.ToCamel() output, err := templatex.With("findOne"). Parse(template.FindOne). Execute(map[string]interface{}{ "withCache": withCache, "upperStartCamelObject": camel, - "lowerStartCamelObject": stringx.From(camel).LowerStart(), + "lowerStartCamelObject": stringx.From(camel).UnTitle(), "originalPrimaryKey": table.PrimaryKey.Name.Source(), - "lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.Snake2Camel()).LowerStart(), + "lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(), "dataType": table.PrimaryKey.DataType, "cacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].KeyExpression, "cacheKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable, diff --git a/tools/goctl/model/sql/gen/fineonebyfield.go b/tools/goctl/model/sql/gen/fineonebyfield.go index 62c66000..13cddc7b 100644 --- a/tools/goctl/model/sql/gen/fineonebyfield.go +++ b/tools/goctl/model/sql/gen/fineonebyfield.go @@ -12,23 +12,23 @@ import ( func genFineOneByField(table Table, withCache bool) (string, error) { t := templatex.With("findOneByField").Parse(template.FindOneByField) var list []string - camelTableName := table.Name.Snake2Camel() + camelTableName := table.Name.ToCamel() for _, field := range table.Fields { if field.IsPrimaryKey || !field.IsKey { continue } - camelFieldName := field.Name.Snake2Camel() + camelFieldName := field.Name.ToCamel() output, err := t.Execute(map[string]interface{}{ "upperStartCamelObject": camelTableName, "upperField": camelFieldName, - "in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).LowerStart(), field.DataType), + "in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).UnTitle(), field.DataType), "withCache": withCache, "cacheKey": table.CacheKey[field.Name.Source()].KeyExpression, "cacheKeyVariable": table.CacheKey[field.Name.Source()].Variable, "primaryKeyLeft": table.CacheKey[table.PrimaryKey.Name.Source()].Left, - "lowerStartCamelObject": stringx.From(camelTableName).LowerStart(), - "lowerStartCamelField": stringx.From(camelFieldName).LowerStart(), - "upperStartCamelPrimaryKey": table.PrimaryKey.Name.Snake2Camel(), + "lowerStartCamelObject": stringx.From(camelTableName).UnTitle(), + "lowerStartCamelField": stringx.From(camelFieldName).UnTitle(), + "upperStartCamelPrimaryKey": table.PrimaryKey.Name.ToCamel(), "originalField": field.Name.Source(), "originalPrimaryField": table.PrimaryKey.Name.Source(), }) diff --git a/tools/goctl/model/sql/gen/gen.go b/tools/goctl/model/sql/gen/gen.go index e7097d0a..45fc8656 100644 --- a/tools/goctl/model/sql/gen/gen.go +++ b/tools/goctl/model/sql/gen/gen.go @@ -23,21 +23,17 @@ const ( type ( defaultGenerator struct { source string - src string dir string console.Console } Option func(generator *defaultGenerator) ) -func NewDefaultGenerator(src, dir string, opt ...Option) *defaultGenerator { - if src == "" { - src = pwd - } +func NewDefaultGenerator(source, dir string, opt ...Option) *defaultGenerator { if dir == "" { dir = pwd } - generator := &defaultGenerator{src: src, dir: dir} + generator := &defaultGenerator{source: source, dir: dir} var optionList []Option optionList = append(optionList, newDefaultOption()) optionList = append(optionList, opt...) @@ -60,10 +56,6 @@ func newDefaultOption() Option { } func (g *defaultGenerator) Start(withCache bool) error { - fileSrc, err := filepath.Abs(g.src) - if err != nil { - return err - } dirAbs, err := filepath.Abs(g.dir) if err != nil { return err @@ -72,21 +64,16 @@ func (g *defaultGenerator) Start(withCache bool) error { if err != nil { return err } - data, err := ioutil.ReadFile(fileSrc) - if err != nil { - return err - } - g.source = string(data) modelList, err := g.genFromDDL(withCache) if err != nil { return err } for tableName, code := range modelList { - name := fmt.Sprintf("%smodel.go", strings.ToLower(stringx.From(tableName).Snake2Camel())) + name := fmt.Sprintf("%smodel.go", strings.ToLower(stringx.From(tableName).ToCamel())) filename := filepath.Join(dirAbs, name) if util.FileExists(filename) { - g.Warning("%s already exists,ignored.", name) + g.Warning("%s already exists, ignored.", name) continue } err = ioutil.WriteFile(filename, []byte(code), os.ModePerm) diff --git a/tools/goctl/model/sql/gen/insert.go b/tools/goctl/model/sql/gen/insert.go index a2b7ca09..a44a9439 100644 --- a/tools/goctl/model/sql/gen/insert.go +++ b/tools/goctl/model/sql/gen/insert.go @@ -12,7 +12,7 @@ func genInsert(table Table, withCache bool) (string, error) { expressions := make([]string, 0) expressionValues := make([]string, 0) for _, filed := range table.Fields { - camel := filed.Name.Snake2Camel() + camel := filed.Name.ToCamel() if camel == "CreateTime" || camel == "UpdateTime" { continue } @@ -22,13 +22,13 @@ func genInsert(table Table, withCache bool) (string, error) { expressions = append(expressions, "?") expressionValues = append(expressionValues, "data."+camel) } - camel := table.Name.Snake2Camel() + camel := table.Name.ToCamel() output, err := templatex.With("insert"). Parse(template.Insert). Execute(map[string]interface{}{ "withCache": withCache, "upperStartCamelObject": camel, - "lowerStartCamelObject": stringx.From(camel).LowerStart(), + "lowerStartCamelObject": stringx.From(camel).UnTitle(), "expression": strings.Join(expressions, ", "), "expressionValues": strings.Join(expressionValues, ", "), }) diff --git a/tools/goctl/model/sql/gen/keys.go b/tools/goctl/model/sql/gen/keys.go index 3b058ce0..a3b3d175 100644 --- a/tools/goctl/model/sql/gen/keys.go +++ b/tools/goctl/model/sql/gen/keys.go @@ -26,14 +26,14 @@ type ( func genCacheKeys(table parser.Table) (map[string]Key, error) { fields := table.Fields m := make(map[string]Key) - camelTableName := table.Name.Snake2Camel() - lowerStartCamelTableName := stringx.From(camelTableName).LowerStart() + camelTableName := table.Name.ToCamel() + lowerStartCamelTableName := stringx.From(camelTableName).UnTitle() for _, field := range fields { if !field.IsKey { continue } - camelFieldName := field.Name.Snake2Camel() - lowerStartCamelFieldName := stringx.From(camelFieldName).LowerStart() + camelFieldName := field.Name.ToCamel() + lowerStartCamelFieldName := stringx.From(camelFieldName).UnTitle() left := fmt.Sprintf("cache%s%sPrefix", camelTableName, camelFieldName) right := fmt.Sprintf("cache#%s#%s#", camelTableName, lowerStartCamelFieldName) variable := fmt.Sprintf("%s%sKey", lowerStartCamelTableName, camelFieldName) diff --git a/tools/goctl/model/sql/gen/new.go b/tools/goctl/model/sql/gen/new.go index 15b598d8..b346068f 100644 --- a/tools/goctl/model/sql/gen/new.go +++ b/tools/goctl/model/sql/gen/new.go @@ -10,7 +10,7 @@ func genNew(table Table, withCache bool) (string, error) { Parse(template.New). Execute(map[string]interface{}{ "withCache": withCache, - "upperStartCamelObject": table.Name.Snake2Camel(), + "upperStartCamelObject": table.Name.ToCamel(), }) if err != nil { return "", err diff --git a/tools/goctl/model/sql/gen/types.go b/tools/goctl/model/sql/gen/types.go index 9d8be7ab..fc29241f 100644 --- a/tools/goctl/model/sql/gen/types.go +++ b/tools/goctl/model/sql/gen/types.go @@ -15,7 +15,7 @@ func genTypes(table Table, withCache bool) (string, error) { Parse(template.Types). Execute(map[string]interface{}{ "withCache": withCache, - "upperStartCamelObject": table.Name.Snake2Camel(), + "upperStartCamelObject": table.Name.ToCamel(), "fields": fieldsString, }) if err != nil { diff --git a/tools/goctl/model/sql/gen/update.go b/tools/goctl/model/sql/gen/update.go index 3a034b63..2a8a0a4d 100644 --- a/tools/goctl/model/sql/gen/update.go +++ b/tools/goctl/model/sql/gen/update.go @@ -11,7 +11,7 @@ import ( func genUpdate(table Table, withCache bool) (string, error) { expressionValues := make([]string, 0) for _, filed := range table.Fields { - camel := filed.Name.Snake2Camel() + camel := filed.Name.ToCamel() if camel == "CreateTime" || camel == "UpdateTime" { continue } @@ -20,8 +20,8 @@ func genUpdate(table Table, withCache bool) (string, error) { } expressionValues = append(expressionValues, "data."+camel) } - expressionValues = append(expressionValues, "data."+table.PrimaryKey.Name.Snake2Camel()) - camelTableName := table.Name.Snake2Camel() + expressionValues = append(expressionValues, "data."+table.PrimaryKey.Name.ToCamel()) + camelTableName := table.Name.ToCamel() output, err := templatex.With("update"). Parse(template.Update). Execute(map[string]interface{}{ @@ -29,7 +29,7 @@ func genUpdate(table Table, withCache bool) (string, error) { "upperStartCamelObject": camelTableName, "primaryCacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].DataKeyExpression, "primaryKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable, - "lowerStartCamelObject": stringx.From(camelTableName).LowerStart(), + "lowerStartCamelObject": stringx.From(camelTableName).UnTitle(), "originalPrimaryKey": table.PrimaryKey.Name.Source(), "expressionValues": strings.Join(expressionValues, ", "), }) diff --git a/tools/goctl/model/sql/gen/vars.go b/tools/goctl/model/sql/gen/vars.go index d2d00943..3d7d200d 100644 --- a/tools/goctl/model/sql/gen/vars.go +++ b/tools/goctl/model/sql/gen/vars.go @@ -13,12 +13,12 @@ func genVars(table Table, withCache bool) (string, error) { for _, v := range table.CacheKey { keys = append(keys, v.VarExpression) } - camel := table.Name.Snake2Camel() + camel := table.Name.ToCamel() output, err := templatex.With("var"). Parse(template.Vars). GoFmt(true). Execute(map[string]interface{}{ - "lowerStartCamelObject": stringx.From(camel).LowerStart(), + "lowerStartCamelObject": stringx.From(camel).UnTitle(), "upperStartCamelObject": camel, "cacheKeys": strings.Join(keys, "\r\n"), "autoIncrement": table.PrimaryKey.AutoIncrement, diff --git a/tools/goctl/model/sql/model/ddlmodel.go b/tools/goctl/model/sql/model/ddlmodel.go new file mode 100644 index 00000000..e89aa610 --- /dev/null +++ b/tools/goctl/model/sql/model/ddlmodel.go @@ -0,0 +1,33 @@ +package model + +import ( + "github.com/tal-tech/go-zero/core/stores/sqlx" +) + +type ( + DDLModel struct { + conn sqlx.SqlConn + } + DDL struct { + Table string `db:"Table"` + DDL string `db:"Create Table"` + } +) + +func NewDDLModel(conn sqlx.SqlConn) *DDLModel { + return &DDLModel{conn: conn} +} + +func (m *DDLModel) ShowDDL(table ...string) ([]string, error) { + var ddl []string + for _, t := range table { + query := `show create table ` + t + var resp DDL + err := m.conn.QueryRow(&resp, query) + if err != nil { + return nil, err + } + ddl = append(ddl, resp.DDL) + } + return ddl, nil +} diff --git a/tools/goctl/model/sql/parser/parser.go b/tools/goctl/model/sql/parser/parser.go index 0b638545..92b4fe5a 100644 --- a/tools/goctl/model/sql/parser/parser.go +++ b/tools/goctl/model/sql/parser/parser.go @@ -81,7 +81,7 @@ func Parse(ddl string) (*Table, error) { } column := index.Columns[0] columnName := column.Column.String() - camelColumnName := stringx.From(columnName).Snake2Camel() + camelColumnName := stringx.From(columnName).ToCamel() // by default, createTime|updateTime findOne is not used. if camelColumnName == "CreateTime" || camelColumnName == "UpdateTime" { continue diff --git a/tools/goctl/util/console/console.go b/tools/goctl/util/console/console.go index 946c6574..fb7b72de 100644 --- a/tools/goctl/util/console/console.go +++ b/tools/goctl/util/console/console.go @@ -19,6 +19,13 @@ type ( } ) +func NewConsole(idea bool) Console { + if idea { + return NewIdeaConsole() + } + return NewColorConsole() +} + func NewColorConsole() *colorConsole { return &colorConsole{} } diff --git a/tools/goctl/util/stringx/string.go b/tools/goctl/util/stringx/string.go index 2ce48d57..4ea890be 100644 --- a/tools/goctl/util/stringx/string.go +++ b/tools/goctl/util/stringx/string.go @@ -6,10 +6,6 @@ import ( "unicode" ) -const ( - emptyString = "" -) - type ( String struct { source string @@ -31,15 +27,9 @@ func (s String) IsEmptyOrSpace() bool { } func (s String) Lower() string { - if s.IsEmptyOrSpace() { - return s.source - } return strings.ToLower(s.source) } func (s String) Upper() string { - if s.IsEmptyOrSpace() { - return s.source - } return strings.ToUpper(s.source) } func (s String) Title() string { @@ -50,10 +40,7 @@ func (s String) Title() string { } // snake->camel(upper start) -func (s String) Snake2Camel() string { - if s.IsEmptyOrSpace() { - return s.source - } +func (s String) ToCamel() string { list := s.splitBy(func(r rune) bool { return r == '_' }, true) @@ -65,10 +52,7 @@ func (s String) Snake2Camel() string { } // camel->snake -func (s String) Camel2Snake() string { - if s.IsEmptyOrSpace() { - return s.source - } +func (s String) ToSnake() string { list := s.splitBy(func(r rune) bool { return unicode.IsUpper(r) }, false) @@ -80,7 +64,7 @@ func (s String) Camel2Snake() string { } // return original string if rune is not letter at index 0 -func (s String) LowerStart() string { +func (s String) UnTitle() string { if s.IsEmptyOrSpace() { return s.source } diff --git a/tools/goctl/util/stringx/string_test.go b/tools/goctl/util/stringx/string_test.go index b0ad07ff..943ee04f 100644 --- a/tools/goctl/util/stringx/string_test.go +++ b/tools/goctl/util/stringx/string_test.go @@ -17,26 +17,26 @@ func TestString_IsEmptyOrSpace(t *testing.T) { } func TestString_Snake2Camel(t *testing.T) { - ret := From("____this_is_snake").Snake2Camel() + ret := From("____this_is_snake").ToCamel() assert.Equal(t, "ThisIsSnake", ret) - ret2 := From("测试_test_Data").Snake2Camel() + ret2 := From("测试_test_Data").ToCamel() assert.Equal(t, "测试TestData", ret2) - ret3 := From("___").Snake2Camel() + ret3 := From("___").ToCamel() assert.Equal(t, "", ret3) - ret4 := From("testData_").Snake2Camel() + ret4 := From("testData_").ToCamel() assert.Equal(t, "TestData", ret4) - ret5 := From("testDataTestData").Snake2Camel() + ret5 := From("testDataTestData").ToCamel() assert.Equal(t, "TestDataTestData", ret5) } func TestString_Camel2Snake(t *testing.T) { - ret := From("ThisIsCCCamel").Camel2Snake() + ret := From("ThisIsCCCamel").ToSnake() assert.Equal(t, "this_is_c_c_camel", ret) - ret2 := From("测试Test_Data_test_data").Camel2Snake() + ret2 := From("测试Test_Data_test_data").ToSnake() assert.Equal(t, "测试_test__data_test_data", ret2) }