golang 生成对应的数据表struct定义

在开发过程中,常常需要将数据库表对应到golang的一个struct,特别是使用一些ORM工具,sqlx库等,我是个懒人,即使数据表的字段不多,我也懒得去一个个对应的敲入代码,更别提数据表字段比较多的情况了,码农的时间,不能浪费在这啊,对吧?所以我在想,是不是有办法可以自动生成。我在工作时,用得最多的是mysql了,因此,本文针对mysql的数据表来自动生成golang 的struct定义。mysql有个自带的数据库information_schema,里面的信息量比较多,朋友们可以去百度下,我这里用到了表COLUMNS,它的字段包含数据库名、表名、字段名、字段类型等,利用这个表的数据,把对应的表的字段信息读取出来,然后再根据golang的语法规则,生成文件就可以了。大致思路确定了,开始动手。

我采用sqlx进行数据库的访问,首先定义一个struct来表示COLUMNS的数据,这里我只需要几个字段,因此,没有把表COLUMNS的所有字段都对应到struct:

type FieldInfo struct {
	ColName    string `db:"COLUMN_NAME"`
	DataType   string `db:"DATA_TYPE"`
	ColComment string `db:"COLUMN_COMMENT"`
	IsNullable string `db:"IS_NULLABLE"`
}

需要指定生成的struct对应的是哪个库、哪个表,最终的golang文件保存地址,这里利用命令行参数来输入:

var dbname= flag.String("db", "", "the database name")
var tblname = flag.String("tbl", "", "the table name to export")
var savepath = flag.String("path", "./", "the path to save file")

另外,我们项目习惯使用下划线“_”来分割单词,比如info_user,表示user表,而生成的struct名称为InfoUser,字段名也是类似规则,因此定义了如下函数来处理这种情况:

func fmtFieldDefine(src string) string {
	temp := strings.Split(src, "_") // 有下划线的,需要拆分
	var str string
	for i := 0; i < len(temp); i++ {
		b := []rune(temp[i])
		for j := 0; j < len(b); j++ {
			if j == 0 {
				// 首字母大写转换
				b[j] -= 32
				str += string(b[j])
			} else {
				str += string(b[j])
			}
		}
	}

	return str
}

即把下划线去掉,且将单词的首字母改为大写。

有些字段,在设计数据库时,是可空的,information_schema->COLUMNS中有个字段IS_NULLABLE专门表示,而golang的sql有几个类型对应:sql.NullString、sql.NullBool、sql.NullFloat64、sql.NullInt64,基本上是可以满足使用要求的了。有人可能会有疑问,假如字段类型为date、timestamp等,该对应哪种呢?通常第三方的类库会转为string类型,那么就对应sql.NullString好了。不过我这里没有进行这方面的处理。

前期工作做好了,开始编码:


func main() {
	flag.Parse()
	fmt.Println("table name -->", *tblname)

	dns := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", dbuser, dbpwd, dbhost, "information_schema")

	db := sqlx.MustConnect("mysql", dns)

	var fs []FieldInfo
	err := db.Select(&fs, "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE FROM COLUMNS WHERE TABLE_NAME=? and table_schema=?", *tblname, *dbname)
	if err != nil {
		fmt.Println(err)
		panic(err)
	}

	if len(fs) > 0 {
		var buffer bytes.Buffer
		buffer.WriteString("package models\n")
		buffer.WriteString("type " + fmtFieldDefine(*tblname) + " struct {\n")
		for _, v := range fs {
			buffer.WriteString("" + fmtFieldDefine(v.ColName) + " ")
			switch v.DataType {
			case "int", "tinyint", "smallint":
				if v.IsNullable == "YES" {
					buffer.WriteString("sql.NullInt64 ")
				} else {
					buffer.WriteString("int ")
				}
			case "bigint":
				if v.IsNullable == "YES" {
					buffer.WriteString("sql.NullInt64 ")
				} else {
					buffer.WriteString("int64 ")
				}
			case "char", "varchar", "longtext", "text", "tinytext":
				if v.IsNullable == "YES" {
					buffer.WriteString("sql.NullString ")
				} else {
					buffer.WriteString("string ")
				}
			case "date", "datetime", "timestamp":
				buffer.WriteString("time.Time ")
			case "double", "float":
				if v.IsNullable == "YES" {
					buffer.WriteString("sql.NullFloat64 ")
				} else {
					buffer.WriteString("float64 ")
				}
			default:
				// 其他类型当成string处理
				if v.IsNullable == "YES" {
					buffer.WriteString("sql.NullString ")
				} else {
					buffer.WriteString("string ")
				}
			}

			buffer.WriteString(fmt.Sprintf("`db:\"%s\" json:\"%s\"`\n", v.ColName, v.ColName))

		}
		buffer.WriteString(`}`)

		fmt.Println(buffer.String())

		filename := *savepath + "\\" + *tblname + ".go"
		f, _ := os.Create(filename)
		f.Write([]byte(buffer.String()))
		f.Close()

		cmd := exec.Command("goimports", "-w", filename)
		cmd.Run()
	} else {
		fmt.Println("查询不到数据")
	}
}

我把每个字段的tag,包括db和json的都加了了,在代码最后,使用goimport工具添加需要import的package,它连format的工作都做了,实在不错。

以下是我生成的一个用户购物概要表的struct定义:

package models

import (
	"database/sql"
	"time"
)

type InfoUserShoppingSummary struct {
	Id            int            `db:"id" json:"id"`
	TransactionId sql.NullString `db:"transaction_id" json:"transaction_id"`
	OutTradeNo    sql.NullString `db:"out_trade_no" json:"out_trade_no"`
	WuId          int            `db:"wu_id" json:"wu_id"`
	WdId          int            `db:"wd_id" json:"wd_id"`
	TotalFee      float64        `db:"total_fee" json:"total_fee"`
	PayStaus      sql.NullInt64  `db:"pay_staus" json:"pay_staus"`
	CreateTime    time.Time      `db:"create_time" json:"create_time"`
	UpdateTime    time.Time      `db:"update_time" json:"update_time"`
	Address       sql.NullString `db:"address" json:"address"`
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值