fix(publish): 最终审查修复波——迁移索引口径 / 入库计数 / 仓储证据
C1(关键):2026-09-22-03 的街拍实体键索引改用最终表达式 (city, year, COALESCE(title, '')),与体检及 StreetSnapEntityState 口径一致。 此前索引按 (city, year) 比体检更窄,同城同年多专题的合法数据会通过体检、 再由索引抛原生 23505;04 退化为幂等兜底并在注释说明真正常态由 03 承载。 新增 db/migrations/README.md,写清迁移链执行顺序与各步前提/不可逆点。 I1:processRunway 的 image_count 改为按实际落库主图行数(countMainImages), 不再用 len(p.Looks)(空主图 / sha1 重复会被跳过,导致计数偏大且不再自愈)。 补 service 单测与「入库后 image_count == 存活主图行数」的 DB 断言。 I2:三个迁移文件不再把已删除的一次性搬迁脚本写成硬前置,改为写明取回方式 (git show c4bafc5:scripts/migrate_single_table/main.go,并须在旧代码树上运行)。 I3:新增 SetRecordStatus / SetStreetRecordStatus 仓储集成测试: pending 经仓储通过后在公开视图可见、驳回后不可见、不存在的 id 返回 ErrNotFound。 Minor:修正锁不住口径的走秀 image_count 测试(改为删主图、留细节图); 修正去重注释与事实不符(含 FindNearDuplicateImage 注释); ListRecords / ListStreetRecords 改用 Scope 杜绝 Count 后复用 *gorm.DB; dbtool 视图改 CREATE OR REPLACE 并重跑 dump(仍 4 视图、无草稿表); 删除挂在 Popular 上的「IDs 返回…」注释;README 改为单表 + status 现状; SetRecordStatus 注释写明有意不校验前置状态;规格补两条已知不一致。
This commit is contained in:
@ -271,8 +271,10 @@ func TestSoftDeleteStreetImageRecomputesCount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSoftDeleteRunwayImage 走秀 image_count 口径是「主图数」(与入库 imageCount = len(Looks) 一致):
|
||||
// 软删细节图不改计数;软删主图才减,且同样是重算(重放 / 跨记录不漂移)。
|
||||
// TestSoftDeleteRunwayImage 走秀 image_count 口径是「存活主图行数」(与入库 countMainImages 一致)。
|
||||
//
|
||||
// 关键断言在「软删一张主图、让细节图**仍存活**」这一步:重算必须排除 is_detail=1 的行。
|
||||
// 若先删细节图再删主图,过滤与否结果相同(旧写法就锁不住口径),故这里把顺序倒过来。
|
||||
func TestSoftDeleteRunwayImage(t *testing.T) {
|
||||
repo := NewReviewRepository(testDB(t))
|
||||
ctx := context.Background()
|
||||
@ -282,20 +284,21 @@ func TestSoftDeleteRunwayImage(t *testing.T) {
|
||||
main2 := seedMainDetailRunwayImage(t, repo, runwayID, "main2", 2, 0)
|
||||
detail := seedMainDetailRunwayImage(t, repo, runwayID, "detail1", 3, 1)
|
||||
|
||||
// 首次软删细节图:主图数仍为 2(若用 COUNT(*) 不排除 is_detail,会错算成 3)。
|
||||
if err := repo.SoftDeleteRunwayImage(ctx, runwayID, detail); err != nil {
|
||||
t.Fatalf("软删细节图失败: %v", err)
|
||||
}
|
||||
if got := runwayImageCount(t, repo, runwayID); got != 2 {
|
||||
t.Fatalf("image_count 只计主图,应为 2,实际 %d", got)
|
||||
}
|
||||
|
||||
// 软删一张主图 → 1。
|
||||
// 先软删一张主图,细节图此刻仍存活:只计主图 → 1(仅 main1)。
|
||||
// 若重算用 COUNT(*) 不排除 is_detail,会把存活的 detail 一并算进来得 2 —— 本断言锁得住。
|
||||
if err := repo.SoftDeleteRunwayImage(ctx, runwayID, main2); err != nil {
|
||||
t.Fatalf("软删主图失败: %v", err)
|
||||
}
|
||||
if got := runwayImageCount(t, repo, runwayID); got != 1 {
|
||||
t.Fatalf("软删一张主图后应为 1,实际 %d", got)
|
||||
t.Fatalf("image_count 只计存活主图,软删一张主图后应为 1(须排除仍存活的细节图),实际 %d", got)
|
||||
}
|
||||
|
||||
// 再软删细节图:主图数不变(细节图本就不计入)。
|
||||
if err := repo.SoftDeleteRunwayImage(ctx, runwayID, detail); err != nil {
|
||||
t.Fatalf("软删细节图失败: %v", err)
|
||||
}
|
||||
if got := runwayImageCount(t, repo, runwayID); got != 1 {
|
||||
t.Fatalf("软删细节图不应改变主图计数,实际 %d", got)
|
||||
}
|
||||
|
||||
// 重放(已软删)+ 跨记录:计数均不得变化。
|
||||
|
||||
Reference in New Issue
Block a user