fix(filelib): 恢复保留原名,撞名报清晰错误而非自动加后缀(ADR-0035,supersede ADR-0033)

恢复不再改名;同名兄弟占位时抛 409 name_conflict_on_restore + 人话提示,
操作者自行重命名现有节点或彻底删除旧节点后再恢复。
This commit is contained in:
ymy
2026-07-31 14:28:34 +08:00
parent a463ab48e6
commit d9cde19bdf
4 changed files with 45 additions and 44 deletions
+14 -16
View File
@@ -10,6 +10,7 @@ import {
createNode,
softDeleteNode,
listChildren,
renameNode,
type FileLibActor,
type TreeServiceDeps,
} from "../../src/database/filelib/treeService.js";
@@ -92,30 +93,27 @@ describe("binService · 恢复", () => {
expect(audits).toHaveLength(1);
});
it("ADR-0033:与活跃兄弟撞名时恢复为「(已恢复)」,不死锁;审计记 renamedFrom", async () => {
it("ADR-0035:撞名时恢复报 name_conflict_on_restore(不自动改名),清名后可恢复", async () => {
const root = await createNode(treeDeps(), ADMIN, { parentId: null, kind: "FOLDER", name: "物理" });
const child = await createNode(treeDeps(), ADMIN, { parentId: root.id, kind: "FOLDER", name: "必修一" });
await softDeleteNode(treeDeps(), ADMIN, child.id);
// 删除后同名新建 活跃兄弟占了名字
// 删除后同名新建 -> 活跃兄弟占了名字
await createNode(treeDeps(), ADMIN, { parentId: root.id, kind: "FOLDER", name: "必修一" });
await expect(restoreBinEntry(binDeps(), ADMIN, child.id)).rejects.toMatchObject({
statusCode: 409,
code: "name_conflict_on_restore",
});
// 改名现有节点后恢复 -> 成功,保留原名
const active = (await listChildren(treeDeps(), ADMIN, root.id)).find((c) => c.name === "必修一")!;
await renameNode(treeDeps(), ADMIN, active.id, "必修一(新)");
const result = await restoreBinEntry(binDeps(), ADMIN, child.id);
expect(result.renamedFrom).toBe("必修一");
expect(result.name).toBe("必修一(已恢复)");
expect(result.name).toBe("必修一");
expect(result.renamedFrom).toBeUndefined();
const visible = await listChildren(treeDeps(), ADMIN, root.id);
expect(visible.map((c) => c.name).sort()).toEqual(["必修一", "必修一(已恢复)"]);
// 再删再恢复:名字已是去重后的「(已恢复)」,不再冲突 → 保持,不二次改名
await softDeleteNode(treeDeps(), ADMIN, child.id);
const second = await restoreBinEntry(binDeps(), ADMIN, child.id);
expect(second.name).toBe("必修一(已恢复)");
expect(second.renamedFrom).toBeUndefined();
const audits = await prisma.auditEntry.findMany({
where: { action: FILE_LIB_AUDIT_ACTIONS.folderRestore },
});
expect(audits).toHaveLength(2);
expect(visible.map((c) => c.name).sort()).toEqual(["必修一", "必修一()"]);
});
});