Persist section renumbering
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
export interface CircuitSectionTransactionStore {
|
||||
updateEquipmentIdentifiers(
|
||||
circuitListId: string,
|
||||
updates: Array<{ id: string; equipmentIdentifier: string }>,
|
||||
tempNamespace: string
|
||||
): void;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import type { CircuitSectionTransactionStore } from "../ports/circuit-section-transaction.store.js";
|
||||
import { CircuitRepository } from "../../db/repositories/circuit.repository.js";
|
||||
import { CircuitSectionRepository } from "../../db/repositories/circuit-section.repository.js";
|
||||
import type {
|
||||
UpdateSectionEquipmentIdentifiersInput,
|
||||
} from "../../shared/validation/circuit.schemas.js";
|
||||
import { CircuitNumberingService } from "./circuit-numbering.service.js";
|
||||
|
||||
export class CircuitWriteService {
|
||||
private readonly circuitRepository: CircuitRepository;
|
||||
private readonly circuitSectionRepository: CircuitSectionRepository;
|
||||
private readonly circuitSectionTransactionStore?: CircuitSectionTransactionStore;
|
||||
private readonly numberingService: CircuitNumberingService;
|
||||
|
||||
constructor(deps?: {
|
||||
circuitRepository?: CircuitRepository;
|
||||
circuitSectionRepository?: CircuitSectionRepository;
|
||||
circuitSectionTransactionStore?: CircuitSectionTransactionStore;
|
||||
numberingService?: CircuitNumberingService;
|
||||
}) {
|
||||
this.circuitRepository = deps?.circuitRepository ?? new CircuitRepository();
|
||||
this.circuitSectionRepository = deps?.circuitSectionRepository ?? new CircuitSectionRepository();
|
||||
this.circuitSectionTransactionStore = deps?.circuitSectionTransactionStore;
|
||||
this.numberingService = deps?.numberingService ?? new CircuitNumberingService();
|
||||
}
|
||||
|
||||
private getCircuitSectionTransactionStore() {
|
||||
if (!this.circuitSectionTransactionStore) {
|
||||
throw new Error("Circuit-section transactions are not configured.");
|
||||
}
|
||||
return this.circuitSectionTransactionStore;
|
||||
}
|
||||
|
||||
async getNextIdentifier(sectionId: string) {
|
||||
return this.numberingService.getNextIdentifier(sectionId);
|
||||
}
|
||||
|
||||
async renumberSection(sectionId: string) {
|
||||
// Explicit renumber operation for one section only.
|
||||
// Never renumbers other sections and never runs implicitly during move/sort operations.
|
||||
const section = await this.circuitSectionRepository.findById(sectionId);
|
||||
if (!section) {
|
||||
throw new Error("Invalid section id.");
|
||||
}
|
||||
const sectionCircuits = await this.circuitRepository.listBySection(sectionId);
|
||||
const otherCircuits = (await this.circuitRepository.listByCircuitList(section.circuitListId)).filter(
|
||||
(circuit) => circuit.sectionId !== sectionId
|
||||
);
|
||||
const otherIdentifiers = new Set(otherCircuits.map((circuit) => circuit.equipmentIdentifier));
|
||||
|
||||
const finalAssignments: Array<{ id: string; equipmentIdentifier: string }> = [];
|
||||
let index = 1;
|
||||
for (const circuit of sectionCircuits) {
|
||||
let candidate = `${section.prefix}${index}`;
|
||||
while (otherIdentifiers.has(candidate)) {
|
||||
index += 1;
|
||||
candidate = `${section.prefix}${index}`;
|
||||
}
|
||||
finalAssignments.push({ id: circuit.id, equipmentIdentifier: candidate });
|
||||
index += 1;
|
||||
}
|
||||
// Uses safe two-phase identifier update to avoid UNIQUE collisions during swaps.
|
||||
this.getCircuitSectionTransactionStore().updateEquipmentIdentifiers(
|
||||
section.circuitListId,
|
||||
finalAssignments,
|
||||
sectionId
|
||||
);
|
||||
|
||||
return this.circuitRepository.listBySection(sectionId);
|
||||
}
|
||||
|
||||
async updateSectionEquipmentIdentifiers(
|
||||
sectionId: string,
|
||||
input: UpdateSectionEquipmentIdentifiersInput
|
||||
) {
|
||||
const section = await this.circuitSectionRepository.findById(sectionId);
|
||||
if (!section) {
|
||||
throw new Error("Invalid section id.");
|
||||
}
|
||||
const sectionCircuits = await this.circuitRepository.listBySection(sectionId);
|
||||
const sectionIds = new Set(sectionCircuits.map((circuit) => circuit.id));
|
||||
if (input.identifiers.length !== sectionCircuits.length) {
|
||||
throw new Error("identifiers must include all circuits in the section.");
|
||||
}
|
||||
for (const entry of input.identifiers) {
|
||||
if (!sectionIds.has(entry.circuitId)) {
|
||||
throw new Error("Circuit id does not belong to section.");
|
||||
}
|
||||
}
|
||||
|
||||
this.getCircuitSectionTransactionStore().updateEquipmentIdentifiers(
|
||||
section.circuitListId,
|
||||
input.identifiers.map((entry) => ({ id: entry.circuitId, equipmentIdentifier: entry.equipmentIdentifier })),
|
||||
sectionId
|
||||
);
|
||||
return this.circuitRepository.listBySection(sectionId);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user