Files
leistungsbilanz-ts/src/db/repositories/project-command-transaction.persistence.ts
T

97 lines
3.0 KiB
TypeScript

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<unknown>,
> {
projectId: string;
expectedRevision: number;
source: ProjectRevisionSource;
description?: string;
actorId?: string;
historyTargetChangeSetId?: string;
command: Command;
}
export interface AppliedProjectCommand<
Forward extends SerializedProjectCommand<unknown>,
Inverse extends SerializedProjectCommand<unknown>,
> {
forward: Forward;
inverse: Inverse;
}
export function executeProjectCommandTransaction<
Command extends SerializedProjectCommand<unknown>,
Inverse extends SerializedProjectCommand<unknown>,
>(
database: AppDatabase,
input: ProjectCommandTransactionInput<Command>,
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<unknown>,
Forward extends SerializedProjectCommand<unknown>,
Inverse extends SerializedProjectCommand<unknown>,
>(
database: AppDatabase,
input: ProjectCommandTransactionInput<Command>,
applyCommand: (
transaction: AppDatabase
) => AppliedProjectCommand<Forward, Inverse>
): { revision: AppendedProjectRevision; inverse: Inverse } {
return executeAppliedProjectCommandTransaction(
database,
input,
applyCommand
);
}
function executeAppliedProjectCommandTransaction<
Command extends SerializedProjectCommand<unknown>,
Forward extends SerializedProjectCommand<unknown>,
Inverse extends SerializedProjectCommand<unknown>,
>(
database: AppDatabase,
input: ProjectCommandTransactionInput<Command>,
applyCommand: (
transaction: AppDatabase
) => AppliedProjectCommand<Forward, Inverse>
): { 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 };
});
}