leistungsbilanz-ts/tests/distribution-board-feeder-circuit-project-command.repository.test.ts

240 lines
7.6 KiB
TypeScript

import path from "node:path";
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { eq } from "drizzle-orm";
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
import {
createDatabaseContext,
type DatabaseContext,
} from "../src/db/database-context.js";
import { DistributionBoardStructureProjectCommandRepository } from "../src/db/repositories/distribution-board-structure-project-command.repository.js";
import { ProjectHistoryRepository } from "../src/db/repositories/project-history.repository.js";
import { circuits } from "../src/db/schema/circuits.js";
import { distributionBoards } from "../src/db/schema/distribution-boards.js";
import { projects } from "../src/db/schema/projects.js";
import {
assertDistributionBoardFeederCircuitProjectCommand,
createDistributionBoardCreateFeederCircuitProjectCommand,
} from "../src/domain/models/distribution-board-feeder-circuit-project-command.model.js";
import { createDistributionBoardUpdateProjectCommand } from "../src/domain/models/distribution-board-project-command.model.js";
import {
createDistributionBoardInsertProjectCommand,
createDistributionBoardStructureSnapshot,
} from "../src/domain/models/distribution-board-structure-project-command.model.js";
import { buildCircuitInsertSnapshot } from "../src/frontend/utils/circuit-structure-command.js";
function createTestDatabase(): DatabaseContext {
const context = createDatabaseContext(":memory:");
migrate(context.db, {
migrationsFolder: path.resolve("src", "db", "migrations"),
});
context.db
.insert(projects)
.values({ id: "project-1", name: "Test project" })
.run();
return context;
}
function setupBoards(
context: DatabaseContext,
repository: DistributionBoardStructureProjectCommandRepository
) {
const source = createDistributionBoardStructureSnapshot(
"project-1",
"NSHV"
);
const downstream = createDistributionBoardStructureSnapshot(
"project-1",
"UV EG"
);
repository.execute({
projectId: "project-1",
expectedRevision: 0,
source: "user",
command: createDistributionBoardInsertProjectCommand(source),
});
repository.execute({
projectId: "project-1",
expectedRevision: 1,
source: "user",
command: createDistributionBoardInsertProjectCommand(downstream),
});
const section = source.sections.find(
(candidate) => candidate.key === "three_phase"
)!;
const circuit = {
...buildCircuitInsertSnapshot({
id: "feeder-circuit",
circuitListId: source.circuitList.id,
category: "three_phase",
deviceRows: [],
values: {
sectionId: section.id,
equipmentIdentifier: `${section.prefix}1`,
displayName: undefined,
sortOrder: 10,
voltage: 400,
isReserve: true,
},
}),
protectionDevice: null,
};
const boardUpdate = createDistributionBoardUpdateProjectCommand(
downstream.distributionBoard.id,
{
feedingDistributionBoardId: source.distributionBoard.id,
feedingCircuitId: circuit.id,
}
);
const command =
createDistributionBoardCreateFeederCircuitProjectCommand(
circuit,
boardUpdate
);
return { source, downstream, circuit, command };
}
describe("distribution-board feeder-circuit project command", () => {
it("creates and links one feeder atomically and supports undo and redo", () => {
const context = createTestDatabase();
try {
const repository =
new DistributionBoardStructureProjectCommandRepository(context.db);
const history = new ProjectHistoryRepository(context.db);
const { source, downstream, circuit, command } = setupBoards(
context,
repository
);
repository.executeFeederCircuit({
projectId: "project-1",
expectedRevision: 2,
source: "user",
command,
});
assert.ok(
context.db
.select()
.from(circuits)
.where(eq(circuits.id, circuit.id))
.get()
);
assert.deepEqual(
context.db
.select({
boardId: distributionBoards.feedingDistributionBoardId,
circuitId: distributionBoards.feedingCircuitId,
})
.from(distributionBoards)
.where(eq(distributionBoards.id, downstream.distributionBoard.id))
.get(),
{
boardId: source.distributionBoard.id,
circuitId: circuit.id,
}
);
const undo = history.getNextCommand("project-1", "undo");
assert.ok(undo);
assertDistributionBoardFeederCircuitProjectCommand(undo.command);
repository.executeFeederCircuit({
projectId: "project-1",
expectedRevision: 3,
source: "undo",
historyTargetChangeSetId: undo.changeSetId,
command: undo.command,
});
assert.equal(
context.db
.select()
.from(circuits)
.where(eq(circuits.id, circuit.id))
.get(),
undefined
);
assert.deepEqual(
context.db
.select({
boardId: distributionBoards.feedingDistributionBoardId,
circuitId: distributionBoards.feedingCircuitId,
})
.from(distributionBoards)
.where(eq(distributionBoards.id, downstream.distributionBoard.id))
.get(),
{ boardId: null, circuitId: null }
);
const redo = history.getNextCommand("project-1", "redo");
assert.ok(redo);
assertDistributionBoardFeederCircuitProjectCommand(redo.command);
repository.executeFeederCircuit({
projectId: "project-1",
expectedRevision: 4,
source: "redo",
historyTargetChangeSetId: redo.changeSetId,
command: redo.command,
});
assert.equal(
context.db
.select({ equipmentIdentifier: circuits.equipmentIdentifier })
.from(circuits)
.where(eq(circuits.id, circuit.id))
.get()?.equipmentIdentifier,
circuit.equipmentIdentifier
);
} finally {
context.close();
}
});
it("rolls back unlinking when the generated circuit changed before undo", () => {
const context = createTestDatabase();
try {
const repository =
new DistributionBoardStructureProjectCommandRepository(context.db);
const history = new ProjectHistoryRepository(context.db);
const { downstream, circuit, command } = setupBoards(context, repository);
repository.executeFeederCircuit({
projectId: "project-1",
expectedRevision: 2,
source: "user",
command,
});
context.db
.update(circuits)
.set({ displayName: "Außerhalb der Historie geändert" })
.where(eq(circuits.id, circuit.id))
.run();
const undo = history.getNextCommand("project-1", "undo");
assert.ok(undo);
assertDistributionBoardFeederCircuitProjectCommand(undo.command);
assert.throws(
() =>
repository.executeFeederCircuit({
projectId: "project-1",
expectedRevision: 3,
source: "undo",
historyTargetChangeSetId: undo.changeSetId,
command: undo.command,
}),
/changed before history removal/
);
const board = context.db
.select()
.from(distributionBoards)
.where(eq(distributionBoards.id, downstream.distributionBoard.id))
.get();
assert.equal(board?.feedingCircuitId, circuit.id);
assert.ok(
context.db
.select()
.from(circuits)
.where(eq(circuits.id, circuit.id))
.get()
);
} finally {
context.close();
}
});
});