mirror of
https://github.com/xxjwxc/public.git
synced 2025-09-26 20:01:19 +08:00
347 lines
8.4 KiB
Go
347 lines
8.4 KiB
Go
package mysqldb
|
||
|
||
import (
|
||
"fmt"
|
||
"regexp"
|
||
"time"
|
||
|
||
"github.com/xxjwxc/public/mylog"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// TabColumnInfo 表信息
|
||
type TabColumnInfo struct {
|
||
ColumnName string
|
||
ColumnType string // 跟数据库一致
|
||
Len string
|
||
NotNull bool
|
||
Comment string // 注释
|
||
}
|
||
|
||
type TablesModel struct {
|
||
ID int `gorm:"primaryKey;column:id" json:"-"` // 主键id
|
||
}
|
||
|
||
type TablesTools struct {
|
||
tabName string
|
||
orm *MySqlDB
|
||
}
|
||
|
||
// Tables
|
||
func NewTabTools(orm *MySqlDB, tabName string) (*TablesTools, error) {
|
||
return &TablesTools{
|
||
orm: orm,
|
||
tabName: tabName,
|
||
}, nil
|
||
}
|
||
|
||
// GetDB 获取db
|
||
func (t *TablesTools) GetDB() *gorm.DB {
|
||
return t.orm.Table(t.tabName)
|
||
}
|
||
|
||
// CreateTable 创建表
|
||
func (t *TablesTools) CreateTable(columns []*TabColumnInfo) error {
|
||
err := t.orm.Table(t.tabName).Set("gorm:table_options", "ENGINE=InnoDB").Migrator().CreateTable(&TablesModel{})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
for _, v := range columns {
|
||
err := t.AddColumn(v)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// notnul := ""
|
||
// if v.NotNull {
|
||
// notnul = "NOT NULL"
|
||
// }
|
||
// _len := v.Len
|
||
// if len(v.Len) > 0 {
|
||
// _len = fmt.Sprintf("(%v)", v.Len)
|
||
// }
|
||
|
||
// sql := fmt.Sprintf("ALTER TABLE `%v` ADD COLUMN `%v` %v%v %v COMMENT '%v';", t.tabName, v.ColumnName, v.ColumnType, _len, notnul, v.Comment)
|
||
// err = t.orm.Exec(sql).Error
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
}
|
||
|
||
return err
|
||
}
|
||
|
||
// HasTable 表是否存在
|
||
func (t *TablesTools) HasTable() bool {
|
||
return t.orm.Migrator().HasTable(t.tabName)
|
||
}
|
||
|
||
// DropTable 如果存在表则删除(删除时会忽略、删除外键约束)
|
||
func (t *TablesTools) DropTable() error {
|
||
return t.orm.Migrator().DropTable(t.tabName)
|
||
}
|
||
|
||
// TruncateTable 截断表
|
||
func (t *TablesTools) TruncateTable() error {
|
||
return t.orm.Exec(fmt.Sprintf("TRUNCATE TABLE %v;", t.tabName)).Error
|
||
}
|
||
|
||
// GetTables 获取所有表名
|
||
func (t *TablesTools) GetTables() (tableList []string, err error) {
|
||
return t.orm.Migrator().GetTables()
|
||
}
|
||
|
||
// RenameTable 重命名表
|
||
func (t *TablesTools) RenameTable(newTabName string) error {
|
||
return t.orm.Migrator().RenameTable(t.tabName, newTabName)
|
||
}
|
||
|
||
// AddColumn 添加列元素
|
||
func (t *TablesTools) AddColumn(column *TabColumnInfo) error {
|
||
notnul := ""
|
||
if column.NotNull {
|
||
notnul = "NOT NULL"
|
||
}
|
||
_len := column.Len
|
||
if len(column.Len) > 0 {
|
||
_len = fmt.Sprintf("(%v)", column.Len)
|
||
}
|
||
|
||
sql := fmt.Sprintf("ALTER TABLE `%v` ADD COLUMN `%v` %v%v %v COMMENT '%v';", t.tabName, column.ColumnName, column.ColumnType, _len, notnul, column.Comment)
|
||
err := t.orm.Exec(sql).Error
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// HasColumn 是否有列
|
||
func (t *TablesTools) HasColumn(column string) bool {
|
||
return t.orm.Table(t.tabName).Migrator().HasColumn(&TablesModel{}, column)
|
||
}
|
||
|
||
// DropColumn 删除列
|
||
func (t *TablesTools) DropColumn(column string) error {
|
||
return t.orm.Table(t.tabName).Migrator().DropColumn(&TablesModel{}, column)
|
||
}
|
||
|
||
// RenameColumn 字段重命名
|
||
func (t *TablesTools) RenameColumn(oldColumn, newColumn string) error {
|
||
return t.orm.Table(t.tabName).Migrator().RenameColumn(&TablesModel{}, oldColumn, newColumn)
|
||
}
|
||
|
||
// ColumnTypes 获取列属性
|
||
func (t *TablesTools) ColumnTypes() ([]gorm.ColumnType, error) {
|
||
return t.orm.Table(t.tabName).Migrator().ColumnTypes(&TablesModel{})
|
||
}
|
||
|
||
// CreateIndex Indexes
|
||
func (t *TablesTools) CreateIndex(column string) error {
|
||
return t.orm.Table(t.tabName).Migrator().CreateIndex(&TablesModel{}, column)
|
||
}
|
||
|
||
// DropIndex Indexes
|
||
func (t *TablesTools) DropIndex(column string) error {
|
||
return t.orm.Table(t.tabName).Migrator().DropIndex(&TablesModel{}, column)
|
||
}
|
||
|
||
// HasIndex Indexes
|
||
func (t *TablesTools) HasIndex(column string) bool {
|
||
return t.orm.Table(t.tabName).Migrator().HasIndex(&TablesModel{}, column)
|
||
}
|
||
|
||
// RenameIndex Indexes
|
||
func (t *TablesTools) RenameIndex(oldColumn, newColumn string) error {
|
||
return t.orm.Table(t.tabName).Migrator().RenameIndex(&TablesModel{}, oldColumn, newColumn)
|
||
}
|
||
|
||
type ColumnTypeInfo struct {
|
||
Name string
|
||
Type string
|
||
Commont string
|
||
}
|
||
|
||
// RawInfo 列信息
|
||
type RawInfo struct {
|
||
ColumnTypes []ColumnTypeInfo
|
||
Values [][]interface{}
|
||
}
|
||
|
||
// Select 查询
|
||
func (t *TablesTools) Select(DB *gorm.DB) (*RawInfo, error) {
|
||
colTypes, err := t.ColumnTypes()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
out := &RawInfo{}
|
||
for i, v := range colTypes {
|
||
commont, _ := v.Comment()
|
||
out.ColumnTypes = append(out.ColumnTypes, ColumnTypeInfo{
|
||
Name: v.Name(),
|
||
Type: ColumnType(colTypes[i]),
|
||
Commont: commont,
|
||
})
|
||
}
|
||
|
||
rows, err := DB.Table(t.tabName).Rows()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
|
||
for rows.Next() {
|
||
var values []interface{} //创建一个与列的数量相当的空接口
|
||
for _, v := range out.ColumnTypes {
|
||
deserialize(v.Type, &values)
|
||
}
|
||
|
||
err := rows.Scan(values...) //开始读行,Scan函数只接受指针变量
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
out.Values = append(out.Values, values) //将单行所有列的键值对附加在总的返回值上(以行为单位)
|
||
}
|
||
|
||
return out, err
|
||
}
|
||
|
||
func deserialize(tp string, data *[]interface{}) interface{} {
|
||
switch tp {
|
||
case "int":
|
||
var tmp int
|
||
*data = append(*data, &tmp)
|
||
case "int64":
|
||
var tmp int64
|
||
*data = append(*data, &tmp)
|
||
case "string":
|
||
var tmp string
|
||
*data = append(*data, &tmp)
|
||
case "[]byte":
|
||
var tmp []byte
|
||
*data = append(*data, &tmp)
|
||
case "time":
|
||
var tmp time.Time
|
||
*data = append(*data, &tmp)
|
||
case "bool":
|
||
var tmp bool
|
||
*data = append(*data, &tmp)
|
||
case "float64":
|
||
var tmp float64
|
||
*data = append(*data, &tmp)
|
||
default:
|
||
mylog.Errorf("type (%v) not match in any way.maybe need to add on", tp)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL",
|
||
// "INT", and "BIGINT".
|
||
func ColumnType(t gorm.ColumnType) string {
|
||
tp, _ := t.ColumnType()
|
||
// Precise matching first.先精确匹配
|
||
if v, ok := TypeMysqlDicMp[tp]; ok {
|
||
return v
|
||
}
|
||
|
||
// Fuzzy Regular Matching.模糊正则匹配
|
||
for _, l := range TypeMysqlMatchList {
|
||
if ok, _ := regexp.MatchString(l.Key, tp); ok {
|
||
return l.Value
|
||
}
|
||
}
|
||
|
||
return tp
|
||
}
|
||
|
||
// TypeMysqlDicMp Accurate matching type.精确匹配类型
|
||
var TypeMysqlDicMp = map[string]string{
|
||
"int": "int",
|
||
"int unsigned": "int",
|
||
"tinyint": "int",
|
||
"tinyint unsigned": "int",
|
||
"mediumint": "int",
|
||
"mediumint unsigned": "int",
|
||
|
||
"smallint": "int64",
|
||
"smallint unsigned": "int64",
|
||
"bigint": "int64",
|
||
"bigint unsigned": "int64",
|
||
"timestamp": "int64",
|
||
"integer": "int64",
|
||
|
||
"varchar": "string",
|
||
"char": "string",
|
||
"json": "string",
|
||
"text": "string",
|
||
"mediumtext": "string",
|
||
"longtext": "string",
|
||
"tinytext": "string",
|
||
"enum": "string",
|
||
"nvarchar": "string",
|
||
|
||
"bit(1)": "[]byte",
|
||
"tinyblob": "[]byte",
|
||
"blob": "[]byte",
|
||
"mediumblob": "[]byte",
|
||
"longblob": "[]byte",
|
||
"binary": "[]byte",
|
||
|
||
"date": "time",
|
||
"datetime": "time",
|
||
"time": "time",
|
||
"smalldatetime": "time", //sqlserver
|
||
|
||
"tinyint(1)": "bool", // tinyint(1) 默认设置成bool
|
||
"tinyint(1) unsigned": "bool", // tinyint(1) 默认设置成bool
|
||
|
||
"double": "float64",
|
||
"double unsigned": "float64",
|
||
"float": "float64",
|
||
"float unsigned": "float64",
|
||
"real": "float64",
|
||
"numeric": "float64",
|
||
}
|
||
|
||
// TypeMysqlMatchList Fuzzy Matching Types.模糊匹配类型
|
||
var TypeMysqlMatchList = []struct {
|
||
Key string
|
||
Value string
|
||
}{
|
||
{`^(tinyint)[(]\d+[)] unsigned`, "int"},
|
||
{`^(smallint)[(]\d+[)] unsigned`, "int"},
|
||
{`^(int)[(]\d+[)] unsigned`, "int"},
|
||
{`^(tinyint)[(]\d+[)]`, "int"},
|
||
{`^(smallint)[(]\d+[)]`, "int"},
|
||
{`^(int)[(]\d+[)]`, "int"},
|
||
{`^(mediumint)[(]\d+[)]`, "int"},
|
||
{`^(mediumint)[(]\d+[)] unsigned`, "int"},
|
||
{`^(integer)[(]\d+[)]`, "int"},
|
||
|
||
{`^(bigint)[(]\d+[)] unsigned`, "int64"},
|
||
{`^(bigint)[(]\d+[)]`, "int64"},
|
||
{`^(timestamp)[(]\d+[)]`, "int64"},
|
||
|
||
{`^(float)[(]\d+,\d+[)] unsigned`, "float64"},
|
||
{`^(double)[(]\d+,\d+[)] unsigned`, "float64"},
|
||
{`^(decimal)[(]\d+,\d+[)]`, "float64"},
|
||
{`^(double)[(]\d+,\d+[)]`, "float64"},
|
||
{`^(float)[(]\d+,\d+[)]`, "float64"},
|
||
|
||
{`^(char)[(]\d+[)]`, "string"},
|
||
{`^(enum)[(](.)+[)]`, "string"},
|
||
{`^(varchar)[(]\d+[)]`, "string"},
|
||
{`^(text)[(]\d+[)]`, "string"},
|
||
{`^(set)[(][\s\S]+[)]`, "string"},
|
||
|
||
{`^(varbinary)[(]\d+[)]`, "[]byte"},
|
||
{`^(blob)[(]\d+[)]`, "[]byte"},
|
||
{`^(binary)[(]\d+[)]`, "[]byte"},
|
||
{`^(bit)[(]\d+[)]`, "[]byte"},
|
||
{`^(geometry)[(]\d+[)]`, "[]byte"},
|
||
|
||
{`^(datetime)[(]\d+[)]`, "time"},
|
||
}
|