import crypto from "node:crypto"; import { and, eq } from "drizzle-orm"; import type { CircuitDeviceRowTransactionStore, CreateCircuitDeviceRowTransactionInput, CreateCircuitWithDeviceRowsTransactionInput, } from "../../domain/ports/circuit-device-row-transaction.store.js"; import type { AppDatabase } from "../database-context.js"; import { circuitDeviceRows } from "../schema/circuit-device-rows.js"; import { circuits } from "../schema/circuits.js"; import { toCircuitCreateValues } from "./circuit.persistence.js"; import { toCircuitDeviceRowCreateValues, } from "./circuit-device-row.persistence.js"; export class CircuitDeviceRowTransactionRepository implements CircuitDeviceRowTransactionStore { constructor(private readonly database: AppDatabase) {} createInCircuit(input: CreateCircuitDeviceRowTransactionInput) { const id = crypto.randomUUID(); this.database.transaction((tx) => { const [circuit] = tx .select({ id: circuits.id }) .from(circuits) .where(eq(circuits.id, input.circuitId)) .limit(1) .all(); if (!circuit) { throw new Error("Der Stromkreis ist ungültig."); } const existingRows = tx .select({ sortOrder: circuitDeviceRows.sortOrder }) .from(circuitDeviceRows) .where(eq(circuitDeviceRows.circuitId, input.circuitId)) .all(); const lastSortOrder = existingRows.reduce( (highest, row) => Math.max(highest, row.sortOrder), 0 ); const sortOrder = input.sortOrder ?? lastSortOrder + 10; tx .insert(circuitDeviceRows) .values(toCircuitDeviceRowCreateValues(id, { ...input, sortOrder })) .run(); tx .update(circuits) .set({ isReserve: 0 }) .where(eq(circuits.id, input.circuitId)) .run(); }); return id; } createCircuitWithDeviceRows(input: CreateCircuitWithDeviceRowsTransactionInput) { if (input.deviceRows.length === 0) { throw new Error("Mindestens eine Gerätezeile ist erforderlich."); } const circuitId = crypto.randomUUID(); const rowIds = input.deviceRows.map(() => crypto.randomUUID()); this.database.transaction((tx) => { tx .insert(circuits) .values( toCircuitCreateValues(circuitId, { ...input.circuit, isReserve: false, }) ) .run(); for (let index = 0; index < input.deviceRows.length; index += 1) { const row = input.deviceRows[index]; tx .insert(circuitDeviceRows) .values( toCircuitDeviceRowCreateValues(rowIds[index], { ...row, circuitId, sortOrder: row.sortOrder ?? (index + 1) * 10, }) ) .run(); } }); return { circuitId, rowIds }; } deleteFromCircuit(rowId: string, expectedCircuitId: string) { this.database.transaction((tx) => { const [row] = tx .select({ id: circuitDeviceRows.id, circuitId: circuitDeviceRows.circuitId }) .from(circuitDeviceRows) .where(eq(circuitDeviceRows.id, rowId)) .limit(1) .all(); if (!row || row.circuitId !== expectedCircuitId) { throw new Error("Die Gerätezeile wurde vor dem Löschen verändert."); } const result = tx .delete(circuitDeviceRows) .where( and( eq(circuitDeviceRows.id, rowId), eq(circuitDeviceRows.circuitId, expectedCircuitId) ) ) .run(); if (result.changes !== 1) { throw new Error("Die Gerätezeile konnte nicht gelöscht werden."); } const remainingRows = tx .select({ id: circuitDeviceRows.id }) .from(circuitDeviceRows) .where(eq(circuitDeviceRows.circuitId, expectedCircuitId)) .all(); tx .update(circuits) .set({ isReserve: remainingRows.length === 0 ? 1 : 0 }) .where(eq(circuits.id, expectedCircuitId)) .run(); }); } }