From d7b98de56a29dd27bff3b0ca25c7eff223409bee Mon Sep 17 00:00:00 2001 From: Julian Appel Date: Sun, 26 Jul 2026 12:30:42 +0200 Subject: [PATCH] Inject application database contexts --- AGENTS.md | 3 + docs/current-architecture.md | 5 ++ docs/spec/07-implementation-phases-todo.md | 3 + scripts/db-backfill-sections.ts | 7 +- scripts/db-migrate-legacy-consumers.ts | 10 +-- .../circuit-device-row.repository.ts | 8 +- .../repositories/circuit-list.repository.ts | 6 +- .../circuit-section.repository.ts | 7 +- src/db/repositories/circuit.repository.ts | 6 +- src/db/repositories/floor.repository.ts | 5 +- .../repositories/global-device.repository.ts | 9 ++- .../repositories/project-device.repository.ts | 6 +- src/db/repositories/project.repository.ts | 7 +- src/db/repositories/room.repository.ts | 5 +- .../composition/application-repositories.ts | 24 ++++++ .../composition/circuit-numbering-service.ts | 10 ++- .../project-device-sync-service.ts | 10 ++- .../controllers/circuit-list.controller.ts | 4 +- .../controllers/circuit-tree.controller.ts | 18 ++--- .../distribution-board.controller.ts | 5 +- src/server/controllers/floor.controller.ts | 4 +- .../controllers/global-device.controller.ts | 9 +-- .../controllers/project-device.controller.ts | 8 +- src/server/controllers/project.controller.ts | 4 +- src/server/controllers/room.controller.ts | 4 +- tests/database-backup.test.ts | 77 +++++++++++++++++++ 26 files changed, 201 insertions(+), 63 deletions(-) create mode 100644 src/server/composition/application-repositories.ts diff --git a/AGENTS.md b/AGENTS.md index d7682e1..bad5345 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,6 +30,9 @@ It must support circuits, device rows, project devices, drag-and-drop restructur directly; do not reintroduce a standalone runtime revision repository. - Runtime domain services receive narrow reader/store dependencies explicitly; concrete SQLite repositories are instantiated only under `src/server/composition`. +- General application repositories also require an explicit `AppDatabase`; + `src/server/composition/application-repositories.ts` owns their runtime + instances, and controllers never import the global SQLite client. - The upgrade-only legacy migration service follows the same dependency rule; its concrete repositories are instantiated only in `scripts/db-migrate-legacy-consumers.ts`. diff --git a/docs/current-architecture.md b/docs/current-architecture.md index af37d9c..a8d4be5 100644 --- a/docs/current-architecture.md +++ b/docs/current-architecture.md @@ -102,6 +102,11 @@ Ein eigenständiges Runtime-Revisions-Repository existiert nicht. `ProjectDeviceSyncService` und `CircuitNumberingService` kennen nur schmale, fachlich benannte Reader-Interfaces. Ihre SQLite-Repositories werden ausschließlich in `src/server/composition/` erzeugt und injiziert. +Auch die allgemeinen Projekt-, Geräte-, Raum-, Geschoss- und Circuit- +Repositories verlangen einen expliziten `AppDatabase`-Kontext. Ihre +Anwendungsinstanzen werden zentral in +`src/server/composition/application-repositories.ts` erzeugt; Controller +importieren weder den globalen SQLite-Client noch konkrete Repository-Klassen. `circuit-device-row.insert` und `circuit-device-row.delete` sind atomare Strukturkommandos. Beim Löschen wird die vollständige Zeile im inversen Kommando gesichert, sodass Undo dieselbe UUID und alle Fachwerte wiederherstellt. diff --git a/docs/spec/07-implementation-phases-todo.md b/docs/spec/07-implementation-phases-todo.md index 181457a..96fea8d 100644 --- a/docs/spec/07-implementation-phases-todo.md +++ b/docs/spec/07-implementation-phases-todo.md @@ -355,6 +355,9 @@ Implemented foundation: standalone runtime revision repository and store interface are removed - runtime project-device synchronization and circuit-numbering services depend on narrow domain readers; server composition injects the SQLite repositories +- all general application repositories require an explicit database context; + server composition owns their runtime instances and controllers contain no + direct global SQLite access - the legacy consumer UI and application read/write endpoints are removed after verified data cutover - retained legacy rows are accessible only through explicit database upgrade tooling - project devices no longer persist duplicate legacy power, phase, cosPhi or remark fields diff --git a/scripts/db-backfill-sections.ts b/scripts/db-backfill-sections.ts index 6526359..08deb06 100644 --- a/scripts/db-backfill-sections.ts +++ b/scripts/db-backfill-sections.ts @@ -1,10 +1,11 @@ +import { db } from "../src/db/client.js"; import { CircuitListRepository } from "../src/db/repositories/circuit-list.repository.js"; import { CircuitSectionRepository } from "../src/db/repositories/circuit-section.repository.js"; import { ProjectRepository } from "../src/db/repositories/project.repository.js"; -const projectRepository = new ProjectRepository(); -const circuitListRepository = new CircuitListRepository(); -const circuitSectionRepository = new CircuitSectionRepository(); +const projectRepository = new ProjectRepository(db); +const circuitListRepository = new CircuitListRepository(db); +const circuitSectionRepository = new CircuitSectionRepository(db); async function run() { const projects = await projectRepository.list(); diff --git a/scripts/db-migrate-legacy-consumers.ts b/scripts/db-migrate-legacy-consumers.ts index f149e28..7da8d70 100644 --- a/scripts/db-migrate-legacy-consumers.ts +++ b/scripts/db-migrate-legacy-consumers.ts @@ -7,14 +7,14 @@ import { ProjectRepository } from "../src/db/repositories/project.repository.js" import { RoomRepository } from "../src/db/repositories/room.repository.js"; import { LegacyConsumerMigrationService } from "../src/domain/services/legacy-consumer-migration.service.js"; -const projectRepository = new ProjectRepository(); -const circuitListRepository = new CircuitListRepository(); +const projectRepository = new ProjectRepository(db); +const circuitListRepository = new CircuitListRepository(db); const migrationRepository = new LegacyConsumerMigrationRepository(db); const migrationService = new LegacyConsumerMigrationService({ circuitListReader: circuitListRepository, - sectionStore: new CircuitSectionRepository(), - circuitReader: new CircuitRepository(), - roomReader: new RoomRepository(), + sectionStore: new CircuitSectionRepository(db), + circuitReader: new CircuitRepository(db), + roomReader: new RoomRepository(db), migrationStore: migrationRepository, }); diff --git a/src/db/repositories/circuit-device-row.repository.ts b/src/db/repositories/circuit-device-row.repository.ts index d9228d3..dc6118d 100644 --- a/src/db/repositories/circuit-device-row.repository.ts +++ b/src/db/repositories/circuit-device-row.repository.ts @@ -1,16 +1,18 @@ import { and, asc, eq, inArray } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { circuitDeviceRows } from "../schema/circuit-device-rows.js"; import { circuitLists } from "../schema/circuit-lists.js"; import { circuits } from "../schema/circuits.js"; import { distributionBoards } from "../schema/distribution-boards.js"; export class CircuitDeviceRowRepository { + constructor(private readonly database: AppDatabase) {} + async listByCircuitList(circuitIds: string[]) { if (!circuitIds.length) { return []; } - return db + return this.database .select() .from(circuitDeviceRows) .where(inArray(circuitDeviceRows.circuitId, circuitIds)) @@ -18,7 +20,7 @@ export class CircuitDeviceRowRepository { } async listLinkedByProjectDevice(projectId: string, projectDeviceId: string) { - return db + return this.database .select({ id: circuitDeviceRows.id, circuitId: circuitDeviceRows.circuitId, diff --git a/src/db/repositories/circuit-list.repository.ts b/src/db/repositories/circuit-list.repository.ts index 87544e1..6386094 100644 --- a/src/db/repositories/circuit-list.repository.ts +++ b/src/db/repositories/circuit-list.repository.ts @@ -1,13 +1,17 @@ import { and, eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { circuitLists } from "../schema/circuit-lists.js"; export class CircuitListRepository { + constructor(private readonly database: AppDatabase) {} + async listByProject(projectId: string) { + const db = this.database; return db.select().from(circuitLists).where(eq(circuitLists.projectId, projectId)); } async findById(projectId: string, circuitListId: string) { + const db = this.database; const [row] = await db .select() .from(circuitLists) diff --git a/src/db/repositories/circuit-section.repository.ts b/src/db/repositories/circuit-section.repository.ts index 7590624..d7817ec 100644 --- a/src/db/repositories/circuit-section.repository.ts +++ b/src/db/repositories/circuit-section.repository.ts @@ -1,7 +1,7 @@ import crypto from "node:crypto"; import { and, asc, eq } from "drizzle-orm"; import { defaultCircuitSectionDefinitions } from "../../domain/models/distribution-board-structure-project-command.model.js"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { circuitSections } from "../schema/circuit-sections.js"; export function createDefaultCircuitSectionValues(circuitListId: string) { @@ -13,12 +13,16 @@ export function createDefaultCircuitSectionValues(circuitListId: string) { } export class CircuitSectionRepository { + constructor(private readonly database: AppDatabase) {} + async findById(sectionId: string) { + const db = this.database; const [row] = await db.select().from(circuitSections).where(eq(circuitSections.id, sectionId)).limit(1); return row ?? null; } async listByCircuitList(circuitListId: string) { + const db = this.database; return db .select() .from(circuitSections) @@ -27,6 +31,7 @@ export class CircuitSectionRepository { } async createDefaults(circuitListId: string) { + const db = this.database; for (const entry of createDefaultCircuitSectionValues(circuitListId)) { const existing = await db .select({ id: circuitSections.id }) diff --git a/src/db/repositories/circuit.repository.ts b/src/db/repositories/circuit.repository.ts index 9f1e3b9..ecbaba0 100644 --- a/src/db/repositories/circuit.repository.ts +++ b/src/db/repositories/circuit.repository.ts @@ -1,9 +1,12 @@ import { asc, eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { circuits } from "../schema/circuits.js"; export class CircuitRepository { + constructor(private readonly database: AppDatabase) {} + async listByCircuitList(circuitListId: string) { + const db = this.database; return db .select() .from(circuits) @@ -12,6 +15,7 @@ export class CircuitRepository { } async listBySection(sectionId: string) { + const db = this.database; return db .select() .from(circuits) diff --git a/src/db/repositories/floor.repository.ts b/src/db/repositories/floor.repository.ts index 3bd0b98..caaabd3 100644 --- a/src/db/repositories/floor.repository.ts +++ b/src/db/repositories/floor.repository.ts @@ -1,9 +1,12 @@ import { asc, eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { floors } from "../schema/floors.js"; export class FloorRepository { + constructor(private readonly database: AppDatabase) {} + async listByProject(projectId: string) { + const db = this.database; return db .select() .from(floors) diff --git a/src/db/repositories/global-device.repository.ts b/src/db/repositories/global-device.repository.ts index 0a8b618..bd18e39 100644 --- a/src/db/repositories/global-device.repository.ts +++ b/src/db/repositories/global-device.repository.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; import { eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { globalDevices } from "../schema/global-devices.js"; import type { CreateGlobalDeviceInput, @@ -8,11 +8,15 @@ import type { } from "../../shared/validation/global-device.schemas.js"; export class GlobalDeviceRepository { + constructor(private readonly database: AppDatabase) {} + async list() { + const db = this.database; return db.select().from(globalDevices); } async create(input: CreateGlobalDeviceInput) { + const db = this.database; const id = crypto.randomUUID(); await db.insert(globalDevices).values({ id, @@ -31,6 +35,7 @@ export class GlobalDeviceRepository { } async update(globalDeviceId: string, input: UpdateGlobalDeviceInput) { + const db = this.database; await db .update(globalDevices) .set({ @@ -49,11 +54,13 @@ export class GlobalDeviceRepository { } async findById(globalDeviceId: string) { + const db = this.database; const [row] = await db.select().from(globalDevices).where(eq(globalDevices.id, globalDeviceId)).limit(1); return row ?? null; } async delete(globalDeviceId: string) { + const db = this.database; await db.delete(globalDevices).where(eq(globalDevices.id, globalDeviceId)); } } diff --git a/src/db/repositories/project-device.repository.ts b/src/db/repositories/project-device.repository.ts index 310aeb2..76d3339 100644 --- a/src/db/repositories/project-device.repository.ts +++ b/src/db/repositories/project-device.repository.ts @@ -1,5 +1,5 @@ import { and, eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { projectDevices } from "../schema/project-devices.js"; import { calculateRowTotalPower } from "../../domain/calculations/circuit-power-calculation.js"; @@ -11,12 +11,16 @@ function withTotalPower(row: typeof projectDevices.$inferSelect) { } export class ProjectDeviceRepository { + constructor(private readonly database: AppDatabase) {} + async listByProject(projectId: string) { + const db = this.database; const rows = await db.select().from(projectDevices).where(eq(projectDevices.projectId, projectId)); return rows.map(withTotalPower); } async findById(projectId: string, projectDeviceId: string) { + const db = this.database; const [row] = await db .select() .from(projectDevices) diff --git a/src/db/repositories/project.repository.ts b/src/db/repositories/project.repository.ts index 39976b8..0ef03a2 100644 --- a/src/db/repositories/project.repository.ts +++ b/src/db/repositories/project.repository.ts @@ -1,17 +1,21 @@ import crypto from "node:crypto"; import { eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { projects } from "../schema/projects.js"; import type { CreateProjectInput, } from "../../shared/validation/project-structure.schemas.js"; export class ProjectRepository { + constructor(private readonly database: AppDatabase) {} + async list() { + const db = this.database; return db.select().from(projects); } async create(input: CreateProjectInput) { + const db = this.database; const id = crypto.randomUUID(); const project = { id, @@ -25,6 +29,7 @@ export class ProjectRepository { } async findById(projectId: string) { + const db = this.database; const [row] = await db.select().from(projects).where(eq(projects.id, projectId)).limit(1); return row ?? null; } diff --git a/src/db/repositories/room.repository.ts b/src/db/repositories/room.repository.ts index ce8c3be..85e21cc 100644 --- a/src/db/repositories/room.repository.ts +++ b/src/db/repositories/room.repository.ts @@ -1,9 +1,12 @@ import { asc, eq } from "drizzle-orm"; -import { db } from "../client.js"; +import type { AppDatabase } from "../database-context.js"; import { rooms } from "../schema/rooms.js"; export class RoomRepository { + constructor(private readonly database: AppDatabase) {} + async listByProject(projectId: string) { + const db = this.database; return db .select() .from(rooms) diff --git a/src/server/composition/application-repositories.ts b/src/server/composition/application-repositories.ts new file mode 100644 index 0000000..8812141 --- /dev/null +++ b/src/server/composition/application-repositories.ts @@ -0,0 +1,24 @@ +import { db } from "../../db/client.js"; +import { CircuitDeviceRowRepository } from "../../db/repositories/circuit-device-row.repository.js"; +import { CircuitListRepository } from "../../db/repositories/circuit-list.repository.js"; +import { CircuitSectionRepository } from "../../db/repositories/circuit-section.repository.js"; +import { CircuitRepository } from "../../db/repositories/circuit.repository.js"; +import { DistributionBoardRepository } from "../../db/repositories/distribution-board.repository.js"; +import { FloorRepository } from "../../db/repositories/floor.repository.js"; +import { GlobalDeviceRepository } from "../../db/repositories/global-device.repository.js"; +import { ProjectDeviceRepository } from "../../db/repositories/project-device.repository.js"; +import { ProjectRepository } from "../../db/repositories/project.repository.js"; +import { RoomRepository } from "../../db/repositories/room.repository.js"; + +export const circuitDeviceRowRepository = + new CircuitDeviceRowRepository(db); +export const circuitListRepository = new CircuitListRepository(db); +export const circuitSectionRepository = new CircuitSectionRepository(db); +export const circuitRepository = new CircuitRepository(db); +export const distributionBoardRepository = + new DistributionBoardRepository(db); +export const floorRepository = new FloorRepository(db); +export const globalDeviceRepository = new GlobalDeviceRepository(db); +export const projectDeviceRepository = new ProjectDeviceRepository(db); +export const projectRepository = new ProjectRepository(db); +export const roomRepository = new RoomRepository(db); diff --git a/src/server/composition/circuit-numbering-service.ts b/src/server/composition/circuit-numbering-service.ts index 265c16b..318d394 100644 --- a/src/server/composition/circuit-numbering-service.ts +++ b/src/server/composition/circuit-numbering-service.ts @@ -1,8 +1,10 @@ -import { CircuitRepository } from "../../db/repositories/circuit.repository.js"; -import { CircuitSectionRepository } from "../../db/repositories/circuit-section.repository.js"; import { CircuitNumberingService } from "../../domain/services/circuit-numbering.service.js"; +import { + circuitRepository, + circuitSectionRepository, +} from "./application-repositories.js"; export const circuitNumberingService = new CircuitNumberingService({ - sectionRepository: new CircuitSectionRepository(), - circuitRepository: new CircuitRepository(), + sectionRepository: circuitSectionRepository, + circuitRepository, }); diff --git a/src/server/composition/project-device-sync-service.ts b/src/server/composition/project-device-sync-service.ts index 26f67d7..c10d3d8 100644 --- a/src/server/composition/project-device-sync-service.ts +++ b/src/server/composition/project-device-sync-service.ts @@ -1,8 +1,10 @@ -import { CircuitDeviceRowRepository } from "../../db/repositories/circuit-device-row.repository.js"; -import { ProjectDeviceRepository } from "../../db/repositories/project-device.repository.js"; import { ProjectDeviceSyncService } from "../../domain/services/project-device-sync.service.js"; +import { + circuitDeviceRowRepository, + projectDeviceRepository, +} from "./application-repositories.js"; export const projectDeviceSyncService = new ProjectDeviceSyncService({ - projectDeviceRepository: new ProjectDeviceRepository(), - deviceRowRepository: new CircuitDeviceRowRepository(), + projectDeviceRepository, + deviceRowRepository: circuitDeviceRowRepository, }); diff --git a/src/server/controllers/circuit-list.controller.ts b/src/server/controllers/circuit-list.controller.ts index a75173e..3d103e8 100644 --- a/src/server/controllers/circuit-list.controller.ts +++ b/src/server/controllers/circuit-list.controller.ts @@ -1,7 +1,5 @@ import type { Request, Response } from "express"; -import { CircuitListRepository } from "../../db/repositories/circuit-list.repository.js"; - -const circuitListRepository = new CircuitListRepository(); +import { circuitListRepository } from "../composition/application-repositories.js"; export async function listCircuitListsByProject(req: Request, res: Response) { const { projectId } = req.params; diff --git a/src/server/controllers/circuit-tree.controller.ts b/src/server/controllers/circuit-tree.controller.ts index 302f57a..ed5463a 100644 --- a/src/server/controllers/circuit-tree.controller.ts +++ b/src/server/controllers/circuit-tree.controller.ts @@ -1,20 +1,16 @@ import type { Request, Response } from "express"; -import { CircuitRepository } from "../../db/repositories/circuit.repository.js"; -import { CircuitDeviceRowRepository } from "../../db/repositories/circuit-device-row.repository.js"; -import { CircuitListRepository } from "../../db/repositories/circuit-list.repository.js"; -import { CircuitSectionRepository } from "../../db/repositories/circuit-section.repository.js"; -import { ProjectRepository } from "../../db/repositories/project.repository.js"; import { calculateCircuitTotalPower, calculateRowTotalPower, } from "../../domain/calculations/circuit-power-calculation.js"; import type { CircuitTreeResponse } from "../../domain/models/circuit-tree.model.js"; - -const circuitListRepository = new CircuitListRepository(); -const circuitSectionRepository = new CircuitSectionRepository(); -const circuitRepository = new CircuitRepository(); -const circuitDeviceRowRepository = new CircuitDeviceRowRepository(); -const projectRepository = new ProjectRepository(); +import { + circuitDeviceRowRepository, + circuitListRepository, + circuitRepository, + circuitSectionRepository, + projectRepository, +} from "../composition/application-repositories.js"; export function isMissingCircuitTreeSchemaError(error: unknown): boolean { if (!(error instanceof Error)) { diff --git a/src/server/controllers/distribution-board.controller.ts b/src/server/controllers/distribution-board.controller.ts index f59ba8b..66276cd 100644 --- a/src/server/controllers/distribution-board.controller.ts +++ b/src/server/controllers/distribution-board.controller.ts @@ -1,16 +1,13 @@ import type { Request, Response } from "express"; -import { db } from "../../db/client.js"; -import { DistributionBoardRepository } from "../../db/repositories/distribution-board.repository.js"; import { createDistributionBoardInsertProjectCommand, createDistributionBoardStructureSnapshot, } from "../../domain/models/distribution-board-structure-project-command.model.js"; import { createDistributionBoardSchema } from "../../shared/validation/project-structure.schemas.js"; import { projectCommandService } from "../composition/project-command-stores.js"; +import { distributionBoardRepository } from "../composition/application-repositories.js"; import { respondWithProjectCommandError } from "./project-command.controller.js"; -const distributionBoardRepository = new DistributionBoardRepository(db); - export async function listDistributionBoardsByProject(req: Request, res: Response) { const { projectId } = req.params; if (typeof projectId !== "string") { diff --git a/src/server/controllers/floor.controller.ts b/src/server/controllers/floor.controller.ts index adaed42..677e728 100644 --- a/src/server/controllers/floor.controller.ts +++ b/src/server/controllers/floor.controller.ts @@ -1,15 +1,13 @@ import type { Request, Response } from "express"; -import { FloorRepository } from "../../db/repositories/floor.repository.js"; import { createProjectFloorInsertProjectCommand, createProjectFloorSnapshot, } from "../../domain/models/project-location-structure-project-command.model.js"; import { createFloorSchema } from "../../shared/validation/project-structure.schemas.js"; import { projectCommandService } from "../composition/project-command-stores.js"; +import { floorRepository } from "../composition/application-repositories.js"; import { respondWithProjectCommandError } from "./project-command.controller.js"; -const floorRepository = new FloorRepository(); - export async function listFloorsByProject(req: Request, res: Response) { const { projectId } = req.params; if (typeof projectId !== "string") { diff --git a/src/server/controllers/global-device.controller.ts b/src/server/controllers/global-device.controller.ts index d8f8546..4168b3c 100644 --- a/src/server/controllers/global-device.controller.ts +++ b/src/server/controllers/global-device.controller.ts @@ -1,13 +1,12 @@ import type { Request, Response } from "express"; -import { GlobalDeviceRepository } from "../../db/repositories/global-device.repository.js"; -import { ProjectDeviceRepository } from "../../db/repositories/project-device.repository.js"; import { createGlobalDeviceSchema, updateGlobalDeviceSchema, } from "../../shared/validation/global-device.schemas.js"; - -const globalDeviceRepository = new GlobalDeviceRepository(); -const projectDeviceRepository = new ProjectDeviceRepository(); +import { + globalDeviceRepository, + projectDeviceRepository, +} from "../composition/application-repositories.js"; export async function listGlobalDevices(_req: Request, res: Response) { const rows = await globalDeviceRepository.list(); diff --git a/src/server/controllers/project-device.controller.ts b/src/server/controllers/project-device.controller.ts index 32100d9..c776ea5 100644 --- a/src/server/controllers/project-device.controller.ts +++ b/src/server/controllers/project-device.controller.ts @@ -1,7 +1,5 @@ import { randomUUID } from "node:crypto"; import type { Request, Response } from "express"; -import { GlobalDeviceRepository } from "../../db/repositories/global-device.repository.js"; -import { ProjectDeviceRepository } from "../../db/repositories/project-device.repository.js"; import { createProjectDeviceUpdateProjectCommand } from "../../domain/models/project-device-project-command.model.js"; import { createProjectDeviceDeleteProjectCommand, @@ -10,6 +8,10 @@ import { } from "../../domain/models/project-device-structure-project-command.model.js"; import { projectDeviceSyncService } from "../composition/project-device-sync-service.js"; import { projectCommandService } from "../composition/project-command-stores.js"; +import { + globalDeviceRepository, + projectDeviceRepository, +} from "../composition/application-repositories.js"; import { createProjectDeviceCommandSchema, disconnectProjectDeviceRowsSchema, @@ -20,8 +22,6 @@ import { import type { CreateProjectDeviceInput } from "../../shared/validation/project-device.schemas.js"; import { respondWithProjectCommandError } from "./project-command.controller.js"; -const globalDeviceRepository = new GlobalDeviceRepository(); -const projectDeviceRepository = new ProjectDeviceRepository(); export async function listProjectDevicesByProject(req: Request, res: Response) { const { projectId } = req.params; if (typeof projectId !== "string") { diff --git a/src/server/controllers/project.controller.ts b/src/server/controllers/project.controller.ts index 7711a55..f739542 100644 --- a/src/server/controllers/project.controller.ts +++ b/src/server/controllers/project.controller.ts @@ -1,15 +1,13 @@ import type { Request, Response } from "express"; -import { ProjectRepository } from "../../db/repositories/project.repository.js"; import { createProjectSchema, updateProjectSettingsSchema, } from "../../shared/validation/project-structure.schemas.js"; import { createProjectSettingsUpdateProjectCommand } from "../../domain/models/project-settings-project-command.model.js"; import { projectCommandService } from "../composition/project-command-stores.js"; +import { projectRepository } from "../composition/application-repositories.js"; import { respondWithProjectCommandError } from "./project-command.controller.js"; -const projectRepository = new ProjectRepository(); - export async function listProjects(_req: Request, res: Response) { const result = await projectRepository.list(); res.json(result); diff --git a/src/server/controllers/room.controller.ts b/src/server/controllers/room.controller.ts index b7d6035..330a538 100644 --- a/src/server/controllers/room.controller.ts +++ b/src/server/controllers/room.controller.ts @@ -1,15 +1,13 @@ import type { Request, Response } from "express"; -import { RoomRepository } from "../../db/repositories/room.repository.js"; import { createProjectRoomInsertProjectCommand, createProjectRoomSnapshot, } from "../../domain/models/project-location-structure-project-command.model.js"; import { createRoomSchema } from "../../shared/validation/project-structure.schemas.js"; import { projectCommandService } from "../composition/project-command-stores.js"; +import { roomRepository } from "../composition/application-repositories.js"; import { respondWithProjectCommandError } from "./project-command.controller.js"; -const roomRepository = new RoomRepository(); - export async function listRoomsByProject(req: Request, res: Response) { const { projectId } = req.params; if (typeof projectId !== "string") { diff --git a/tests/database-backup.test.ts b/tests/database-backup.test.ts index 6c960bd..88778e5 100644 --- a/tests/database-backup.test.ts +++ b/tests/database-backup.test.ts @@ -10,6 +10,15 @@ import { verifyDatabaseFile, } from "../src/db/database-backup.js"; import { createDatabaseContext } from "../src/db/database-context.js"; +import { CircuitDeviceRowRepository } from "../src/db/repositories/circuit-device-row.repository.js"; +import { CircuitListRepository } from "../src/db/repositories/circuit-list.repository.js"; +import { CircuitSectionRepository } from "../src/db/repositories/circuit-section.repository.js"; +import { CircuitRepository } from "../src/db/repositories/circuit.repository.js"; +import { FloorRepository } from "../src/db/repositories/floor.repository.js"; +import { GlobalDeviceRepository } from "../src/db/repositories/global-device.repository.js"; +import { ProjectDeviceRepository } from "../src/db/repositories/project-device.repository.js"; +import { ProjectRepository } from "../src/db/repositories/project.repository.js"; +import { RoomRepository } from "../src/db/repositories/room.repository.js"; import { projects } from "../src/db/schema/projects.js"; describe("database backup and restore", () => { @@ -86,3 +95,71 @@ describe("database backup and restore", () => { } }); }); + +describe("application repository database contexts", () => { + it("keep reads and writes inside their injected database", async () => { + const first = createDatabaseContext(":memory:"); + const second = createDatabaseContext(":memory:"); + try { + for (const context of [first, second]) { + migrate(context.db, { + migrationsFolder: path.resolve("src", "db", "migrations"), + }); + } + + const firstProjects = new ProjectRepository(first.db); + const secondProjects = new ProjectRepository(second.db); + const project = await firstProjects.create({ name: "Nur in Datenbank A" }); + + assert.equal((await firstProjects.list()).length, 1); + assert.deepEqual(await secondProjects.list(), []); + + const firstGlobalDevices = new GlobalDeviceRepository(first.db); + const secondGlobalDevices = new GlobalDeviceRepository(second.db); + await firstGlobalDevices.create({ + name: "Steckdose", + displayName: "Steckdose", + quantity: 1, + installedPowerPerUnitKw: 0.2, + demandFactor: 1, + }); + + assert.equal((await firstGlobalDevices.list()).length, 1); + assert.deepEqual(await secondGlobalDevices.list(), []); + + assert.deepEqual( + await new CircuitListRepository(first.db).listByProject(project.id), + [] + ); + assert.deepEqual( + await new CircuitSectionRepository(first.db).listByCircuitList( + "unknown-list" + ), + [] + ); + assert.deepEqual( + await new CircuitRepository(first.db).listByCircuitList("unknown-list"), + [] + ); + assert.deepEqual( + await new CircuitDeviceRowRepository(first.db).listByCircuitList([]), + [] + ); + assert.deepEqual( + await new FloorRepository(first.db).listByProject(project.id), + [] + ); + assert.deepEqual( + await new RoomRepository(first.db).listByProject(project.id), + [] + ); + assert.deepEqual( + await new ProjectDeviceRepository(first.db).listByProject(project.id), + [] + ); + } finally { + first.close(); + second.close(); + } + }); +});