Add editable project floors and rooms

This commit is contained in:
2026-07-31 14:46:06 +02:00
parent 1e3c721cfa
commit 1eed19ef6b
15 changed files with 743 additions and 80 deletions
+9 -1
View File
@@ -1,4 +1,4 @@
import { asc, eq } from "drizzle-orm";
import { and, asc, eq } from "drizzle-orm";
import type { AppDatabase } from "../database-context.js";
import { floors } from "../schema/floors.js";
@@ -13,4 +13,12 @@ export class FloorRepository {
.where(eq(floors.projectId, projectId))
.orderBy(asc(floors.sortOrder), asc(floors.name));
}
async findById(projectId: string, floorId: string) {
return this.database
.select()
.from(floors)
.where(and(eq(floors.projectId, projectId), eq(floors.id, floorId)))
.get() ?? null;
}
}
@@ -2,16 +2,22 @@ import { and, eq } from "drizzle-orm";
import {
assertProjectFloorDeleteProjectCommand,
assertProjectFloorInsertProjectCommand,
assertProjectFloorUpdateProjectCommand,
assertProjectRoomDeleteProjectCommand,
assertProjectRoomInsertProjectCommand,
assertProjectRoomUpdateProjectCommand,
createProjectFloorDeleteProjectCommand,
createProjectFloorInsertProjectCommand,
createProjectFloorUpdateProjectCommand,
createProjectRoomDeleteProjectCommand,
createProjectRoomInsertProjectCommand,
createProjectRoomUpdateProjectCommand,
projectFloorDeleteCommandType,
projectFloorInsertCommandType,
projectFloorUpdateCommandType,
projectRoomDeleteCommandType,
projectRoomInsertCommandType,
projectRoomUpdateCommandType,
type ProjectFloorSnapshot,
type ProjectLocationStructureProjectCommand,
type ProjectRoomSnapshot,
@@ -62,6 +68,9 @@ export class ProjectLocationStructureProjectCommandRepository
projectId,
command.payload.floor
);
case projectFloorUpdateCommandType:
assertProjectFloorUpdateProjectCommand(command);
return this.updateFloor(database, projectId, command.payload.expected, command.payload.target);
case projectRoomInsertCommandType:
assertProjectRoomInsertProjectCommand(command);
return this.insertRoom(
@@ -76,6 +85,9 @@ export class ProjectLocationStructureProjectCommandRepository
projectId,
command.payload.room
);
case projectRoomUpdateCommandType:
assertProjectRoomUpdateProjectCommand(command);
return this.updateRoom(database, projectId, command.payload.expected, command.payload.target);
}
}
@@ -126,7 +138,7 @@ export class ProjectLocationStructureProjectCommandRepository
.get();
if (referencedRoom) {
throw new Error(
"A project floor with assigned rooms cannot be removed by history."
"Die Etage kann nicht gelöscht werden, solange Räume zugeordnet sind."
);
}
const referencedDistributionBoard = database
@@ -137,7 +149,7 @@ export class ProjectLocationStructureProjectCommandRepository
.get();
if (referencedDistributionBoard) {
throw new Error(
"A project floor assigned to a distribution board cannot be removed by history."
"Die Etage kann nicht gelöscht werden, solange eine Verteilung zugeordnet ist."
);
}
const deleted = database
@@ -191,6 +203,70 @@ export class ProjectLocationStructureProjectCommandRepository
return createProjectRoomDeleteProjectCommand(room);
}
private updateFloor(
database: AppDatabase,
projectId: string,
expected: ProjectFloorSnapshot,
target: ProjectFloorSnapshot
) {
const persisted = database
.select()
.from(floors)
.where(and(eq(floors.id, expected.id), eq(floors.projectId, projectId)))
.get();
if (!persisted || !sameRecord(expected, persisted)) {
throw new Error("Project floor changed before update.");
}
const updated = database
.update(floors)
.set({ name: target.name })
.where(and(eq(floors.id, expected.id), eq(floors.projectId, projectId)))
.run();
if (updated.changes !== 1) {
throw new Error("Die Etage konnte nicht aktualisiert werden.");
}
return createProjectFloorUpdateProjectCommand(target, expected);
}
private updateRoom(
database: AppDatabase,
projectId: string,
expected: ProjectRoomSnapshot,
target: ProjectRoomSnapshot
) {
const persisted = database
.select()
.from(rooms)
.where(and(eq(rooms.id, expected.id), eq(rooms.projectId, projectId)))
.get();
if (!persisted || !sameRecord(expected, persisted)) {
throw new Error("Project room changed before update.");
}
if (target.floorId) {
const targetFloor = database
.select({ id: floors.id })
.from(floors)
.where(and(eq(floors.id, target.floorId), eq(floors.projectId, projectId)))
.get();
if (!targetFloor) {
throw new Error("Project room references a foreign floor.");
}
}
const updated = database
.update(rooms)
.set({
floorId: target.floorId,
roomNumber: target.roomNumber,
roomName: target.roomName,
})
.where(and(eq(rooms.id, expected.id), eq(rooms.projectId, projectId)))
.run();
if (updated.changes !== 1) {
throw new Error("Der Raum konnte nicht aktualisiert werden.");
}
return createProjectRoomUpdateProjectCommand(target, expected);
}
private deleteRoom(
database: AppDatabase,
projectId: string,
@@ -217,7 +293,7 @@ export class ProjectLocationStructureProjectCommandRepository
.get();
if (referencedDeviceRow) {
throw new Error(
"A referenced project room cannot be removed by history."
"Der Raum kann nicht gelöscht werden, solange er in einem Stromkreis verwendet wird."
);
}
const deleted = database
+9 -1
View File
@@ -1,4 +1,4 @@
import { asc, eq } from "drizzle-orm";
import { and, asc, eq } from "drizzle-orm";
import type { AppDatabase } from "../database-context.js";
import { rooms } from "../schema/rooms.js";
@@ -13,4 +13,12 @@ export class RoomRepository {
.where(eq(rooms.projectId, projectId))
.orderBy(asc(rooms.roomNumber), asc(rooms.roomName));
}
async findById(projectId: string, roomId: string) {
return this.database
.select()
.from(rooms)
.where(and(eq(rooms.projectId, projectId), eq(rooms.id, roomId)))
.get() ?? null;
}
}