MySQL建表语句生成Golang代码

1. 背景

对于后台开发新的需求时,一般会先进行各种表的设计,写各个表的建表语句

然后根据建立的表,写对应的model代码、基础的增删改查代码(基础的增删改查服务可以划入DAO(Data Access Object)层)。

model代码都有一些固定的格式,可以通过解析SQL建表语句,来自动生成model代码,

对于不同的表,基础的增删改查代码大概率只是换了个表名或者数据库,因此也可以自动生成。

通过自动生成代码,减少重复工作,提示开发效率。

2. 整体介绍

.
├── README.md
├── code2file
│   └── code2file.go
├── go.mod
├── go.sum
├── main.go
├── sql2code_tpl
│   ├── sql2code_tpl.go
│   ├── sql2dao_tpl.txt
│   └── sql2model_tpl.txt
├── sql2dao
│   ├── sql2dao.go
│   └── sql2dao_test.go
├── sql2model
│   ├── sql2model.go
│   ├── sql2model_test.go
│   └── tidb_types.go
├── test
│   └── t_student.sql
└── util
    └── util_strings
        └── util_strings.go

7 directories, 15 files

sql2code_tpl: 主要是model和dao的模版代码

sql2model:MySQL建表语句到Model代码的主要处理流程

sql2dao:MySQL建表语句到Dao代码到主要处理流程

3. sql到model

使用SQL解析器获得表名及每一列信息,使用模版生成model代码。

package {{.PackageName}}

// {{.Comment}}
type {{.ModelName}} struct {
{{- range .Rows}}
    {{.Name}} {{.GoType}} {{.Tags}} // {{.Comment}}
{{- end}}
}

func ({{.ModelName}}) TableName() string {
    return "{{.OriginTblName}}"
}

使用SQL解析器解析建表语句,获得表名,及每一列的列名,注释等信息,主要代码如下

func SQLParse(sql, tablePrefix string) (*ModelTable, error) {
    cts, err := parseCreateTableStmt(sql)
    if err != nil {
        log.Printf("parseCreateTableStmt fail,err:%v", err)
        return nil, err
    }
    mt := &ModelTable{}
    primaryKey := ""

    // table name
    tblName := TableNamePrefixCut(cts.Table.Name.L, tablePrefix)
    mt.ModelName = TableName2ModelName(tblName)
    mt.OriginTblName = cts.Table.Name.L

    // primary
    for _, ctt := range cts.Constraints {
        // only contain one primary key
        if ctt.Tp == ast.ConstraintPrimaryKey {
            if len(ctt.Keys) >= 0 {
                primaryKey = ctt.Keys[0].Column.Name.L
            }
            break
        }
    }

    // comment
    for _, op := range cts.Options {
        if op.Tp == ast.TableOptionComment {
            mt.Comment = op.StrValue
        }
    }

    modelRows := make([]ModelRow, 0, len(cts.Cols))
    for _, col := range cts.Cols {
        nameLow := col.Name.Name.L
        modelRow := ModelRow{
            Name: util_strings.ToCamel(col.Name.Name.L), // 需要去除下划线转驼峰
        }
        //fmt.Printf("col: %+v %+v %v %v\n", col.Name, col.Tp, HasUnsignedFlag(col.Tp.GetFlag()), col.Tp.GetType())
        modelRow.GoType = sqlType2GoType(col.Tp.GetType(), col.Tp.GetFlag())
        for _, op := range col.Options {
            if op.Tp == ast.ColumnOptionComment {
                exprVal, ok := op.Expr.(*test_driver.ValueExpr)
                if !ok {
                    fmt.Println("op.Expr.(*test_driver.ValueExpr) fail.")
                    continue
                }
                modelRow.Comment = exprVal.Datum.GetString()
                break
            }
        }
        if primaryKey == col.Name.Name.L {
            modelRow.Tags = fmt.Sprintf("gorm:\"column:%v; primary_key\" json:\"%v\"", nameLow, nameLow)
        } else {
            modelRow.Tags = fmt.Sprintf("gorm:\"column:%v;\" json:\"%v\"", nameLow, nameLow)
        }
        //fmt.Println(modelRow.Tags)
        modelRows = append(modelRows, modelRow)
    }
    mt.Rows = modelRows
    return mt, nil
}

