合并:重复地点不再反复判「备份新增」,到访的活动改按身份比

- DiffPlaces 的 byCoord/byName 改为多值索引 + take() 逐条认领未用项:真机一个坐标下会有
  多条同名同坐标的地点(实测「柳州站」3 条),单槽位时同一坐标最多只配上 2 条,第 3 条
  永远判「备份新增」⇒ 每次合并都再插一条重复地点、差异永远归不了零(实测 368→438→439)。
  修完:地点新增 70→67、合并后再比对归零、再点合并直接「没有要写入的改动」。
- 到访的「活动」由按名称比改为按身份(ZUID_)比,两边都缺 UUID 才退回名称:16 个活动改名
  曾把 355 条到访全变成同因冲突,且逐条选「用实机」只写回 activity_id(映射回同一个活动)
  改不掉名字。loadStoredVisits 为此多 JOIN 一次 entity_raw 取 ZACTIVITY.ZUID_。
- 回归用例 4 条(重复地点一一配上、活动改名不算冲突、换活动仍要报、缺 UUID 退回名称)+
  「合并后地点差异归零」断言 3 处;两处改动都做过变异验证。
- 实测(09-28 备份并进 09-14 数据集):到访冲突 253→6,合并两次地点数 438→439 变为 435→435。
This commit is contained in:
tamakyi
2026-09-28 19:31:21 +08:00
parent f2ce6646c4
commit 10d23e03cf
5 changed files with 172 additions and 22 deletions
+8 -3
View File
@@ -239,17 +239,21 @@ func (s *Server) countOther(ctx context.Context, datasetID int64) (movements, we
// loadStoredVisits 读出该数据集的全部到访,并把原始行留档里的 UUID 解出来当对齐键。
// 没有留档的行就是站点新建的(真机不会给它 UUID),对齐键留空。
// 所挂活动的 UUID 也一样:到访层面按活动身份比对,才不会因活动改名而全线报冲突。
func (s *Server) loadStoredVisits(ctx context.Context, datasetID int64) ([]rond.StoredVisit, error) {
rows, err := s.db.QueryContext(ctx, `
SELECT v.src_pk, v.arrival, v.departure, COALESCE(v.remark,''), COALESCE(v.emoji,''),
v.bookmarked, v.is_user_added, COALESCE(p.src_pk,0),
COALESCE(p.name,''), COALESCE(p.lat,0), COALESCE(p.lon,0), COALESCE(a.name,''),
COALESCE(er.raw #>> '{ZIDENTIFIER_,$blob}','')
COALESCE(er.raw #>> '{ZIDENTIFIER_,$blob}',''),
COALESCE(aer.raw #>> '{ZUID_,$blob}','')
FROM visits v
LEFT JOIN places p ON p.id = v.place_id
LEFT JOIN activities a ON a.id = v.activity_id
LEFT JOIN entity_raw er ON er.dataset_id = v.dataset_id
AND er.entity = 'ZVISIT' AND er.src_pk = v.src_pk
LEFT JOIN entity_raw aer ON aer.dataset_id = v.dataset_id
AND aer.entity = 'ZACTIVITY' AND aer.src_pk = a.src_pk
WHERE v.dataset_id = $1`, datasetID)
if err != nil {
return nil, err
@@ -263,9 +267,9 @@ func (s *Server) loadStoredVisits(ctx context.Context, datasetID int64) ([]rond.
var placePK int
var placeName string
var lat, lon float64
var b64 string
var b64, actB64 string
if err := rows.Scan(&sv.SrcPK, &arr, &dep, &sv.Remark, &sv.Emoji, &sv.Bookmarked,
&sv.UserAdded, &placePK, &placeName, &lat, &lon, &sv.ActivityName, &b64); err != nil {
&sv.UserAdded, &placePK, &placeName, &lat, &lon, &sv.ActivityName, &b64, &actB64); err != nil {
return nil, err
}
sv.Arrival = &arr
@@ -278,6 +282,7 @@ func (s *Server) loadStoredVisits(ctx context.Context, datasetID int64) ([]rond.
sv.PlaceKey = rond.PlaceCoordKey(lat, lon)
}
sv.UUID = uuidFromBase64(b64)
sv.ActivityUUID = uuidFromBase64(actB64)
out = append(out, sv)
}
return out, rows.Err()