备份与迷雾的差异分析、合并执行,附属数据改挂坐标键
备份(.rondbackup)与迷雾(.fwss)各加一层「先看差异再动手」: - 迷雾:上传先出差异页,说清叠加能补多少、整体替换会丢多少,并在真实底图上 用绿/灰/红标出会新增 / 不变 / 会丢的区域 - 备份:与当前数据集按 UUID 逐条比对(rond 每次导出都会重排 Z_PK,编号认不出人), 新增合入、冲突逐条选、仅站内有逐条勾选删除,全在一个事务里执行; 合入的行写回 entity_raw,保证再传同一份备份时差异归零 - 地点按坐标对齐:站点的「补全地址」会把地点改名,拿名称当键会让一整个地点的 到访全变成假冲突 - 附属数据(备注/结论/访客票/图片)从 dataset_id+src_pk 换成坐标键,换数据集不再失联; 访客票没有 dataset_id,回填按活跃数据集认领 - 修正 contentHash 拿 Z_PK 当指纹的隐患,以及两处「src_pk 跨快照稳定」的错误注释 导出格式(.rondbackup / .fwss)保持原样,往返测试通过。
This commit is contained in:
@@ -156,6 +156,13 @@ type Backup struct {
|
||||
// RawRows 是各实体在 Core Data 里的完整原始行:「表名 -> Z_PK -> 列名 -> 值」。
|
||||
// 站点只映射了其中一部分字段,留档让导出能逐列还原,不必依赖基线库补剩下的列。
|
||||
RawRows map[string]map[int]map[string]any
|
||||
|
||||
// VisitUUID / ActivityUUID 是真机给每条到访、每个活动存的 16 字节 UUID(小写十六进制)。
|
||||
// **这是跨备份唯一稳定的对齐键**:rond 每次导出/同步都会重排 Z_PK——实测两份备份里
|
||||
// 822 条到访的 UUID 完全一致、Z_PK 100% 不同——所以「这份备份」与「库里的那一份」
|
||||
// 之间只能按它对齐。地点/标签/交通方式没有 UUID,只能退到名称与坐标。
|
||||
VisitUUID map[int]string
|
||||
ActivityUUID map[int]string
|
||||
}
|
||||
|
||||
// Open 解压备份包到 dir,返回可用的 SQLite 连接。
|
||||
@@ -465,9 +472,38 @@ func Parse(db *sql.DB) (*Backup, error) {
|
||||
} else {
|
||||
log.Printf("抓取原始行留档失败(导出将退回基线补列): %v", rerr)
|
||||
}
|
||||
// 对齐键:导出不依赖它,但「两份数据比对」全靠它,缺了就只能放弃逐条对齐
|
||||
if b.VisitUUID, err = uuidColumn(db, "ZVISIT", "ZIDENTIFIER_"); err != nil {
|
||||
return nil, fmt.Errorf("读取到访 UUID: %w", err)
|
||||
}
|
||||
if b.ActivityUUID, err = uuidColumn(db, "ZACTIVITY", "ZUID_"); err != nil {
|
||||
return nil, fmt.Errorf("读取活动 UUID: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// uuidColumn 读出某表某一列的 UUID,返回 Z_PK -> 小写十六进制。
|
||||
// 列不存在(很老的备份)返回空表而不是错误;全零或空的当作没有。
|
||||
func uuidColumn(db *sql.DB, table, col string) (map[int]string, error) {
|
||||
rows, err := db.Query(fmt.Sprintf(`SELECT Z_PK, hex(%s) FROM %s`, col, table))
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer rows.Close()
|
||||
out := map[int]string{}
|
||||
for rows.Next() {
|
||||
var pk int
|
||||
var h sql.NullString
|
||||
if err := rows.Scan(&pk, &h); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.Valid && strings.Trim(h.String, "0") != "" {
|
||||
out[pk] = strings.ToLower(h.String)
|
||||
}
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// rawTables 是需要整行留档的 Core Data 表(站点管理的实体 + 标签分组)。
|
||||
var rawTables = []string{"ZLOCATION", "ZVISIT", "ZMOVEMENT", "ZHOURLYWEATHER", "ZACTIVITY", "ZTAG", "ZTAGGROUP", "ZTRANSPORT"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user