improve data type conversion (#236)
* improve data type conversion * update doc
This commit is contained in:
@@ -78,8 +78,8 @@ goctl model 为go-zero下的工具模块中的组件之一,目前支持识别m
|
|||||||
Password string `db:"password"` // 用户密码
|
Password string `db:"password"` // 用户密码
|
||||||
Mobile string `db:"mobile"` // 手机号
|
Mobile string `db:"mobile"` // 手机号
|
||||||
Gender string `db:"gender"` // 男|女|未公开
|
Gender string `db:"gender"` // 男|女|未公开
|
||||||
Nickname string `db:"nickname"` // 用户昵称
|
Nickname sql.NullString `db:"nickname"` // 用户昵称
|
||||||
CreateTime time.Time `db:"create_time"`
|
CreateTime sql.NullTime `db:"create_time"`
|
||||||
UpdateTime time.Time `db:"update_time"`
|
UpdateTime time.Time `db:"update_time"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -347,3 +347,33 @@ OPTIONS:
|
|||||||
|
|
||||||
目前,我认为除了基本的CURD外,其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。
|
目前,我认为除了基本的CURD外,其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。
|
||||||
|
|
||||||
|
# 类型转换规则
|
||||||
|
| mysql dataType | golang dataType | golang dataType(if null&&default null) |
|
||||||
|
|----------------|-----------------|----------------------------------------|
|
||||||
|
| bool | int64 | sql.NullInt64 |
|
||||||
|
| boolean | int64 | sql.NullInt64 |
|
||||||
|
| tinyint | int64 | sql.NullInt64 |
|
||||||
|
| smallint | int64 | sql.NullInt64 |
|
||||||
|
| mediumint | int64 | sql.NullInt64 |
|
||||||
|
| int | int64 | sql.NullInt64 |
|
||||||
|
| integer | int64 | sql.NullInt64 |
|
||||||
|
| bigint | int64 | sql.NullInt64 |
|
||||||
|
| float | float64 | sql.NullFloat64 |
|
||||||
|
| double | float64 | sql.NullFloat64 |
|
||||||
|
| decimal | float64 | sql.NullFloat64 |
|
||||||
|
| date | time.Time | sql.NullTime |
|
||||||
|
| datetime | time.Time | sql.NullTime |
|
||||||
|
| timestamp | time.Time | sql.NullTime |
|
||||||
|
| time | string | sql.NullString |
|
||||||
|
| year | time.Time | sql.NullInt64 |
|
||||||
|
| char | string | sql.NullString |
|
||||||
|
| varchar | string | sql.NullString |
|
||||||
|
| binary | string | sql.NullString |
|
||||||
|
| varbinary | string | sql.NullString |
|
||||||
|
| tinytext | string | sql.NullString |
|
||||||
|
| text | string | sql.NullString |
|
||||||
|
| mediumtext | string | sql.NullString |
|
||||||
|
| longtext | string | sql.NullString |
|
||||||
|
| enum | string | sql.NullString |
|
||||||
|
| set | string | sql.NullString |
|
||||||
|
| json | string | sql.NullString |
|
||||||
@@ -41,12 +41,34 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConvertDataType(dataBaseType string) (goDataType string, err error) {
|
func ConvertDataType(dataBaseType string, isDefaultNull bool) (string, error) {
|
||||||
tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)]
|
tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)]
|
||||||
if !ok {
|
if !ok {
|
||||||
err = fmt.Errorf("unexpected database type: %s", dataBaseType)
|
return "", fmt.Errorf("unexpected database type: %s", dataBaseType)
|
||||||
return
|
}
|
||||||
|
|
||||||
|
return mayConvertNullType(tp, isDefaultNull), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mayConvertNullType(goDataType string, isDefaultNull bool) string {
|
||||||
|
if !isDefaultNull {
|
||||||
|
return goDataType
|
||||||
|
}
|
||||||
|
|
||||||
|
switch goDataType {
|
||||||
|
case "int64":
|
||||||
|
return "sql.NullInt64"
|
||||||
|
case "int32":
|
||||||
|
return "sql.NullInt32"
|
||||||
|
case "float64":
|
||||||
|
return "sql.NullFloat64"
|
||||||
|
case "bool":
|
||||||
|
return "sql.NullBool"
|
||||||
|
case "string":
|
||||||
|
return "sql.NullString"
|
||||||
|
case "time.Time":
|
||||||
|
return "sql.NullTime"
|
||||||
|
default:
|
||||||
|
return goDataType
|
||||||
}
|
}
|
||||||
goDataType = tp
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestConvertDataType(t *testing.T) {
|
func TestConvertDataType(t *testing.T) {
|
||||||
v, err := ConvertDataType("tinyint")
|
v, err := ConvertDataType("tinyint", false)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "int64", v)
|
assert.Equal(t, "int64", v)
|
||||||
|
|
||||||
v, err = ConvertDataType("timestamp")
|
v, err = ConvertDataType("tinyint", true)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "sql.NullInt64", v)
|
||||||
|
|
||||||
|
v, err = ConvertDataType("timestamp", false)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "time.Time", v)
|
assert.Equal(t, "time.Time", v)
|
||||||
|
|
||||||
_, err = ConvertDataType("float32")
|
v, err = ConvertDataType("timestamp", true)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "sql.NullTime", v)
|
||||||
|
|
||||||
|
_, err = ConvertDataType("float32", false)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,3 +15,12 @@ CREATE TABLE `user` (
|
|||||||
UNIQUE KEY `mobile_index` (`mobile`)
|
UNIQUE KEY `mobile_index` (`mobile`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `student` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
|
||||||
|
`age` tinyint DEFAULT NULL,
|
||||||
|
`score` float(10,0) DEFAULT NULL,
|
||||||
|
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`update_time` timestamp NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
-- 用户表 --
|
|
||||||
CREATE TABLE `user1` (
|
|
||||||
`id` bigint(10) NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',
|
|
||||||
`password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',
|
|
||||||
`mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
|
|
||||||
`gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',
|
|
||||||
`nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',
|
|
||||||
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `name_index` (`name`),
|
|
||||||
UNIQUE KEY `mobile_index` (`mobile`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
||||||
|
|
||||||
@@ -9,11 +9,13 @@ type (
|
|||||||
conn sqlx.SqlConn
|
conn sqlx.SqlConn
|
||||||
}
|
}
|
||||||
Column struct {
|
Column struct {
|
||||||
Name string `db:"COLUMN_NAME"`
|
Name string `db:"COLUMN_NAME"`
|
||||||
DataType string `db:"DATA_TYPE"`
|
DataType string `db:"DATA_TYPE"`
|
||||||
Key string `db:"COLUMN_KEY"`
|
Key string `db:"COLUMN_KEY"`
|
||||||
Extra string `db:"EXTRA"`
|
Extra string `db:"EXTRA"`
|
||||||
Comment string `db:"COLUMN_COMMENT"`
|
Comment string `db:"COLUMN_COMMENT"`
|
||||||
|
ColumnDefault interface{} `db:"COLUMN_DEFAULT"`
|
||||||
|
IsNullAble string `db:"IS_NULLABLE"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ func (m *InformationSchemaModel) GetAllTables(database string) ([]string, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *InformationSchemaModel) FindByTableName(db, table string) ([]*Column, error) {
|
func (m *InformationSchemaModel) FindByTableName(db, table string) ([]*Column, error) {
|
||||||
querySql := `select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
|
querySql := `select COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
|
||||||
var reply []*Column
|
var reply []*Column
|
||||||
err := m.conn.QueryRows(&reply, querySql, db, table)
|
err := m.conn.QueryRows(&reply, querySql, db, table)
|
||||||
return reply, err
|
return reply, err
|
||||||
|
|||||||
@@ -112,7 +112,17 @@ func Parse(ddl string) (*Table, error) {
|
|||||||
if column.Type.Comment != nil {
|
if column.Type.Comment != nil {
|
||||||
comment = string(column.Type.Comment.Val)
|
comment = string(column.Type.Comment.Val)
|
||||||
}
|
}
|
||||||
dataType, err := converter.ConvertDataType(column.Type.Type)
|
var isDefaultNull = true
|
||||||
|
if column.Type.NotNull {
|
||||||
|
isDefaultNull = false
|
||||||
|
} else {
|
||||||
|
if column.Type.Default == nil {
|
||||||
|
isDefaultNull = false
|
||||||
|
} else if string(column.Type.Default.Val) != "null" {
|
||||||
|
isDefaultNull = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataType, err := converter.ConvertDataType(column.Type.Type, isDefaultNull)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -170,7 +180,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
primaryColumn := primaryColumns[0]
|
primaryColumn := primaryColumns[0]
|
||||||
primaryFt, err := converter.ConvertDataType(primaryColumn.DataType)
|
isDefaultNull := primaryColumn.ColumnDefault == nil && primaryColumn.IsNullAble == "YES"
|
||||||
|
primaryFt, err := converter.ConvertDataType(primaryColumn.DataType, isDefaultNull)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -189,7 +200,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
|
|||||||
}
|
}
|
||||||
for key, columns := range keyMap {
|
for key, columns := range keyMap {
|
||||||
for _, item := range columns {
|
for _, item := range columns {
|
||||||
dt, err := converter.ConvertDataType(item.DataType)
|
isColumnDefaultNull := item.ColumnDefault == nil && item.IsNullAble == "YES"
|
||||||
|
dt, err := converter.ConvertDataType(item.DataType, isColumnDefaultNull)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ func TestConvertColumn(t *testing.T) {
|
|||||||
for _, item := range table.Fields {
|
for _, item := range table.Fields {
|
||||||
if item.Name.Source() == "mobile" {
|
if item.Name.Source() == "mobile" {
|
||||||
assert.True(t, item.IsUniqueKey)
|
assert.True(t, item.IsUniqueKey)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user