/** * DrugMapper - Infrastructure Layer * Convierte entre Domain (Drug) y Persistence (DB rows). */ import type { Drug, AdministrationRoute, DrugCategory } from '../../domain/entities/Drug.js'; import { ContentStatus } from '../../domain/value-objects/ContentStatus.js'; export interface DrugRow { id: string; slug: string; generic_name: string; trade_name?: string | null; category: string; line: string; frequency: string; presentation: string; adult_dose: string; pediatric_dose?: string | null; routes?: string[] | null; dilution?: string | null; indications?: string[] | null; contraindications?: string[] | null; side_effects?: string | null; antidote?: string | null; notes?: string[] | null; critical_points?: string[] | null; source?: string | null; status: string; version: string; latest_version: string; created_at: Date | string; updated_at: Date | string; created_by: string; updated_by?: string | null; } /** * Convierte una fila de BD a entidad de dominio. */ export function toDomain(row: DrugRow): Drug { const status = typeof row.status === 'string' ? ContentStatus.fromString(row.status) : ContentStatus.DRAFT; const createdAt = row.created_at instanceof Date ? row.created_at : new Date(String(row.created_at)); const updatedAt = row.updated_at instanceof Date ? row.updated_at : new Date(String(row.updated_at)); return { id: row.id, slug: row.slug, genericName: row.generic_name, tradeName: row.trade_name ?? undefined, category: row.category as DrugCategory, line: row.line === 'first' || row.line === 'second' ? row.line : 'first', frequency: row.frequency === 'high' || row.frequency === 'medium' || row.frequency === 'low' ? row.frequency : 'medium', presentation: row.presentation, adultDose: row.adult_dose, pediatricDose: row.pediatric_dose ?? undefined, routes: (row.routes ?? []) as AdministrationRoute[], dilution: row.dilution ?? undefined, indications: row.indications ?? [], contraindications: row.contraindications ?? [], sideEffects: row.side_effects ?? undefined, antidote: row.antidote ?? undefined, notes: row.notes ?? [], criticalPoints: row.critical_points ?? [], source: row.source ?? undefined, status, version: row.version ?? '1.0.0', latestVersion: row.latest_version ?? row.version ?? '1.0.0', createdAt, updatedAt, createdBy: row.created_by, updatedBy: row.updated_by ?? undefined, }; } /** * Convierte entidad de dominio a objeto para persistencia (snake_case). */ export function toPersistence(drug: Drug): Record { return { id: drug.id, slug: drug.slug, generic_name: drug.genericName, trade_name: drug.tradeName ?? null, category: drug.category, line: drug.line, frequency: drug.frequency, presentation: drug.presentation, adult_dose: drug.adultDose, pediatric_dose: drug.pediatricDose ?? null, routes: [...drug.routes], dilution: drug.dilution ?? null, indications: [...drug.indications], contraindications: [...drug.contraindications], side_effects: drug.sideEffects ?? null, antidote: drug.antidote ?? null, notes: [...drug.notes], critical_points: [...drug.criticalPoints], source: drug.source ?? null, status: drug.status.toString(), version: drug.version, latest_version: drug.latestVersion, created_by: drug.createdBy, updated_by: drug.updatedBy ?? drug.createdBy, }; }