138 lines
5.2 KiB
TypeScript
138 lines
5.2 KiB
TypeScript
import type { Request, Response } from "express";
|
|
import {
|
|
calculateCircuitTotalPower,
|
|
calculateRowTotalPower,
|
|
} from "../../domain/calculations/circuit-power-calculation.js";
|
|
import type { CircuitTreeResponse } from "../../domain/models/circuit-tree.model.js";
|
|
import {
|
|
circuitDeviceRowRepository,
|
|
circuitListRepository,
|
|
circuitRepository,
|
|
circuitSectionRepository,
|
|
projectRepository,
|
|
} from "../composition/application-repositories.js";
|
|
|
|
export function isMissingCircuitTreeSchemaError(error: unknown): boolean {
|
|
if (!(error instanceof Error)) {
|
|
return false;
|
|
}
|
|
return (
|
|
error.message.includes("no such table: circuit_sections") ||
|
|
error.message.includes("no such table: circuits") ||
|
|
error.message.includes("no such table: circuit_device_rows")
|
|
);
|
|
}
|
|
|
|
export async function getCircuitTree(req: Request, res: Response) {
|
|
const { projectId, circuitListId } = req.params;
|
|
if (typeof projectId !== "string" || typeof circuitListId !== "string") {
|
|
return res.status(400).json({ error: "Invalid parameters" });
|
|
}
|
|
|
|
const list = await circuitListRepository.findById(projectId, circuitListId);
|
|
if (!list) {
|
|
return res.status(404).json({ error: "Circuit list not found" });
|
|
}
|
|
const project = await projectRepository.findById(projectId);
|
|
if (!project) {
|
|
return res.status(404).json({ error: "Project not found" });
|
|
}
|
|
|
|
try {
|
|
const sections = await circuitSectionRepository.listByCircuitList(circuitListId);
|
|
const circuits = await circuitRepository.listByCircuitList(circuitListId);
|
|
const rows = await circuitDeviceRowRepository.listByCircuitList(circuits.map((entry) => entry.id));
|
|
|
|
const sectionById = new Map(sections.map((section) => [section.id, section]));
|
|
const rowsByCircuitId = new Map<string, typeof rows>();
|
|
for (const row of rows) {
|
|
if (!rowsByCircuitId.has(row.circuitId)) {
|
|
rowsByCircuitId.set(row.circuitId, []);
|
|
}
|
|
rowsByCircuitId.get(row.circuitId)!.push(row);
|
|
}
|
|
|
|
const tree: CircuitTreeResponse = {
|
|
circuitListId,
|
|
currentRevision: project.currentRevision,
|
|
sections: sections.map((section) => ({
|
|
id: section.id,
|
|
key: section.key,
|
|
displayName: section.displayName,
|
|
prefix: section.prefix,
|
|
sortOrder: section.sortOrder,
|
|
circuits: [],
|
|
})),
|
|
};
|
|
const sectionBlocks = new Map(tree.sections.map((section) => [section.id, section]));
|
|
|
|
for (const circuit of circuits) {
|
|
const section = sectionById.get(circuit.sectionId);
|
|
if (!section || section.circuitListId !== circuit.circuitListId) {
|
|
continue;
|
|
}
|
|
const deviceRows = (rowsByCircuitId.get(circuit.id) ?? []).map((row) => ({
|
|
id: row.id,
|
|
linkedProjectDeviceId: row.linkedProjectDeviceId ?? undefined,
|
|
legacyConsumerId: row.legacyConsumerId ?? undefined,
|
|
sortOrder: row.sortOrder,
|
|
name: row.name,
|
|
displayName: row.displayName,
|
|
phaseType: row.phaseType ?? undefined,
|
|
connectionKind: row.connectionKind ?? undefined,
|
|
costGroup: row.costGroup ?? undefined,
|
|
category: row.category ?? undefined,
|
|
level: row.level ?? undefined,
|
|
roomId: row.roomId ?? undefined,
|
|
roomNumberSnapshot: row.roomNumberSnapshot ?? undefined,
|
|
roomNameSnapshot: row.roomNameSnapshot ?? undefined,
|
|
quantity: row.quantity,
|
|
powerPerUnit: row.powerPerUnit,
|
|
simultaneityFactor: row.simultaneityFactor,
|
|
cosPhi: row.cosPhi ?? undefined,
|
|
remark: row.remark ?? undefined,
|
|
overriddenFields: row.overriddenFields ?? undefined,
|
|
rowTotalPower: calculateRowTotalPower(row.quantity, row.powerPerUnit, row.simultaneityFactor),
|
|
}));
|
|
const circuitTotalPower = calculateCircuitTotalPower(deviceRows);
|
|
|
|
sectionBlocks.get(section.id)?.circuits.push({
|
|
id: circuit.id,
|
|
circuitListId: circuit.circuitListId,
|
|
sectionId: circuit.sectionId,
|
|
equipmentIdentifier: circuit.equipmentIdentifier,
|
|
displayName: circuit.displayName ?? undefined,
|
|
sortOrder: circuit.sortOrder,
|
|
protectionType: circuit.protectionType ?? undefined,
|
|
protectionRatedCurrent: circuit.protectionRatedCurrent ?? undefined,
|
|
protectionCharacteristic: circuit.protectionCharacteristic ?? undefined,
|
|
cableType: circuit.cableType ?? undefined,
|
|
cableCrossSection: circuit.cableCrossSection ?? undefined,
|
|
cableLength: circuit.cableLength ?? undefined,
|
|
rcdAssignment: circuit.rcdAssignment ?? undefined,
|
|
terminalDesignation: circuit.terminalDesignation ?? undefined,
|
|
voltage: circuit.voltage ?? undefined,
|
|
controlRequirement: circuit.controlRequirement ?? undefined,
|
|
status: circuit.status ?? undefined,
|
|
isReserve: Boolean(circuit.isReserve),
|
|
remark: circuit.remark ?? undefined,
|
|
circuitTotalPower,
|
|
deviceRows,
|
|
});
|
|
}
|
|
|
|
return res.json(tree);
|
|
} catch (error) {
|
|
if (isMissingCircuitTreeSchemaError(error)) {
|
|
return res.json({
|
|
circuitListId,
|
|
currentRevision: project.currentRevision,
|
|
sections: [],
|
|
warning:
|
|
"Circuit-first tables are not available yet. Run database migrations (including 0008_circuit_first_model).",
|
|
});
|
|
}
|
|
throw error;
|
|
}
|
|
}
|