95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
import { assertExternalCsvConfiguration } from "../../external-model/csv/external-csv-configuration.js";
|
|
import type { ExternalCsvConfiguration } from "../../external-model/csv/external-csv-contracts.js";
|
|
import type { SerializedProjectCommand } from "./project-command.model.js";
|
|
|
|
export const externalCsvConfigurationUpdateCommandType =
|
|
"external-csv-configuration.update" as const;
|
|
export const externalCsvConfigurationCommandSchemaVersion = 1 as const;
|
|
|
|
export interface ExternalCsvConfigurationSnapshot {
|
|
id: string;
|
|
projectId: string;
|
|
configurationVersion: number;
|
|
configuration: ExternalCsvConfiguration;
|
|
}
|
|
|
|
export interface ExternalCsvConfigurationUpdatePayload {
|
|
expected: ExternalCsvConfigurationSnapshot | null;
|
|
target: ExternalCsvConfigurationSnapshot | null;
|
|
}
|
|
|
|
export interface ExternalCsvConfigurationUpdateProjectCommand
|
|
extends SerializedProjectCommand<ExternalCsvConfigurationUpdatePayload> {
|
|
schemaVersion: typeof externalCsvConfigurationCommandSchemaVersion;
|
|
type: typeof externalCsvConfigurationUpdateCommandType;
|
|
}
|
|
|
|
export function createExternalCsvConfigurationUpdateProjectCommand(
|
|
expected: ExternalCsvConfigurationSnapshot | null,
|
|
target: ExternalCsvConfigurationSnapshot | null
|
|
): ExternalCsvConfigurationUpdateProjectCommand {
|
|
const command: ExternalCsvConfigurationUpdateProjectCommand = {
|
|
schemaVersion: externalCsvConfigurationCommandSchemaVersion,
|
|
type: externalCsvConfigurationUpdateCommandType,
|
|
payload: { expected, target },
|
|
};
|
|
assertExternalCsvConfigurationUpdateProjectCommand(command);
|
|
return command;
|
|
}
|
|
|
|
export function assertExternalCsvConfigurationUpdateProjectCommand(
|
|
command: SerializedProjectCommand<unknown>
|
|
): asserts command is ExternalCsvConfigurationUpdateProjectCommand {
|
|
if (
|
|
command.schemaVersion !== externalCsvConfigurationCommandSchemaVersion ||
|
|
command.type !== externalCsvConfigurationUpdateCommandType ||
|
|
!isRecord(command.payload)
|
|
) {
|
|
throw new Error("Unsupported external CSV configuration update command.");
|
|
}
|
|
assertSnapshot(command.payload.expected, "expected");
|
|
assertSnapshot(command.payload.target, "target");
|
|
if (command.payload.expected === null && command.payload.target === null) {
|
|
throw new Error("External CSV configuration command must change state.");
|
|
}
|
|
if (
|
|
command.payload.expected !== null &&
|
|
command.payload.target !== null &&
|
|
(command.payload.expected.id !== command.payload.target.id ||
|
|
command.payload.expected.projectId !== command.payload.target.projectId)
|
|
) {
|
|
throw new Error("External CSV configuration identity must remain stable.");
|
|
}
|
|
}
|
|
|
|
function assertSnapshot(
|
|
value: unknown,
|
|
field: string
|
|
): asserts value is ExternalCsvConfigurationSnapshot | null {
|
|
if (value === null) {
|
|
return;
|
|
}
|
|
if (!isRecord(value)) {
|
|
throw new Error(`${field} external CSV configuration must be an object or null.`);
|
|
}
|
|
assertId(value.id, `${field}.id`);
|
|
assertId(value.projectId, `${field}.projectId`);
|
|
if (!Number.isSafeInteger(value.configurationVersion) || (value.configurationVersion as number) < 1) {
|
|
throw new Error(`${field}.configurationVersion must be a positive integer.`);
|
|
}
|
|
assertExternalCsvConfiguration(value.configuration);
|
|
if (Object.keys(value).length !== 4) {
|
|
throw new Error(`${field} external CSV configuration contains unknown fields.`);
|
|
}
|
|
}
|
|
|
|
function assertId(value: unknown, field: string) {
|
|
if (typeof value !== "string" || !value.trim()) {
|
|
throw new Error(`${field} must be a non-empty string.`);
|
|
}
|
|
}
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
}
|