3. sql到dao

  • 获得MySQL建表语句的表名信息
  • 使用模版生成CRUD代码

查看代码

 package {{.PackageName}}

{{template "addTemplate" .}}
{{template "deleteTemplate" .}}
{{template "updateTemplate" .}}
{{template "getMultiTemplate" .}}
{{template "getCountTemplate" .}}
{{template "getOneTemplate" .}}

{{define "addTemplate"}}
func Add{{.ModelName}}(ctx context.Context,obj *{{.ModelPackage}}.{{.ModelName}}, whereMap map[string]interface{}) (error, int64) {
    if whereMap != nil {
        err, existObj := GetOne{{.ModelName}}(ctx, whereMap)
        if err != nil {
            log.Printf("[Add{{.ModelName}}]GetOne{{.ModelName}} fail, err:%v, obj:%v", err, obj)
            return err, int64(0)
        }
        if existObj != nil && existObj.AddTime > int64(0) {
            logs.CtxInfo(ctx, "[Add{{.ModelName}}] {{.ModelName}} exist, existsObj:%v", existObj)
            return nil, existObj.ID
        }
    }

    if obj.AddTime <= 0 { obj.addtime="util_datetime.CurrentMS()" } if obj.updatetime <="0" res :="{{.DBConect}}.Create(obj)" res.error !="nil" log.printf("[add{{.modelname}}]add{{.modelname}} fail, err:%v, obj:%v", res.error, obj) return int64(0) obj.id {{end}} {{define "deletetemplate"}} func delete{{.modelname}}(ctx context.context,wheremap map[string]interface{}) (error, int64) query wheremap) log.printf("delete{{.modelname}} failed, wheremap:%v", rowsaffected nil, "updatetemplate"}} update{{.modelname}}(ctx context.context, wheremap map[string]interface{}, setmap obj updatetime, ok !ok || updatetime.(int64) setmap["update_time"]="util_datetime.CurrentMS()" log.printf("[update{{.modelname}}]update{{.modelname}} wheremap:%v, setmap:%v", wheremap, setmap) "getmultitemplate"}} getmulti{{.modelname}}s(ctx offset, limit int64, orderby, groupby, fields string) []*{{.modelpackage}}.{{.modelname}}) objs orderby) fields) groupby) limit) res.error.error()="=" "record not found" nil log.printf("[getmulti{{.modelname}}s]getmulti{{.modelname}}s err:%v", res.error) "getcounttemplate"}} getmulti{{.modelname}}scount(ctx cnt log.printf("getmulti{{.modelname}}scount "getonetemplate"}} getone{{.modelname}}(ctx map[string]interface{},fields string)(error, *{{.modelpackage}}.{{.modelname}}) err, 0, 1, "", err len(objs)>= 1 {
        return nil, objs[0]
    }
    return nil, nil
}

{{end}}</=>

主要是根据表名获取对应的model名称、包名等,再利用模版生成代码。

func SQL2Dao(sql string, tablePrefix, packagePrefix, dbCon string) (string, error) {
    tblName, err := sql2model.TableNameGetFromSQL(sql, tablePrefix)
    if err != nil {
        return "", err
    }

    modelPackage := sql2model.ModelPackageGet(tblName, tablePrefix, packagePrefix)
    packageName := DaoPackageNameGet(tblName, tablePrefix, packagePrefix)

    df := DaoFile{
        PackageName:  packageName,
        ModelPackage: modelPackage,
        ModelName:    sql2model.TableName2ModelName(tblName),
        DBConect:     dbCon,
    }
    return daoFileGen(df)
}

4. 使用方式

Usage of this program:
  -dbcon string
        db connect name
  -if string
        File path of the SQL statement that creates the table
  -op int
        1:gen model code 2:gen dao code 3:both (default 1)
  -pp string
        package prefix add for go file
  -sql string
        SQL statement to create table
  -tp string
        table prefix of table name to cut

5. 使用实例

$ go run main.go -if=./test/t_student.sql -dbcon=UserDB -tp="t_" -pp=user -op=3
model code have been write to  ./output/user_student.go
model code have been write to  ./output/user_student_service.go

6. 完整代码

5. 参考

