gocctl model v20200819 (#18)
* rename snake、came method * new: generate model from data source * add change log md * update model doc * update doc * beauty code
This commit is contained in:
@@ -195,6 +195,13 @@ ts需要指定webapi所在目录
|
|||||||
goctl api dart -api user/user.api -dir ./src
|
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使用)
|
## 根据定义好的简单go文件生成mongo代码文件(仅限golang使用)
|
||||||
```shell
|
```shell
|
||||||
goctl model mongo -src {{yourDir}}/xiao/service/xhb/user/model/usermodel.go -cache yes
|
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 分别表示生成返回单个对象的查询方法,返回多个对象的查询方法,设置该字段方法
|
o是改字段需要生产的操作函数 可以取得get,find,set 分别表示生成返回单个对象的查询方法,返回多个对象的查询方法,设置该字段方法
|
||||||
生成的目标文件会覆盖该简单go文件
|
生成的目标文件会覆盖该简单go文件
|
||||||
|
|
||||||
## goctl rpc生成
|
## goctl rpc生成(业务剥离中,暂未开放)
|
||||||
|
|
||||||
命令 `goctl rpc proto -proto ${proto} -service ${serviceName} -project ${projectName} -dir ${directory} -shared ${shared}`
|
命令 `goctl rpc proto -proto ${proto} -service ${serviceName} -project ${projectName} -dir ${directory} -shared ${shared}`
|
||||||
如: `goctl rpc proto -proto test.proto -service test -project xjy -dir .`
|
如: `goctl rpc proto -proto test.proto -service test -project xjy -dir .`
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
|
||||||
"github.com/tal-tech/go-zero/core/logx"
|
"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/apigen"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/dartgen"
|
"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/docker"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/feature"
|
"github.com/tal-tech/go-zero/tools/goctl/feature"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
|
"github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
|
||||||
"github.com/urfave/cli"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -191,25 +192,64 @@ var (
|
|||||||
{
|
{
|
||||||
Name: "model",
|
Name: "model",
|
||||||
Usage: "generate model code",
|
Usage: "generate model code",
|
||||||
Flags: []cli.Flag{
|
Subcommands: []cli.Command{
|
||||||
cli.StringFlag{
|
{
|
||||||
Name: "src, s",
|
Name: "mysql",
|
||||||
Usage: "the file path of the ddl source file",
|
Usage: `generate mysql model"`,
|
||||||
},
|
Subcommands: []cli.Command{
|
||||||
cli.StringFlag{
|
{
|
||||||
Name: "dir, d",
|
Name: "ddl",
|
||||||
Usage: "the target dir",
|
Usage: `generate mysql model from ddl"`,
|
||||||
},
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{
|
cli.StringFlag{
|
||||||
Name: "cache, c",
|
Name: "src, s",
|
||||||
Usage: "generate code with cache [optional]",
|
Usage: "the file path of the ddl source file",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.StringFlag{
|
||||||
Name: "idea",
|
Name: "dir, d",
|
||||||
Usage: "for idea plugin [optional]",
|
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",
|
Name: "config",
|
||||||
|
|||||||
10
tools/goctl/model/sql/CHANGELOG.md
Normal file
10
tools/goctl/model/sql/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Change log
|
||||||
|
|
||||||
|
# 2020-08-20
|
||||||
|
* 新增支持通过连接数据库生成model
|
||||||
|
* 支持数据库多表生成
|
||||||
|
* 优化stringx
|
||||||
|
|
||||||
|
# 2020-08-19
|
||||||
|
* 重构model代码生成逻辑
|
||||||
|
* 实现从ddl解析表信息生成代码
|
||||||
@@ -4,21 +4,28 @@ goctl model 为go-zero下的工具模块中的组件之一,目前支持识别m
|
|||||||
|
|
||||||
# 快速开始
|
# 快速开始
|
||||||
|
|
||||||
```
|
* 通过ddl生成
|
||||||
$ goctl model -src ./sql/user.sql -dir ./model -c true
|
|
||||||
```
|
|
||||||
|
|
||||||
详情用法请参考[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
|
model
|
||||||
│ ├── error.go
|
│ ├── error.go
|
||||||
│ └── usermodel.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:
|
NAME:
|
||||||
goctl model - generate model code
|
goctl model mysql - generate mysql model"
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
goctl model [command options] [arguments...]
|
goctl model mysql command [command options] [arguments...]
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
ddl generate mysql model from ddl"
|
||||||
|
datasource generate model from datasource"
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--src value, -s value the file path of the ddl source file
|
--help, -h show help
|
||||||
--dir value, -d value the target dir
|
|
||||||
--cache, -c generate code with cache [optional]
|
|
||||||
--idea for idea plugin [optional]
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# 生成规则
|
# 生成规则
|
||||||
@@ -198,22 +205,43 @@ OPTIONS:
|
|||||||
|
|
||||||
我们默认用户在建表时会创建createTime、updateTime字段(忽略大小写、下划线命名风格)且默认值均为`CURRENT_TIMESTAMP`,而updateTime支持`ON UPDATE CURRENT_TIMESTAMP`,对于这两个字段生成`insert`、`update`时会被移除,不在赋值范畴内,当然,如果你不需要这两个字段那也无大碍。
|
我们默认用户在建表时会创建createTime、updateTime字段(忽略大小写、下划线命名风格)且默认值均为`CURRENT_TIMESTAMP`,而updateTime支持`ON UPDATE CURRENT_TIMESTAMP`,对于这两个字段生成`insert`、`update`时会被移除,不在赋值范畴内,当然,如果你不需要这两个字段那也无大碍。
|
||||||
* 带缓存模式
|
* 带缓存模式
|
||||||
|
* ddl
|
||||||
```
|
|
||||||
$ goctl model -src {filename} -dir {dir} -cache true
|
```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`字段均属于单字段索引。
|
目前仅支持redis缓存,如果选择带缓存模式,即生成的`FindOne(ByXxx)`&`Delete`代码会生成带缓存逻辑的代码,目前仅支持单索引字段(除全文索引外),对于联合索引我们默认认为不需要带缓存,且不属于通用型代码,因此没有放在代码生成行列,如example中user表中的`id`、`name`、`mobile`字段均属于单字段索引。
|
||||||
|
|
||||||
* 不带缓存模式
|
* 不带缓存模式
|
||||||
|
|
||||||
```
|
* ddl
|
||||||
$ goctl model -src {filename} -dir {dir}
|
|
||||||
```
|
```shell script
|
||||||
|
$ goctl model -src={filename} -dir={dir}
|
||||||
|
```
|
||||||
|
* datasource
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
$ goctl model mysql datasource -url={datasource} -table={tables} -dir={dir}
|
||||||
|
```
|
||||||
or
|
or
|
||||||
```
|
* ddl
|
||||||
$ goctl model -src {filename} -dir {dir} -cache false
|
|
||||||
```
|
```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结构。
|
生成代码仅基本的CURD结构。
|
||||||
|
|
||||||
# 缓存
|
# 缓存
|
||||||
@@ -238,10 +266,6 @@ OPTIONS:
|
|||||||
|
|
||||||
# QA
|
# QA
|
||||||
|
|
||||||
* goctl model支持根据数据库连接后选择表生成代码吗?
|
|
||||||
|
|
||||||
目前暂时不支持,在后面会向这个方向扩展。
|
|
||||||
|
|
||||||
* goctl model除了命令行模式,支持插件模式吗?
|
* goctl model除了命令行模式,支持插件模式吗?
|
||||||
|
|
||||||
很快支持idea插件。
|
很快支持idea插件。
|
||||||
|
|||||||
@@ -1,24 +1,85 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
|
"io/ioutil"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/util/console"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Mysql(ctx *cli.Context) error {
|
const (
|
||||||
src := ctx.String("src")
|
flagSrc = "src"
|
||||||
dir := ctx.String("dir")
|
flagDir = "dir"
|
||||||
cache := ctx.Bool("cache")
|
flagCache = "cache"
|
||||||
idea := ctx.Bool("idea")
|
flagIdea = "idea"
|
||||||
var log console.Console
|
flagUrl = "url"
|
||||||
if idea {
|
flagTable = "table"
|
||||||
log = console.NewIdeaConsole()
|
)
|
||||||
} else {
|
|
||||||
log = console.NewColorConsole()
|
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
|
||||||
}
|
}
|
||||||
generator := gen.NewDefaultGenerator(src, dir, gen.WithConsoleOption(log))
|
data, err := ioutil.ReadFile(fileSrc)
|
||||||
err := generator.Start(cache)
|
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 {
|
if err != nil {
|
||||||
log.Error("%v", err)
|
log.Error("%v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# generate usermodel with cache
|
# generate model with cache from ddl
|
||||||
goctl model -src ./sql/user.sql -dir ./model -c true
|
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"
|
||||||
@@ -27,14 +27,14 @@ func genDelete(table Table, withCache bool) (string, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
camel := table.Name.Snake2Camel()
|
camel := table.Name.ToCamel()
|
||||||
output, err := templatex.With("delete").
|
output, err := templatex.With("delete").
|
||||||
Parse(template.Delete).
|
Parse(template.Delete).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"upperStartCamelObject": camel,
|
"upperStartCamelObject": camel,
|
||||||
"withCache": withCache,
|
"withCache": withCache,
|
||||||
"containsIndexCache": containsIndexCache,
|
"containsIndexCache": containsIndexCache,
|
||||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.Snake2Camel()).LowerStart(),
|
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
|
||||||
"dataType": table.PrimaryKey.DataType,
|
"dataType": table.PrimaryKey.DataType,
|
||||||
"keys": strings.Join(keySet.KeysStr(), "\n"),
|
"keys": strings.Join(keySet.KeysStr(), "\n"),
|
||||||
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func genField(field parser.Field) (string, error) {
|
|||||||
output, err := templatex.With("types").
|
output, err := templatex.With("types").
|
||||||
Parse(template.Field).
|
Parse(template.Field).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"name": field.Name.Snake2Camel(),
|
"name": field.Name.ToCamel(),
|
||||||
"type": field.DataType,
|
"type": field.DataType,
|
||||||
"tag": tag,
|
"tag": tag,
|
||||||
"hasComment": field.Comment != "",
|
"hasComment": field.Comment != "",
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func genFindOne(table Table, withCache bool) (string, error) {
|
func genFindOne(table Table, withCache bool) (string, error) {
|
||||||
camel := table.Name.Snake2Camel()
|
camel := table.Name.ToCamel()
|
||||||
output, err := templatex.With("findOne").
|
output, err := templatex.With("findOne").
|
||||||
Parse(template.FindOne).
|
Parse(template.FindOne).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"withCache": withCache,
|
"withCache": withCache,
|
||||||
"upperStartCamelObject": camel,
|
"upperStartCamelObject": camel,
|
||||||
"lowerStartCamelObject": stringx.From(camel).LowerStart(),
|
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
|
||||||
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
"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,
|
"dataType": table.PrimaryKey.DataType,
|
||||||
"cacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].KeyExpression,
|
"cacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].KeyExpression,
|
||||||
"cacheKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
|
"cacheKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
|
||||||
|
|||||||
@@ -12,23 +12,23 @@ import (
|
|||||||
func genFineOneByField(table Table, withCache bool) (string, error) {
|
func genFineOneByField(table Table, withCache bool) (string, error) {
|
||||||
t := templatex.With("findOneByField").Parse(template.FindOneByField)
|
t := templatex.With("findOneByField").Parse(template.FindOneByField)
|
||||||
var list []string
|
var list []string
|
||||||
camelTableName := table.Name.Snake2Camel()
|
camelTableName := table.Name.ToCamel()
|
||||||
for _, field := range table.Fields {
|
for _, field := range table.Fields {
|
||||||
if field.IsPrimaryKey || !field.IsKey {
|
if field.IsPrimaryKey || !field.IsKey {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
camelFieldName := field.Name.Snake2Camel()
|
camelFieldName := field.Name.ToCamel()
|
||||||
output, err := t.Execute(map[string]interface{}{
|
output, err := t.Execute(map[string]interface{}{
|
||||||
"upperStartCamelObject": camelTableName,
|
"upperStartCamelObject": camelTableName,
|
||||||
"upperField": camelFieldName,
|
"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,
|
"withCache": withCache,
|
||||||
"cacheKey": table.CacheKey[field.Name.Source()].KeyExpression,
|
"cacheKey": table.CacheKey[field.Name.Source()].KeyExpression,
|
||||||
"cacheKeyVariable": table.CacheKey[field.Name.Source()].Variable,
|
"cacheKeyVariable": table.CacheKey[field.Name.Source()].Variable,
|
||||||
"primaryKeyLeft": table.CacheKey[table.PrimaryKey.Name.Source()].Left,
|
"primaryKeyLeft": table.CacheKey[table.PrimaryKey.Name.Source()].Left,
|
||||||
"lowerStartCamelObject": stringx.From(camelTableName).LowerStart(),
|
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
|
||||||
"lowerStartCamelField": stringx.From(camelFieldName).LowerStart(),
|
"lowerStartCamelField": stringx.From(camelFieldName).UnTitle(),
|
||||||
"upperStartCamelPrimaryKey": table.PrimaryKey.Name.Snake2Camel(),
|
"upperStartCamelPrimaryKey": table.PrimaryKey.Name.ToCamel(),
|
||||||
"originalField": field.Name.Source(),
|
"originalField": field.Name.Source(),
|
||||||
"originalPrimaryField": table.PrimaryKey.Name.Source(),
|
"originalPrimaryField": table.PrimaryKey.Name.Source(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,21 +23,17 @@ const (
|
|||||||
type (
|
type (
|
||||||
defaultGenerator struct {
|
defaultGenerator struct {
|
||||||
source string
|
source string
|
||||||
src string
|
|
||||||
dir string
|
dir string
|
||||||
console.Console
|
console.Console
|
||||||
}
|
}
|
||||||
Option func(generator *defaultGenerator)
|
Option func(generator *defaultGenerator)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewDefaultGenerator(src, dir string, opt ...Option) *defaultGenerator {
|
func NewDefaultGenerator(source, dir string, opt ...Option) *defaultGenerator {
|
||||||
if src == "" {
|
|
||||||
src = pwd
|
|
||||||
}
|
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
dir = pwd
|
dir = pwd
|
||||||
}
|
}
|
||||||
generator := &defaultGenerator{src: src, dir: dir}
|
generator := &defaultGenerator{source: source, dir: dir}
|
||||||
var optionList []Option
|
var optionList []Option
|
||||||
optionList = append(optionList, newDefaultOption())
|
optionList = append(optionList, newDefaultOption())
|
||||||
optionList = append(optionList, opt...)
|
optionList = append(optionList, opt...)
|
||||||
@@ -60,10 +56,6 @@ func newDefaultOption() Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultGenerator) Start(withCache bool) error {
|
func (g *defaultGenerator) Start(withCache bool) error {
|
||||||
fileSrc, err := filepath.Abs(g.src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dirAbs, err := filepath.Abs(g.dir)
|
dirAbs, err := filepath.Abs(g.dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -72,21 +64,16 @@ func (g *defaultGenerator) Start(withCache bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(fileSrc)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
g.source = string(data)
|
|
||||||
modelList, err := g.genFromDDL(withCache)
|
modelList, err := g.genFromDDL(withCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for tableName, code := range modelList {
|
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)
|
filename := filepath.Join(dirAbs, name)
|
||||||
if util.FileExists(filename) {
|
if util.FileExists(filename) {
|
||||||
g.Warning("%s already exists,ignored.", name)
|
g.Warning("%s already exists, ignored.", name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(filename, []byte(code), os.ModePerm)
|
err = ioutil.WriteFile(filename, []byte(code), os.ModePerm)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func genInsert(table Table, withCache bool) (string, error) {
|
|||||||
expressions := make([]string, 0)
|
expressions := make([]string, 0)
|
||||||
expressionValues := make([]string, 0)
|
expressionValues := make([]string, 0)
|
||||||
for _, filed := range table.Fields {
|
for _, filed := range table.Fields {
|
||||||
camel := filed.Name.Snake2Camel()
|
camel := filed.Name.ToCamel()
|
||||||
if camel == "CreateTime" || camel == "UpdateTime" {
|
if camel == "CreateTime" || camel == "UpdateTime" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -22,13 +22,13 @@ func genInsert(table Table, withCache bool) (string, error) {
|
|||||||
expressions = append(expressions, "?")
|
expressions = append(expressions, "?")
|
||||||
expressionValues = append(expressionValues, "data."+camel)
|
expressionValues = append(expressionValues, "data."+camel)
|
||||||
}
|
}
|
||||||
camel := table.Name.Snake2Camel()
|
camel := table.Name.ToCamel()
|
||||||
output, err := templatex.With("insert").
|
output, err := templatex.With("insert").
|
||||||
Parse(template.Insert).
|
Parse(template.Insert).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"withCache": withCache,
|
"withCache": withCache,
|
||||||
"upperStartCamelObject": camel,
|
"upperStartCamelObject": camel,
|
||||||
"lowerStartCamelObject": stringx.From(camel).LowerStart(),
|
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
|
||||||
"expression": strings.Join(expressions, ", "),
|
"expression": strings.Join(expressions, ", "),
|
||||||
"expressionValues": strings.Join(expressionValues, ", "),
|
"expressionValues": strings.Join(expressionValues, ", "),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ type (
|
|||||||
func genCacheKeys(table parser.Table) (map[string]Key, error) {
|
func genCacheKeys(table parser.Table) (map[string]Key, error) {
|
||||||
fields := table.Fields
|
fields := table.Fields
|
||||||
m := make(map[string]Key)
|
m := make(map[string]Key)
|
||||||
camelTableName := table.Name.Snake2Camel()
|
camelTableName := table.Name.ToCamel()
|
||||||
lowerStartCamelTableName := stringx.From(camelTableName).LowerStart()
|
lowerStartCamelTableName := stringx.From(camelTableName).UnTitle()
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
if !field.IsKey {
|
if !field.IsKey {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
camelFieldName := field.Name.Snake2Camel()
|
camelFieldName := field.Name.ToCamel()
|
||||||
lowerStartCamelFieldName := stringx.From(camelFieldName).LowerStart()
|
lowerStartCamelFieldName := stringx.From(camelFieldName).UnTitle()
|
||||||
left := fmt.Sprintf("cache%s%sPrefix", camelTableName, camelFieldName)
|
left := fmt.Sprintf("cache%s%sPrefix", camelTableName, camelFieldName)
|
||||||
right := fmt.Sprintf("cache#%s#%s#", camelTableName, lowerStartCamelFieldName)
|
right := fmt.Sprintf("cache#%s#%s#", camelTableName, lowerStartCamelFieldName)
|
||||||
variable := fmt.Sprintf("%s%sKey", lowerStartCamelTableName, camelFieldName)
|
variable := fmt.Sprintf("%s%sKey", lowerStartCamelTableName, camelFieldName)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ func genNew(table Table, withCache bool) (string, error) {
|
|||||||
Parse(template.New).
|
Parse(template.New).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"withCache": withCache,
|
"withCache": withCache,
|
||||||
"upperStartCamelObject": table.Name.Snake2Camel(),
|
"upperStartCamelObject": table.Name.ToCamel(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func genTypes(table Table, withCache bool) (string, error) {
|
|||||||
Parse(template.Types).
|
Parse(template.Types).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"withCache": withCache,
|
"withCache": withCache,
|
||||||
"upperStartCamelObject": table.Name.Snake2Camel(),
|
"upperStartCamelObject": table.Name.ToCamel(),
|
||||||
"fields": fieldsString,
|
"fields": fieldsString,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
func genUpdate(table Table, withCache bool) (string, error) {
|
func genUpdate(table Table, withCache bool) (string, error) {
|
||||||
expressionValues := make([]string, 0)
|
expressionValues := make([]string, 0)
|
||||||
for _, filed := range table.Fields {
|
for _, filed := range table.Fields {
|
||||||
camel := filed.Name.Snake2Camel()
|
camel := filed.Name.ToCamel()
|
||||||
if camel == "CreateTime" || camel == "UpdateTime" {
|
if camel == "CreateTime" || camel == "UpdateTime" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -20,8 +20,8 @@ func genUpdate(table Table, withCache bool) (string, error) {
|
|||||||
}
|
}
|
||||||
expressionValues = append(expressionValues, "data."+camel)
|
expressionValues = append(expressionValues, "data."+camel)
|
||||||
}
|
}
|
||||||
expressionValues = append(expressionValues, "data."+table.PrimaryKey.Name.Snake2Camel())
|
expressionValues = append(expressionValues, "data."+table.PrimaryKey.Name.ToCamel())
|
||||||
camelTableName := table.Name.Snake2Camel()
|
camelTableName := table.Name.ToCamel()
|
||||||
output, err := templatex.With("update").
|
output, err := templatex.With("update").
|
||||||
Parse(template.Update).
|
Parse(template.Update).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
@@ -29,7 +29,7 @@ func genUpdate(table Table, withCache bool) (string, error) {
|
|||||||
"upperStartCamelObject": camelTableName,
|
"upperStartCamelObject": camelTableName,
|
||||||
"primaryCacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].DataKeyExpression,
|
"primaryCacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].DataKeyExpression,
|
||||||
"primaryKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
|
"primaryKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
|
||||||
"lowerStartCamelObject": stringx.From(camelTableName).LowerStart(),
|
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
|
||||||
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
||||||
"expressionValues": strings.Join(expressionValues, ", "),
|
"expressionValues": strings.Join(expressionValues, ", "),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ func genVars(table Table, withCache bool) (string, error) {
|
|||||||
for _, v := range table.CacheKey {
|
for _, v := range table.CacheKey {
|
||||||
keys = append(keys, v.VarExpression)
|
keys = append(keys, v.VarExpression)
|
||||||
}
|
}
|
||||||
camel := table.Name.Snake2Camel()
|
camel := table.Name.ToCamel()
|
||||||
output, err := templatex.With("var").
|
output, err := templatex.With("var").
|
||||||
Parse(template.Vars).
|
Parse(template.Vars).
|
||||||
GoFmt(true).
|
GoFmt(true).
|
||||||
Execute(map[string]interface{}{
|
Execute(map[string]interface{}{
|
||||||
"lowerStartCamelObject": stringx.From(camel).LowerStart(),
|
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
|
||||||
"upperStartCamelObject": camel,
|
"upperStartCamelObject": camel,
|
||||||
"cacheKeys": strings.Join(keys, "\r\n"),
|
"cacheKeys": strings.Join(keys, "\r\n"),
|
||||||
"autoIncrement": table.PrimaryKey.AutoIncrement,
|
"autoIncrement": table.PrimaryKey.AutoIncrement,
|
||||||
|
|||||||
33
tools/goctl/model/sql/model/ddlmodel.go
Normal file
33
tools/goctl/model/sql/model/ddlmodel.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
@@ -81,7 +81,7 @@ func Parse(ddl string) (*Table, error) {
|
|||||||
}
|
}
|
||||||
column := index.Columns[0]
|
column := index.Columns[0]
|
||||||
columnName := column.Column.String()
|
columnName := column.Column.String()
|
||||||
camelColumnName := stringx.From(columnName).Snake2Camel()
|
camelColumnName := stringx.From(columnName).ToCamel()
|
||||||
// by default, createTime|updateTime findOne is not used.
|
// by default, createTime|updateTime findOne is not used.
|
||||||
if camelColumnName == "CreateTime" || camelColumnName == "UpdateTime" {
|
if camelColumnName == "CreateTime" || camelColumnName == "UpdateTime" {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewConsole(idea bool) Console {
|
||||||
|
if idea {
|
||||||
|
return NewIdeaConsole()
|
||||||
|
}
|
||||||
|
return NewColorConsole()
|
||||||
|
}
|
||||||
|
|
||||||
func NewColorConsole() *colorConsole {
|
func NewColorConsole() *colorConsole {
|
||||||
return &colorConsole{}
|
return &colorConsole{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
emptyString = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
String struct {
|
String struct {
|
||||||
source string
|
source string
|
||||||
@@ -31,15 +27,9 @@ func (s String) IsEmptyOrSpace() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s String) Lower() string {
|
func (s String) Lower() string {
|
||||||
if s.IsEmptyOrSpace() {
|
|
||||||
return s.source
|
|
||||||
}
|
|
||||||
return strings.ToLower(s.source)
|
return strings.ToLower(s.source)
|
||||||
}
|
}
|
||||||
func (s String) Upper() string {
|
func (s String) Upper() string {
|
||||||
if s.IsEmptyOrSpace() {
|
|
||||||
return s.source
|
|
||||||
}
|
|
||||||
return strings.ToUpper(s.source)
|
return strings.ToUpper(s.source)
|
||||||
}
|
}
|
||||||
func (s String) Title() string {
|
func (s String) Title() string {
|
||||||
@@ -50,10 +40,7 @@ func (s String) Title() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// snake->camel(upper start)
|
// snake->camel(upper start)
|
||||||
func (s String) Snake2Camel() string {
|
func (s String) ToCamel() string {
|
||||||
if s.IsEmptyOrSpace() {
|
|
||||||
return s.source
|
|
||||||
}
|
|
||||||
list := s.splitBy(func(r rune) bool {
|
list := s.splitBy(func(r rune) bool {
|
||||||
return r == '_'
|
return r == '_'
|
||||||
}, true)
|
}, true)
|
||||||
@@ -65,10 +52,7 @@ func (s String) Snake2Camel() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// camel->snake
|
// camel->snake
|
||||||
func (s String) Camel2Snake() string {
|
func (s String) ToSnake() string {
|
||||||
if s.IsEmptyOrSpace() {
|
|
||||||
return s.source
|
|
||||||
}
|
|
||||||
list := s.splitBy(func(r rune) bool {
|
list := s.splitBy(func(r rune) bool {
|
||||||
return unicode.IsUpper(r)
|
return unicode.IsUpper(r)
|
||||||
}, false)
|
}, false)
|
||||||
@@ -80,7 +64,7 @@ func (s String) Camel2Snake() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return original string if rune is not letter at index 0
|
// return original string if rune is not letter at index 0
|
||||||
func (s String) LowerStart() string {
|
func (s String) UnTitle() string {
|
||||||
if s.IsEmptyOrSpace() {
|
if s.IsEmptyOrSpace() {
|
||||||
return s.source
|
return s.source
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,26 +17,26 @@ func TestString_IsEmptyOrSpace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestString_Snake2Camel(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)
|
assert.Equal(t, "ThisIsSnake", ret)
|
||||||
|
|
||||||
ret2 := From("测试_test_Data").Snake2Camel()
|
ret2 := From("测试_test_Data").ToCamel()
|
||||||
assert.Equal(t, "测试TestData", ret2)
|
assert.Equal(t, "测试TestData", ret2)
|
||||||
|
|
||||||
ret3 := From("___").Snake2Camel()
|
ret3 := From("___").ToCamel()
|
||||||
assert.Equal(t, "", ret3)
|
assert.Equal(t, "", ret3)
|
||||||
|
|
||||||
ret4 := From("testData_").Snake2Camel()
|
ret4 := From("testData_").ToCamel()
|
||||||
assert.Equal(t, "TestData", ret4)
|
assert.Equal(t, "TestData", ret4)
|
||||||
|
|
||||||
ret5 := From("testDataTestData").Snake2Camel()
|
ret5 := From("testDataTestData").ToCamel()
|
||||||
assert.Equal(t, "TestDataTestData", ret5)
|
assert.Equal(t, "TestDataTestData", ret5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestString_Camel2Snake(t *testing.T) {
|
func TestString_Camel2Snake(t *testing.T) {
|
||||||
ret := From("ThisIsCCCamel").Camel2Snake()
|
ret := From("ThisIsCCCamel").ToSnake()
|
||||||
assert.Equal(t, "this_is_c_c_camel", ret)
|
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)
|
assert.Equal(t, "测试_test__data_test_data", ret2)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user