- 补入库:server/internal/db/dump.go、redis 分页/扫描预算测试、opsxdb-mcp main_test、 packages/opsxdb-mcp package-lock、docs 审计与对比文档等 37 个新文件 - 含结构扁平化进行中的 80 处修改与 155 处旧结构删除(server/ src/ src-tauri/ 为当前有效源) - 构建产物(bin/target/dist)与签名私钥仍按规则排除
78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// DumpMode 表转储范围:仅结构 / 仅数据 / 结构+数据(对齐 Navicat「转储 SQL 文件」三态)。
|
|
const (
|
|
DumpStructure = "structure"
|
|
DumpData = "data"
|
|
DumpBoth = "structure_data"
|
|
)
|
|
|
|
// DumpTable 把单表转储为 .sql 写入 w(流式,数据部分复用 ExportQuery 的 insert 编码)。
|
|
// 不自动附带 DROP TABLE,避免导入时误删既有表;注释头标注来源与时间便于追溯。
|
|
func DumpTable(ctx context.Context, c ConnReq, w io.Writer) error {
|
|
mode := strings.ToLower(strings.TrimSpace(c.Format))
|
|
if mode == "" {
|
|
mode = DumpBoth
|
|
}
|
|
if mode != DumpStructure && mode != DumpData && mode != DumpBoth {
|
|
return fmt.Errorf("mode 仅支持 structure/data/structure_data")
|
|
}
|
|
if strings.TrimSpace(c.Table) == "" {
|
|
return fmt.Errorf("缺少表名")
|
|
}
|
|
// table 支持 "库.表" 形式:拆出 database,避免整体被引号包住导致 No database selected
|
|
if i := strings.Index(c.Table, "."); i > 0 {
|
|
if strings.TrimSpace(c.Database) == "" {
|
|
c.Database = c.Table[:i]
|
|
}
|
|
c.Table = c.Table[i+1:]
|
|
}
|
|
// 数据部分复用 insert 编码:值拷贝整个 ConnReq,只覆盖导出相关字段
|
|
dataReq := c
|
|
dataReq.Format = "insert"
|
|
dataReq.SQL = SelectAllSQL(c.Driver, c.Table)
|
|
if mode == DumpData {
|
|
return ExportQuery(ctx, dataReq, w)
|
|
}
|
|
var b strings.Builder
|
|
fmt.Fprintf(&b, "-- OpsxDB 表转储 %s\n-- 表: %s\n-- 时间: %s\n\n",
|
|
modeLabel(mode), c.Table, time.Now().Format("2006-01-02 15:04:05"))
|
|
ddl, err := GetDDL(ctx, c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.WriteString(strings.TrimRight(ddl, ";\n"))
|
|
b.WriteString(";\n")
|
|
if mode == DumpBoth {
|
|
b.WriteString("\n")
|
|
}
|
|
if _, err := io.WriteString(w, b.String()); err != nil {
|
|
return err
|
|
}
|
|
if mode == DumpBoth {
|
|
if err := ExportQuery(ctx, dataReq, w); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func modeLabel(mode string) string {
|
|
switch mode {
|
|
case DumpStructure:
|
|
return "· 仅结构"
|
|
case DumpData:
|
|
return "· 仅数据"
|
|
default:
|
|
return "· 结构和数据"
|
|
}
|
|
}
|