/** * Company Mapper * * Handles transformations between Company domain entities and DTOs. * Uses Zod schemas from @archer/api-interface for validation. * * Transformations: * - toDomain: DTO (persistence) → Domain entity * - toDTO: Domain entity → DTO (persistence) * - fromRequest: Request data → Domain entity * * @layer Application */ import { companyResponseSchema, createCompanyRequestSchema, updateCompanyRequestSchema, } from '@archer/api-interface'; import { Company, CompanyType } from '../../domain/entities/Company'; import type { IMapper } from './IMapper'; /** * Company DTO (persistence format) * * Matches the structure returned by companyResponseSchema */ interface CompanyDTO { id: string; name: string; type: 'platform_admin' | 'client'; createdAt: string | Date; updatedAt: string | Date; } /** * CompanyMapper * * Implements IMapper for Company entity transformations. * Uses Zod schemas for runtime validation. */ export class CompanyMapper implements IMapper { /** * Converts DTO to domain entity * * @param dto - Company DTO from persistence * @returns Company domain entity * @throws Error if DTO validation fails */ toDomain(dto: CompanyDTO): Company { // Validate DTO structure using Zod schema const validated = companyResponseSchema.parse({ id: dto.id, name: dto.name, type: dto.type, createdAt: dto.createdAt, updatedAt: dto.updatedAt, }); // Map API enum values to domain enum values const domainType = this.mapToDomainType(validated.type); // Reconstruct domain entity from persistence return Company.fromPersistence({ id: validated.id, name: validated.name, type: domainType, createdAt: validated.createdAt, updatedAt: validated.updatedAt, }); } /** * Converts domain entity to DTO * * @param entity - Company domain entity * @returns Company DTO for persistence */ toDTO(entity: Company): CompanyDTO { // Map domain enum to API enum const apiType = this.mapToApiType(entity.type); return { id: entity.id, name: entity.name, type: apiType, createdAt: entity.createdAt.toISOString(), updatedAt: entity.updatedAt.toISOString(), }; } /** * Converts request data to domain entity (for create operations) * * @param request - Create company request data * @returns Company domain entity * @throws Error if request validation fails */ fromRequest(request: unknown): Company { // Validate request using Zod schema const validated = createCompanyRequestSchema.parse(request); // Map API enum to domain enum const domainType = this.mapToDomainType(validated.type); // Generate new ID const id = crypto.randomUUID(); // Create new domain entity return Company.create({ id, name: validated.name, type: domainType, }); } /** * Converts update request data to partial domain entity * * @param request - Update company request data * @param existingCompany - Existing company entity * @returns Updated Company domain entity * @throws Error if request validation fails */ fromUpdateRequest(request: unknown, existingCompany: Company): Company { // Validate update request using Zod schema const validated = updateCompanyRequestSchema.parse(request); // Apply updates to existing company return existingCompany.update({ name: validated.name, // Note: Type is immutable per API schema }); } /** * Maps API enum type to domain enum type * * @param apiType - API company type ('platform_admin' | 'client' | 'supplier' | 'partner') * @returns Domain CompanyType */ private mapToDomainType( apiType: 'platform_admin' | 'client' | 'supplier' | 'partner', ): CompanyType { switch (apiType) { case 'platform_admin': return CompanyType.INDIVIDUAL; // Map platform_admin to INDIVIDUAL case 'client': return CompanyType.CORPORATE; // Map client to CORPORATE case 'supplier': case 'partner': // New types - map to CORPORATE for now (future: add SUPPLIER/PARTNER to dashboard) return CompanyType.CORPORATE; default: // TypeScript exhaustiveness check const _exhaustive: never = apiType; throw new Error(`Unknown API company type: ${_exhaustive}`); } } /** * Maps domain enum type to API enum type * * @param domainType - Domain CompanyType * @returns API company type ('platform_admin' | 'client') */ private mapToApiType(domainType: CompanyType): 'platform_admin' | 'client' { switch (domainType) { case CompanyType.INDIVIDUAL: return 'platform_admin'; // Map INDIVIDUAL to platform_admin case CompanyType.CORPORATE: return 'client'; // Map CORPORATE to client default: // TypeScript exhaustiveness check const _exhaustive: never = domainType; throw new Error(`Unknown domain company type: ${_exhaustive}`); } } /** * Batch conversion: DTOs to domain entities * * @param dtos - Array of company DTOs * @returns Array of Company domain entities */ toDomainArray(dtos: CompanyDTO[]): Company[] { return dtos.map((dto) => this.toDomain(dto)); } /** * Batch conversion: domain entities to DTOs * * @param entities - Array of Company domain entities * @returns Array of company DTOs */ toDTOArray(entities: Company[]): CompanyDTO[] { return entities.map((entity) => this.toDTO(entity)); } } // Export singleton instance for use across application export const companyMapper = new CompanyMapper();