202 lines
6.8 KiB
TypeScript
202 lines
6.8 KiB
TypeScript
import crypto from "node:crypto";
|
|
import { asc, eq } from "drizzle-orm";
|
|
import {
|
|
parseProjectStateSnapshot,
|
|
projectStateSnapshotSchemaVersion,
|
|
serializeProjectStateSnapshot,
|
|
type ProjectStateSnapshot,
|
|
} from "../../domain/models/project-state-snapshot.model.js";
|
|
import type { AppDatabase } from "../database-context.js";
|
|
import { circuitDeviceRows } from "../schema/circuit-device-rows.js";
|
|
import { circuitLists } from "../schema/circuit-lists.js";
|
|
import { circuitSections } from "../schema/circuit-sections.js";
|
|
import { circuits } from "../schema/circuits.js";
|
|
import { distributionBoards } from "../schema/distribution-boards.js";
|
|
import { floors } from "../schema/floors.js";
|
|
import { projectDevices } from "../schema/project-devices.js";
|
|
import { projects } from "../schema/projects.js";
|
|
import { rooms } from "../schema/rooms.js";
|
|
|
|
export interface PersistedProjectStateSnapshot {
|
|
currentRevision: number;
|
|
state: ProjectStateSnapshot;
|
|
payloadJson: string;
|
|
payloadSha256: string;
|
|
}
|
|
|
|
export function readProjectStateSnapshot(
|
|
database: AppDatabase,
|
|
projectId: string
|
|
): PersistedProjectStateSnapshot | null {
|
|
const project = database
|
|
.select({
|
|
id: projects.id,
|
|
name: projects.name,
|
|
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
|
threePhaseVoltageV: projects.threePhaseVoltageV,
|
|
currentRevision: projects.currentRevision,
|
|
})
|
|
.from(projects)
|
|
.where(eq(projects.id, projectId))
|
|
.get();
|
|
if (!project) {
|
|
return null;
|
|
}
|
|
|
|
const boardRows = database
|
|
.select()
|
|
.from(distributionBoards)
|
|
.where(eq(distributionBoards.projectId, projectId))
|
|
.orderBy(asc(distributionBoards.name), asc(distributionBoards.id))
|
|
.all();
|
|
const listRows = database
|
|
.select()
|
|
.from(circuitLists)
|
|
.where(eq(circuitLists.projectId, projectId))
|
|
.orderBy(asc(circuitLists.name), asc(circuitLists.id))
|
|
.all();
|
|
const sectionRows = database
|
|
.select({
|
|
id: circuitSections.id,
|
|
circuitListId: circuitSections.circuitListId,
|
|
key: circuitSections.key,
|
|
displayName: circuitSections.displayName,
|
|
prefix: circuitSections.prefix,
|
|
sortOrder: circuitSections.sortOrder,
|
|
})
|
|
.from(circuitSections)
|
|
.innerJoin(
|
|
circuitLists,
|
|
eq(circuitLists.id, circuitSections.circuitListId)
|
|
)
|
|
.where(eq(circuitLists.projectId, projectId))
|
|
.orderBy(
|
|
asc(circuitSections.circuitListId),
|
|
asc(circuitSections.sortOrder),
|
|
asc(circuitSections.id)
|
|
)
|
|
.all();
|
|
const circuitRows = database
|
|
.select({
|
|
id: circuits.id,
|
|
circuitListId: circuits.circuitListId,
|
|
sectionId: circuits.sectionId,
|
|
equipmentIdentifier: circuits.equipmentIdentifier,
|
|
displayName: circuits.displayName,
|
|
sortOrder: circuits.sortOrder,
|
|
protectionType: circuits.protectionType,
|
|
protectionRatedCurrent: circuits.protectionRatedCurrent,
|
|
protectionCharacteristic: circuits.protectionCharacteristic,
|
|
cableType: circuits.cableType,
|
|
cableCrossSection: circuits.cableCrossSection,
|
|
cableLength: circuits.cableLength,
|
|
rcdAssignment: circuits.rcdAssignment,
|
|
terminalDesignation: circuits.terminalDesignation,
|
|
voltage: circuits.voltage,
|
|
controlRequirement: circuits.controlRequirement,
|
|
status: circuits.status,
|
|
isReserve: circuits.isReserve,
|
|
remark: circuits.remark,
|
|
})
|
|
.from(circuits)
|
|
.innerJoin(circuitLists, eq(circuitLists.id, circuits.circuitListId))
|
|
.where(eq(circuitLists.projectId, projectId))
|
|
.orderBy(
|
|
asc(circuits.circuitListId),
|
|
asc(circuits.sortOrder),
|
|
asc(circuits.id)
|
|
)
|
|
.all();
|
|
const deviceRowRows = database
|
|
.select({
|
|
id: circuitDeviceRows.id,
|
|
circuitId: circuitDeviceRows.circuitId,
|
|
linkedProjectDeviceId: circuitDeviceRows.linkedProjectDeviceId,
|
|
legacyConsumerId: circuitDeviceRows.legacyConsumerId,
|
|
sortOrder: circuitDeviceRows.sortOrder,
|
|
name: circuitDeviceRows.name,
|
|
displayName: circuitDeviceRows.displayName,
|
|
phaseType: circuitDeviceRows.phaseType,
|
|
connectionKind: circuitDeviceRows.connectionKind,
|
|
costGroup: circuitDeviceRows.costGroup,
|
|
category: circuitDeviceRows.category,
|
|
level: circuitDeviceRows.level,
|
|
roomId: circuitDeviceRows.roomId,
|
|
roomNumberSnapshot: circuitDeviceRows.roomNumberSnapshot,
|
|
roomNameSnapshot: circuitDeviceRows.roomNameSnapshot,
|
|
quantity: circuitDeviceRows.quantity,
|
|
powerPerUnit: circuitDeviceRows.powerPerUnit,
|
|
simultaneityFactor: circuitDeviceRows.simultaneityFactor,
|
|
cosPhi: circuitDeviceRows.cosPhi,
|
|
remark: circuitDeviceRows.remark,
|
|
overriddenFields: circuitDeviceRows.overriddenFields,
|
|
})
|
|
.from(circuitDeviceRows)
|
|
.innerJoin(circuits, eq(circuits.id, circuitDeviceRows.circuitId))
|
|
.innerJoin(circuitLists, eq(circuitLists.id, circuits.circuitListId))
|
|
.where(eq(circuitLists.projectId, projectId))
|
|
.orderBy(
|
|
asc(circuitDeviceRows.circuitId),
|
|
asc(circuitDeviceRows.sortOrder),
|
|
asc(circuitDeviceRows.id)
|
|
)
|
|
.all();
|
|
const projectDeviceRows = database
|
|
.select()
|
|
.from(projectDevices)
|
|
.where(eq(projectDevices.projectId, projectId))
|
|
.orderBy(asc(projectDevices.displayName), asc(projectDevices.id))
|
|
.all();
|
|
const floorRows = database
|
|
.select()
|
|
.from(floors)
|
|
.where(eq(floors.projectId, projectId))
|
|
.orderBy(asc(floors.sortOrder), asc(floors.id))
|
|
.all();
|
|
const roomRows = database
|
|
.select()
|
|
.from(rooms)
|
|
.where(eq(rooms.projectId, projectId))
|
|
.orderBy(asc(rooms.roomNumber), asc(rooms.id))
|
|
.all();
|
|
|
|
const deviceRowsByCircuit = new Map<string, typeof deviceRowRows>();
|
|
for (const row of deviceRowRows) {
|
|
const entries = deviceRowsByCircuit.get(row.circuitId) ?? [];
|
|
entries.push(row);
|
|
deviceRowsByCircuit.set(row.circuitId, entries);
|
|
}
|
|
|
|
const state = parseProjectStateSnapshot({
|
|
schemaVersion: projectStateSnapshotSchemaVersion,
|
|
project: {
|
|
id: project.id,
|
|
name: project.name,
|
|
singlePhaseVoltageV: project.singlePhaseVoltageV,
|
|
threePhaseVoltageV: project.threePhaseVoltageV,
|
|
},
|
|
distributionBoards: boardRows,
|
|
circuitLists: listRows,
|
|
circuitSections: sectionRows,
|
|
circuits: circuitRows.map((circuit) => ({
|
|
...circuit,
|
|
isReserve: Boolean(circuit.isReserve),
|
|
deviceRows: deviceRowsByCircuit.get(circuit.id) ?? [],
|
|
})),
|
|
projectDevices: projectDeviceRows,
|
|
floors: floorRows,
|
|
rooms: roomRows,
|
|
});
|
|
const payloadJson = serializeProjectStateSnapshot(state);
|
|
return {
|
|
currentRevision: project.currentRevision,
|
|
state,
|
|
payloadJson,
|
|
payloadSha256: hashProjectStatePayload(payloadJson),
|
|
};
|
|
}
|
|
|
|
export function hashProjectStatePayload(payloadJson: string) {
|
|
return crypto.createHash("sha256").update(payloadJson).digest("hex");
|
|
}
|