Persist circuit group moves

This commit is contained in:
2026-07-30 20:03:11 +02:00
parent 9ad91887b2
commit 3399fcd88b
15 changed files with 652 additions and 4 deletions
@@ -0,0 +1,104 @@
import { and, eq } from "drizzle-orm";
import {
assertCircuitGroupMoveProjectCommand,
createCircuitGroupMoveProjectCommand,
invertCircuitGroupMovePlan,
} from "../../domain/models/circuit-group-move-project-command.model.js";
import type {
CircuitGroupMoveProjectCommandStore,
ExecuteCircuitGroupMoveCommandInput,
} from "../../domain/ports/circuit-group-move-project-command.store.js";
import { parseGroupedEquipmentIdentifier } from "../../domain/services/circuit-group-numbering.js";
import type { AppDatabase } from "../database-context.js";
import { circuitLists } from "../schema/circuit-lists.js";
import { circuitSections } from "../schema/circuit-sections.js";
import { circuits } from "../schema/circuits.js";
import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js";
export class CircuitGroupMoveProjectCommandRepository
implements CircuitGroupMoveProjectCommandStore
{
constructor(private readonly database: AppDatabase) {}
execute(input: ExecuteCircuitGroupMoveCommandInput) {
assertCircuitGroupMoveProjectCommand(input.command);
return executeProjectCommandTransaction(
this.database,
input,
(tx) => this.applyCommand(tx, input)
);
}
private applyCommand(
database: AppDatabase,
input: ExecuteCircuitGroupMoveCommandInput
) {
const plan = input.command.payload;
const list = database
.select({ projectId: circuitLists.projectId })
.from(circuitLists)
.where(eq(circuitLists.id, plan.circuitListId))
.get();
if (!list || list.projectId !== input.projectId) {
throw new Error("Circuit list does not belong to project.");
}
const source = database
.select()
.from(circuitSections)
.where(eq(circuitSections.id, plan.expectedSectionId))
.get();
const target = database
.select()
.from(circuitSections)
.where(eq(circuitSections.id, plan.targetSectionId))
.get();
const expectedBmk = parseGroupedEquipmentIdentifier(
plan.expectedEquipmentIdentifier
);
const targetBmk = parseGroupedEquipmentIdentifier(
plan.targetEquipmentIdentifier
);
if (
!source ||
!target ||
source.circuitListId !== plan.circuitListId ||
target.circuitListId !== plan.circuitListId ||
source.category === null ||
source.category !== target.category ||
source.category !== expectedBmk?.category ||
source.groupNumber !== expectedBmk.groupNumber ||
target.category !== targetBmk?.category ||
target.groupNumber !== targetBmk.groupNumber
) {
throw new Error(
"Circuit move requires matching source and target groups."
);
}
const updated = database
.update(circuits)
.set({
sectionId: plan.targetSectionId,
equipmentIdentifier: plan.targetEquipmentIdentifier,
sortOrder: plan.targetSortOrder,
})
.where(
and(
eq(circuits.id, plan.circuitId),
eq(circuits.circuitListId, plan.circuitListId),
eq(circuits.sectionId, plan.expectedSectionId),
eq(
circuits.equipmentIdentifier,
plan.expectedEquipmentIdentifier
),
eq(circuits.sortOrder, plan.expectedSortOrder)
)
)
.run();
if (updated.changes !== 1) {
throw new Error("Circuit changed before group move.");
}
return createCircuitGroupMoveProjectCommand(
invertCircuitGroupMovePlan(plan)
);
}
}