blackopsrepl's picture
Upload 30 files
50f82a1 verified
"""
Converters for bidirectional transformation between domain objects and API models.
"""
from datetime import date
from typing import Dict, List, Optional
from solverforge_legacy.solver import SolverStatus
from solverforge_legacy.solver.score import HardSoftScore
from . import domain
# ************************************************************************
# Helper functions
# ************************************************************************
def date_to_iso(d: Optional[date]) -> Optional[str]:
"""Convert a date to ISO format string."""
return d.isoformat() if d else None
def iso_to_date(s: Optional[str]) -> Optional[date]:
"""Convert an ISO format string to a date."""
return date.fromisoformat(s) if s else None
# ************************************************************************
# Domain -> Model conversions
# ************************************************************************
def work_calendar_to_model(wc: domain.WorkCalendar) -> domain.WorkCalendarModel:
"""Convert a WorkCalendar domain object to its API model."""
return domain.WorkCalendarModel(
id=wc.id,
from_date=date_to_iso(wc.from_date),
to_date=date_to_iso(wc.to_date),
)
def crew_to_model(crew: domain.Crew) -> domain.CrewModel:
"""Convert a Crew domain object to its API model."""
return domain.CrewModel(id=crew.id, name=crew.name)
def job_to_model(job: domain.Job) -> domain.JobModel:
"""Convert a Job domain object to its API model."""
return domain.JobModel(
id=job.id,
name=job.name,
duration_in_days=job.duration_in_days,
min_start_date=date_to_iso(job.min_start_date),
max_end_date=date_to_iso(job.max_end_date),
ideal_end_date=date_to_iso(job.ideal_end_date),
tags=list(job.tags),
crew=crew_to_model(job.crew) if job.crew else None,
start_date=date_to_iso(job.start_date),
end_date=date_to_iso(job.get_end_date()),
)
def schedule_to_model(schedule: domain.MaintenanceSchedule) -> domain.MaintenanceScheduleModel:
"""Convert a MaintenanceSchedule domain object to its API model."""
return domain.MaintenanceScheduleModel(
work_calendar=work_calendar_to_model(schedule.work_calendar),
crews=[crew_to_model(c) for c in schedule.crews],
jobs=[job_to_model(j) for j in schedule.jobs],
start_date_range=[date_to_iso(d) for d in schedule.start_date_range],
score=str(schedule.score) if schedule.score else None,
solver_status=schedule.solver_status.name if schedule.solver_status else None,
)
# ************************************************************************
# Model -> Domain conversions
# ************************************************************************
def model_to_work_calendar(model: domain.WorkCalendarModel) -> domain.WorkCalendar:
"""Convert a WorkCalendarModel to its domain object."""
return domain.WorkCalendar(
id=model.id,
from_date=iso_to_date(model.from_date),
to_date=iso_to_date(model.to_date),
)
def model_to_crew(model: domain.CrewModel) -> domain.Crew:
"""Convert a CrewModel to its domain object."""
return domain.Crew(id=model.id, name=model.name)
def model_to_schedule(model: domain.MaintenanceScheduleModel) -> domain.MaintenanceSchedule:
"""
Convert a MaintenanceScheduleModel to its domain object.
Handles reference resolution for crew assignments.
"""
# Create work calendar
work_calendar = model_to_work_calendar(model.work_calendar)
# Create crews and lookup
crews: List[domain.Crew] = [model_to_crew(c) for c in model.crews]
crew_lookup: Dict[str, domain.Crew] = {c.id: c for c in crews}
# Create jobs with crew references resolved
jobs: List[domain.Job] = []
for job_model in model.jobs:
# Resolve crew reference
crew = None
if job_model.crew:
if isinstance(job_model.crew, str):
crew = crew_lookup.get(job_model.crew)
elif isinstance(job_model.crew, domain.CrewModel):
crew = crew_lookup.get(job_model.crew.id)
job = domain.Job(
id=job_model.id,
name=job_model.name,
duration_in_days=job_model.duration_in_days,
min_start_date=iso_to_date(job_model.min_start_date),
max_end_date=iso_to_date(job_model.max_end_date),
ideal_end_date=iso_to_date(job_model.ideal_end_date),
tags=set(job_model.tags) if job_model.tags else set(),
crew=crew,
start_date=iso_to_date(job_model.start_date) if job_model.start_date else None,
)
jobs.append(job)
# Parse start_date_range
start_date_range = (
[iso_to_date(d) for d in model.start_date_range]
if model.start_date_range
else []
)
# Parse score
score = None
if model.score:
score = HardSoftScore.parse(model.score)
# Parse solver status
solver_status = SolverStatus.NOT_SOLVING
if model.solver_status:
solver_status = SolverStatus[model.solver_status]
return domain.MaintenanceSchedule(
work_calendar=work_calendar,
crews=crews,
jobs=jobs,
start_date_range=start_date_range,
score=score,
solver_status=solver_status,
)