Files
MyGoNavi/internal/db/change_preview.go
TonyJiangWJ 1965564386 feat(data-grid): 增强数据表编辑与展示体验
- 新增变更预览能力,支持在提交前查看删除、更新和新增对应的 SQL 语句
- 增加表格密度配置,统一控制默认列宽、行高、字号与单元格内边距
- 优化 DataGrid 编辑状态展示,区分新增、修改和删除行列的视觉反馈
- 调整导出入口与 Wails 前端绑定,补齐变更预览相关调用与测试覆盖
2026-05-10 19:00:47 +08:00

136 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package db
import (
"fmt"
"sort"
"strings"
"time"
"GoNavi-Wails/internal/connection"
)
// GenerateChangePreview 将 ChangeSet 转为可读 SQL 语句(不执行)。
// quoteIdent 用于引用列名/表名MySQL: backtick, PostgreSQL: double quote
func GenerateChangePreview(tableName string, changes connection.ChangeSet, quoteIdent func(string) string) (deletes, updates, inserts []string) {
qt := quoteIdent
// Deletes
for _, pk := range changes.Deletes {
var conds []string
for _, k := range sortedKeys(pk) {
v := pk[k]
conds = append(conds, fmt.Sprintf("%s = %s", qt(k), formatLiteral(v)))
}
if len(conds) > 0 {
deletes = append(deletes, fmt.Sprintf("DELETE FROM %s WHERE %s;", qt(tableName), strings.Join(conds, " AND ")))
}
}
// Updates
for _, row := range changes.Updates {
var sets []string
for _, k := range sortedKeys(row.Values) {
v := row.Values[k]
sets = append(sets, fmt.Sprintf("%s = %s", qt(k), formatLiteral(v)))
}
if len(sets) == 0 {
continue
}
var conds []string
for _, k := range sortedKeys(row.Keys) {
v := row.Keys[k]
conds = append(conds, fmt.Sprintf("%s = %s", qt(k), formatLiteral(v)))
}
if len(conds) == 0 {
continue
}
updates = append(updates, fmt.Sprintf("UPDATE %s SET %s WHERE %s;", qt(tableName), strings.Join(sets, ", "), strings.Join(conds, " AND ")))
}
// Inserts
for _, row := range changes.Inserts {
var cols []string
var vals []string
for _, k := range sortedKeys(row) {
v := row[k]
if v == nil {
continue
}
cols = append(cols, qt(k))
vals = append(vals, formatLiteral(v))
}
if len(cols) == 0 {
continue
}
inserts = append(inserts, fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s);", qt(tableName), strings.Join(cols, ", "), strings.Join(vals, ", ")))
}
return deletes, updates, inserts
}
// sortedKeys 返回 map 的键排序切片,保证输出确定性。
func sortedKeys(m map[string]interface{}) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
// formatLiteral 将 Go 值转为 SQL 字面量字符串。
func formatLiteral(v interface{}) string {
if v == nil {
return "NULL"
}
switch t := v.(type) {
case string:
escaped := strings.ReplaceAll(t, "\\", "\\\\")
escaped = strings.ReplaceAll(escaped, "'", "\\'")
return fmt.Sprintf("'%s'", escaped)
case float64:
return formatNumber(t)
case float32:
return formatNumber(float64(t))
case int:
return fmt.Sprintf("%d", t)
case int64:
return fmt.Sprintf("%d", t)
case int32:
return fmt.Sprintf("%d", t)
case int16:
return fmt.Sprintf("%d", t)
case int8:
return fmt.Sprintf("%d", t)
case uint64:
return fmt.Sprintf("%d", t)
case uint32:
return fmt.Sprintf("%d", t)
case uint16:
return fmt.Sprintf("%d", t)
case uint8:
return fmt.Sprintf("%d", t)
case uint:
return fmt.Sprintf("%d", t)
case time.Time:
return fmt.Sprintf("'%s'", t.Format("2006-01-02 15:04:05"))
case bool:
if t {
return "TRUE"
}
return "FALSE"
case []byte:
return formatLiteral(string(t))
default:
escaped := strings.ReplaceAll(fmt.Sprintf("%v", t), "'", "\\'")
return fmt.Sprintf("'%s'", escaped)
}
}
func formatNumber(f float64) string {
if f == float64(int64(f)) {
return fmt.Sprintf("%d", int64(f))
}
return fmt.Sprintf("%v", f)
}