github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgSql/Sync.go (about)

     1  package kmgSql
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/bronze1man/kmg/kmgStrings"
     8  	//"github.com/bronze1man/kmg/kmgDebug"
     9  )
    10  
    11  //读取数据库的表字段,不区分大小写(某些系统的mysql不区分大小写)
    12  //写入数据库的表字段,区分大小写
    13  type Table struct {
    14  	Name       string
    15  	FieldList  map[string]DbType
    16  	PrimaryKey string
    17  	UniqueKey  [][]string
    18  	Null       []string
    19  }
    20  
    21  type DbType string
    22  
    23  const (
    24  	DbTypeInt              DbType = `int(11) DEFAULT 0`
    25  	DbTypeIntAutoIncrement DbType = `int(11) unsigned AUTO_INCREMENT`
    26  	DbTypeString           DbType = `varchar(255) COLLATE utf8_bin DEFAULT ""`
    27  	DbTypeLongString       DbType = `longtext COLLATE utf8_bin DEFAULT ""`
    28  	DbTypeFloat            DbType = `float default 0`
    29  	DbTypeDatetime         DbType = `datetime DEFAULT "0000-00-00 00:00:00"`
    30  	DbTypeBool             DbType = `tinyint(4) DEFAULT 0`
    31  	DbTypeLongBlob         DbType = `LONGBLOB`
    32  )
    33  
    34  func (t DbType) GetMysqlFieldType() MysqlFieldType {
    35  	switch t {
    36  	case DbTypeInt:
    37  		return MysqlFieldType{
    38  			DataType: MysqlDataTypeInt32,
    39  			Default:  "0",
    40  		}
    41  	case DbTypeIntAutoIncrement:
    42  		return MysqlFieldType{
    43  			DataType:        MysqlDataTypeInt32,
    44  			IsUnsigned:      true,
    45  			IsAutoIncrement: true,
    46  		}
    47  	case DbTypeString:
    48  		return MysqlFieldType{
    49  			DataType:         MysqlDataTypeVarchar,
    50  			Default:          "",
    51  			CharacterSetName: "utf8",
    52  			CollationName:    "utf8_bin",
    53  			StringLength:     255,
    54  		}
    55  	case DbTypeLongString:
    56  		return MysqlFieldType{
    57  			DataType:         MysqlDataTypeLongText,
    58  			Default:          "",
    59  			CharacterSetName: "utf8",
    60  			CollationName:    "utf8_bin",
    61  		}
    62  	case DbTypeFloat:
    63  		return MysqlFieldType{
    64  			DataType: MysqlDataTypeFloat,
    65  			Default:  "0",
    66  		}
    67  	case DbTypeDatetime:
    68  		return MysqlFieldType{
    69  			DataType: MysqlDataTypeDateTime,
    70  			Default:  "0000-00-00 00:00:00",
    71  		}
    72  	case DbTypeBool:
    73  		return MysqlFieldType{
    74  			DataType: MysqlDataTypeInt8,
    75  			Default:  "0",
    76  		}
    77  	case DbTypeLongBlob:
    78  		return MysqlFieldType{
    79  			DataType: MysqlDataTypeLongBlob,
    80  		}
    81  	default:
    82  		panic(fmt.Errorf("Unsupport DbType %s", t))
    83  	}
    84  }
    85  
    86  func MustSyncTable(tableConf Table) {
    87  	MustVerifyTableConfig(tableConf)
    88  	if MustIsTableExist(tableConf.Name) {
    89  		MustModifyTable(tableConf)
    90  	} else {
    91  		MustCreateTable(tableConf)
    92  	}
    93  }
    94  
    95  func MustForceSyncTable(tableConf Table) {
    96  	MustVerifyTableConfig(tableConf)
    97  	if MustIsTableExist(tableConf.Name) {
    98  		MustForceModifyTable(tableConf)
    99  	} else {
   100  		MustCreateTable(tableConf)
   101  	}
   102  }
   103  
   104  func MustIsTableExist(tableName string) bool {
   105  	ret := MustQueryOne("SHOW TABLE STATUS WHERE Name=?", tableName)
   106  	if len(ret) <= 0 {
   107  		return false
   108  	} else {
   109  		return true
   110  	}
   111  }
   112  
   113  func MustVerifyTableConfig(tableConf Table) {
   114  	fieldNameFieldMap := map[string]bool{}
   115  	for name := range tableConf.FieldList {
   116  		name := strings.ToLower(name)
   117  		if fieldNameFieldMap[name] {
   118  			panic(fmt.Errorf("[MustVerifyTableConfig] Table[%s] Field[%s] 两个字段名只有大小写不一致",
   119  				tableConf.Name, name))
   120  		}
   121  		fieldNameFieldMap[name] = true
   122  	}
   123  }
   124  
   125  func MustCreateTable(tableConf Table) {
   126  	sql := "CREATE TABLE IF NOT EXISTS `" + tableConf.Name + "` \n("
   127  	sqlItemList := []string{}
   128  	hasPrimaryKey := false
   129  	for fieldName, fieldType := range tableConf.FieldList {
   130  		if tableConf.PrimaryKey == fieldName {
   131  			hasPrimaryKey = true
   132  			//continue
   133  		}
   134  		sqlField := "`" + fieldName + "` " + string(fieldType)
   135  		if !kmgStrings.IsInSlice(tableConf.Null, fieldName) {
   136  			sqlField += " NOT NULL"
   137  		}
   138  		sqlItemList = append(sqlItemList, sqlField)
   139  	}
   140  	if tableConf.PrimaryKey != "" {
   141  		if !hasPrimaryKey {
   142  			panic(fmt.Sprintf(`tableConf.PrimaryKey[%s], 但是这个主键不在字段列表里面`, tableConf.PrimaryKey))
   143  		}
   144  		//sqlItemList = append(sqlItemList, "`"+tableConf.PrimaryKey+"` int(11) unsigned AUTO_INCREMENT")
   145  		sqlItemList = append(sqlItemList, "PRIMARY KEY (`"+tableConf.PrimaryKey+"`)")
   146  	}
   147  	for _, group := range tableConf.UniqueKey {
   148  		uniqueSql := "UNIQUE INDEX ("
   149  		uniqueKeyList := []string{}
   150  		for _, key := range group {
   151  			uniqueKeyList = append(uniqueKeyList, "`"+key+"`")
   152  		}
   153  		uniqueSql += strings.Join(uniqueKeyList, ",") + ")"
   154  		sqlItemList = append(sqlItemList, uniqueSql)
   155  	}
   156  	sql += strings.Join(sqlItemList, ",\n")
   157  	sql += "\n) engine=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"
   158  	MustExec(sql)
   159  }
   160  
   161  func MustModifyTable(tableConf Table) {
   162  	MysqlFieldTypeList := mustMysqlGetTableFieldTypeList(tableConf.Name)
   163  	dbFieldNameList := []string{}
   164  	for _, row := range MysqlFieldTypeList {
   165  		dbFieldNameList = append(dbFieldNameList, strings.ToLower(row.Name))
   166  	}
   167  	for _, f1 := range dbFieldNameList {
   168  		found := false
   169  		for f2 := range tableConf.FieldList {
   170  			if strings.EqualFold(f2, f1) {
   171  				found = true
   172  				break
   173  			}
   174  		}
   175  		if !found {
   176  			fmt.Printf("[kmgSql.SyncTable] 数据库中包含多余字段 Table[%s] Field[%s]\n", tableConf.Name, f1)
   177  		}
   178  	}
   179  	for fieldName, fieldType := range tableConf.FieldList {
   180  		if !kmgStrings.IsInSlice(dbFieldNameList, strings.ToLower(fieldName)) {
   181  			MustAddNewField(tableConf, fieldName)
   182  			continue
   183  		}
   184  		for _, row := range MysqlFieldTypeList {
   185  			if row.Name == fieldName {
   186  				if !fieldType.GetMysqlFieldType().Equal(row.Type) {
   187  					fmt.Printf("[kmgSql.SyncTable] Table[%s] Field[%s] OldType[%s] NewType[%s] 数据库字段类型不一致\n",
   188  						tableConf.Name, fieldName, row.Type.String(), fieldType.GetMysqlFieldType().String())
   189  				}
   190  				break
   191  			}
   192  			if strings.EqualFold(row.Name, fieldName) {
   193  				fmt.Printf("[kmgSql.SyncTable] Table[%s] OldField[%s] NewField[%s] 数据库字段大小写不一致\n",
   194  					tableConf.Name, fieldName, row.Name)
   195  				break
   196  			}
   197  		}
   198  	}
   199  }
   200  
   201  func MustForceModifyTable(tableConf Table) {
   202  	MysqlFieldTypeList := mustMysqlGetTableFieldTypeList(tableConf.Name)
   203  	dbFieldNameList := []string{}
   204  	for _, row := range MysqlFieldTypeList {
   205  		dbFieldNameList = append(dbFieldNameList, row.Name)
   206  	}
   207  	for _, f1 := range dbFieldNameList {
   208  		found := false
   209  		for f2 := range tableConf.FieldList {
   210  			if f2 == f1 {
   211  				found = true
   212  				break
   213  			}
   214  		}
   215  		if !found {
   216  			MustExec(fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN `%s`", tableConf.Name, f1))
   217  		}
   218  	}
   219  	for fieldName, fieldType := range tableConf.FieldList {
   220  		if kmgStrings.IsInSlice(dbFieldNameList, fieldName) {
   221  			for _, row := range MysqlFieldTypeList {
   222  				if row.Name == fieldName {
   223  					if !fieldType.GetMysqlFieldType().Equal(row.Type) {
   224  						MustExec(fmt.Sprintf("ALTER TABLE `%s` CHANGE COLUMN `%s` `%s` %s NOT NULL", tableConf.Name, fieldName, fieldName, fieldType))
   225  					}
   226  					break
   227  				}
   228  			}
   229  			continue
   230  		}
   231  		MustAddNewField(tableConf, fieldName)
   232  	}
   233  }
   234  
   235  func MustAddNewField(tableConf Table, newFieldName string) {
   236  	newFieldType := tableConf.FieldList[newFieldName]
   237  	sql := "ALTER TABLE `" + tableConf.Name + "` ADD `" + newFieldName + "` " + string(newFieldType)
   238  	if !kmgStrings.IsInSlice(tableConf.Null, newFieldName) {
   239  		sql += " NOT NULL"
   240  	}
   241  	MustExec(sql)
   242  }