import type { SerializedProjectCommand } from "../../domain/models/project-command.model.js"; import type { AppendedProjectRevision, ProjectRevisionSource, } from "../../domain/ports/project-revision.store.js"; import type { AppDatabase } from "../database-context.js"; import { applyProjectHistoryTransition } from "./project-history.persistence.js"; import { appendProjectRevision } from "./project-revision.persistence.js"; export interface ProjectCommandTransactionInput< Command extends SerializedProjectCommand, > { projectId: string; expectedRevision: number; source: ProjectRevisionSource; description?: string; actorId?: string; historyTargetChangeSetId?: string; command: Command; } export interface AppliedProjectCommand< Forward extends SerializedProjectCommand, Inverse extends SerializedProjectCommand, > { forward: Forward; inverse: Inverse; } export function executeProjectCommandTransaction< Command extends SerializedProjectCommand, Inverse extends SerializedProjectCommand, >( database: AppDatabase, input: ProjectCommandTransactionInput, applyCommand: (transaction: AppDatabase) => Inverse ): { revision: AppendedProjectRevision; inverse: Inverse } { return executeAppliedProjectCommandTransaction( database, input, (transaction) => ({ forward: input.command, inverse: applyCommand(transaction), }) ); } export function executeProjectCommandTransactionWithAppliedForward< Command extends SerializedProjectCommand, Forward extends SerializedProjectCommand, Inverse extends SerializedProjectCommand, >( database: AppDatabase, input: ProjectCommandTransactionInput, applyCommand: ( transaction: AppDatabase ) => AppliedProjectCommand ): { revision: AppendedProjectRevision; inverse: Inverse } { return executeAppliedProjectCommandTransaction( database, input, applyCommand ); } function executeAppliedProjectCommandTransaction< Command extends SerializedProjectCommand, Forward extends SerializedProjectCommand, Inverse extends SerializedProjectCommand, >( database: AppDatabase, input: ProjectCommandTransactionInput, applyCommand: ( transaction: AppDatabase ) => AppliedProjectCommand ): { revision: AppendedProjectRevision; inverse: Inverse } { return database.transaction((tx) => { const { forward, inverse } = applyCommand(tx); const revision = appendProjectRevision(tx, { projectId: input.projectId, expectedRevision: input.expectedRevision, source: input.source, description: input.description, actorId: input.actorId, forward, inverse, }); applyProjectHistoryTransition(tx, { projectId: input.projectId, source: input.source, recordedChangeSetId: revision.changeSetId, targetChangeSetId: input.historyTargetChangeSetId, }); return { revision, inverse }; }); }