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