Original: https://www.cnblogs.com/amos01/p/16659999.html
Author: Amos01
Title: MySQL建表语句生成Golang代码

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/611914/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Consul 入门-集群搭建

    集群搭建 通过 Docker 来搭建一个由3个 Server 组成的数据中心集群,再启动一个 Client 容器来做服务注册和发现的入口,开模拟看看 Server 启动命令 拉取最…

    数据库 2023年6月6日
    093
  • MySQL实战45讲 18

    18 | 为什么这些SQL语句逻辑相同,性能却差异巨大? 在 MySQL 中,有很多看上去逻辑相同,但性能却差异巨大的 SQL 语句。对这些语句使用不当的话,就会不经意间导致整个数…

    数据库 2023年5月24日
    097
  • flowable 查询、完成、作废、删除 任务

    /** * 查询我的任务 * from fhadmin.cn * @param USERNAME * @return 返回任务列表 */ protected List findMy…

    数据库 2023年6月6日
    0210
  • Docker从入门到精通

    1 容器简介1.1 什么是 Linux 容器1.2 容器不就是虚拟化吗1.3 容器发展简史2 什么是 Docker?2.1 Docker 如何工作?2.2 Docker 技术是否与…

    数据库 2023年6月14日
    092
  • zabbix监控用户,模组管理

    zabbix用户模组管理 用户管理 用户组 用户角色 用户 模板管理 模板组 模板 模板的监控项的参数也可以copy来 加入触发器 导出模板查看格式 posted @2022-09…

    数据库 2023年6月14日
    055
  • 详解apollo的设计与使用

    apollo 是一款由携程团队开发的配置中心,可以实现配置的集中管理、分环境管理、即时生效等等。在这篇博客中,我们可以了解到: 这里我回答的是为什么使用配置中心,而不是为什么使用 …

    数据库 2023年6月6日
    097
  • MySQL函数学习(二)—–数值型函数

    注:笔记旨在记录 二、MySQL 数值型函数 \ 函 数 名 称 作 用 完 成 1 RAND 取随机数,可设置参数种子 勾 2 ABS 求x的绝对值 勾 3 SIGN 求x的正负…

    数据库 2023年6月16日
    076
  • [spring]spring中java实现类代替注解开发

    9.使用javaconfig实现代替xml配置 The central artifacts in Spring’s new Java-configuration sup…

    数据库 2023年6月16日
    074
  • podman对容器映像签名和分发

    熟悉podman 如何使用 Podman 对容器映像进行签名和分发 熟悉podman 此示例容器将运行一个非常基本的 httpd 服务器,该服务器仅为其索引页提供服务 [root@…

    数据库 2023年6月14日
    0112
  • SQLZOO练习5–join(表的连接)

    game表: idmdatestadiumteam1team2 1001 8 June 2012 National Stadium, Warsaw POL GRE 1002 8 J…

    数据库 2023年6月16日
    075
  • SQL语句实战学习

    参考:https://zhuanlan.zhihu.com/p/38354000再次感谢作者的整理!! 1.数据已提前准备好了,已知有如下4张表:学生表:student 成绩表:s…

    数据库 2023年6月16日
    083
  • Redis和Mysql保持数据一致性

    1、简述 在高并发的场景下,大量的请求直接访问Mysql很容易造成性能问题。所以,我们都会用Redis来做数据的缓存,削减对数据库的请求。但是,Mysql和Redis是两种不同的数…

    数据库 2023年6月16日
    085
  • 三种移除list中的元素(可靠)

    /** * 直接使用foreach方法移除list中的元素会抛异常 * Exception in thread "main" java.util.Concurr…

    数据库 2023年6月14日
    0125
  • RocksDB线程局部缓存

    在开发过程中,我们经常会遇到并发问题,解决并发问题通常的方法是加锁保护,比如常用的spinlock,mutex或者rwlock,当然也可以采用无锁编程,对实现要求就比较高了。对于任…

    数据库 2023年6月9日
    080
  • 数据连接池

    dbcp 1.引入jar包 导入这两个jar包 下载jar包地址:Maven Repository: Search/Browse/Explore (mvnrepository.co…

    数据库 2023年5月24日
    092
  • MySQL80下载安装/使用/连接报错

    @ * – 一、MySQL80下载 + 这里用社区版Community Server + 下载运行 * 仅Server Only安装就行 * 产品配置,click ne…

    数据库 2023年5月24日
    0111
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球