Files
tech-log-frontend/src/features/reference-feature/contracts/reference-mapper.ts
T

98 lines
2.9 KiB
TypeScript

import {
createReferenceResource,
type ReferenceResource,
} from "../domain/reference-resource.ts";
import {
mappingFailure,
mappingSuccess,
type MappingResult,
type InstalledBoundaryMapper,
} from "../../../contracts/boundary-mapper.ts";
export type ReferenceResourceView = Readonly<{
resourceId: string;
title: string;
createdAt: string | null;
optimistic?: boolean;
}>;
function mapReferenceDto(value: unknown): MappingResult<ReferenceResource> {
if (!value || typeof value !== "object") {
return mappingFailure("MAPPING_INVARIANT_REJECTED");
}
const dto = value as Record<string, unknown>;
if (typeof dto.id !== "string" || typeof dto.name !== "string") {
return mappingFailure("MAPPING_INVARIANT_REJECTED");
}
try {
return mappingSuccess(
createReferenceResource({
id: dto.id,
displayName: dto.name,
createdAt: typeof dto.createdAt === "string" ? dto.createdAt : null,
}),
);
} catch {
return mappingFailure("MAPPING_INVARIANT_REJECTED");
}
}
export function mapReferenceOperation(
operationId: string,
payload: unknown,
): MappingResult<ReferenceResource | readonly ReferenceResource[]> {
if (operationId === "LIST_REFERENCE_RESOURCES") {
if (!Array.isArray(payload)) {
return mappingFailure("MAPPING_INVARIANT_REJECTED");
}
if (payload.length > 100) return mappingFailure("OUTPUT_LIMIT_EXCEEDED");
const output: ReferenceResource[] = [];
for (const item of payload) {
const mapped = mapReferenceDto(item);
if (!mapped.ok) return mapped;
output.push(mapped.value);
}
return mappingSuccess(Object.freeze(output));
}
if (
operationId === "CREATE_REFERENCE_RESOURCE" ||
operationId === "GET_REFERENCE_RESOURCE"
) {
return mapReferenceDto(payload);
}
return mappingFailure("MAPPING_INVARIANT_REJECTED");
}
export const REFERENCE_BOUNDARY_MAPPERS = Object.freeze({
ReferenceResourceListMapper: Object.freeze({
mapperId: "ReferenceResourceListMapper",
mapperVersion: 1,
inputSchemaId: "ReferenceResourceListPayload",
outputContractId: "ReferenceResourceList",
owner: "feature-frontend-reference-feature-vertical-slice",
maxOutputItems: 100,
map: (input: unknown) =>
mapReferenceOperation("LIST_REFERENCE_RESOURCES", input),
}),
ReferenceResourceMapper: Object.freeze({
mapperId: "ReferenceResourceMapper",
mapperVersion: 1,
inputSchemaId: "ReferenceResourcePayload",
outputContractId: "ReferenceResource",
owner: "feature-frontend-reference-feature-vertical-slice",
maxOutputItems: 1,
map: (input: unknown) =>
mapReferenceOperation("GET_REFERENCE_RESOURCE", input),
}),
} satisfies Readonly<Record<string, InstalledBoundaryMapper>>);
export function toReferenceView(
resource: ReferenceResource,
): ReferenceResourceView {
return Object.freeze({
resourceId: resource.id,
title: resource.displayName,
createdAt: resource.createdAt,
});
}