在Golang的Web编程中,有时候我们创建了一个SQL的表,需要编写对应的结构体的代码。这是一项繁琐无聊的工作。本文介绍一种自动将创建表格的SQL语句转换成Golang的ORM结构体的代码,从而提高编程效率。代码来自于我的Github。
例子:下面是一个创建user
表的sql语句
CREATE TABLE `USER`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`ip_address` INT NOT NULL DEFAULT 0 COMMENT 'ip_address',
`nickname` VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'user note',
`description` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'user description',
`creator_email` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'creator email',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
`deleted_at` TIMESTAMP NULL DEFAULT NULL COMMENT 'delete time',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='user table';
函数SqlToGo
将其转化成下面的代码。其中,包名是可以选择的。
package sql_to_go_test
import (
"time"
)
type USER struct {
Id uint `comment:"primary key"`
IpAddress int `comment:"ip_address"`
Nickname string `comment:"user note"`
Description string `comment:"user description"`
CreatorEmail string `comment:"creator email"`
CreatedAt time.Time `comment:"create time"`
DeletedAt time.Time `comment:"delete time"`
}
SqlToGo
主要做了2件事。
github.com/xwb1989/sqlparser
去解析,获取表的名字,字段名,字段类型,字段的注释。var sqlTypeMap = map[string]string{
"int": "int",
"integer": "int",
"tinyint": "int8",
"smallint": "int16",
"mediumint": "int32",
"bigint": "int64",
"int unsigned": "uint",
"integer unsigned": "uint",
"tinyint unsigned": "uint8",
"smallint unsigned": "uint16",
"mediumint unsigned": "uint32",
"bigint unsigned": "uint64",
"bit": "byte",
"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",
"datetime": "time.Time",
"timestamp": "time.Time",
"time": "time.Time",
"float": "float64",
"double": "float64",
"decimal": "float64",
"binary": "string",
"varbinary": "string",
}
在SQL的命名规范中,字段的命名一般都是下划线分隔的,例如ip_address
。而Golang的struct
的字段的命名是驼峰式的。
SqlToGo
会将其字段命名转化为驼峰式的。对应的转化代码如下。
基本思想是,扫描字符串,如果遇到字符_
,并且_
的字符是一个英文字母,将将其转化为大写,并且忽略这个_
。
// In sql, table name often is snake_case
// In Go, struct name often is camel case
func snakeCaseToCamel(str string) string {
builder := strings.Builder{}
index := 0
if str[0] >= 'a' && str[0] <= 'z' {
builder.WriteByte(str[0] - ('a' - 'A'))
index = 1
}
for i := index; i < len(str); i++ {
if str[i] == '_' && i+1 < len(str) {
if str[i+1] >= 'a' && str[i+1] <= 'z' {
builder.WriteByte(str[i+1] - ('a' - 'A'))
i++
continue
}
}
builder.WriteByte(str[i])
}
return builder.String()
}
经过SQL语句的解析,转换,字符串的拼接,就将一个SQL
语句转化成Golang的结构体了。