├── .gitignore ├── Makefile ├── README.md ├── builder ├── builder.go ├── command.go ├── create_file.go ├── findSql │ ├── find_columns.go │ ├── find_tables.go │ └── interface_sql.go └── template.go ├── core ├── config.go ├── driver.go ├── gofile.go └── schema.go ├── dialect ├── gorm │ └── gorm_to_go.go ├── maria │ └── gen.go ├── mongo │ └── gen.go ├── mssql │ └── gen.go ├── mysql │ ├── find_columns_sql.go │ ├── mysql.go │ └── schema.go ├── pgsql │ ├── find_columns_sql.go │ ├── gen.go │ └── pgsql.go └── sqlite │ └── db.go ├── go.mod ├── go.sum ├── main.go └── utils ├── color.go ├── db_to_go.go ├── flag.go ├── utils.go └── utils_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | bin 8 | _gen 9 | 10 | # Test binary, built with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | *.idea 16 | # Dependency directories (remove the comment below to include it) 17 | # vendor/ 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | ## build@编译程序。 4 | .PHONY:build 5 | build:clean 6 | @go build -o ./bin/ 7 | @echo "\033[31m ☕️ 编译完成\033[0m"; 8 | 9 | ## clean@清理编译、日志和缓存等数据。 10 | .PHONY:clean 11 | clean: 12 | @rm -rf ./logs; 13 | @rm -rf ./log; 14 | @rm -rf ./debug; 15 | @rm -rf ./tmp; 16 | @rm -rf ./temp; 17 | @rm -rf ./model; 18 | @rm -rf ./db2go; 19 | @rm -rf ./bin; 20 | @rm -rf ./_gen; 21 | @echo "\033[31m ✅ 清理完毕\033[0m"; 22 | 23 | 24 | ## commit @提交Git(格式:make commit msg=备注内容,msg为可选参数)。 25 | .PHONY:commit 26 | message:=$(if $(msg),$(msg),"Rebuilded at $$(date '+%Y年%m月%d日 %H时%M分%S秒')") 27 | commit: 28 | @echo "\033[0;34mPush to remote...\033[0m" 29 | @git add . 30 | @git commit -m $(message) 31 | @echo "\033[0;31m 💿 Commit完毕\033[0m" 32 | 33 | 34 | ## push @提交并推送到Git仓库(格式:make push msg=备注内容,msg为可选参数)。 35 | .PHONY:push 36 | push:commit 37 | @git push #origin master 38 | @echo "\033[0;31m ⬆️ Push完毕\033[0m" 39 | 40 | 41 | ## test@执行测试。 42 | .PHONY:test 43 | test: build 44 | @./bin/db2go -driver=pgsql -host=localhost -port=5432 -user=postgres -auth=123456 -dbname=deeplink -gorm=true -package=hello 45 | 46 | 47 | ## help@查看make帮助。 48 | .PHONY:help 49 | help:Makefile 50 | @echo "Usage:\n make [command]" 51 | @echo 52 | @echo "Available Commands:" 53 | @sed -n "s/^##//p" $< | column -t -s '@' |grep --color=auto "^[[:space:]][a-z]\+[[:space:]]" 54 | @echo 55 | @echo "For more to see https://makefiletutorial.com/" 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # db2go 2 | 一个使 mysql、pgsql.sql 数据库表自动生成 go struct 的工具 3 | 4 | ### 快速使用 5 | 6 | 将项目放入到GOPATH/src目录下,进入项目根目录下进行 7 | 8 | ```shell 9 | $ go build 10 | ``` 11 | 12 | 对于不同的操作系统 13 | 14 | `windows` 15 | 16 | ```shell 17 | $ db2go.exe -host=127.0.0.1 -port=5432 -user=postgres -pwd=postgres -dbname=db_test -gorm=true -driver=pgsql.sql 18 | ``` 19 | 20 | `linux` 21 | 22 | ```shell 23 | $ ./db2go -host=127.0.0.1 -port=3306 -user=root -pwd=root -dbname=db_test -gorm=true -driver=mysql -package=hello 24 | ``` 25 | 26 | ### 命令行提示 27 | 28 | 执行 29 | 30 | ```shell 31 | $ ./db2go -help 32 | ``` 33 | 34 | 35 | 36 | ```powershell 37 | Usage of db2go.exe: 38 | -dbname string 39 | 必填,数据库名称,否则会报错 40 | -driver string 41 | 必填,需要连接的数据库,现在只支持mysql、pgsql.sql 例如 -driver=mysql,-driver=pgsql.sql 42 | -gorm 43 | 选填,是否添加 gorm tag,true添加,false不添加,默认不添加 44 | -host string 45 | 选填,数据库ip,默认为localhost (default "localhost") 46 | -outdir string 47 | 选填,go 文件输出路径,不设置的话会输出到当前程序所在路径 (default "./go_output") 48 | -package string 49 | 选填,go 文件中 package 的名字,默认为 package main (default "main") 50 | -port int 51 | 必填,数据库端口 52 | -pwd string 53 | 必填,数据库密码 54 | -table string 55 | 选填,需要导出的数据库表名称,如果不设置的话会将该数据库所有的表导出 56 | -user string 57 | 必填,数据库用户名 58 | ``` 59 | 60 | -------------------------------------------------------------------------------- /builder/builder.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package builder 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "os" 11 | "time" 12 | 13 | "github.com/yishuihanj/db2go/builder/findSql" 14 | "github.com/yishuihanj/db2go/core" 15 | "github.com/yishuihanj/db2go/dialect/pgsql" 16 | "github.com/yishuihanj/db2go/utils" 17 | ) 18 | 19 | var Tables []string 20 | var Columns []*findSql.Column 21 | 22 | // 生成器工厂 23 | func schemaFactory(driver core.DatabaseDriver, cfg *core.Config) core.Schema { 24 | switch driver { 25 | // case core.MySQL: 26 | // return mysql.New(cfg) 27 | // case core.PostgreSQL: 28 | // return pgsql.New(cfg) 29 | // case core.SQLite: 30 | // return new(mysql.Generator) 31 | // case core.MariaDB: 32 | // return new(mysql.Generator) 33 | // case core.MongoDB: 34 | // return new(mysql.Generator) 35 | // case core.Oracle: 36 | // return new(mysql.Generator) 37 | default: 38 | return pgsql.New(cfg) 39 | } 40 | } 41 | 42 | // 执行生成命令 43 | func Generate(driver core.DatabaseDriver, cfg *core.Config) error { 44 | schema := schemaFactory(driver, cfg) 45 | tables, err := schema.Tables() 46 | if err != nil { 47 | return err 48 | } 49 | if len(tables) == 0 { 50 | return errors.New("the count of tables in the database is 0") 51 | } 52 | 53 | if err := os.MkdirAll(cfg.Out, os.ModePerm); err != nil { 54 | return err 55 | } 56 | 57 | // 单文件输出 58 | if cfg.Pile { 59 | gofile := utils.PathTrim(fmt.Sprintf("%s/%s.go", cfg.Out, cfg.DbName)) 60 | f, err := os.Create(gofile) 61 | if err != nil { 62 | return err 63 | } 64 | data := Schema2Template(driver, cfg, tables...) 65 | if err := Execute(f, data); err != nil { 66 | return err 67 | } 68 | fmt.Printf(" 📖 生成文件:%s\n", gofile) 69 | return nil 70 | } 71 | 72 | // 多文件输出 73 | for _, table := range tables { 74 | gofile := utils.PathTrim(fmt.Sprintf("%s/%s.go", cfg.Out, table.Name)) 75 | f, err := os.Create(gofile) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | data := Schema2Template(driver, cfg, table) 81 | if err := Execute(f, data); err != nil { 82 | return err 83 | } 84 | fmt.Printf(" 🚀 生成文件: %s\n", gofile) 85 | } 86 | return nil 87 | } 88 | 89 | func Schema2Template(driver core.DatabaseDriver, cfg *core.Config, tables ...core.Table) *GenTemplate { 90 | t := &GenTemplate{ 91 | Generator: cfg.AppName, 92 | Version: cfg.Version, 93 | Source: fmt.Sprintf("%s://%s:%d/%s", driver, cfg.Host, cfg.Port, cfg.DbName), 94 | Date: time.Now().Format("2006-01-02"), 95 | Package: cfg.Package, 96 | } 97 | if len(tables) == 1 { 98 | t.Source = fmt.Sprintf("%s://%s:%d/%s/%s", driver, cfg.Host, cfg.Port, cfg.DbName, tables[0].Name) 99 | } 100 | 101 | for _, table := range tables { 102 | obj := Struct{ 103 | Name: utils.Pascal(table.Name), 104 | Comment: table.Comment, 105 | } 106 | for _, column := range table.Columns { 107 | obj.Fields = append(obj.Fields, Field{ 108 | Name: utils.Pascal(column.Name), 109 | Type: column.Type, // fixme 转换 110 | Tag: column.Default, 111 | Comment: column.Comment, 112 | }) 113 | } 114 | t.Imports = table.SpecialPack 115 | t.Structs = append(t.Structs, obj) 116 | } 117 | return t 118 | } 119 | -------------------------------------------------------------------------------- /builder/command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package builder 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | 11 | "github.com/yishuihanj/db2go/core" 12 | "github.com/yishuihanj/db2go/dialect/gorm" 13 | "github.com/yishuihanj/db2go/utils" 14 | ) 15 | 16 | // 版本信息 17 | const AppName = "db2go" 18 | const VERSION = "v1.0.0" 19 | 20 | var ( 21 | _driver string 22 | _host string 23 | _port int 24 | _user string 25 | _auth string 26 | _dbName string 27 | _package string 28 | _out string 29 | _clean bool 30 | _version bool 31 | _help bool 32 | _pile bool 33 | ) 34 | 35 | // 初始化Flag 36 | func initFlag() { 37 | utils.Usage = Usage 38 | utils.StringVar(&_driver, "driver", "", "DB驱动") 39 | utils.StringVar(&_host, "host", "localhost", "主机名") 40 | utils.IntVar(&_port, "port", 0, "端口") 41 | utils.StringVar(&_user, "user", "", "用户名") 42 | utils.StringVar(&_auth, "auth", "", "密码") 43 | utils.StringVar(&_dbName, "dbname", "", "数据库名称") 44 | utils.BoolVar(&gorm.Gorm, "gorm", false, "是否添加gorm标签") 45 | utils.StringVar(&_out, "out", "./_gen", "输出路径") 46 | utils.StringVar(&_package, "package", "model", "go文件包名") 47 | utils.BoolVar(&_clean, "clean", false, "是否清理输出目录") 48 | utils.BoolVar(&_version, "version", false, "查看版本") 49 | utils.BoolVar(&_pile, "pile", false, "单文件输出") 50 | utils.BoolVar(&_help, "help", false, "查看帮助") 51 | } 52 | 53 | // 加载命令行参数 54 | func Load() (core.DatabaseDriver, *core.Config) { 55 | defer func() { 56 | if err := recover(); err != nil { 57 | fmt.Printf("\033[%dmAn error occurred: %v\033[0m\n\n", utils.FgRed, err) 58 | Usage() 59 | os.Exit(1) 60 | } 61 | }() 62 | 63 | initFlag() 64 | if err := utils.Parse(); err != nil { 65 | panic(err) 66 | } 67 | 68 | if _help || len(os.Args) == 1 { 69 | Usage() 70 | os.Exit(0) 71 | } 72 | 73 | if _version { 74 | fmt.Println(VERSION) 75 | os.Exit(0) 76 | } 77 | 78 | if err := check(); err != nil { 79 | panic(err) 80 | } 81 | if _clean { 82 | os.RemoveAll(_out) 83 | os.Exit(0) 84 | } 85 | return core.DriverValue(_driver), &core.Config{ 86 | AppName: AppName, 87 | Version: VERSION, 88 | Host: _host, 89 | Port: _port, 90 | User: _user, 91 | Auth: _auth, 92 | DbName: _dbName, 93 | Package: _package, 94 | Out: _out, 95 | Pile: _pile, 96 | } 97 | } 98 | 99 | // 检查命令行参数 100 | func check() error { 101 | if len(_driver) == 0 { 102 | return fmt.Errorf("driver is needed") 103 | } 104 | 105 | if !core.Supported(_driver) { 106 | return fmt.Errorf("the driver named %v is not supported", _driver) 107 | } 108 | 109 | if len(_dbName) == 0 { 110 | return fmt.Errorf("dbname is needed") 111 | } 112 | return nil 113 | } 114 | 115 | // 打印帮助信息 116 | func Usage() { 117 | fmt.Println("\033[1;34m Welcome to db2go\033[0m") 118 | fmt.Printf("\033[1;34m ______ ______ ______ _____ \n | \\ |_____] | ____ | |\n |_____/ |_____] 2 |______||_____| (%v)\033[0m\n", VERSION) 119 | fmt.Printf(` 120 | Usage: 121 | db2go dbname= [option]... 122 | 123 | Command: 124 | mysql 从mysql数据库生成表实体 125 | pgsql 从postgres数据库生成表实体 126 | help 查看帮助 127 | 128 | Option: 129 | -host 主机名 130 | -host 主机名 131 | -host 主机名 132 | -host 主机名 133 | -host 主机名 134 | -host 主机名 135 | 136 | Default param: 137 | mysql: -host=localhost -port=3306 -user=root -auth="" 138 | pgsql: -host=localhost -port=5432 -user=postgres -auth=postgres 139 | 140 | Example: 141 | db2go -driver=pgsql -dbname=testdb 142 | db2go -driver=pgsql -host=localhost -port=5432 -user=postgres -auth=postgres -dbname=testdb -gorm -package=entity 143 | 144 | 更多详情,请参考 https://github.com/hollson/db2go 145 | 146 | `) 147 | } 148 | -------------------------------------------------------------------------------- /builder/create_file.go: -------------------------------------------------------------------------------- 1 | package builder 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //创建文件 9 | func CreateFile(_tableName, s string, outDir string) error { 10 | exist, err := pathExists(outDir) 11 | if err != nil { 12 | return err 13 | } 14 | //文件夹不存在 创建 15 | if !exist { 16 | fmt.Printf("\"%s\" 输出目录不存在,创建目录...\n", outDir) 17 | os.Mkdir(outDir, os.ModePerm) 18 | } 19 | 20 | f, err := os.Create(fmt.Sprintf("%s/%s.go", outDir, _tableName)) 21 | defer f.Close() 22 | if err != nil { 23 | fmt.Printf("错误! 创建 %s.go 文件失败,err:%v", _tableName, err.Error()) 24 | return err 25 | } else { 26 | _, err = f.Write([]byte(s)) 27 | if err != nil { 28 | fmt.Printf("错误! 创建 %s.go 文件失败,err:%v", _tableName, err.Error()) 29 | return err 30 | } 31 | } 32 | fmt.Printf("创建 %s.go 文件成功,路径为:%s\n", _tableName, f.Name()) 33 | return nil 34 | } 35 | 36 | func pathExists(path string) (bool, error) { 37 | _, err := os.Stat(path) 38 | if err == nil { 39 | return true, nil 40 | } 41 | if os.IsNotExist(err) { 42 | return false, nil 43 | } 44 | return false, err 45 | } 46 | -------------------------------------------------------------------------------- /builder/findSql/find_columns.go: -------------------------------------------------------------------------------- 1 | package findSql 2 | 3 | type Column struct { 4 | ColumnName string // 字段名 5 | NotNull string // 是否为空 6 | DefaultValue string // 默认值 7 | IsPrimaryKey string // 是否是主键 8 | ColumnType string // 字段类型 9 | Comment string // 注释 10 | } 11 | 12 | // 查找表中的字段 13 | func FindColumns(sqlInterface SqlInterface, _tableName string) ([]*Column, error) { 14 | db := sqlInterface.GetDB() 15 | rows, err := db.Query(sqlInterface.FindColumnsString(), _tableName) 16 | if err != nil { 17 | return nil, err 18 | } 19 | defer rows.Close() 20 | columns := make([]*Column, 0, 0) 21 | for rows.Next() { 22 | var column Column 23 | err = rows.Scan(&column.ColumnName, 24 | &column.NotNull, 25 | &column.DefaultValue, 26 | &column.IsPrimaryKey, 27 | &column.Comment, 28 | &column.ColumnType) 29 | if err != nil { 30 | return nil, err 31 | } 32 | columns = append(columns, &column) 33 | } 34 | return columns, nil 35 | 36 | } 37 | -------------------------------------------------------------------------------- /builder/findSql/find_tables.go: -------------------------------------------------------------------------------- 1 | package findSql 2 | 3 | //查找该数据库的数据库表 4 | func FindTables(model SqlInterface) ([]string, error) { 5 | db := model.GetDB() 6 | rows, err := db.Query(model.FindTableString()) 7 | if err != nil { 8 | return nil, err 9 | } 10 | defer rows.Close() 11 | tablesName := make([]string, 0, 0) 12 | for rows.Next() { 13 | var tableName string 14 | err = rows.Scan(&tableName) 15 | if err != nil { 16 | return nil, err 17 | } 18 | tablesName = append(tablesName, tableName) 19 | } 20 | return tablesName, nil 21 | } 22 | -------------------------------------------------------------------------------- /builder/findSql/interface_sql.go: -------------------------------------------------------------------------------- 1 | package findSql 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "strings" 8 | 9 | "github.com/yishuihanj/db2go/dialect/mysql" 10 | "github.com/yishuihanj/db2go/dialect/pgsql" 11 | ) 12 | 13 | type SqlInterface interface { 14 | Init(userName, pwd, host string, port int, dbName string) error 15 | FindTableString() string 16 | FindColumnsString() string 17 | DBNameString() string 18 | GetDB() *sql.DB 19 | } 20 | 21 | var driverMap map[string]SqlInterface 22 | 23 | func init() { 24 | driverMap = make(map[string]SqlInterface, 0) 25 | driverMap["mysql"] = &mysql.MySql{} 26 | driverMap["pgsql"] = &pgsql.PostgresSql{} 27 | } 28 | 29 | func SelectDriver(driver string) (SqlInterface, error) { 30 | driver = strings.ToLower(driver) 31 | model, ok := driverMap[driver] 32 | if !ok { 33 | fmt.Println(driver) 34 | return nil, errors.New("错误:该程序不包含该数据库的导出功能,请检查 -driver 是否设置正确...") 35 | } 36 | return model, nil 37 | } 38 | -------------------------------------------------------------------------------- /builder/template.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | 使用template模板方式,将Struct对象转换为go文件 7 | */ 8 | package builder 9 | 10 | import ( 11 | "fmt" 12 | "io" 13 | "strings" 14 | "text/template" 15 | 16 | "github.com/yishuihanj/db2go/utils" 17 | ) 18 | 19 | // Go文件模板 20 | var _template = `// Code generated by {{.Generator}}. DO NOT EDIT. 21 | // source: {{.Source}} 22 | // {{.Generator}}: {{.Version}} 23 | // date: {{.Date}} 24 | 25 | package {{.Package}} {{ifImports .Imports}} 26 | {{range .Structs}}{{ifComment .Comment}} 27 | type {{.Name}} struct { 28 | {{range .Fields}}{{.Name}} {{.Type}} {{.Tag}}{{if ne .Comment ""}} //{{.Comment}}{{end}} 29 | {{ end }} 30 | } 31 | {{end}}` 32 | 33 | type GenTemplate struct { 34 | Generator string // 生成器名称 35 | Version string // 生成器版本 36 | Source string // 生成的来源(模板数据来源,如:192.168.0.10:5432/testdb/tableName) 37 | Date string // 生成日期 38 | Package string // 包名 39 | Imports []string // 依赖包 40 | Structs []Struct // 结构体 41 | } 42 | 43 | // Go文件中的结构体 44 | type Struct struct { 45 | Name string // 结构体名称 46 | Comment string // 结构体注释 47 | Fields []Field // 结构体字段 48 | Methods []Method // todo:结构体方法 49 | } 50 | 51 | // Go文件中的结构体字段 52 | type Field struct { 53 | Name string // 字段名称 54 | Type string // 字段类型 55 | Tag string // 字段标签 56 | Comment string // 字段注释 57 | } 58 | 59 | // todo:Go文件中的方法 60 | type Method struct { 61 | // ... 62 | } 63 | 64 | // 自定义模板表达式:加载依赖包 65 | func IfImports(imports []string) string { 66 | if len(imports) > 0 { 67 | utils.RangeStringsFunc(imports, func(s string) string { 68 | return fmt.Sprintf("\t\"%s\"", s) 69 | }) 70 | return fmt.Sprintf(` 71 | import ( 72 | %s 73 | )`, strings.Join(imports, "\n")) 74 | } 75 | return "" 76 | } 77 | 78 | // 自定义模板表达式:成员注释 79 | func IfComment(comment string) string { 80 | if len(comment) > 0 { 81 | return fmt.Sprintf("// %s", comment) 82 | } 83 | return "" 84 | } 85 | 86 | // 模板生成输出内容 87 | func Execute(w io.Writer, tpl *GenTemplate) error { 88 | t := template.New("text") // 定义模板对象 89 | t = t.Funcs(template.FuncMap{"ifImports": IfImports}) // 控制自定义元素 90 | t = t.Funcs(template.FuncMap{"ifComment": IfComment}) // 控制自定义元素 91 | t, err := t.Parse(_template) // 92 | if err != nil { 93 | return err 94 | } 95 | 96 | if err := t.Execute(w, tpl); err != nil { 97 | return err 98 | } 99 | return nil 100 | } 101 | -------------------------------------------------------------------------------- /core/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package core 6 | 7 | import ( 8 | "fmt" 9 | ) 10 | 11 | // 数据库代码生成器配置项 12 | type Config struct { 13 | AppName string // 应用名称 14 | Version string // 应用版本 15 | Host string // 主机 16 | Port int // 端口,具化默认值 17 | User string // 用户,具化默认值 18 | Auth string // 密码,具化默认值 19 | DbName string // 数据库 20 | Package string // 包名 21 | Out string // 输出路径 22 | Pile bool // 单文件输出 23 | } 24 | 25 | func (c *Config) String()string { 26 | return fmt.Sprintf("%+v",*c) 27 | } -------------------------------------------------------------------------------- /core/driver.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | 代码生成器所支持的数据库驱动项 7 | */ 8 | package core 9 | 10 | // database driver type 11 | type DatabaseDriver int 12 | 13 | const ( 14 | Unknown DatabaseDriver = iota 15 | MySQL 16 | PostgreSQL 17 | SQLite 18 | MongoDB 19 | MariaDB 20 | Oracle 21 | SQLServer 22 | ) 23 | 24 | // driver name 25 | func (d DatabaseDriver) String() string { 26 | return []string{"MySQL", "PostgreSQL", "SQLite", "MongoDB", "MariaDB", "Oracle", "SQLServer"}[d-1] 27 | } 28 | 29 | // driver short name 30 | func (d DatabaseDriver) Name() string { 31 | return []string{"mysql", "pgsql", "sqlite", "mongo", "maria", "oracle", "mssql"}[d-1] 32 | } 33 | 34 | // get driver value by driver short name 35 | func DriverValue(name string) DatabaseDriver { 36 | if d, ok := map[string]DatabaseDriver{ 37 | "mysql": MySQL, 38 | "pgsql": PostgreSQL, 39 | "sqlite": SQLite, 40 | "mongo": MongoDB, 41 | "maria": MariaDB, 42 | "oracle": Oracle, 43 | "mssql": SQLServer, 44 | }[name]; ok { 45 | return d 46 | } 47 | return Unknown 48 | } 49 | 50 | // Determine whether the driver is supported 51 | func Supported(name string) bool { 52 | ds := []DatabaseDriver{ 53 | MySQL, 54 | PostgreSQL, 55 | // SQLite, 56 | // MongoDB, 57 | // MariaDB, 58 | // Oracle, 59 | // SQLServer, 60 | } 61 | for _, v := range ds { 62 | if DriverValue(name) == v { 63 | return true 64 | } 65 | } 66 | return false 67 | } 68 | -------------------------------------------------------------------------------- /core/gofile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Go文件结构定义 7 | */ 8 | package core 9 | // 10 | // type Template struct { 11 | // Generator string // 生成器名称 12 | // Version string // 生成器版本 13 | // Source string // 生成的来源(模板数据来源,如:192.168.0.10:5432/testdb/tableName) 14 | // Date string // 生成日期 15 | // Package string // 包名 16 | // Imports []string // 依赖包 17 | // Structs []Struct // 结构体 18 | // } 19 | // 20 | // // Go文件中的结构体 21 | // type Struct struct { 22 | // StructName string // 结构体名称 23 | // StructComment string // 结构体注释 24 | // Fields []Field // 结构体字段 25 | // Methods []Method // todo:结构体方法 26 | // } 27 | // 28 | // // Go文件中的结构体字段 29 | // type Field struct { 30 | // Name string // 字段名称 31 | // Type string // 字段类型 32 | // Tag string // 字段标签 33 | // Comment string // 字段注释 34 | // } 35 | // 36 | // // todo:Go文件中的方法 37 | // type Method struct { 38 | // // ... 39 | // } 40 | -------------------------------------------------------------------------------- /core/schema.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Schema定义了代码生成器所依赖的数据库信息 7 | */ 8 | package core 9 | 10 | // 数据库信息 11 | type Schema interface { 12 | Tables() ([]Table, error) 13 | // 类型映射 14 | } 15 | 16 | // 数据库表 17 | type Table struct { 18 | Name string // 表名 19 | Columns []Column // 字段 20 | Comment string // 注释 21 | // 特殊类型的依赖包 22 | // 如pg.Int64Array类型,须引用"github.com/lib/pg" 23 | SpecialPack []string 24 | } 25 | 26 | // 数据库表字段 27 | type Column struct { 28 | Primary bool // 是否主键 29 | Name string // 字段 30 | Type string // 类型 31 | Size int // 长度 32 | NotNull bool // 不为Null 33 | Default string // 默认值 34 | Comment string // 注释 35 | } 36 | -------------------------------------------------------------------------------- /dialect/gorm/gorm_to_go.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/yishuihanj/db2go/builder/findSql" 8 | ) 9 | 10 | var Gorm bool 11 | 12 | //向字段中添加 Gorm tag 13 | func AddGormTag(column *findSql.Column) string { 14 | //如果没有开启gorm 则 不需要转换 // dogner 15 | if !Gorm { 16 | return "" 17 | } 18 | tag := fmt.Sprintf("\t`gorm:\"column:%s", column.ColumnName) 19 | if column.NotNull == "true" { 20 | tag += fmt.Sprintf(";not null") 21 | } 22 | if column.DefaultValue != "" && column.IsPrimaryKey != "true" { 23 | if strings.Contains(column.DefaultValue, "''") { //如果有 ''则置为 空字符串 24 | column.DefaultValue = fmt.Sprintf("''") 25 | } 26 | tag += fmt.Sprintf(";default:%s", column.DefaultValue) 27 | } 28 | if column.IsPrimaryKey == "true" { 29 | tag += fmt.Sprintf(";primaryKey") 30 | } 31 | if column.ColumnType != "" { 32 | tag += fmt.Sprintf(";type:%s", column.ColumnType) 33 | } 34 | if column.Comment != "" { 35 | tag += fmt.Sprintf(";commnet:'%s'", column.Comment) 36 | } 37 | end := fmt.Sprintf("\"`") 38 | return tag + end 39 | } 40 | -------------------------------------------------------------------------------- /dialect/maria/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package maria -------------------------------------------------------------------------------- /dialect/mongo/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mongo -------------------------------------------------------------------------------- /dialect/mssql/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mssql -------------------------------------------------------------------------------- /dialect/mysql/find_columns_sql.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | var findColumnSql = `SELECT 4 | COLUMN_NAME AS column_name, 5 | #IS_NULLABLE as not_null 6 | (CASE IS_NULLABLE WHEN 'YES' THEN 'true' WHEN 'NO' THEN 'false' END) as not_null, 7 | (CASE ISNULL(COLUMN_DEFAULT) WHEN true THEN '' ELSE COLUMN_DEFAULT END) as default_value, 8 | (CASE COLUMN_KEY WHEN 'PRI' THEN 'true' ELSE 'false' END ) as is_primary_key, 9 | COLUMN_COMMENT as comment, 10 | COLUMN_TYPE as column_type 11 | FROM 12 | information_schema.COLUMNS 13 | WHERE 14 | table_name = ?` 15 | -------------------------------------------------------------------------------- /dialect/mysql/mysql.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | _ "github.com/go-sql-driver/mysql" 7 | ) 8 | 9 | type MySql struct { 10 | DB *sql.DB 11 | DBName string 12 | } 13 | 14 | //连接pgsql数据库 15 | func (this *MySql) Init(userName, pwd, host string, port int, dbName string) error { 16 | dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:%v)/%s", userName, pwd, host, port, dbName) 17 | _db, err := sql.Open("mysql", dataSourceName) 18 | if err != nil { 19 | return err 20 | } 21 | this.DB = _db 22 | this.DBName = dbName 23 | return nil 24 | } 25 | func (this *MySql) FindTableString() string { 26 | return fmt.Sprintf("select table_name from information_schema.tables where table_schema='%s'", this.DBName) 27 | } 28 | func (*MySql) FindColumnsString() string { 29 | return findColumnSql 30 | } 31 | 32 | func (this *MySql) DBNameString() string { 33 | return this.DBName 34 | } 35 | 36 | func (this *MySql) GetDB() *sql.DB { 37 | return this.DB 38 | } 39 | -------------------------------------------------------------------------------- /dialect/mysql/schema.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mysql 6 | 7 | import ( 8 | "github.com/yishuihanj/db2go/core" 9 | ) 10 | 11 | type Generator struct { 12 | Host string 13 | Port int 14 | User string 15 | Auth string 16 | DbName string 17 | } 18 | 19 | func New(config *core.Config) *Generator { 20 | gen := &Generator{ 21 | Host: "", 22 | Port: 0, 23 | User: "", 24 | Auth: "", 25 | DbName: "", 26 | } 27 | return gen 28 | } 29 | 30 | 31 | func (g *Generator) Gen() error { 32 | 33 | panic("implement me") 34 | } 35 | -------------------------------------------------------------------------------- /dialect/pgsql/find_columns_sql.go: -------------------------------------------------------------------------------- 1 | package pgsql 2 | 3 | var findColumnSql = `SELECT A.attname AS COLUMN_NAME, 4 | A.attnotnull AS not_null, 5 | COALESCE ( pg_get_expr ( ad.adbin, ad.adrelid ), '' ) AS default_value, 6 | COALESCE ( ct.contype = 'p', FALSE ) AS is_primary_key, 7 | COALESCE(b.description,'') AS comment, 8 | CASE 9 | 10 | WHEN A.atttypid = ANY ( '{int,int8,int2}' :: regtype [] ) 11 | AND EXISTS ( 12 | SELECT 13 | 1 14 | FROM 15 | pg_attrdef ad 16 | WHERE 17 | ad.adrelid = A.attrelid 18 | AND ad.adnum = A.attnum) THEN 19 | CASE 20 | A.atttypid 21 | WHEN 'int' :: regtype THEN 22 | 'serial' 23 | WHEN 'int8' :: regtype THEN 24 | 'bigserial' 25 | WHEN 'int2' :: regtype THEN 26 | 'smallserial' 27 | END 28 | WHEN A.atttypid = ANY ( '{uuid}' :: regtype [] ) 29 | AND COALESCE ( pg_get_expr ( ad.adbin, ad.adrelid ), '' ) != '' THEN 30 | 'autogenuuid' ELSE format_type ( A.atttypid, A.atttypmod ) 31 | END AS column_type 32 | FROM 33 | pg_attribute 34 | A JOIN ONLY pg_class C ON C.oid = A.attrelid 35 | JOIN ONLY pg_namespace n ON n.oid = C.relnamespace 36 | LEFT JOIN pg_constraint ct ON ct.conrelid = C.oid 37 | AND A.attnum = ANY ( ct.conkey ) 38 | AND ct.contype = 'p' 39 | LEFT JOIN pg_attrdef ad ON ad.adrelid = C.oid 40 | AND ad.adnum = A.attnum 41 | LEFT JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid 42 | WHERE 43 | A.attisdropped = FALSE 44 | AND n.nspname = 'public' 45 | AND C.relname = $1 46 | AND A.attnum > 0 47 | ORDER BY 48 | A.attnum` 49 | 50 | //find table sql 51 | var findTableSql = `SELECT 52 | A.relname AS NAME 53 | FROM 54 | pg_class A 55 | WHERE 56 | A.relnamespace = ( SELECT oid FROM pg_namespace WHERE nspname = 'public' ) --用户表一般存储在public模式下 57 | 58 | AND A.relkind = 'r' 59 | ORDER BY 60 | A.relname` 61 | -------------------------------------------------------------------------------- /dialect/pgsql/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pgsql 6 | 7 | import ( 8 | "database/sql" 9 | "fmt" 10 | 11 | "github.com/yishuihanj/db2go/core" 12 | ) 13 | 14 | type Database struct { 15 | Host string 16 | Port int 17 | User string 18 | Auth string 19 | DbName string 20 | } 21 | 22 | func New(c *core.Config) *Database { 23 | gen := &Database{ 24 | Host: c.Host, 25 | Port: c.Port, 26 | User: c.User, 27 | Auth: c.Auth, 28 | DbName: c.DbName, 29 | } 30 | if gen.Port == 0 { 31 | gen.Port = 5432 32 | } 33 | if len(gen.User) == 0 { 34 | gen.User = "postgres" 35 | } 36 | if len(gen.Auth) == 0 { 37 | gen.Auth = "postgres" 38 | } 39 | return gen 40 | } 41 | 42 | func (g *Database) Close() error { 43 | return nil 44 | } 45 | 46 | // 连接字符串 47 | func (g *Database) source() string { 48 | return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", 49 | g.User, g.Auth, g.Host, g.Port, g.DbName) 50 | } 51 | 52 | // 查询数据库表清单SQL 53 | func (g *Database) tablesSQL() string { 54 | return `SELECT a.tablename, 55 | COALESCE(c.description,'') AS comment 56 | FROM pg_tables a 57 | LEFT JOIN pg_class b on a.tablename=b.relname 58 | LEFT JOIN pg_description c on b.oid=c.objoid and c.objsubid=0 59 | WHERE a.schemaname='public';` 60 | } 61 | 62 | // 查询数据表定义SQL 63 | func (g *Database) columnsSQL(tableName string) string { 64 | return fmt.Sprintf(` 65 | SELECT a.attname AS field_name, --字段表名 66 | a.attnotnull AS not_null, --是否为NULL 67 | a.attlen AS field_size, -- 字段大小 68 | COALESCE (ct.contype = 'p', FALSE ) AS is_primary_key, -- 是否主键 69 | COALESCE (pg_get_expr(ad.adbin, ad.adrelid),'') AS default_value, -- 默认值 70 | COALESCE(b.description,'') AS comment, --注释 71 | CASE WHEN a.atttypid = ANY ('{int,int8,int2}'::regtype[]) AND EXISTS (SELECT 1 FROM pg_attrdef ad WHERE ad.adrelid = a.attrelid AND ad.adnum = a.attnum ) 72 | THEN CASE a.atttypid 73 | WHEN 'int'::regtype THEN 'serial' 74 | WHEN 'int8'::regtype THEN 'bigserial' 75 | WHEN 'int2'::regtype THEN 'smallserial' END 76 | WHEN a.atttypid = ANY ('{uuid}'::regtype[]) AND COALESCE (pg_get_expr(ad.adbin, ad.adrelid ),'')<>'' 77 | THEN 'autogenuuid' ELSE format_type( a.atttypid, a.atttypmod ) 78 | END AS field_type -- 标识类型 79 | FROM pg_attribute a 80 | INNER JOIN ONLY pg_class C ON C.oid = a.attrelid 81 | INNER JOIN ONLY pg_namespace n ON n.oid = C.relnamespace 82 | LEFT JOIN pg_constraint ct ON ct.conrelid = C.oid AND a.attnum = ANY ( ct.conkey ) AND ct.contype = 'p' 83 | LEFT JOIN pg_attrdef ad ON ad.adrelid = C.oid AND ad.adnum = a.attnum 84 | LEFT JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid 85 | LEFT join pg_type t ON a.atttypid = t.oid 86 | WHERE a.attisdropped = FALSE AND a.attnum > 0 AND n.nspname = 'public' AND C.relname ='%s' -- 表名 87 | ORDER BY a.attnum 88 | `, tableName) 89 | } 90 | 91 | // 92 | func (g *Database) Tables() (ret []core.Table, err error) { 93 | _db, err := sql.Open("postgres", g.source()) 94 | if err != nil { 95 | return nil, err 96 | } 97 | fmt.Printf(" 💻 连接数据库: %s\n", g.source()) 98 | defer _db.Close() 99 | 100 | rows, err := _db.Query(g.tablesSQL()) 101 | if err != nil { 102 | return nil, err 103 | } 104 | defer rows.Close() 105 | 106 | for rows.Next() { 107 | var t = core.Table{} 108 | if err := rows.Scan(&t.Name, &t.Comment); err != nil { 109 | return nil, err 110 | } 111 | cs, err := g.columns(t.Name, _db) 112 | if err != nil { 113 | return nil, err 114 | } 115 | t.Columns = cs 116 | ret = append(ret, t) 117 | } 118 | return 119 | } 120 | 121 | func (g *Database) columns(tableName string, db *sql.DB) (ret []core.Column, err error) { 122 | rows, err := db.Query(g.columnsSQL(tableName)) 123 | if err != nil { 124 | return nil, err 125 | } 126 | defer rows.Close() 127 | var t = core.Column{} 128 | for rows.Next() { 129 | if err := rows.Scan( 130 | &t.Name, 131 | &t.NotNull, 132 | &t.Size, 133 | &t.Primary, 134 | &t.Default, 135 | &t.Comment, 136 | &t.Type); err != nil { 137 | return nil, err 138 | } 139 | ret = append(ret, t) 140 | } 141 | return 142 | } 143 | 144 | // 类型映射 145 | func TypeMapping() { 146 | 147 | } 148 | 149 | func (g *Database) Gen() error { 150 | 151 | panic("implement me") 152 | } 153 | -------------------------------------------------------------------------------- /dialect/pgsql/pgsql.go: -------------------------------------------------------------------------------- 1 | package pgsql 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | _ "github.com/lib/pq" 7 | ) 8 | 9 | type PostgresSql struct { 10 | DB *sql.DB 11 | DBName string 12 | } 13 | 14 | //连接pgsql数据库 15 | func (this *PostgresSql) Init(userName, pwd, host string, port int, dbName string) error { 16 | dataSourceName := fmt.Sprintf("user=%s password=%s host=%s port=%d dbname=%s sslmode=disable", userName, pwd, host, port, dbName) 17 | _db, err := sql.Open("postgres", dataSourceName) 18 | if err != nil { 19 | return err 20 | } 21 | this.DB = _db 22 | this.DBName = dbName 23 | return nil 24 | } 25 | func (this *PostgresSql) FindTableString() string { 26 | return findTableSql 27 | } 28 | func (*PostgresSql) FindColumnsString() string { 29 | return findColumnSql 30 | } 31 | 32 | func (this *PostgresSql) DBNameString() string { 33 | return this.DBName 34 | } 35 | func (this *PostgresSql) GetDB() *sql.DB { 36 | return this.DB 37 | } 38 | -------------------------------------------------------------------------------- /dialect/sqlite/db.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlite -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/yishuihanj/db2go 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/go-sql-driver/mysql v1.6.0 7 | github.com/lib/pq v1.10.2 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 2 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 3 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 4 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 5 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | 8 | "github.com/yishuihanj/db2go/builder" 9 | ) 10 | 11 | //go:generate go build 12 | func main() { 13 | // 加载命令行参数 14 | driver, cfg := builder.Load() 15 | 16 | // 执行生成命令 17 | if err := builder.Generate(driver, cfg); err != nil { 18 | fmt.Println(err.Error()) 19 | os.Exit(1) 20 | } 21 | 22 | // 格式化 23 | cmd := exec.Command("go", "fmt", cfg.Out) 24 | if err := cmd.Start(); err != nil { 25 | fmt.Printf("format go files failed,%v", err) 26 | os.Exit(1) 27 | } 28 | fmt.Printf(" ✅ 完成任务\n\n") 29 | } 30 | -------------------------------------------------------------------------------- /utils/color.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package utils 6 | 7 | // 颜色 8 | type Color int 9 | 10 | // 前景色 11 | const ( 12 | FgBlack Color = iota + 30 // 30: 黑色 13 | FgRed // 31: 红色 14 | FgGreen // 32: 绿色 15 | FgYellow // 33: 黄色 16 | FgBlue // 34: 蓝色 17 | FgMagenta // 35: 品红/洋紫 18 | FgCyan // 36: 青色 19 | FgWhite // 37: 白色 20 | ) 21 | 22 | // 背景色 23 | const ( 24 | BgBlack Color = iota + 40 // 40: 黑色 25 | BgRed // 41: 红色 26 | BgGreen // 42: 绿色 27 | BgYellow // 43: 黄色 28 | BgBlue // 44: 蓝色 29 | BgMagenta // 45: 品红/洋紫 30 | BgCyan // 46: 青色 31 | BgWhite // 47: 白色 32 | ) 33 | 34 | // 样式 35 | type Style int 36 | 37 | const ( 38 | Reset Style = iota // 0: 重置 39 | Bold // 1: 加粗 40 | Faint // 2: 模糊 41 | Italic // 3: 斜体 42 | Underline // 4: 下划线 43 | BlinkSlow // 5: 慢速闪烁 44 | BlinkRapid // 6: 快速闪烁 45 | ReverseVideo // 7: 反白/反向显示 46 | Concealed // 8: 隐藏/暗格 47 | CrossedOut // 9: 删除 48 | ) 49 | 50 | -------------------------------------------------------------------------------- /utils/db_to_go.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/yishuihanj/db2go/builder/findSql" 8 | "github.com/yishuihanj/db2go/dialect/gorm" 9 | ) 10 | 11 | var Pkg string 12 | 13 | //将字段名转换成结构体字段 不包含tag 14 | func ColumnsToStruct(_tableName string, columns []*findSql.Column) string { 15 | columnString := "" 16 | for _, column := range columns { 17 | singleString := fmt.Sprintf("\t%s\t%s", splitUnderline(column.ColumnName), typeConvert(column.ColumnType)) 18 | singleString = singleString + gorm.AddGormTag(column) + "\n" 19 | columnString += singleString 20 | } 21 | return fmt.Sprintf("package %s\ntype %s struct {\n%s}", Pkg, splitUnderline(_tableName), columnString) 22 | } 23 | 24 | //如果字符串有下滑线的则将下划线除去 并开头字母大写 例如 v1_user 变为 V1User 25 | func splitUnderline(s string) string { 26 | arr := strings.Split(s, "_") 27 | ret := "" 28 | for _, v := range arr { 29 | ret += strings.Title(v) 30 | } 31 | return ret 32 | } 33 | 34 | 35 | //类型转换,没有的类型在这里面添加 36 | func typeConvert(s string) string { 37 | if strings.Contains(s, "[]") { 38 | if strings.Contains(s, "char") || strings.Contains(s, "text") { 39 | return "pq.StringArray" 40 | } 41 | if strings.Contains(s, "integer") { 42 | return "pq.Int64Array" 43 | } 44 | } 45 | if strings.Contains(s, "char") || In(s, []string{"text", "longtext"}) { 46 | return "string" 47 | } 48 | if In(s, []string{"bigserial", "serial", "big serial", "int"}) { 49 | return "int" 50 | } 51 | if In(s, []string{"bigint"}) { 52 | return "int64" 53 | } 54 | if In(s, []string{"integer"}) { 55 | return "int32" 56 | } 57 | if In(s, []string{"smallint"}) { 58 | return "int16" 59 | } 60 | if In(s, []string{"numeric", "decimal", "real"}) { 61 | return "decimal.Decimal" 62 | } 63 | if In(s, []string{"bytea"}) { 64 | return "[]byte" 65 | } 66 | if strings.Contains(s, "time") || In(s, []string{"date"}) { 67 | return "time.Time" 68 | } 69 | 70 | return "interface{}" 71 | } 72 | -------------------------------------------------------------------------------- /utils/flag.go: -------------------------------------------------------------------------------- 1 | // 从系统flag库改造而来,调整了系统panic处理机制和usage调用方式等 2 | package utils 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | "io" 8 | "os" 9 | "reflect" 10 | "sort" 11 | "strconv" 12 | "strings" 13 | "time" 14 | ) 15 | 16 | // ErrHelp is the error returned if the -help or -h flag is invoked 17 | // but no such flag is defined. 18 | var ErrHelp = errors.New("flag: help requested") 19 | 20 | // errParse is returned by Set if a flag's value fails to parse, such as with an invalid integer for Int. 21 | // It then gets wrapped through failf to provide more information. 22 | var errParse = errors.New("parse error") 23 | 24 | // errRange is returned by Set if a flag's value is out of range. 25 | // It then gets wrapped through failf to provide more information. 26 | var errRange = errors.New("value out of range") 27 | 28 | func numError(err error) error { 29 | ne, ok := err.(*strconv.NumError) 30 | if !ok { 31 | return err 32 | } 33 | if ne.Err == strconv.ErrSyntax { 34 | return errParse 35 | } 36 | if ne.Err == strconv.ErrRange { 37 | return errRange 38 | } 39 | return err 40 | } 41 | 42 | // -- bool Value 43 | type boolValue bool 44 | 45 | func newBoolValue(val bool, p *bool) *boolValue { 46 | *p = val 47 | return (*boolValue)(p) 48 | } 49 | 50 | func (b *boolValue) Set(s string) error { 51 | v, err := strconv.ParseBool(s) 52 | if err != nil { 53 | err = errParse 54 | } 55 | *b = boolValue(v) 56 | return err 57 | } 58 | 59 | func (b *boolValue) Get() interface{} { return bool(*b) } 60 | 61 | func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } 62 | 63 | func (b *boolValue) IsBoolFlag() bool { return true } 64 | 65 | // optional interface to indicate boolean flags that can be 66 | // supplied without "=value" text 67 | type boolFlag interface { 68 | Value 69 | IsBoolFlag() bool 70 | } 71 | 72 | // -- int Value 73 | type intValue int 74 | 75 | func newIntValue(val int, p *int) *intValue { 76 | *p = val 77 | return (*intValue)(p) 78 | } 79 | 80 | func (i *intValue) Set(s string) error { 81 | v, err := strconv.ParseInt(s, 0, strconv.IntSize) 82 | if err != nil { 83 | err = numError(err) 84 | } 85 | *i = intValue(v) 86 | return err 87 | } 88 | 89 | func (i *intValue) Get() interface{} { return int(*i) } 90 | 91 | func (i *intValue) String() string { return strconv.Itoa(int(*i)) } 92 | 93 | // -- int64 Value 94 | type int64Value int64 95 | 96 | func newInt64Value(val int64, p *int64) *int64Value { 97 | *p = val 98 | return (*int64Value)(p) 99 | } 100 | 101 | func (i *int64Value) Set(s string) error { 102 | v, err := strconv.ParseInt(s, 0, 64) 103 | if err != nil { 104 | err = numError(err) 105 | } 106 | *i = int64Value(v) 107 | return err 108 | } 109 | 110 | func (i *int64Value) Get() interface{} { return int64(*i) } 111 | 112 | func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } 113 | 114 | // -- uint Value 115 | type uintValue uint 116 | 117 | func newUintValue(val uint, p *uint) *uintValue { 118 | *p = val 119 | return (*uintValue)(p) 120 | } 121 | 122 | func (i *uintValue) Set(s string) error { 123 | v, err := strconv.ParseUint(s, 0, strconv.IntSize) 124 | if err != nil { 125 | err = numError(err) 126 | } 127 | *i = uintValue(v) 128 | return err 129 | } 130 | 131 | func (i *uintValue) Get() interface{} { return uint(*i) } 132 | 133 | func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } 134 | 135 | // -- uint64 Value 136 | type uint64Value uint64 137 | 138 | func newUint64Value(val uint64, p *uint64) *uint64Value { 139 | *p = val 140 | return (*uint64Value)(p) 141 | } 142 | 143 | func (i *uint64Value) Set(s string) error { 144 | v, err := strconv.ParseUint(s, 0, 64) 145 | if err != nil { 146 | err = numError(err) 147 | } 148 | *i = uint64Value(v) 149 | return err 150 | } 151 | 152 | func (i *uint64Value) Get() interface{} { return uint64(*i) } 153 | 154 | func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } 155 | 156 | // -- string Value 157 | type stringValue string 158 | 159 | func newStringValue(val string, p *string) *stringValue { 160 | *p = val 161 | return (*stringValue)(p) 162 | } 163 | 164 | func (s *stringValue) Set(val string) error { 165 | *s = stringValue(val) 166 | return nil 167 | } 168 | 169 | func (s *stringValue) Get() interface{} { return string(*s) } 170 | 171 | func (s *stringValue) String() string { return string(*s) } 172 | 173 | // -- float64 Value 174 | type float64Value float64 175 | 176 | func newFloat64Value(val float64, p *float64) *float64Value { 177 | *p = val 178 | return (*float64Value)(p) 179 | } 180 | 181 | func (f *float64Value) Set(s string) error { 182 | v, err := strconv.ParseFloat(s, 64) 183 | if err != nil { 184 | err = numError(err) 185 | } 186 | *f = float64Value(v) 187 | return err 188 | } 189 | 190 | func (f *float64Value) Get() interface{} { return float64(*f) } 191 | 192 | func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } 193 | 194 | // -- time.Duration Value 195 | type durationValue time.Duration 196 | 197 | func newDurationValue(val time.Duration, p *time.Duration) *durationValue { 198 | *p = val 199 | return (*durationValue)(p) 200 | } 201 | 202 | func (d *durationValue) Set(s string) error { 203 | v, err := time.ParseDuration(s) 204 | if err != nil { 205 | err = errParse 206 | } 207 | *d = durationValue(v) 208 | return err 209 | } 210 | 211 | func (d *durationValue) Get() interface{} { return time.Duration(*d) } 212 | 213 | func (d *durationValue) String() string { return (*time.Duration)(d).String() } 214 | 215 | type funcValue func(string) error 216 | 217 | func (f funcValue) Set(s string) error { return f(s) } 218 | 219 | func (f funcValue) String() string { return "" } 220 | 221 | // Value is the interface to the dynamic value stored in a flag. 222 | // (The default value is represented as a string.) 223 | // 224 | // If a Value has an IsBoolFlag() bool method returning true, 225 | // the command-line parser makes -name equivalent to -name=true 226 | // rather than using the next command-line argument. 227 | // 228 | // Set is called once, in command line order, for each flag present. 229 | // The flag package may call the String method with a zero-valued receiver, 230 | // such as a nil pointer. 231 | type Value interface { 232 | String() string 233 | Set(string) error 234 | } 235 | 236 | // Getter is an interface that allows the contents of a Value to be retrieved. 237 | // It wraps the Value interface, rather than being part of it, because it 238 | // appeared after Go 1 and its compatibility rules. All Value types provided 239 | // by this package satisfy the Getter interface, except the type used by Func. 240 | type Getter interface { 241 | Value 242 | Get() interface{} 243 | } 244 | 245 | // ErrorHandling defines how FlagSet.Parse behaves if the parse fails. 246 | type ErrorHandling int 247 | 248 | // These constants cause FlagSet.Parse to behave as described if the parse fails. 249 | const ( 250 | ContinueOnError ErrorHandling = iota // Return a descriptive error. 251 | ExitOnError // Call os.Exit(2) or for -h/-help Exit(0). 252 | PanicOnError // Call panic with a descriptive error. 253 | ) 254 | 255 | // A FlagSet represents a set of defined flags. The zero value of a FlagSet 256 | // has no name and has ContinueOnError error handling. 257 | // 258 | // Flag names must be unique within a FlagSet. An attempt to define a flag whose 259 | // name is already in use will cause a panic. 260 | type FlagSet struct { 261 | // Usage is the function called when an error occurs while parsing flags. 262 | // The field is a function (not a method) that may be changed to point to 263 | // a custom error handler. What happens after Usage is called depends 264 | // on the ErrorHandling setting; for the command line, this defaults 265 | // to ExitOnError, which exits the program after calling Usage. 266 | Usage func() 267 | 268 | name string 269 | parsed bool 270 | actual map[string]*Flag 271 | formal map[string]*Flag 272 | args []string // arguments after flags 273 | errorHandling ErrorHandling 274 | output io.Writer // nil means stderr; use Output() accessor 275 | } 276 | 277 | // A Flag represents the state of a flag. 278 | type Flag struct { 279 | Name string // name as it appears on command line 280 | Usage string // help message 281 | Value Value // value as set 282 | DefValue string // default value (as text); for usage message 283 | } 284 | 285 | // sortFlags returns the flags as a slice in lexicographical sorted order. 286 | func sortFlags(flags map[string]*Flag) []*Flag { 287 | result := make([]*Flag, len(flags)) 288 | i := 0 289 | for _, f := range flags { 290 | result[i] = f 291 | i++ 292 | } 293 | sort.Slice(result, func(i, j int) bool { 294 | return result[i].Name < result[j].Name 295 | }) 296 | return result 297 | } 298 | 299 | // Output returns the destination for usage and error messages. os.Stderr is returned if 300 | // output was not set or was set to nil. 301 | func (f *FlagSet) Output() io.Writer { 302 | if f.output == nil { 303 | return os.Stderr 304 | } 305 | return f.output 306 | } 307 | 308 | // Name returns the name of the flag set. 309 | func (f *FlagSet) Name() string { 310 | return f.name 311 | } 312 | 313 | // ErrorHandling returns the error handling behavior of the flag set. 314 | func (f *FlagSet) ErrorHandling() ErrorHandling { 315 | return f.errorHandling 316 | } 317 | 318 | // SetOutput sets the destination for usage and error messages. 319 | // If output is nil, os.Stderr is used. 320 | func (f *FlagSet) SetOutput(output io.Writer) { 321 | f.output = output 322 | } 323 | 324 | // VisitAll visits the flags in lexicographical order, calling fn for each. 325 | // It visits all flags, even those not set. 326 | func (f *FlagSet) VisitAll(fn func(*Flag)) { 327 | for _, flag := range sortFlags(f.formal) { 328 | fn(flag) 329 | } 330 | } 331 | 332 | // VisitAll visits the command-line flags in lexicographical order, calling 333 | // fn for each. It visits all flags, even those not set. 334 | func VisitAll(fn func(*Flag)) { 335 | CommandLine.VisitAll(fn) 336 | } 337 | 338 | // Visit visits the flags in lexicographical order, calling fn for each. 339 | // It visits only those flags that have been set. 340 | func (f *FlagSet) Visit(fn func(*Flag)) { 341 | for _, flag := range sortFlags(f.actual) { 342 | fn(flag) 343 | } 344 | } 345 | 346 | // Visit visits the command-line flags in lexicographical order, calling fn 347 | // for each. It visits only those flags that have been set. 348 | func Visit(fn func(*Flag)) { 349 | CommandLine.Visit(fn) 350 | } 351 | 352 | // Lookup returns the Flag structure of the named flag, returning nil if none exists. 353 | func (f *FlagSet) Lookup(name string) *Flag { 354 | return f.formal[name] 355 | } 356 | 357 | // Lookup returns the Flag structure of the named command-line flag, 358 | // returning nil if none exists. 359 | func Lookup(name string) *Flag { 360 | return CommandLine.formal[name] 361 | } 362 | 363 | // Set sets the value of the named flag. 364 | func (f *FlagSet) Set(name, value string) error { 365 | flag, ok := f.formal[name] 366 | if !ok { 367 | return fmt.Errorf("no such flag -%v", name) 368 | } 369 | err := flag.Value.Set(value) 370 | if err != nil { 371 | return err 372 | } 373 | if f.actual == nil { 374 | f.actual = make(map[string]*Flag) 375 | } 376 | f.actual[name] = flag 377 | return nil 378 | } 379 | 380 | // Set sets the value of the named command-line flag. 381 | func Set(name, value string) error { 382 | return CommandLine.Set(name, value) 383 | } 384 | 385 | // isZeroValue determines whether the string represents the zero 386 | // value for a flag. 387 | func isZeroValue(flag *Flag, value string) bool { 388 | // Build a zero value of the flag's Value type, and see if the 389 | // result of calling its String method equals the value passed in. 390 | // This works unless the Value type is itself an interface type. 391 | typ := reflect.TypeOf(flag.Value) 392 | var z reflect.Value 393 | if typ.Kind() == reflect.Ptr { 394 | z = reflect.New(typ.Elem()) 395 | } else { 396 | z = reflect.Zero(typ) 397 | } 398 | return value == z.Interface().(Value).String() 399 | } 400 | 401 | // UnquoteUsage extracts a back-quoted name from the usage 402 | // string for a flag and returns it and the un-quoted usage. 403 | // Given "a `name` to show" it returns ("name", "a name to show"). 404 | // If there are no back quotes, the name is an educated guess of the 405 | // type of the flag's value, or the empty string if the flag is boolean. 406 | func UnquoteUsage(flag *Flag) (name string, usage string) { 407 | // Look for a back-quoted name, but avoid the strings package. 408 | usage = flag.Usage 409 | for i := 0; i < len(usage); i++ { 410 | if usage[i] == '`' { 411 | for j := i + 1; j < len(usage); j++ { 412 | if usage[j] == '`' { 413 | name = usage[i+1 : j] 414 | usage = usage[:i] + name + usage[j+1:] 415 | return name, usage 416 | } 417 | } 418 | break // Only one back quote; use type name. 419 | } 420 | } 421 | // No explicit name, so use type if we can find one. 422 | name = "value" 423 | switch flag.Value.(type) { 424 | case boolFlag: 425 | name = "" 426 | case *durationValue: 427 | name = "duration" 428 | case *float64Value: 429 | name = "float" 430 | case *intValue, *int64Value: 431 | name = "int" 432 | case *stringValue: 433 | name = "string" 434 | case *uintValue, *uint64Value: 435 | name = "uint" 436 | } 437 | return 438 | } 439 | 440 | // PrintDefaults prints, to standard error unless configured otherwise, the 441 | // default values of all defined command-line flags in the set. See the 442 | // documentation for the global function PrintDefaults for more information. 443 | func (f *FlagSet) PrintDefaults() { 444 | f.VisitAll(func(flag *Flag) { 445 | s := fmt.Sprintf(" -%s", flag.Name) // Two spaces before -; see next two comments. 446 | name, usage := UnquoteUsage(flag) 447 | if len(name) > 0 { 448 | s += " " + name 449 | } 450 | // Boolean flags of one ASCII letter are so common we 451 | // treat them specially, putting their usage on the same line. 452 | if len(s) <= 4 { // space, space, '-', 'x'. 453 | s += "\t" 454 | } else { 455 | // Four spaces before the tab triggers good alignment 456 | // for both 4- and 8-space tab stops. 457 | s += "\n \t" 458 | } 459 | s += strings.ReplaceAll(usage, "\n", "\n \t") 460 | 461 | if !isZeroValue(flag, flag.DefValue) { 462 | if _, ok := flag.Value.(*stringValue); ok { 463 | // put quotes on the value 464 | s += fmt.Sprintf(" (default %q)", flag.DefValue) 465 | } else { 466 | s += fmt.Sprintf(" (default %v)", flag.DefValue) 467 | } 468 | } 469 | fmt.Fprint(f.Output(), s, "\n") 470 | }) 471 | } 472 | 473 | // PrintDefaults prints, to standard error unless configured otherwise, 474 | // a usage message showing the default settings of all defined 475 | // command-line flags. 476 | // For an integer valued flag x, the default output has the form 477 | // -x int 478 | // usage-message-for-x (default 7) 479 | // The usage message will appear on a separate line for anything but 480 | // a bool flag with a one-byte name. For bool flags, the type is 481 | // omitted and if the flag name is one byte the usage message appears 482 | // on the same line. The parenthetical default is omitted if the 483 | // default is the zero value for the type. The listed type, here int, 484 | // can be changed by placing a back-quoted name in the flag's usage 485 | // string; the first such item in the message is taken to be a parameter 486 | // name to show in the message and the back quotes are stripped from 487 | // the message when displayed. For instance, given 488 | // flag.String("I", "", "search `directory` for include files") 489 | // the output will be 490 | // -I directory 491 | // search directory for include files. 492 | // 493 | // To change the destination for flag messages, call CommandLine.SetOutput. 494 | func PrintDefaults() { 495 | CommandLine.PrintDefaults() 496 | } 497 | 498 | // defaultUsage is the default function to print a usage message. 499 | func (f *FlagSet) defaultUsage() { 500 | if f.name == "" { 501 | fmt.Fprintf(f.Output(), "Usage:\n") 502 | } else { 503 | fmt.Fprintf(f.Output(), "Usage of %s:\n", f.name) 504 | } 505 | f.PrintDefaults() 506 | } 507 | 508 | // NOTE: Usage is not just defaultUsage(CommandLine) 509 | // because it serves (via godoc flag Usage) as the example 510 | // for how to write your own usage function. 511 | 512 | // Usage prints a usage message documenting all defined command-line flags 513 | // to CommandLine's output, which by default is os.Stderr. 514 | // It is called when an error occurs while parsing flags. 515 | // The function is a variable that may be changed to point to a custom function. 516 | // By default it prints a simple header and calls PrintDefaults; for details about the 517 | // format of the output and how to control it, see the documentation for PrintDefaults. 518 | // Custom usage functions may choose to exit the program; by default exiting 519 | // happens anyway as the command line's error handling strategy is set to 520 | // ExitOnError. 521 | var Usage = func() { 522 | fmt.Fprintf(CommandLine.Output(), "Usage of %s:\n", os.Args[0]) 523 | PrintDefaults() 524 | } 525 | 526 | // NFlag returns the number of flags that have been set. 527 | func (f *FlagSet) NFlag() int { return len(f.actual) } 528 | 529 | // NFlag returns the number of command-line flags that have been set. 530 | func NFlag() int { return len(CommandLine.actual) } 531 | 532 | // Arg returns the i'th argument. Arg(0) is the first remaining argument 533 | // after flags have been processed. Arg returns an empty string if the 534 | // requested element does not exist. 535 | func (f *FlagSet) Arg(i int) string { 536 | if i < 0 || i >= len(f.args) { 537 | return "" 538 | } 539 | return f.args[i] 540 | } 541 | 542 | // Arg returns the i'th command-line argument. Arg(0) is the first remaining argument 543 | // after flags have been processed. Arg returns an empty string if the 544 | // requested element does not exist. 545 | func Arg(i int) string { 546 | return CommandLine.Arg(i) 547 | } 548 | 549 | // NArg is the number of arguments remaining after flags have been processed. 550 | func (f *FlagSet) NArg() int { return len(f.args) } 551 | 552 | // NArg is the number of arguments remaining after flags have been processed. 553 | func NArg() int { return len(CommandLine.args) } 554 | 555 | // Args returns the non-flag arguments. 556 | func (f *FlagSet) Args() []string { return f.args } 557 | 558 | // Args returns the non-flag command-line arguments. 559 | func Args() []string { return CommandLine.args } 560 | 561 | // BoolVar defines a bool flag with specified name, default value, and usage string. 562 | // The argument p points to a bool variable in which to store the value of the flag. 563 | func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { 564 | f.Var(newBoolValue(value, p), name, usage) 565 | } 566 | 567 | // BoolVar defines a bool flag with specified name, default value, and usage string. 568 | // The argument p points to a bool variable in which to store the value of the flag. 569 | func BoolVar(p *bool, name string, value bool, usage string) { 570 | CommandLine.Var(newBoolValue(value, p), name, usage) 571 | } 572 | 573 | // Bool defines a bool flag with specified name, default value, and usage string. 574 | // The return value is the address of a bool variable that stores the value of the flag. 575 | func (f *FlagSet) Bool(name string, value bool, usage string) *bool { 576 | p := new(bool) 577 | f.BoolVar(p, name, value, usage) 578 | return p 579 | } 580 | 581 | // Bool defines a bool flag with specified name, default value, and usage string. 582 | // The return value is the address of a bool variable that stores the value of the flag. 583 | func Bool(name string, value bool, usage string) *bool { 584 | return CommandLine.Bool(name, value, usage) 585 | } 586 | 587 | // IntVar defines an int flag with specified name, default value, and usage string. 588 | // The argument p points to an int variable in which to store the value of the flag. 589 | func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { 590 | f.Var(newIntValue(value, p), name, usage) 591 | } 592 | 593 | // IntVar defines an int flag with specified name, default value, and usage string. 594 | // The argument p points to an int variable in which to store the value of the flag. 595 | func IntVar(p *int, name string, value int, usage string) { 596 | CommandLine.Var(newIntValue(value, p), name, usage) 597 | } 598 | 599 | // Int defines an int flag with specified name, default value, and usage string. 600 | // The return value is the address of an int variable that stores the value of the flag. 601 | func (f *FlagSet) Int(name string, value int, usage string) *int { 602 | p := new(int) 603 | f.IntVar(p, name, value, usage) 604 | return p 605 | } 606 | 607 | // Int defines an int flag with specified name, default value, and usage string. 608 | // The return value is the address of an int variable that stores the value of the flag. 609 | func Int(name string, value int, usage string) *int { 610 | return CommandLine.Int(name, value, usage) 611 | } 612 | 613 | // Int64Var defines an int64 flag with specified name, default value, and usage string. 614 | // The argument p points to an int64 variable in which to store the value of the flag. 615 | func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { 616 | f.Var(newInt64Value(value, p), name, usage) 617 | } 618 | 619 | // Int64Var defines an int64 flag with specified name, default value, and usage string. 620 | // The argument p points to an int64 variable in which to store the value of the flag. 621 | func Int64Var(p *int64, name string, value int64, usage string) { 622 | CommandLine.Var(newInt64Value(value, p), name, usage) 623 | } 624 | 625 | // Int64 defines an int64 flag with specified name, default value, and usage string. 626 | // The return value is the address of an int64 variable that stores the value of the flag. 627 | func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { 628 | p := new(int64) 629 | f.Int64Var(p, name, value, usage) 630 | return p 631 | } 632 | 633 | // Int64 defines an int64 flag with specified name, default value, and usage string. 634 | // The return value is the address of an int64 variable that stores the value of the flag. 635 | func Int64(name string, value int64, usage string) *int64 { 636 | return CommandLine.Int64(name, value, usage) 637 | } 638 | 639 | // UintVar defines a uint flag with specified name, default value, and usage string. 640 | // The argument p points to a uint variable in which to store the value of the flag. 641 | func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { 642 | f.Var(newUintValue(value, p), name, usage) 643 | } 644 | 645 | // UintVar defines a uint flag with specified name, default value, and usage string. 646 | // The argument p points to a uint variable in which to store the value of the flag. 647 | func UintVar(p *uint, name string, value uint, usage string) { 648 | CommandLine.Var(newUintValue(value, p), name, usage) 649 | } 650 | 651 | // Uint defines a uint flag with specified name, default value, and usage string. 652 | // The return value is the address of a uint variable that stores the value of the flag. 653 | func (f *FlagSet) Uint(name string, value uint, usage string) *uint { 654 | p := new(uint) 655 | f.UintVar(p, name, value, usage) 656 | return p 657 | } 658 | 659 | // Uint defines a uint flag with specified name, default value, and usage string. 660 | // The return value is the address of a uint variable that stores the value of the flag. 661 | func Uint(name string, value uint, usage string) *uint { 662 | return CommandLine.Uint(name, value, usage) 663 | } 664 | 665 | // Uint64Var defines a uint64 flag with specified name, default value, and usage string. 666 | // The argument p points to a uint64 variable in which to store the value of the flag. 667 | func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { 668 | f.Var(newUint64Value(value, p), name, usage) 669 | } 670 | 671 | // Uint64Var defines a uint64 flag with specified name, default value, and usage string. 672 | // The argument p points to a uint64 variable in which to store the value of the flag. 673 | func Uint64Var(p *uint64, name string, value uint64, usage string) { 674 | CommandLine.Var(newUint64Value(value, p), name, usage) 675 | } 676 | 677 | // Uint64 defines a uint64 flag with specified name, default value, and usage string. 678 | // The return value is the address of a uint64 variable that stores the value of the flag. 679 | func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { 680 | p := new(uint64) 681 | f.Uint64Var(p, name, value, usage) 682 | return p 683 | } 684 | 685 | // Uint64 defines a uint64 flag with specified name, default value, and usage string. 686 | // The return value is the address of a uint64 variable that stores the value of the flag. 687 | func Uint64(name string, value uint64, usage string) *uint64 { 688 | return CommandLine.Uint64(name, value, usage) 689 | } 690 | 691 | // StringVar defines a string flag with specified name, default value, and usage string. 692 | // The argument p points to a string variable in which to store the value of the flag. 693 | func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { 694 | f.Var(newStringValue(value, p), name, usage) 695 | } 696 | 697 | // StringVar defines a string flag with specified name, default value, and usage string. 698 | // The argument p points to a string variable in which to store the value of the flag. 699 | func StringVar(p *string, name string, value string, usage string) { 700 | CommandLine.Var(newStringValue(value, p), name, usage) 701 | } 702 | 703 | // String defines a string flag with specified name, default value, and usage string. 704 | // The return value is the address of a string variable that stores the value of the flag. 705 | func (f *FlagSet) String(name string, value string, usage string) *string { 706 | p := new(string) 707 | f.StringVar(p, name, value, usage) 708 | return p 709 | } 710 | 711 | // String defines a string flag with specified name, default value, and usage string. 712 | // The return value is the address of a string variable that stores the value of the flag. 713 | func String(name string, value string, usage string) *string { 714 | return CommandLine.String(name, value, usage) 715 | } 716 | 717 | // Float64Var defines a float64 flag with specified name, default value, and usage string. 718 | // The argument p points to a float64 variable in which to store the value of the flag. 719 | func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { 720 | f.Var(newFloat64Value(value, p), name, usage) 721 | } 722 | 723 | // Float64Var defines a float64 flag with specified name, default value, and usage string. 724 | // The argument p points to a float64 variable in which to store the value of the flag. 725 | func Float64Var(p *float64, name string, value float64, usage string) { 726 | CommandLine.Var(newFloat64Value(value, p), name, usage) 727 | } 728 | 729 | // Float64 defines a float64 flag with specified name, default value, and usage string. 730 | // The return value is the address of a float64 variable that stores the value of the flag. 731 | func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { 732 | p := new(float64) 733 | f.Float64Var(p, name, value, usage) 734 | return p 735 | } 736 | 737 | // Float64 defines a float64 flag with specified name, default value, and usage string. 738 | // The return value is the address of a float64 variable that stores the value of the flag. 739 | func Float64(name string, value float64, usage string) *float64 { 740 | return CommandLine.Float64(name, value, usage) 741 | } 742 | 743 | // DurationVar defines a time.Duration flag with specified name, default value, and usage string. 744 | // The argument p points to a time.Duration variable in which to store the value of the flag. 745 | // The flag accepts a value acceptable to time.ParseDuration. 746 | func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { 747 | f.Var(newDurationValue(value, p), name, usage) 748 | } 749 | 750 | // DurationVar defines a time.Duration flag with specified name, default value, and usage string. 751 | // The argument p points to a time.Duration variable in which to store the value of the flag. 752 | // The flag accepts a value acceptable to time.ParseDuration. 753 | func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { 754 | CommandLine.Var(newDurationValue(value, p), name, usage) 755 | } 756 | 757 | // Duration defines a time.Duration flag with specified name, default value, and usage string. 758 | // The return value is the address of a time.Duration variable that stores the value of the flag. 759 | // The flag accepts a value acceptable to time.ParseDuration. 760 | func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { 761 | p := new(time.Duration) 762 | f.DurationVar(p, name, value, usage) 763 | return p 764 | } 765 | 766 | // Duration defines a time.Duration flag with specified name, default value, and usage string. 767 | // The return value is the address of a time.Duration variable that stores the value of the flag. 768 | // The flag accepts a value acceptable to time.ParseDuration. 769 | func Duration(name string, value time.Duration, usage string) *time.Duration { 770 | return CommandLine.Duration(name, value, usage) 771 | } 772 | 773 | // Func defines a flag with the specified name and usage string. 774 | // Each time the flag is seen, fn is called with the value of the flag. 775 | // If fn returns a non-nil error, it will be treated as a flag value parsing error. 776 | func (f *FlagSet) Func(name, usage string, fn func(string) error) { 777 | f.Var(funcValue(fn), name, usage) 778 | } 779 | 780 | // Func defines a flag with the specified name and usage string. 781 | // Each time the flag is seen, fn is called with the value of the flag. 782 | // If fn returns a non-nil error, it will be treated as a flag value parsing error. 783 | func Func(name, usage string, fn func(string) error) { 784 | CommandLine.Func(name, usage, fn) 785 | } 786 | 787 | // Var defines a flag with the specified name and usage string. The type and 788 | // value of the flag are represented by the first argument, of type Value, which 789 | // typically holds a user-defined implementation of Value. For instance, the 790 | // caller could create a flag that turns a comma-separated string into a slice 791 | // of strings by giving the slice the methods of Value; in particular, Set would 792 | // decompose the comma-separated string into the slice. 793 | func (f *FlagSet) Var(value Value, name string, usage string) { 794 | // Remember the default value as a string; it won't change. 795 | flag := &Flag{name, usage, value, value.String()} 796 | _, alreadythere := f.formal[name] 797 | if alreadythere { 798 | var msg string 799 | if f.name == "" { 800 | msg = fmt.Sprintf("flag redefined: %s", name) 801 | } else { 802 | msg = fmt.Sprintf("%s flag redefined: %s", f.name, name) 803 | } 804 | fmt.Fprintln(f.Output(), msg) 805 | panic(msg) // Happens only if flags are declared with identical names 806 | } 807 | if f.formal == nil { 808 | f.formal = make(map[string]*Flag) 809 | } 810 | f.formal[name] = flag 811 | } 812 | 813 | // Var defines a flag with the specified name and usage string. The type and 814 | // value of the flag are represented by the first argument, of type Value, which 815 | // typically holds a user-defined implementation of Value. For instance, the 816 | // caller could create a flag that turns a comma-separated string into a slice 817 | // of strings by giving the slice the methods of Value; in particular, Set would 818 | // decompose the comma-separated string into the slice. 819 | func Var(value Value, name string, usage string) { 820 | CommandLine.Var(value, name, usage) 821 | } 822 | 823 | // failf prints to standard error a formatted error and usage message and 824 | // returns the error. 825 | func (f *FlagSet) failf(format string, a ...interface{}) error { 826 | err := fmt.Errorf(format, a...) 827 | // fmt.Fprintln(f.Output(), err) 828 | // f.usage() // 禁止自动打印usage 829 | return err 830 | } 831 | 832 | // usage calls the Usage method for the flag set if one is specified, 833 | // or the appropriate default usage function otherwise. 834 | func (f *FlagSet) usage() { 835 | if f.Usage == nil { 836 | f.defaultUsage() 837 | } else { 838 | f.Usage() 839 | } 840 | } 841 | 842 | // parseOne parses one flag. It reports whether a flag was seen. 843 | func (f *FlagSet) parseOne() (bool, error) { 844 | if len(f.args) == 0 { 845 | return false, nil 846 | } 847 | s := f.args[0] 848 | if len(s) < 2 || s[0] != '-' { 849 | return false, nil 850 | } 851 | numMinuses := 1 852 | if s[1] == '-' { 853 | numMinuses++ 854 | if len(s) == 2 { // "--" terminates the flags 855 | f.args = f.args[1:] 856 | return false, nil 857 | } 858 | } 859 | name := s[numMinuses:] 860 | if len(name) == 0 || name[0] == '-' || name[0] == '=' { 861 | return false, f.failf("bad flag syntax: %s", s) 862 | } 863 | 864 | // it's a flag. does it have an argument? 865 | f.args = f.args[1:] 866 | hasValue := false 867 | value := "" 868 | for i := 1; i < len(name); i++ { // equals cannot be first 869 | if name[i] == '=' { 870 | value = name[i+1:] 871 | hasValue = true 872 | name = name[0:i] 873 | break 874 | } 875 | } 876 | m := f.formal 877 | flag, alreadythere := m[name] // BUG 878 | if !alreadythere { 879 | if name == "help" || name == "h" { // special case for nice help message. 880 | f.usage() 881 | return false, ErrHelp 882 | } 883 | return false, f.failf("-%s not defined", name) 884 | } 885 | 886 | if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg 887 | if hasValue { 888 | if err := fv.Set(value); err != nil { 889 | return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err) 890 | } 891 | } else { 892 | if err := fv.Set("true"); err != nil { 893 | return false, f.failf("invalid boolean flag %s: %v", name, err) 894 | } 895 | } 896 | } else { 897 | // It must have a value, which might be the next argument. 898 | if !hasValue && len(f.args) > 0 { 899 | // value is the next arg 900 | hasValue = true 901 | value, f.args = f.args[0], f.args[1:] 902 | } 903 | if !hasValue { 904 | return false, f.failf("flag needs an argument: -%s", name) 905 | } 906 | if err := flag.Value.Set(value); err != nil { 907 | return false, f.failf("invalid value %q for flag -%s: %v", value, name, err) 908 | } 909 | } 910 | if f.actual == nil { 911 | f.actual = make(map[string]*Flag) 912 | } 913 | f.actual[name] = flag 914 | return true, nil 915 | } 916 | 917 | // Parse parses flag definitions from the argument list, which should not 918 | // include the command name. Must be called after all flags in the FlagSet 919 | // are defined and before flags are accessed by the program. 920 | // The return value will be ErrHelp if -help or -h were set but not defined. 921 | func (f *FlagSet) Parse(arguments []string) error { 922 | f.parsed = true 923 | f.args = arguments 924 | for { 925 | seen, err := f.parseOne() 926 | if seen { 927 | continue 928 | } 929 | if err == nil { 930 | break 931 | } 932 | switch f.errorHandling { 933 | case ContinueOnError: 934 | return err 935 | case ExitOnError: 936 | // if err == ErrHelp { 937 | // os.Exit(0) 938 | // } 939 | // os.Exit(2) 940 | return err 941 | case PanicOnError: 942 | // panic(err) 943 | return err 944 | } 945 | } 946 | return nil 947 | } 948 | 949 | // Parsed reports whether f.Parse has been called. 950 | func (f *FlagSet) Parsed() bool { 951 | return f.parsed 952 | } 953 | 954 | // Parse parses the command-line flags from os.Args[1:]. Must be called 955 | // after all flags are defined and before flags are accessed by the program. 956 | func Parse() error { 957 | // Ignore errors; CommandLine is set for ExitOnError. 958 | return CommandLine.Parse(os.Args[1:]) 959 | } 960 | 961 | // Parsed reports whether the command-line flags have been parsed. 962 | func Parsed() bool { 963 | return CommandLine.Parsed() 964 | } 965 | 966 | // CommandLine is the default set of command-line flags, parsed from os.Args. 967 | // The top-level functions such as BoolVar, Arg, and so on are wrappers for the 968 | // methods of CommandLine. 969 | var CommandLine = NewFlagSet(os.Args[0], ExitOnError) 970 | 971 | func init() { 972 | // Override generic FlagSet default Usage with call to global Usage. 973 | // Note: This is not CommandLine.Usage = Usage, 974 | // because we want any eventual call to use any updated value of Usage, 975 | // not the value it has when this line is run. 976 | CommandLine.Usage = commandLineUsage 977 | } 978 | 979 | func commandLineUsage() { 980 | Usage() 981 | } 982 | 983 | // NewFlagSet returns a new, empty flag set with the specified name and 984 | // error handling property. If the name is not empty, it will be printed 985 | // in the default usage message and in error messages. 986 | func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { 987 | f := &FlagSet{ 988 | name: name, 989 | errorHandling: errorHandling, 990 | } 991 | f.Usage = f.defaultUsage 992 | return f 993 | } 994 | 995 | // Init sets the name and error handling property for a flag set. 996 | // By default, the zero FlagSet uses an empty name and the 997 | // ContinueOnError error handling policy. 998 | func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { 999 | f.name = name 1000 | f.errorHandling = errorHandling 1001 | } 1002 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | // _ "github.com/lib/pq" 5 | "strings" 6 | ) 7 | 8 | const BLANK = "" 9 | 10 | // 数组中是否包含该字符 11 | func In(s string, arr []string) bool { 12 | for _, v := range arr { 13 | if v == s { 14 | return true 15 | } 16 | } 17 | return false 18 | } 19 | 20 | // 转换为帕斯卡命名 21 | // 如: userName => UserName 22 | // user_name => UserName 23 | func Pascal(title string) string { 24 | arr := strings.FieldsFunc(title, func(c rune) bool { return c == '_' }) 25 | RangeStringsFunc(arr, func(s string) string { return strings.Title(s) }) 26 | return strings.Join(arr, BLANK) 27 | } 28 | 29 | // 遍历处理集合成员 30 | func RangeStringsFunc(arr []string, f func(string) string) { 31 | for k, v := range arr { 32 | arr[k] = f(v) 33 | } 34 | } 35 | 36 | func PathTrim(path string) string { 37 | return strings.ReplaceAll(path, "//", "/") 38 | } 39 | -------------------------------------------------------------------------------- /utils/utils_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hollson. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package utils 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | ) 11 | 12 | // 格式: "\033[风格;前景色;背景色m内容\033[0m" 13 | //go:generate echo -e "\033[4;31;42m你好\033[0m" 14 | func TestColor(t *testing.T) { 15 | fmt.Printf("\033[%dm%s\033[0m\n", FgMagenta, "带前景色的字体") 16 | fmt.Printf("\033[%d;%dm%s\033[0m\n", Bold, FgBlue, "带前景色和样式的字体") 17 | fmt.Printf("\033[%d;%dm%s\033[0m\n", FgBlue, BgGreen, "带前景色和背景色的字体") 18 | fmt.Printf("\033[%d;%d;%dm%s\033[0m\n", Underline, FgWhite, BgMagenta, "带前景色、背景色和样式的字体") 19 | } 20 | 21 | func TestPascal(t *testing.T) { 22 | fmt.Println(Pascal("_user_name")) 23 | fmt.Println(Pascal("_username")) 24 | fmt.Println(Pascal("_user_last_name")) 25 | fmt.Println(Pascal("user_name")) 26 | fmt.Println(Pascal("User_Name")) 27 | fmt.Println(Pascal("USERNAME")) 28 | fmt.Println(Pascal("username")) 29 | fmt.Println(Pascal("user__name")) 30 | fmt.Println(Pascal("_user_name_")) 31 | fmt.Println(Pascal("_user_name_99")) 32 | } 33 | --------------------------------------------------------------------------------