Ei kuvausta
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dict_sql_generator.go 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package sqldef
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "unicode/utf8"
  7. "git.x2erp.com/qdy/go-db/sqldef/generators"
  8. )
  9. // DictSQLGenerator 字典表SQL生成器
  10. type DictSQLGenerator struct {
  11. TableIDPrefix string // 表ID前缀,如 "TBL"
  12. ColumnIDPrefix string // 字段ID前缀,如 "COL"
  13. }
  14. // NewDictSQLGenerator 创建生成器
  15. func NewDictSQLGenerator() *DictSQLGenerator {
  16. return &DictSQLGenerator{
  17. TableIDPrefix: "TBL",
  18. ColumnIDPrefix: "COL",
  19. }
  20. }
  21. // DictSQLs 字典表SQL集合
  22. type DictSQLs struct {
  23. TableSQL string // 主表SQL
  24. ColumnSQLs map[string]string // 字段名 -> SQL映射
  25. }
  26. // GenerateDictSQLsFromTable 从TableDDL生成字典表SQL
  27. func (gen *DictSQLGenerator) GenerateDictSQLsFromTable(table generators.TableDDL) (*DictSQLs, error) {
  28. if table.Schema == nil {
  29. return nil, fmt.Errorf("表 %s 没有Schema信息", table.Name)
  30. }
  31. // 生成表ID
  32. tableID := gen.generateTableID(table.Name)
  33. // 1. 生成主表SQL
  34. tableSQL := gen.generateMainTableSQL(tableID, table)
  35. // 2. 生成子表SQL映射
  36. columnSQLs := gen.generateColumnSQLs(tableID, table.Schema.Columns)
  37. return &DictSQLs{
  38. TableSQL: tableSQL,
  39. ColumnSQLs: columnSQLs,
  40. }, nil
  41. }
  42. // GenerateDictSQLsFromRegistry 从注册表中获取所有表的字典SQL
  43. func (gen *DictSQLGenerator) GenerateDictSQLsFromRegistry() (map[string]*DictSQLs, error) {
  44. globalRegistry.ensureInit()
  45. globalRegistry.mu.RLock()
  46. defer globalRegistry.mu.RUnlock()
  47. result := make(map[string]*DictSQLs)
  48. for tableName, tableDDL := range globalRegistry.tables {
  49. sqls, err := gen.GenerateDictSQLsFromTable(tableDDL)
  50. if err != nil {
  51. return nil, fmt.Errorf("生成表 %s 的字典SQL失败: %w", tableName, err)
  52. }
  53. result[tableName] = sqls
  54. }
  55. return result, nil
  56. }
  57. // generateTableID 生成表ID
  58. func (gen *DictSQLGenerator) generateTableID(tableName string) string {
  59. // 使用表名首字母大写 + 时间戳
  60. timestamp := time.Now().UnixNano() / 1000000 // 毫秒
  61. firstChar, _ := utf8.DecodeRuneInString(tableName)
  62. if firstChar == utf8.RuneError {
  63. firstChar = 'T'
  64. }
  65. return fmt.Sprintf("%s%c%06d", gen.TableIDPrefix, firstChar, timestamp%1000000)
  66. }
  67. // generateMainTableSQL 生成主表SQL
  68. func (gen *DictSQLGenerator) generateMainTableSQL(tableID string, table generators.TableDDL) string {
  69. // 转义表注释中的单引号
  70. comment := strings.ReplaceAll(table.Comment, "'", "''")
  71. sql := fmt.Sprintf("INSERT INTO dict_table (table_id, table_name, table_comment, created_at) VALUES ('%s', '%s', '%s', NOW());",
  72. tableID, table.Name, comment)
  73. return sql
  74. }
  75. // generateColumnSQLs 生成子表SQL映射
  76. func (gen *DictSQLGenerator) generateColumnSQLs(tableID string, columns []generators.ColumnSchema) map[string]string {
  77. sqlMap := make(map[string]string)
  78. for i, column := range columns {
  79. // 生成字段ID
  80. columnID := gen.generateColumnID(tableID, column.Name, i)
  81. // 转义字段注释中的单引号
  82. comment := strings.ReplaceAll(column.Comment, "'", "''")
  83. // 生成字段类型字符串
  84. columnType := gen.generateColumnTypeString(column)
  85. // 判断是否可为空
  86. isNullable := "1" // true
  87. if gen.isNotNullColumn(column.Options) {
  88. isNullable = "0" // false
  89. }
  90. // 处理默认值
  91. defaultValue := gen.formatDefaultValue(column.Default)
  92. // 判断是否为主键
  93. isPrimaryKey := "0" // false
  94. if gen.isPrimaryKeyColumn(column.Options) {
  95. isPrimaryKey = "1" // true
  96. }
  97. 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);",
  98. columnID, tableID, column.Name, columnType, comment, isNullable, defaultValue, i, isPrimaryKey)
  99. sqlMap[column.Name] = sql
  100. }
  101. return sqlMap
  102. }
  103. // generateColumnID 生成字段ID
  104. func (gen *DictSQLGenerator) generateColumnID(tableID string, columnName string, index int) string {
  105. // 使用表ID + 字段名首字母 + 序号
  106. firstChar, _ := utf8.DecodeRuneInString(columnName)
  107. if firstChar == utf8.RuneError {
  108. firstChar = 'C'
  109. }
  110. return fmt.Sprintf("%s%c%02d", gen.ColumnIDPrefix, firstChar, index)
  111. }
  112. // generateColumnTypeString 生成字段类型字符串
  113. func (gen *DictSQLGenerator) generateColumnTypeString(column generators.ColumnSchema) string {
  114. switch column.Type {
  115. case TypeVarchar:
  116. return fmt.Sprintf("VARCHAR(%d)", column.Length)
  117. case TypeChar:
  118. return fmt.Sprintf("CHAR(%d)", column.Length)
  119. case TypeDecimal:
  120. return fmt.Sprintf("DECIMAL(%d,%d)", column.Precision, column.Scale)
  121. case TypeInt, TypeBigInt, TypeTinyInt:
  122. return column.Type
  123. case TypeDateTime, TypeTimestamp, TypeDate, TypeTime:
  124. return column.Type
  125. case TypeText:
  126. return "TEXT"
  127. case TypeBool:
  128. return "BOOL"
  129. case TypeJson:
  130. return "JSON"
  131. case TypeBlob:
  132. return "BLOB"
  133. case TypeFloat:
  134. return "FLOAT"
  135. case TypeDouble:
  136. return "DOUBLE"
  137. default:
  138. return column.Type
  139. }
  140. }
  141. // isNotNullColumn 判断是否为NOT NULL列
  142. func (gen *DictSQLGenerator) isNotNullColumn(options []string) bool {
  143. for _, opt := range options {
  144. if strings.EqualFold(opt, "NOT NULL") {
  145. return true
  146. }
  147. }
  148. return false
  149. }
  150. // isPrimaryKeyColumn 判断是否为主键列
  151. func (gen *DictSQLGenerator) isPrimaryKeyColumn(options []string) bool {
  152. for _, opt := range options {
  153. if strings.EqualFold(opt, "PRIMARY KEY") {
  154. return true
  155. }
  156. }
  157. return false
  158. }
  159. // formatDefaultValue 格式化默认值
  160. func (gen *DictSQLGenerator) formatDefaultValue(defaultValue string) string {
  161. if defaultValue == "" {
  162. return "NULL"
  163. }
  164. // 如果是 CURRENT_TIMESTAMP 等函数,直接使用
  165. upperValue := strings.ToUpper(defaultValue)
  166. if strings.Contains(upperValue, "CURRENT_TIMESTAMP") ||
  167. strings.Contains(upperValue, "NULL") ||
  168. strings.Contains(upperValue, "TRUE") ||
  169. strings.Contains(upperValue, "FALSE") {
  170. return fmt.Sprintf("'%s'", defaultValue)
  171. }
  172. // 其他情况需要转义单引号
  173. escapedValue := strings.ReplaceAll(defaultValue, "'", "''")
  174. return fmt.Sprintf("'%s'", escapedValue)
  175. }