mirror of
				https://github.com/xxjwxc/public.git
				synced 2025-10-31 11:17:04 +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"},
 | ||
| }
 | 
