Complete Revit object editor assignments

This commit is contained in:
Julian Appel 2026-09-30 14:35:14 +02:00
parent 4489cd76f0
commit 77d775fde1
25 changed files with 853 additions and 77 deletions

View file

@ -7,6 +7,9 @@ import { createDatabaseContext, type AppDatabase } from "../src/db/database-cont
import { ExternalObjectRowAssignmentProjectCommandRepository } from "../src/db/repositories/external-object-row-assignment-project-command.repository.js";
import { ExternalObjectNewRowProjectCommandRepository } from "../src/db/repositories/external-object-new-row-project-command.repository.js";
import { ExternalObjectNewCircuitProjectCommandRepository } from "../src/db/repositories/external-object-new-circuit-project-command.repository.js";
import { CircuitDeviceRowStructureProjectCommandRepository } from "../src/db/repositories/circuit-device-row-structure-project-command.repository.js";
import { CircuitStructureProjectCommandRepository } from "../src/db/repositories/circuit-structure-project-command.repository.js";
import { CircuitGroupSubtreeProjectCommandRepository } from "../src/db/repositories/circuit-group-subtree-project-command.repository.js";
import { toCircuitDeviceRowSnapshot } from "../src/db/repositories/circuit-device-row-structure.persistence.js";
import { circuitDeviceRows } from "../src/db/schema/circuit-device-rows.js";
import { circuitLists } from "../src/db/schema/circuit-lists.js";
@ -31,6 +34,10 @@ import {
externalObjectAssignToNewCircuitCommandType,
} from "../src/domain/models/external-object-new-circuit-project-command.model.js";
import type { ExternalModelObjectSnapshot } from "../src/external-model/domain/external-model-contracts.js";
import { createCircuitDeviceRowDeleteProjectCommand } from "../src/domain/models/circuit-device-row-structure-project-command.model.js";
import { createCircuitDeleteProjectCommand } from "../src/domain/models/circuit-structure-project-command.model.js";
import { createCircuitGroupDeleteSubtreeProjectCommand } from "../src/domain/models/circuit-group-subtree-project-command.model.js";
import { assertDistributionBoardHasNoExternalObjects, assertRoomHasNoExternalObjects } from "../src/db/repositories/external-object-deletion-guard.persistence.js";
function createFixture(initialObjectRowId: string | null = "row-1") {
const context = createDatabaseContext(":memory:");
@ -626,4 +633,63 @@ describe("external object new-circuit project command", () => {
context.close();
}
});
it("detaches linked objects on row deletion and restores the exact link on undo", () => {
const context = createFixture();
try {
const repository = new CircuitDeviceRowStructureProjectCommandRepository(context.db);
const deleted = repository.execute({
projectId: "project-1",
expectedRevision: 0,
source: "user",
command: createCircuitDeviceRowDeleteProjectCommand("row-1", "circuit-1"),
});
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
assert.equal(context.db.select().from(circuitDeviceRows).where(eq(circuitDeviceRows.id, "row-1")).get(), undefined);
repository.execute({
projectId: "project-1",
expectedRevision: 1,
source: "undo",
historyTargetChangeSetId: deleted.revision.changeSetId,
command: deleted.inverse,
});
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-1");
assert.ok(context.db.select().from(circuitDeviceRows).where(eq(circuitDeviceRows.id, "row-1")).get());
} finally {
context.close();
}
});
it("preserves external links through circuit and populated-group deletion undo", () => {
for (const kind of ["circuit", "group"] as const) {
const context = createFixture();
try {
const repository = kind === "circuit"
? new CircuitStructureProjectCommandRepository(context.db)
: new CircuitGroupSubtreeProjectCommandRepository(context.db);
const command = kind === "circuit"
? createCircuitDeleteProjectCommand("circuit-1", "list-1")
: createCircuitGroupDeleteSubtreeProjectCommand(
(repository as CircuitGroupSubtreeProjectCommandRepository).capture("project-1", "section-1")
);
const deleted = repository.execute({ projectId: "project-1", expectedRevision: 0, source: "user", command } as never);
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, null);
repository.execute({ projectId: "project-1", expectedRevision: 1, source: "undo", historyTargetChangeSetId: deleted.revision.changeSetId, command: deleted.inverse } as never);
assert.equal(context.db.select().from(externalModelObjects).get()!.circuitDeviceRowId, "row-1");
} finally {
context.close();
}
}
});
it("blocks room and distribution-board deletion while external objects reference them", () => {
const context = createFixture(null);
try {
assert.throws(() => assertDistributionBoardHasNoExternalObjects(context.db, "project-1", "board-1"), /Revit-Objekte/);
assert.throws(() => assertRoomHasNoExternalObjects(context.db, "project-1", "room-1"), /Revit-Objekte/);
} finally {
context.close();
}
});
});