Add logical distribution board feed links

This commit is contained in:
Julian Appel 2026-09-27 22:21:58 +02:00
parent b50c00c0ac
commit b893c72534
23 changed files with 3732 additions and 45 deletions

View file

@ -9,16 +9,18 @@ import type { SerializedProjectCommand } from "./project-command.model.js";
export const distributionBoardUpdateCommandType =
"distribution-board.update" as const;
// The info-card fields were added additively to schema version 1: every
// previously stored command remains valid, and the inverse is still derived
// from the persisted row for exactly the changed fields.
export const distributionBoardUpdateCommandSchemaVersion = 1 as const;
// Version 2 adds logical feeding references. Version-1 commands remain
// executable and can only change the fields they originally knew.
export const distributionBoardUpdateCommandSchemaVersion = 2 as const;
const legacyDistributionBoardUpdateCommandSchemaVersion = 1 as const;
export interface DistributionBoardUpdateValues
extends Record<DistributionBoardInfoField, string | null> {
floorId: string | null;
supplyType: DistributionBoardSupplyType | null;
simultaneityFactor: number;
feedingDistributionBoardId: string | null;
feedingCircuitId: string | null;
}
export type DistributionBoardUpdateField =
@ -41,16 +43,20 @@ export interface DistributionBoardUpdateCommandPayload {
export interface DistributionBoardUpdateProjectCommand
extends SerializedProjectCommand<DistributionBoardUpdateCommandPayload> {
schemaVersion: typeof distributionBoardUpdateCommandSchemaVersion;
schemaVersion:
| typeof legacyDistributionBoardUpdateCommandSchemaVersion
| typeof distributionBoardUpdateCommandSchemaVersion;
type: typeof distributionBoardUpdateCommandType;
}
export function createDistributionBoardUpdateProjectCommand(
distributionBoardId: string,
patch: DistributionBoardUpdatePatch
patch: DistributionBoardUpdatePatch,
schemaVersion: DistributionBoardUpdateProjectCommand["schemaVersion"] =
distributionBoardUpdateCommandSchemaVersion
): DistributionBoardUpdateProjectCommand {
const command: DistributionBoardUpdateProjectCommand = {
schemaVersion: distributionBoardUpdateCommandSchemaVersion,
schemaVersion,
type: distributionBoardUpdateCommandType,
payload: {
distributionBoardId,
@ -68,7 +74,8 @@ export function assertDistributionBoardUpdateProjectCommand(
command: SerializedProjectCommand<unknown>
): asserts command is DistributionBoardUpdateProjectCommand {
if (
command.schemaVersion !== distributionBoardUpdateCommandSchemaVersion ||
(command.schemaVersion !== legacyDistributionBoardUpdateCommandSchemaVersion &&
command.schemaVersion !== distributionBoardUpdateCommandSchemaVersion) ||
command.type !== distributionBoardUpdateCommandType ||
!isPlainObject(command.payload)
) {
@ -93,7 +100,12 @@ export function assertDistributionBoardUpdateProjectCommand(
(change.field !== "floorId" &&
change.field !== "supplyType" &&
change.field !== "simultaneityFactor" &&
change.field !== "feedingDistributionBoardId" &&
change.field !== "feedingCircuitId" &&
!isInfoField(change.field)) ||
(command.schemaVersion === legacyDistributionBoardUpdateCommandSchemaVersion &&
(change.field === "feedingDistributionBoardId" ||
change.field === "feedingCircuitId")) ||
seen.has(change.field)
) {
throw new Error(
@ -105,7 +117,9 @@ export function assertDistributionBoardUpdateProjectCommand(
} else if (change.field === "floorId") {
if (
change.value !== null &&
(typeof change.value !== "string" || !change.value.trim())
(typeof change.value !== "string" ||
!change.value.trim() ||
change.value !== change.value.trim())
) {
throw new Error("floorId must be a non-empty string or null.");
}
@ -118,6 +132,16 @@ export function assertDistributionBoardUpdateProjectCommand(
) {
throw new Error("supplyType is invalid.");
}
} else if (
change.field === "feedingDistributionBoardId" ||
change.field === "feedingCircuitId"
) {
if (
change.value !== null &&
(typeof change.value !== "string" || !change.value.trim())
) {
throw new Error(`${change.field} must be a non-empty string or null.`);
}
} else if (
typeof change.value !== "number" ||
!Number.isFinite(change.value) ||