1 Star 0 Fork 0

goeoeo/cycmd

Create your Gitee Account
Explore and code with more than 13.5 million developers,Free private repositories !:)
Sign up
文件
Clone or Download
table2struct.go 14.73 KB
Copy Edit Raw Blame History
yu authored 2021-09-11 09:57 +08:00 . 项目名称变更
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
package t2go
import (
"database/sql"
"errors"
"fmt"
"gitee.com/phpdi/cycmd/internal/word"
"log"
"os"
"os/exec"
"sort"
"strings"
_ "github.com/go-sql-driver/mysql"
)
//map for converting mysql type to golang types
var typeForMysqlToGo = map[string]string{
"int": "int64",
"integer": "int64",
"tinyint": "int64",
"smallint": "int64",
"mediumint": "int64",
"bigint": "int64",
"int unsigned": "int64",
"integer unsigned": "int64",
"tinyint unsigned": "int64",
"smallint unsigned": "int64",
"mediumint unsigned": "int64",
"bigint unsigned": "int64",
"bit": "int64",
"bool": "bool",
"enum": "string",
"set": "string",
"varchar": "string",
"char": "string",
"tinytext": "string",
"mediumtext": "string",
"text": "string",
"longtext": "string",
"blob": "string",
"tinyblob": "string",
"mediumblob": "string",
"longblob": "string",
"date": "time.Time", // time.Time or string
"datetime": "time.Time", // time.Time or string
"timestamp": "time.Time", // time.Time or string
"time": "time.Time", // time.Time or string
"float": "float64",
"double": "float64",
"decimal": "float64",
"binary": "string",
"varbinary": "string",
}
var typeForGoToPb = map[string]string{
"int64": "google.protobuf.Int64Value",
"string": "google.protobuf.StringValue",
"time.Time": "google.protobuf.Timestamp",
"float64": "google.protobuf.FloatValue",
}
var typeToPbFunc = map[string]string{
"int64": "pbutil.ToProtoInt64",
"string": "pbutil.ToProtoString",
"time.Time": "pbutil.ToProtoTimestamp",
"float64": "pbutil.ToProtoFloat",
}
var typeFromPbFunc = map[string]string{
"int64": "pbutil.FromProtoInt64",
"string": "pbutil.FromProtoString",
"time.Time": "pbutil.FromProtoTimestamp",
"float64": "pbutil.FromProtoFloat",
}
type Table2Struct struct {
dsn string
savePath string
db *sql.DB
table string
prefix string
config *T2tConfig
err error
realNameMethod string
enableJsonTag bool // 是否添加json的tag, 默认不添加
packageName string // 生成struct的包名(默认为空的话, 则取名为: package model)
tagKey string // tag字段的key值,默认是orm
dateToTime bool // 是否将 date相关字段转换为 time.Time,默认否
}
type T2tConfig struct {
StructNameToHump bool // 结构体名称是否转为驼峰式,默认为false
RmTagIfUcFirsted bool // 如果字段首字母本来就是大写, 就不添加tag, 默认false添加, true不添加
TagToLower bool // tag的字段名字是否转换为小写, 如果本身有大写字母的话, 默认false不转
JsonTagToHump bool // json tag是否转为驼峰,默认为false,不转换
UcFirstOnly bool // 字段首字母大写的同时, 是否要把其他字母转换为小写,默认false不转换
SeperatFile bool // 每个struct放入单独的文件,默认false,放入同一个文件
}
func NewTable2Struct() *Table2Struct {
return &Table2Struct{}
}
func (t *Table2Struct) Dsn(d string) *Table2Struct {
t.dsn = d
return t
}
func (t *Table2Struct) TagKey(r string) *Table2Struct {
t.tagKey = r
return t
}
func (t *Table2Struct) PackageName(r string) *Table2Struct {
t.packageName = r
return t
}
func (t *Table2Struct) RealNameMethod(r string) *Table2Struct {
t.realNameMethod = r
return t
}
func (t *Table2Struct) SavePath(p string) *Table2Struct {
t.savePath = p
return t
}
func (t *Table2Struct) DB(d *sql.DB) *Table2Struct {
t.db = d
return t
}
func (t *Table2Struct) Table(tab string) *Table2Struct {
t.table = tab
return t
}
func (t *Table2Struct) Prefix(p string) *Table2Struct {
t.prefix = p
return t
}
func (t *Table2Struct) EnableJsonTag(p bool) *Table2Struct {
t.enableJsonTag = p
return t
}
func (t *Table2Struct) DateToTime(d bool) *Table2Struct {
t.dateToTime = d
return t
}
func (t *Table2Struct) Config(c *T2tConfig) *Table2Struct {
t.config = c
return t
}
//写入到文件
func (t *Table2Struct) RunToFile() error {
packageName := t.getPackageName()
structContent, err := t.getStructContent()
if err != nil {
return err
}
importContent := t.getImportContent(structContent)
// 写入文件struct
var savePath = t.savePath
// 是否指定保存路径
if savePath == "" {
savePath = "model.go"
}
filePath := fmt.Sprintf("%s", savePath)
f, err := os.Create(filePath)
if err != nil {
log.Println("Can not write file")
return err
}
defer f.Close()
f.WriteString(packageName + importContent + structContent)
cmd := exec.Command("gofmt", "-w", filePath)
cmd.Run()
log.Println("gen model finish!!!")
return nil
}
//直接输出struct
func (t *Table2Struct) Run() (content string, err error) {
var (
structContent string
columnsContent string
pbContent string
dtoContent string
)
if structContent, err = t.getStructContent(); err != nil {
return
}
if columnsContent, err = t.getConstColumns(); err != nil {
return
}
if pbContent, err = t.getProtoContent(); err != nil {
return
}
if dtoContent, err = t.getDtoContent(); err != nil {
return
}
content = columnsContent + structContent + pbContent + dtoContent
return
}
// 包名
func (t *Table2Struct) getPackageName() (packageName string) {
if t.packageName == "" {
packageName = "package model\n\n"
} else {
packageName = fmt.Sprintf("package %s\n\n", t.packageName)
}
return
}
func (t *Table2Struct) getConstColumns() (constContent string, err error) {
// 链接mysql, 获取db对象
t.dialMysql()
if t.err != nil {
return "", t.err
}
// 获取表和字段的shcema
tableColumns, err := t.getColumns()
if err != nil {
return "", err
}
for tableName, item := range tableColumns {
constContent += fmt.Sprintf("const(\n //%s \n", tableName)
for _, v := range item {
contName := fmt.Sprintf(" %s_%s", word.UnderscoreToUpperCamelCase(tableName), v.ColumnName)
constContent += fmt.Sprintf("%s=\"%s\" //%s\n", contName, word.CamelCaseToUnderscore(v.ColumnName), v.ColumnComment)
}
constContent += ")\n"
}
return
}
//structContent
func (t *Table2Struct) getStructContent() (structContent string, err error) {
// 链接mysql, 获取db对象
t.dialMysql()
if t.err != nil {
return "", t.err
}
// 获取表和字段的shcema
tableColumns, err := t.getColumns()
if err != nil {
return "", err
}
// 组装struct
for tableRealName, item := range tableColumns {
// 去除前缀
if t.prefix != "" {
tableRealName = tableRealName[len(t.prefix):]
}
tableName := tableRealName
structName := tableName
if t.config.StructNameToHump {
structName = t.camelCase(structName)
}
switch len(structName) {
case 0:
case 1:
structName = strings.ToUpper(structName[0:1])
default:
// 字符长度大于1时
structName = strings.ToUpper(structName[0:1]) + structName[1:]
}
depth := 1
structContent += "type " + structName + " struct {\n"
for _, v := range item {
//structContent += tab(depth) + v.ColumnName + " " + v.Type + " " + v.Json + "\n"
// 字段注释
var clumnComment string
if v.ColumnComment != "" {
clumnComment = fmt.Sprintf(" // %s", v.ColumnComment)
}
structContent += fmt.Sprintf("%s%s %s %s%s\n",
tab(depth), v.ColumnName, v.Type, v.Tag, clumnComment)
}
structContent += tab(depth-1) + "}\n\n"
// 添加 method 获取真实表名
if t.realNameMethod != "" {
structContent += fmt.Sprintf("func (%s) %s() string {\n",
structName, t.realNameMethod)
structContent += fmt.Sprintf("%sreturn \"%s\"\n",
tab(depth), tableRealName)
structContent += "}\n\n"
}
}
return
}
//PbContent proto消息
func (t *Table2Struct) getProtoContent() (content string, err error) {
// 链接mysql, 获取db对象
t.dialMysql()
if t.err != nil {
return "", t.err
}
// 获取表和字段的shcema
tableColumns, err := t.getColumns()
if err != nil {
return "", err
}
// 组装struct
for tableRealName, columns := range tableColumns {
tableRealName = word.UnderscoreToUpperCamelCase(tableRealName)
content += fmt.Sprintf("message %s {\n", tableRealName)
//固定字段顺序
sort.SliceStable(columns, func(i, j int) bool {
return columns[i].ColumnName < columns[j].ColumnName
})
for k, column := range columns {
typeName := typeForGoToPb[column.Type]
content += fmt.Sprintf(" //%s\n", column.ColumnComment)
content += fmt.Sprintf(" %s %s = %d;\n", typeName, word.CamelCaseToUnderscore(column.ColumnName), k+1)
}
content += "}\n"
}
return
}
/*
func Product_PbProduct(product *entity.Product) (ack *pb.Product) {
return &pb.Product{
AccessSysId: pbutil.ToProtoString(product.AccessSysId),
CataId: pbutil.ToProtoString(product.CataId),
ProdId: pbutil.ToProtoString(product.ProdId),
ProdCode: pbutil.ToProtoString(product.ProdCode),
Name: pbutil.ToProtoString(product.Name),
Description: pbutil.ToProtoString(product.Description),
EffectiveTime: pbutil.ToProtoTimestamp(product.EffectiveTime),
ExpirationTime: pbutil.ToProtoTimestamp(product.ExpirationTime),
Remark: pbutil.ToProtoString(product.Remark),
CreateTime: pbutil.ToProtoTimestamp(product.CreateTime),
UpdateTime: pbutil.ToProtoTimestamp(product.UpdateTime),
}
}
*/
//dto
func (t *Table2Struct) getDtoContent() (content string, err error) {
// 链接mysql, 获取db对象
t.dialMysql()
if t.err != nil {
return "", t.err
}
// 获取表和字段的shcema
tableColumns, err := t.getColumns()
if err != nil {
return "", err
}
// 组装struct
for tableRealName, columns := range tableColumns {
tableRealName = word.UnderscoreToUpperCamelCase(tableRealName)
content += "//ToPb\n"
tab := " "
content += fmt.Sprintf("func %s_Pb%s(req *entity.%s) (ack *pb.%s) {\n", tableRealName, tableRealName, tableRealName, tableRealName)
content += fmt.Sprintf("%sreturn &pb.%s{\n", tab, tableRealName)
//固定字段顺序
sort.SliceStable(columns, func(i, j int) bool {
return columns[i].ColumnName < columns[j].ColumnName
})
for _, column := range columns {
content += fmt.Sprintf("%s%s%s: %s(req.%s),\n", tab, tab, column.ColumnName, typeToPbFunc[column.Type], column.ColumnName)
}
content += " }\n}\n"
}
// 组装struct
for tableRealName, columns := range tableColumns {
tableRealName = word.UnderscoreToUpperCamelCase(tableRealName)
content += "//ToEntity\n"
tab := " "
content += fmt.Sprintf("func Pb%s_%s(req *pb.%s) (ack *entity.%s) {\n", tableRealName, tableRealName, tableRealName, tableRealName)
content += fmt.Sprintf("%sreturn &entity.%s{\n", tab, tableRealName)
//固定字段顺序
sort.SliceStable(columns, func(i, j int) bool {
return columns[i].ColumnName < columns[j].ColumnName
})
for _, column := range columns {
content += fmt.Sprintf("%s%s%s: %s(req.%s),\n", tab, tab, column.ColumnName, typeFromPbFunc[column.Type], column.ColumnName)
}
content += " }\n}\n"
}
return
}
//importContent
func (t *Table2Struct) getImportContent(structContent string) (importContent string) {
if strings.Contains(structContent, "time.Time") {
importContent = "import \"time\"\n\n"
}
return
}
func (t *Table2Struct) dialMysql() {
if t.db == nil {
if t.dsn == "" {
t.err = errors.New("dsn数据库配置缺失")
return
}
t.db, t.err = sql.Open("mysql", t.dsn)
}
return
}
type column struct {
ColumnName string
Type string
Nullable string
TableName string
ColumnComment string
Tag string
}
// Function for fetching schema definition of passed table
func (t *Table2Struct) getColumns(table ...string) (tableColumns map[string][]column, err error) {
// 根据设置,判断是否要把 date 相关字段替换为 string
if t.dateToTime == false {
typeForMysqlToGo["date"] = "string"
typeForMysqlToGo["datetime"] = "string"
typeForMysqlToGo["timestamp"] = "string"
typeForMysqlToGo["time"] = "string"
}
tableColumns = make(map[string][]column)
// sql
var sqlStr = `SELECT COLUMN_NAME,DATA_TYPE,IS_NULLABLE,TABLE_NAME,COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE table_schema = DATABASE()`
// 是否指定了具体的table
if t.table != "" {
sqlStr += fmt.Sprintf(" AND TABLE_NAME = '%s'", t.prefix+t.table)
}
// sql排序
sqlStr += " order by TABLE_NAME asc, ORDINAL_POSITION asc"
rows, err := t.db.Query(sqlStr)
if err != nil {
log.Println("Error reading table information: ", err.Error())
return
}
defer rows.Close()
for rows.Next() {
col := column{}
err = rows.Scan(&col.ColumnName, &col.Type, &col.Nullable, &col.TableName, &col.ColumnComment)
if err != nil {
log.Println(err.Error())
return
}
//col.Json = strings.ToLower(col.ColumnName)
col.Tag = col.ColumnName
col.ColumnComment = col.ColumnComment
col.ColumnName = t.camelCase(col.ColumnName)
col.Type = typeForMysqlToGo[col.Type]
jsonTag := col.Tag
// 字段首字母本身大写, 是否需要删除tag
if t.config.RmTagIfUcFirsted &&
col.ColumnName[0:1] == strings.ToUpper(col.ColumnName[0:1]) {
col.Tag = "-"
} else {
// 是否需要将tag转换成小写
if t.config.TagToLower {
col.Tag = strings.ToLower(col.Tag)
jsonTag = col.Tag
}
if t.config.JsonTagToHump {
jsonTag = t.camelCase(jsonTag)
}
//if col.Nullable == "YES" {
// col.Json = fmt.Sprintf("`json:\"%s,omitempty\"`", col.Json)
//} else {
//}
}
s := ""
if t.tagKey != "" {
s = fmt.Sprintf("%s:\"%s\" ", t.tagKey, col.Tag)
}
if t.enableJsonTag {
//col.Json = fmt.Sprintf("`json:\"%s\" %s:\"%s\"`", col.Json, t.config.TagKey, col.Json)
s += fmt.Sprintf("json:\"%s\"", jsonTag)
}
if s != "" {
col.Tag = fmt.Sprintf("`%s`", s)
}
//columns = append(columns, col)
if _, ok := tableColumns[col.TableName]; !ok {
tableColumns[col.TableName] = []column{}
}
tableColumns[col.TableName] = append(tableColumns[col.TableName], col)
}
return
}
func (t *Table2Struct) camelCase(str string) string {
// 是否有表前缀, 设置了就先去除表前缀
if t.prefix != "" {
str = strings.Replace(str, t.prefix, "", 1)
}
var text string
//for _, p := range strings.Split(name, "_") {
for _, p := range strings.Split(str, "_") {
// 字段首字母大写的同时, 是否要把其他字母转换为小写
switch len(p) {
case 0:
case 1:
text += strings.ToUpper(p[0:1])
default:
// 字符长度大于1时
if t.config.UcFirstOnly == true {
text += strings.ToUpper(p[0:1]) + strings.ToLower(p[1:])
} else {
text += strings.ToUpper(p[0:1]) + p[1:]
}
}
}
return text
}
func tab(depth int) string {
return strings.Repeat(" ", depth)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/goeoeo/cycmd.git
git@gitee.com:goeoeo/cycmd.git
goeoeo
cycmd
cycmd
db9a10692ab2

Search