package sqldef import ( "fmt" "strings" "time" "unicode/utf8" "git.x2erp.com/qdy/go-db/sqldef/generators" ) // DictSQLGenerator 字典表SQL生成器 type DictSQLGenerator struct { TableIDPrefix string // 表ID前缀,如 "TBL" ColumnIDPrefix string // 字段ID前缀,如 "COL" } // NewDictSQLGenerator 创建生成器 func NewDictSQLGenerator() *DictSQLGenerator { return &DictSQLGenerator{ TableIDPrefix: "TBL", ColumnIDPrefix: "COL", } } // DictSQLs 字典表SQL集合 type DictSQLs struct { TableSQL string // 主表SQL ColumnSQLs map[string]string // 字段名 -> SQL映射 } // GenerateDictSQLsFromTable 从TableDDL生成字典表SQL func (gen *DictSQLGenerator) GenerateDictSQLsFromTable(table generators.TableDDL) (*DictSQLs, error) { if table.Schema == nil { return nil, fmt.Errorf("表 %s 没有Schema信息", table.Name) } // 生成表ID tableID := gen.generateTableID(table.Name) // 1. 生成主表SQL tableSQL := gen.generateMainTableSQL(tableID, table) // 2. 生成子表SQL映射 columnSQLs := gen.generateColumnSQLs(tableID, table.Schema.Columns) return &DictSQLs{ TableSQL: tableSQL, ColumnSQLs: columnSQLs, }, nil } // GenerateDictSQLsFromRegistry 从注册表中获取所有表的字典SQL func (gen *DictSQLGenerator) GenerateDictSQLsFromRegistry() (map[string]*DictSQLs, error) { globalRegistry.ensureInit() globalRegistry.mu.RLock() defer globalRegistry.mu.RUnlock() result := make(map[string]*DictSQLs) for tableName, tableDDL := range globalRegistry.tables { sqls, err := gen.GenerateDictSQLsFromTable(tableDDL) if err != nil { return nil, fmt.Errorf("生成表 %s 的字典SQL失败: %w", tableName, err) } result[tableName] = sqls } return result, nil } // generateTableID 生成表ID func (gen *DictSQLGenerator) generateTableID(tableName string) string { // 使用表名首字母大写 + 时间戳 timestamp := time.Now().UnixNano() / 1000000 // 毫秒 firstChar, _ := utf8.DecodeRuneInString(tableName) if firstChar == utf8.RuneError { firstChar = 'T' } return fmt.Sprintf("%s%c%06d", gen.TableIDPrefix, firstChar, timestamp%1000000) } // generateMainTableSQL 生成主表SQL func (gen *DictSQLGenerator) generateMainTableSQL(tableID string, table generators.TableDDL) string { // 转义表注释中的单引号 comment := strings.ReplaceAll(table.Comment, "'", "''") sql := fmt.Sprintf("INSERT INTO dict_table (table_id, table_name, table_comment, created_at) VALUES ('%s', '%s', '%s', NOW());", tableID, table.Name, comment) return sql } // generateColumnSQLs 生成子表SQL映射 func (gen *DictSQLGenerator) generateColumnSQLs(tableID string, columns []generators.ColumnSchema) map[string]string { sqlMap := make(map[string]string) for i, column := range columns { // 生成字段ID columnID := gen.generateColumnID(tableID, column.Name, i) // 转义字段注释中的单引号 comment := strings.ReplaceAll(column.Comment, "'", "''") // 生成字段类型字符串 columnType := gen.generateColumnTypeString(column) // 判断是否可为空 isNullable := "1" // true if gen.isNotNullColumn(column.Options) { isNullable = "0" // false } // 处理默认值 defaultValue := gen.formatDefaultValue(column.Default) // 判断是否为主键 isPrimaryKey := "0" // false if gen.isPrimaryKeyColumn(column.Options) { isPrimaryKey = "1" // true } sql := fmt.Sprintf("INSERT INTO dict_column (column_id, table_id, column_name, column_type, column_comment, is_nullable, column_default, sort_order, created_at, is_primary_key) VALUES ('%s', '%s', '%s', '%s', '%s', %s, %s, %d, NOW(), %s);", columnID, tableID, column.Name, columnType, comment, isNullable, defaultValue, i, isPrimaryKey) sqlMap[column.Name] = sql } return sqlMap } // generateColumnID 生成字段ID func (gen *DictSQLGenerator) generateColumnID(tableID string, columnName string, index int) string { // 使用表ID + 字段名首字母 + 序号 firstChar, _ := utf8.DecodeRuneInString(columnName) if firstChar == utf8.RuneError { firstChar = 'C' } return fmt.Sprintf("%s%c%02d", gen.ColumnIDPrefix, firstChar, index) } // generateColumnTypeString 生成字段类型字符串 func (gen *DictSQLGenerator) generateColumnTypeString(column generators.ColumnSchema) string { switch column.Type { case TypeVarchar: return fmt.Sprintf("VARCHAR(%d)", column.Length) case TypeChar: return fmt.Sprintf("CHAR(%d)", column.Length) case TypeDecimal: return fmt.Sprintf("DECIMAL(%d,%d)", column.Precision, column.Scale) case TypeInt, TypeBigInt, TypeTinyInt: return column.Type case TypeDateTime, TypeTimestamp, TypeDate, TypeTime: return column.Type case TypeText: return "TEXT" case TypeBool: return "BOOL" case TypeJson: return "JSON" case TypeBlob: return "BLOB" case TypeFloat: return "FLOAT" case TypeDouble: return "DOUBLE" default: return column.Type } } // isNotNullColumn 判断是否为NOT NULL列 func (gen *DictSQLGenerator) isNotNullColumn(options []string) bool { for _, opt := range options { if strings.EqualFold(opt, "NOT NULL") { return true } } return false } // isPrimaryKeyColumn 判断是否为主键列 func (gen *DictSQLGenerator) isPrimaryKeyColumn(options []string) bool { for _, opt := range options { if strings.EqualFold(opt, "PRIMARY KEY") { return true } } return false } // formatDefaultValue 格式化默认值 func (gen *DictSQLGenerator) formatDefaultValue(defaultValue string) string { if defaultValue == "" { return "NULL" } // 如果是 CURRENT_TIMESTAMP 等函数,直接使用 upperValue := strings.ToUpper(defaultValue) if strings.Contains(upperValue, "CURRENT_TIMESTAMP") || strings.Contains(upperValue, "NULL") || strings.Contains(upperValue, "TRUE") || strings.Contains(upperValue, "FALSE") { return fmt.Sprintf("'%s'", defaultValue) } // 其他情况需要转义单引号 escapedValue := strings.ReplaceAll(defaultValue, "'", "''") return fmt.Sprintf("'%s'", escapedValue) }