blackopsrepl's picture
Upload 30 files
50f82a1 verified
Raw
History Blame Contribute Delete
5.39 kB
"""
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,
)