Random walk to my blog

my blog for sharing my knowledge,experience and viewpoint

0%

SQL的创建语句转化成Golang的ORM结构体(struct)

在Golang的Web编程中,有时候我们创建了一个SQL的表,需要编写对应的结构体的代码。这是一项繁琐无聊的工作。本文介绍一种自动将创建表格的SQL语句转换成Golang的ORM结构体的代码,从而提高编程效率。代码来自于我的Github

例子

例子:下面是一个创建user表的sql语句

1
2
3
4
5
6
7
8
9
10
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将其转化成下面的代码。其中,包名是可以选择的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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件事。

  1. 解析sql语句,这里使用第三方包github.com/xwb1989/sqlparser去解析,获取表的名字,字段名,字段类型,字段的注释。
  2. 将解析的MySQL数据类型转化为Golang的数据类型,并且将以上的数据,做字符串的拼接,拼接成一个Golang的struct文件。
    MySQL与Golang的类型对应映射如下.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    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会将其字段命名转化为驼峰式的。对应的转化代码如下。
基本思想是,扫描字符串,如果遇到字符_,并且_的字符是一个英文字母,将将其转化为大写,并且忽略这个_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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的结构体了。