Inject application database contexts

This commit is contained in:
2026-07-26 12:30:42 +02:00
parent 859fa4a42a
commit d7b98de56a
26 changed files with 201 additions and 63 deletions
+3
View File
@@ -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. directly; do not reintroduce a standalone runtime revision repository.
- Runtime domain services receive narrow reader/store dependencies explicitly; - Runtime domain services receive narrow reader/store dependencies explicitly;
concrete SQLite repositories are instantiated only under `src/server/composition`. 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; - The upgrade-only legacy migration service follows the same dependency rule;
its concrete repositories are instantiated only in its concrete repositories are instantiated only in
`scripts/db-migrate-legacy-consumers.ts`. `scripts/db-migrate-legacy-consumers.ts`.
+5
View File
@@ -102,6 +102,11 @@ Ein eigenständiges Runtime-Revisions-Repository existiert nicht.
`ProjectDeviceSyncService` und `CircuitNumberingService` kennen nur schmale, `ProjectDeviceSyncService` und `CircuitNumberingService` kennen nur schmale,
fachlich benannte Reader-Interfaces. Ihre SQLite-Repositories werden fachlich benannte Reader-Interfaces. Ihre SQLite-Repositories werden
ausschließlich in `src/server/composition/` erzeugt und injiziert. 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 `circuit-device-row.insert` und `circuit-device-row.delete` sind atomare
Strukturkommandos. Beim Löschen wird die vollständige Zeile im inversen Strukturkommandos. Beim Löschen wird die vollständige Zeile im inversen
Kommando gesichert, sodass Undo dieselbe UUID und alle Fachwerte wiederherstellt. Kommando gesichert, sodass Undo dieselbe UUID und alle Fachwerte wiederherstellt.
@@ -355,6 +355,9 @@ Implemented foundation:
standalone runtime revision repository and store interface are removed standalone runtime revision repository and store interface are removed
- runtime project-device synchronization and circuit-numbering services depend - runtime project-device synchronization and circuit-numbering services depend
on narrow domain readers; server composition injects the SQLite repositories 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 - 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 - retained legacy rows are accessible only through explicit database upgrade tooling
- project devices no longer persist duplicate legacy power, phase, cosPhi or remark fields - project devices no longer persist duplicate legacy power, phase, cosPhi or remark fields
+4 -3
View File
@@ -1,10 +1,11 @@
import { db } from "../src/db/client.js";
import { CircuitListRepository } from "../src/db/repositories/circuit-list.repository.js"; import { CircuitListRepository } from "../src/db/repositories/circuit-list.repository.js";
import { CircuitSectionRepository } from "../src/db/repositories/circuit-section.repository.js"; import { CircuitSectionRepository } from "../src/db/repositories/circuit-section.repository.js";
import { ProjectRepository } from "../src/db/repositories/project.repository.js"; import { ProjectRepository } from "../src/db/repositories/project.repository.js";
const projectRepository = new ProjectRepository(); const projectRepository = new ProjectRepository(db);
const circuitListRepository = new CircuitListRepository(); const circuitListRepository = new CircuitListRepository(db);
const circuitSectionRepository = new CircuitSectionRepository(); const circuitSectionRepository = new CircuitSectionRepository(db);
async function run() { async function run() {
const projects = await projectRepository.list(); const projects = await projectRepository.list();
+5 -5
View File
@@ -7,14 +7,14 @@ import { ProjectRepository } from "../src/db/repositories/project.repository.js"
import { RoomRepository } from "../src/db/repositories/room.repository.js"; import { RoomRepository } from "../src/db/repositories/room.repository.js";
import { LegacyConsumerMigrationService } from "../src/domain/services/legacy-consumer-migration.service.js"; import { LegacyConsumerMigrationService } from "../src/domain/services/legacy-consumer-migration.service.js";
const projectRepository = new ProjectRepository(); const projectRepository = new ProjectRepository(db);
const circuitListRepository = new CircuitListRepository(); const circuitListRepository = new CircuitListRepository(db);
const migrationRepository = new LegacyConsumerMigrationRepository(db); const migrationRepository = new LegacyConsumerMigrationRepository(db);
const migrationService = new LegacyConsumerMigrationService({ const migrationService = new LegacyConsumerMigrationService({
circuitListReader: circuitListRepository, circuitListReader: circuitListRepository,
sectionStore: new CircuitSectionRepository(), sectionStore: new CircuitSectionRepository(db),
circuitReader: new CircuitRepository(), circuitReader: new CircuitRepository(db),
roomReader: new RoomRepository(), roomReader: new RoomRepository(db),
migrationStore: migrationRepository, migrationStore: migrationRepository,
}); });
@@ -1,16 +1,18 @@
import { and, asc, eq, inArray } from "drizzle-orm"; 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 { circuitDeviceRows } from "../schema/circuit-device-rows.js";
import { circuitLists } from "../schema/circuit-lists.js"; import { circuitLists } from "../schema/circuit-lists.js";
import { circuits } from "../schema/circuits.js"; import { circuits } from "../schema/circuits.js";
import { distributionBoards } from "../schema/distribution-boards.js"; import { distributionBoards } from "../schema/distribution-boards.js";
export class CircuitDeviceRowRepository { export class CircuitDeviceRowRepository {
constructor(private readonly database: AppDatabase) {}
async listByCircuitList(circuitIds: string[]) { async listByCircuitList(circuitIds: string[]) {
if (!circuitIds.length) { if (!circuitIds.length) {
return []; return [];
} }
return db return this.database
.select() .select()
.from(circuitDeviceRows) .from(circuitDeviceRows)
.where(inArray(circuitDeviceRows.circuitId, circuitIds)) .where(inArray(circuitDeviceRows.circuitId, circuitIds))
@@ -18,7 +20,7 @@ export class CircuitDeviceRowRepository {
} }
async listLinkedByProjectDevice(projectId: string, projectDeviceId: string) { async listLinkedByProjectDevice(projectId: string, projectDeviceId: string) {
return db return this.database
.select({ .select({
id: circuitDeviceRows.id, id: circuitDeviceRows.id,
circuitId: circuitDeviceRows.circuitId, circuitId: circuitDeviceRows.circuitId,
@@ -1,13 +1,17 @@
import { and, eq } from "drizzle-orm"; 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"; import { circuitLists } from "../schema/circuit-lists.js";
export class CircuitListRepository { export class CircuitListRepository {
constructor(private readonly database: AppDatabase) {}
async listByProject(projectId: string) { async listByProject(projectId: string) {
const db = this.database;
return db.select().from(circuitLists).where(eq(circuitLists.projectId, projectId)); return db.select().from(circuitLists).where(eq(circuitLists.projectId, projectId));
} }
async findById(projectId: string, circuitListId: string) { async findById(projectId: string, circuitListId: string) {
const db = this.database;
const [row] = await db const [row] = await db
.select() .select()
.from(circuitLists) .from(circuitLists)
@@ -1,7 +1,7 @@
import crypto from "node:crypto"; import crypto from "node:crypto";
import { and, asc, eq } from "drizzle-orm"; import { and, asc, eq } from "drizzle-orm";
import { defaultCircuitSectionDefinitions } from "../../domain/models/distribution-board-structure-project-command.model.js"; 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"; import { circuitSections } from "../schema/circuit-sections.js";
export function createDefaultCircuitSectionValues(circuitListId: string) { export function createDefaultCircuitSectionValues(circuitListId: string) {
@@ -13,12 +13,16 @@ export function createDefaultCircuitSectionValues(circuitListId: string) {
} }
export class CircuitSectionRepository { export class CircuitSectionRepository {
constructor(private readonly database: AppDatabase) {}
async findById(sectionId: string) { async findById(sectionId: string) {
const db = this.database;
const [row] = await db.select().from(circuitSections).where(eq(circuitSections.id, sectionId)).limit(1); const [row] = await db.select().from(circuitSections).where(eq(circuitSections.id, sectionId)).limit(1);
return row ?? null; return row ?? null;
} }
async listByCircuitList(circuitListId: string) { async listByCircuitList(circuitListId: string) {
const db = this.database;
return db return db
.select() .select()
.from(circuitSections) .from(circuitSections)
@@ -27,6 +31,7 @@ export class CircuitSectionRepository {
} }
async createDefaults(circuitListId: string) { async createDefaults(circuitListId: string) {
const db = this.database;
for (const entry of createDefaultCircuitSectionValues(circuitListId)) { for (const entry of createDefaultCircuitSectionValues(circuitListId)) {
const existing = await db const existing = await db
.select({ id: circuitSections.id }) .select({ id: circuitSections.id })
+5 -1
View File
@@ -1,9 +1,12 @@
import { asc, eq } from "drizzle-orm"; import { asc, eq } from "drizzle-orm";
import { db } from "../client.js"; import type { AppDatabase } from "../database-context.js";
import { circuits } from "../schema/circuits.js"; import { circuits } from "../schema/circuits.js";
export class CircuitRepository { export class CircuitRepository {
constructor(private readonly database: AppDatabase) {}
async listByCircuitList(circuitListId: string) { async listByCircuitList(circuitListId: string) {
const db = this.database;
return db return db
.select() .select()
.from(circuits) .from(circuits)
@@ -12,6 +15,7 @@ export class CircuitRepository {
} }
async listBySection(sectionId: string) { async listBySection(sectionId: string) {
const db = this.database;
return db return db
.select() .select()
.from(circuits) .from(circuits)
+4 -1
View File
@@ -1,9 +1,12 @@
import { asc, eq } from "drizzle-orm"; import { asc, eq } from "drizzle-orm";
import { db } from "../client.js"; import type { AppDatabase } from "../database-context.js";
import { floors } from "../schema/floors.js"; import { floors } from "../schema/floors.js";
export class FloorRepository { export class FloorRepository {
constructor(private readonly database: AppDatabase) {}
async listByProject(projectId: string) { async listByProject(projectId: string) {
const db = this.database;
return db return db
.select() .select()
.from(floors) .from(floors)
@@ -1,6 +1,6 @@
import crypto from "node:crypto"; import crypto from "node:crypto";
import { eq } from "drizzle-orm"; 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 { globalDevices } from "../schema/global-devices.js";
import type { import type {
CreateGlobalDeviceInput, CreateGlobalDeviceInput,
@@ -8,11 +8,15 @@ import type {
} from "../../shared/validation/global-device.schemas.js"; } from "../../shared/validation/global-device.schemas.js";
export class GlobalDeviceRepository { export class GlobalDeviceRepository {
constructor(private readonly database: AppDatabase) {}
async list() { async list() {
const db = this.database;
return db.select().from(globalDevices); return db.select().from(globalDevices);
} }
async create(input: CreateGlobalDeviceInput) { async create(input: CreateGlobalDeviceInput) {
const db = this.database;
const id = crypto.randomUUID(); const id = crypto.randomUUID();
await db.insert(globalDevices).values({ await db.insert(globalDevices).values({
id, id,
@@ -31,6 +35,7 @@ export class GlobalDeviceRepository {
} }
async update(globalDeviceId: string, input: UpdateGlobalDeviceInput) { async update(globalDeviceId: string, input: UpdateGlobalDeviceInput) {
const db = this.database;
await db await db
.update(globalDevices) .update(globalDevices)
.set({ .set({
@@ -49,11 +54,13 @@ export class GlobalDeviceRepository {
} }
async findById(globalDeviceId: string) { async findById(globalDeviceId: string) {
const db = this.database;
const [row] = await db.select().from(globalDevices).where(eq(globalDevices.id, globalDeviceId)).limit(1); const [row] = await db.select().from(globalDevices).where(eq(globalDevices.id, globalDeviceId)).limit(1);
return row ?? null; return row ?? null;
} }
async delete(globalDeviceId: string) { async delete(globalDeviceId: string) {
const db = this.database;
await db.delete(globalDevices).where(eq(globalDevices.id, globalDeviceId)); await db.delete(globalDevices).where(eq(globalDevices.id, globalDeviceId));
} }
} }
@@ -1,5 +1,5 @@
import { and, eq } from "drizzle-orm"; 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 { projectDevices } from "../schema/project-devices.js";
import { calculateRowTotalPower } from "../../domain/calculations/circuit-power-calculation.js"; import { calculateRowTotalPower } from "../../domain/calculations/circuit-power-calculation.js";
@@ -11,12 +11,16 @@ function withTotalPower(row: typeof projectDevices.$inferSelect) {
} }
export class ProjectDeviceRepository { export class ProjectDeviceRepository {
constructor(private readonly database: AppDatabase) {}
async listByProject(projectId: string) { async listByProject(projectId: string) {
const db = this.database;
const rows = await db.select().from(projectDevices).where(eq(projectDevices.projectId, projectId)); const rows = await db.select().from(projectDevices).where(eq(projectDevices.projectId, projectId));
return rows.map(withTotalPower); return rows.map(withTotalPower);
} }
async findById(projectId: string, projectDeviceId: string) { async findById(projectId: string, projectDeviceId: string) {
const db = this.database;
const [row] = await db const [row] = await db
.select() .select()
.from(projectDevices) .from(projectDevices)
+6 -1
View File
@@ -1,17 +1,21 @@
import crypto from "node:crypto"; import crypto from "node:crypto";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "../client.js"; import type { AppDatabase } from "../database-context.js";
import { projects } from "../schema/projects.js"; import { projects } from "../schema/projects.js";
import type { import type {
CreateProjectInput, CreateProjectInput,
} from "../../shared/validation/project-structure.schemas.js"; } from "../../shared/validation/project-structure.schemas.js";
export class ProjectRepository { export class ProjectRepository {
constructor(private readonly database: AppDatabase) {}
async list() { async list() {
const db = this.database;
return db.select().from(projects); return db.select().from(projects);
} }
async create(input: CreateProjectInput) { async create(input: CreateProjectInput) {
const db = this.database;
const id = crypto.randomUUID(); const id = crypto.randomUUID();
const project = { const project = {
id, id,
@@ -25,6 +29,7 @@ export class ProjectRepository {
} }
async findById(projectId: string) { async findById(projectId: string) {
const db = this.database;
const [row] = await db.select().from(projects).where(eq(projects.id, projectId)).limit(1); const [row] = await db.select().from(projects).where(eq(projects.id, projectId)).limit(1);
return row ?? null; return row ?? null;
} }
+4 -1
View File
@@ -1,9 +1,12 @@
import { asc, eq } from "drizzle-orm"; import { asc, eq } from "drizzle-orm";
import { db } from "../client.js"; import type { AppDatabase } from "../database-context.js";
import { rooms } from "../schema/rooms.js"; import { rooms } from "../schema/rooms.js";
export class RoomRepository { export class RoomRepository {
constructor(private readonly database: AppDatabase) {}
async listByProject(projectId: string) { async listByProject(projectId: string) {
const db = this.database;
return db return db
.select() .select()
.from(rooms) .from(rooms)
@@ -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);
@@ -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 { CircuitNumberingService } from "../../domain/services/circuit-numbering.service.js";
import {
circuitRepository,
circuitSectionRepository,
} from "./application-repositories.js";
export const circuitNumberingService = new CircuitNumberingService({ export const circuitNumberingService = new CircuitNumberingService({
sectionRepository: new CircuitSectionRepository(), sectionRepository: circuitSectionRepository,
circuitRepository: new CircuitRepository(), circuitRepository,
}); });
@@ -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 { ProjectDeviceSyncService } from "../../domain/services/project-device-sync.service.js";
import {
circuitDeviceRowRepository,
projectDeviceRepository,
} from "./application-repositories.js";
export const projectDeviceSyncService = new ProjectDeviceSyncService({ export const projectDeviceSyncService = new ProjectDeviceSyncService({
projectDeviceRepository: new ProjectDeviceRepository(), projectDeviceRepository,
deviceRowRepository: new CircuitDeviceRowRepository(), deviceRowRepository: circuitDeviceRowRepository,
}); });
@@ -1,7 +1,5 @@
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { CircuitListRepository } from "../../db/repositories/circuit-list.repository.js"; import { circuitListRepository } from "../composition/application-repositories.js";
const circuitListRepository = new CircuitListRepository();
export async function listCircuitListsByProject(req: Request, res: Response) { export async function listCircuitListsByProject(req: Request, res: Response) {
const { projectId } = req.params; const { projectId } = req.params;
@@ -1,20 +1,16 @@
import type { Request, Response } from "express"; 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 { import {
calculateCircuitTotalPower, calculateCircuitTotalPower,
calculateRowTotalPower, calculateRowTotalPower,
} from "../../domain/calculations/circuit-power-calculation.js"; } from "../../domain/calculations/circuit-power-calculation.js";
import type { CircuitTreeResponse } from "../../domain/models/circuit-tree.model.js"; import type { CircuitTreeResponse } from "../../domain/models/circuit-tree.model.js";
import {
const circuitListRepository = new CircuitListRepository(); circuitDeviceRowRepository,
const circuitSectionRepository = new CircuitSectionRepository(); circuitListRepository,
const circuitRepository = new CircuitRepository(); circuitRepository,
const circuitDeviceRowRepository = new CircuitDeviceRowRepository(); circuitSectionRepository,
const projectRepository = new ProjectRepository(); projectRepository,
} from "../composition/application-repositories.js";
export function isMissingCircuitTreeSchemaError(error: unknown): boolean { export function isMissingCircuitTreeSchemaError(error: unknown): boolean {
if (!(error instanceof Error)) { if (!(error instanceof Error)) {
@@ -1,16 +1,13 @@
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { db } from "../../db/client.js";
import { DistributionBoardRepository } from "../../db/repositories/distribution-board.repository.js";
import { import {
createDistributionBoardInsertProjectCommand, createDistributionBoardInsertProjectCommand,
createDistributionBoardStructureSnapshot, createDistributionBoardStructureSnapshot,
} from "../../domain/models/distribution-board-structure-project-command.model.js"; } from "../../domain/models/distribution-board-structure-project-command.model.js";
import { createDistributionBoardSchema } from "../../shared/validation/project-structure.schemas.js"; import { createDistributionBoardSchema } from "../../shared/validation/project-structure.schemas.js";
import { projectCommandService } from "../composition/project-command-stores.js"; import { projectCommandService } from "../composition/project-command-stores.js";
import { distributionBoardRepository } from "../composition/application-repositories.js";
import { respondWithProjectCommandError } from "./project-command.controller.js"; import { respondWithProjectCommandError } from "./project-command.controller.js";
const distributionBoardRepository = new DistributionBoardRepository(db);
export async function listDistributionBoardsByProject(req: Request, res: Response) { export async function listDistributionBoardsByProject(req: Request, res: Response) {
const { projectId } = req.params; const { projectId } = req.params;
if (typeof projectId !== "string") { if (typeof projectId !== "string") {
+1 -3
View File
@@ -1,15 +1,13 @@
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { FloorRepository } from "../../db/repositories/floor.repository.js";
import { import {
createProjectFloorInsertProjectCommand, createProjectFloorInsertProjectCommand,
createProjectFloorSnapshot, createProjectFloorSnapshot,
} from "../../domain/models/project-location-structure-project-command.model.js"; } from "../../domain/models/project-location-structure-project-command.model.js";
import { createFloorSchema } from "../../shared/validation/project-structure.schemas.js"; import { createFloorSchema } from "../../shared/validation/project-structure.schemas.js";
import { projectCommandService } from "../composition/project-command-stores.js"; import { projectCommandService } from "../composition/project-command-stores.js";
import { floorRepository } from "../composition/application-repositories.js";
import { respondWithProjectCommandError } from "./project-command.controller.js"; import { respondWithProjectCommandError } from "./project-command.controller.js";
const floorRepository = new FloorRepository();
export async function listFloorsByProject(req: Request, res: Response) { export async function listFloorsByProject(req: Request, res: Response) {
const { projectId } = req.params; const { projectId } = req.params;
if (typeof projectId !== "string") { if (typeof projectId !== "string") {
@@ -1,13 +1,12 @@
import type { Request, Response } from "express"; 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 { import {
createGlobalDeviceSchema, createGlobalDeviceSchema,
updateGlobalDeviceSchema, updateGlobalDeviceSchema,
} from "../../shared/validation/global-device.schemas.js"; } from "../../shared/validation/global-device.schemas.js";
import {
const globalDeviceRepository = new GlobalDeviceRepository(); globalDeviceRepository,
const projectDeviceRepository = new ProjectDeviceRepository(); projectDeviceRepository,
} from "../composition/application-repositories.js";
export async function listGlobalDevices(_req: Request, res: Response) { export async function listGlobalDevices(_req: Request, res: Response) {
const rows = await globalDeviceRepository.list(); const rows = await globalDeviceRepository.list();
@@ -1,7 +1,5 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import type { Request, Response } from "express"; 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 { createProjectDeviceUpdateProjectCommand } from "../../domain/models/project-device-project-command.model.js";
import { import {
createProjectDeviceDeleteProjectCommand, createProjectDeviceDeleteProjectCommand,
@@ -10,6 +8,10 @@ import {
} from "../../domain/models/project-device-structure-project-command.model.js"; } from "../../domain/models/project-device-structure-project-command.model.js";
import { projectDeviceSyncService } from "../composition/project-device-sync-service.js"; import { projectDeviceSyncService } from "../composition/project-device-sync-service.js";
import { projectCommandService } from "../composition/project-command-stores.js"; import { projectCommandService } from "../composition/project-command-stores.js";
import {
globalDeviceRepository,
projectDeviceRepository,
} from "../composition/application-repositories.js";
import { import {
createProjectDeviceCommandSchema, createProjectDeviceCommandSchema,
disconnectProjectDeviceRowsSchema, disconnectProjectDeviceRowsSchema,
@@ -20,8 +22,6 @@ import {
import type { CreateProjectDeviceInput } from "../../shared/validation/project-device.schemas.js"; import type { CreateProjectDeviceInput } from "../../shared/validation/project-device.schemas.js";
import { respondWithProjectCommandError } from "./project-command.controller.js"; import { respondWithProjectCommandError } from "./project-command.controller.js";
const globalDeviceRepository = new GlobalDeviceRepository();
const projectDeviceRepository = new ProjectDeviceRepository();
export async function listProjectDevicesByProject(req: Request, res: Response) { export async function listProjectDevicesByProject(req: Request, res: Response) {
const { projectId } = req.params; const { projectId } = req.params;
if (typeof projectId !== "string") { if (typeof projectId !== "string") {
+1 -3
View File
@@ -1,15 +1,13 @@
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { ProjectRepository } from "../../db/repositories/project.repository.js";
import { import {
createProjectSchema, createProjectSchema,
updateProjectSettingsSchema, updateProjectSettingsSchema,
} from "../../shared/validation/project-structure.schemas.js"; } from "../../shared/validation/project-structure.schemas.js";
import { createProjectSettingsUpdateProjectCommand } from "../../domain/models/project-settings-project-command.model.js"; import { createProjectSettingsUpdateProjectCommand } from "../../domain/models/project-settings-project-command.model.js";
import { projectCommandService } from "../composition/project-command-stores.js"; import { projectCommandService } from "../composition/project-command-stores.js";
import { projectRepository } from "../composition/application-repositories.js";
import { respondWithProjectCommandError } from "./project-command.controller.js"; import { respondWithProjectCommandError } from "./project-command.controller.js";
const projectRepository = new ProjectRepository();
export async function listProjects(_req: Request, res: Response) { export async function listProjects(_req: Request, res: Response) {
const result = await projectRepository.list(); const result = await projectRepository.list();
res.json(result); res.json(result);
+1 -3
View File
@@ -1,15 +1,13 @@
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { RoomRepository } from "../../db/repositories/room.repository.js";
import { import {
createProjectRoomInsertProjectCommand, createProjectRoomInsertProjectCommand,
createProjectRoomSnapshot, createProjectRoomSnapshot,
} from "../../domain/models/project-location-structure-project-command.model.js"; } from "../../domain/models/project-location-structure-project-command.model.js";
import { createRoomSchema } from "../../shared/validation/project-structure.schemas.js"; import { createRoomSchema } from "../../shared/validation/project-structure.schemas.js";
import { projectCommandService } from "../composition/project-command-stores.js"; import { projectCommandService } from "../composition/project-command-stores.js";
import { roomRepository } from "../composition/application-repositories.js";
import { respondWithProjectCommandError } from "./project-command.controller.js"; import { respondWithProjectCommandError } from "./project-command.controller.js";
const roomRepository = new RoomRepository();
export async function listRoomsByProject(req: Request, res: Response) { export async function listRoomsByProject(req: Request, res: Response) {
const { projectId } = req.params; const { projectId } = req.params;
if (typeof projectId !== "string") { if (typeof projectId !== "string") {
+77
View File
@@ -10,6 +10,15 @@ import {
verifyDatabaseFile, verifyDatabaseFile,
} from "../src/db/database-backup.js"; } from "../src/db/database-backup.js";
import { createDatabaseContext } from "../src/db/database-context.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"; import { projects } from "../src/db/schema/projects.js";
describe("database backup and restore", () => { 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();
}
});
});