Add configurable distribution supply types
This commit is contained in:
@@ -6,9 +6,19 @@ import {
|
||||
createDistributionBoardInsertProjectCommand,
|
||||
distributionBoardDeleteCommandType,
|
||||
distributionBoardInsertCommandType,
|
||||
normalizeDistributionBoardStructureProjectCommand,
|
||||
type DistributionBoardStructureProjectCommand,
|
||||
type DistributionBoardStructureSnapshot,
|
||||
legacyDistributionBoardStructureCommandSchemaVersion,
|
||||
} from "../../domain/models/distribution-board-structure-project-command.model.js";
|
||||
import {
|
||||
assertDistributionBoardUpdateProjectCommand,
|
||||
createDistributionBoardUpdateProjectCommand,
|
||||
type DistributionBoardUpdateField,
|
||||
type DistributionBoardUpdatePatch,
|
||||
type DistributionBoardUpdateProjectCommand,
|
||||
type DistributionBoardUpdateValues,
|
||||
} from "../../domain/models/distribution-board-project-command.model.js";
|
||||
import type {
|
||||
DistributionBoardStructureProjectCommandStore,
|
||||
ExecuteDistributionBoardStructureCommandInput,
|
||||
@@ -18,6 +28,7 @@ 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 { projects } from "../schema/projects.js";
|
||||
import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js";
|
||||
|
||||
@@ -35,26 +46,52 @@ export class DistributionBoardStructureProjectCommandRepository
|
||||
);
|
||||
}
|
||||
|
||||
executeUpdate(
|
||||
input: Omit<
|
||||
ExecuteDistributionBoardStructureCommandInput,
|
||||
"command"
|
||||
> & {
|
||||
command: DistributionBoardUpdateProjectCommand;
|
||||
}
|
||||
) {
|
||||
assertDistributionBoardUpdateProjectCommand(input.command);
|
||||
return executeProjectCommandTransaction(
|
||||
this.database,
|
||||
input,
|
||||
(tx) => this.update(tx, input)
|
||||
);
|
||||
}
|
||||
|
||||
private applyCommand(
|
||||
database: AppDatabase,
|
||||
projectId: string,
|
||||
command: DistributionBoardStructureProjectCommand
|
||||
): DistributionBoardStructureProjectCommand {
|
||||
if (command.type === distributionBoardInsertCommandType) {
|
||||
assertDistributionBoardInsertProjectCommand(command);
|
||||
return this.insert(
|
||||
const normalized =
|
||||
normalizeDistributionBoardStructureProjectCommand(command);
|
||||
if (normalized.type === distributionBoardInsertCommandType) {
|
||||
assertDistributionBoardInsertProjectCommand(normalized);
|
||||
const inverse = this.insert(
|
||||
database,
|
||||
projectId,
|
||||
command.payload.structure
|
||||
normalized.payload.structure
|
||||
);
|
||||
return command.schemaVersion ===
|
||||
legacyDistributionBoardStructureCommandSchemaVersion
|
||||
? toLegacyStructureCommand(inverse)
|
||||
: inverse;
|
||||
}
|
||||
if (command.type === distributionBoardDeleteCommandType) {
|
||||
assertDistributionBoardDeleteProjectCommand(command);
|
||||
return this.delete(
|
||||
if (normalized.type === distributionBoardDeleteCommandType) {
|
||||
assertDistributionBoardDeleteProjectCommand(normalized);
|
||||
const inverse = this.delete(
|
||||
database,
|
||||
projectId,
|
||||
command.payload.structure
|
||||
normalized.payload.structure
|
||||
);
|
||||
return command.schemaVersion ===
|
||||
legacyDistributionBoardStructureCommandSchemaVersion
|
||||
? toLegacyStructureCommand(inverse)
|
||||
: inverse;
|
||||
}
|
||||
throw new Error("Unsupported distribution-board structure command.");
|
||||
}
|
||||
@@ -73,13 +110,33 @@ export class DistributionBoardStructureProjectCommandRepository
|
||||
);
|
||||
}
|
||||
const project = database
|
||||
.select({ id: projects.id })
|
||||
.select({
|
||||
id: projects.id,
|
||||
enabledSupplyTypes:
|
||||
projects.enabledDistributionBoardSupplyTypes,
|
||||
})
|
||||
.from(projects)
|
||||
.where(eq(projects.id, projectId))
|
||||
.get();
|
||||
if (!project) {
|
||||
throw new Error("Project not found.");
|
||||
}
|
||||
assertSupplyTypeEnabled(
|
||||
project.enabledSupplyTypes,
|
||||
structure.distributionBoard.supplyType
|
||||
);
|
||||
if (structure.distributionBoard.floorId !== null) {
|
||||
const floor = database
|
||||
.select({ projectId: floors.projectId })
|
||||
.from(floors)
|
||||
.where(eq(floors.id, structure.distributionBoard.floorId))
|
||||
.get();
|
||||
if (!floor || floor.projectId !== projectId) {
|
||||
throw new Error(
|
||||
"Distribution-board floor does not belong to project."
|
||||
);
|
||||
}
|
||||
}
|
||||
const existingBoard = database
|
||||
.select({ id: distributionBoards.id })
|
||||
.from(distributionBoards)
|
||||
@@ -179,6 +236,139 @@ export class DistributionBoardStructureProjectCommandRepository
|
||||
}
|
||||
return createDistributionBoardInsertProjectCommand(structure);
|
||||
}
|
||||
|
||||
private update(
|
||||
database: AppDatabase,
|
||||
input: Omit<
|
||||
ExecuteDistributionBoardStructureCommandInput,
|
||||
"command"
|
||||
> & {
|
||||
command: DistributionBoardUpdateProjectCommand;
|
||||
}
|
||||
) {
|
||||
const current = database
|
||||
.select()
|
||||
.from(distributionBoards)
|
||||
.where(
|
||||
and(
|
||||
eq(
|
||||
distributionBoards.id,
|
||||
input.command.payload.distributionBoardId
|
||||
),
|
||||
eq(distributionBoards.projectId, input.projectId)
|
||||
)
|
||||
)
|
||||
.get();
|
||||
if (!current) {
|
||||
throw new Error("Distribution board does not belong to project.");
|
||||
}
|
||||
const project = database
|
||||
.select({
|
||||
enabledSupplyTypes:
|
||||
projects.enabledDistributionBoardSupplyTypes,
|
||||
})
|
||||
.from(projects)
|
||||
.where(eq(projects.id, input.projectId))
|
||||
.get();
|
||||
if (!project) {
|
||||
throw new Error("Project not found.");
|
||||
}
|
||||
const patch = Object.fromEntries(
|
||||
input.command.payload.changes.map((change) => [
|
||||
change.field,
|
||||
change.value,
|
||||
])
|
||||
) as DistributionBoardUpdatePatch;
|
||||
if (patch.floorId !== undefined && patch.floorId !== null) {
|
||||
const floor = database
|
||||
.select({ projectId: floors.projectId })
|
||||
.from(floors)
|
||||
.where(eq(floors.id, patch.floorId))
|
||||
.get();
|
||||
if (!floor || floor.projectId !== input.projectId) {
|
||||
throw new Error(
|
||||
"Distribution-board floor does not belong to project."
|
||||
);
|
||||
}
|
||||
}
|
||||
if (patch.supplyType !== undefined) {
|
||||
assertSupplyTypeEnabled(
|
||||
project.enabledSupplyTypes,
|
||||
patch.supplyType
|
||||
);
|
||||
}
|
||||
const inversePatch = Object.fromEntries(
|
||||
input.command.payload.changes.map((change) => [
|
||||
change.field,
|
||||
getDistributionBoardFieldValue(current, change.field),
|
||||
])
|
||||
) as DistributionBoardUpdatePatch;
|
||||
const inverse = createDistributionBoardUpdateProjectCommand(
|
||||
current.id,
|
||||
inversePatch
|
||||
);
|
||||
const updated = database
|
||||
.update(distributionBoards)
|
||||
.set(patch)
|
||||
.where(
|
||||
and(
|
||||
eq(distributionBoards.id, current.id),
|
||||
eq(distributionBoards.projectId, input.projectId)
|
||||
)
|
||||
)
|
||||
.run();
|
||||
if (updated.changes !== 1) {
|
||||
throw new Error(
|
||||
"Distribution board changed before command execution."
|
||||
);
|
||||
}
|
||||
return inverse;
|
||||
}
|
||||
}
|
||||
|
||||
function assertSupplyTypeEnabled(
|
||||
enabledSupplyTypes: (typeof projects.$inferSelect)["enabledDistributionBoardSupplyTypes"],
|
||||
supplyType: (typeof distributionBoards.$inferSelect)["supplyType"]
|
||||
) {
|
||||
if (
|
||||
supplyType !== null &&
|
||||
!enabledSupplyTypes.includes(supplyType)
|
||||
) {
|
||||
throw new Error(
|
||||
`Die Netzart ${supplyType} ist in den Projekteinstellungen nicht aktiviert.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function toLegacyStructureCommand(
|
||||
command:
|
||||
| ReturnType<typeof createDistributionBoardInsertProjectCommand>
|
||||
| ReturnType<typeof createDistributionBoardDeleteProjectCommand>
|
||||
): DistributionBoardStructureProjectCommand {
|
||||
const {
|
||||
floorId: _floorId,
|
||||
supplyType: _supplyType,
|
||||
...distributionBoard
|
||||
} = command.payload.structure.distributionBoard;
|
||||
return {
|
||||
schemaVersion: legacyDistributionBoardStructureCommandSchemaVersion,
|
||||
type: command.type,
|
||||
payload: {
|
||||
structure: {
|
||||
...command.payload.structure,
|
||||
distributionBoard,
|
||||
},
|
||||
},
|
||||
} as DistributionBoardStructureProjectCommand;
|
||||
}
|
||||
|
||||
function getDistributionBoardFieldValue<
|
||||
TField extends DistributionBoardUpdateField,
|
||||
>(
|
||||
distributionBoard: typeof distributionBoards.$inferSelect,
|
||||
field: TField
|
||||
): DistributionBoardUpdateValues[TField] {
|
||||
return distributionBoard[field] as DistributionBoardUpdateValues[TField];
|
||||
}
|
||||
|
||||
function structureMatches(
|
||||
|
||||
Reference in New Issue
Block a user