Files
leistungsbilanz-ts/src/server/controllers/circuit-tree.controller.ts
T

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;
}
}