"""Business rules for the minimal component registry.""" from uuid import UUID from app.components.exceptions import ( ComponentActorRequired, ComponentNotFound, ComponentValidationError, DuplicateComponentAssetID, ) from app.components.models import ComponentCreateRequest, ComponentDetail from app.components.repository import ComponentRepository class ComponentService: """Minimal component workflows independent of FastAPI.""" def __init__(self, repository: ComponentRepository): self.repository = repository @staticmethod def _normalize_optional_text(value: str | None, field_name: str) -> str | None: if value is None: return None normalized = str(value).strip() if not normalized: raise ComponentValidationError( f"{field_name} must not be blank when supplied" ) if len(normalized) > 255: raise ComponentValidationError( f"{field_name} must not exceed 255 characters" ) return normalized @staticmethod def _map_component(component: dict) -> ComponentDetail: return ComponentDetail(**component) def create_component( self, request: ComponentCreateRequest, *, actor_user_id: UUID | None, ) -> ComponentDetail: if actor_user_id is None: raise ComponentActorRequired() asset_id = self._normalize_optional_text(request.asset_id, "asset_id") values = { "manufacturer": self._normalize_optional_text( request.manufacturer, "manufacturer" ), "model": self._normalize_optional_text(request.model, "model"), "manufacturer_serial": self._normalize_optional_text( request.manufacturer_serial, "manufacturer_serial" ), } try: with self.repository.transaction() as repository: component = repository.create_component( component_type=request.component_type, asset_id=asset_id, created_by=actor_user_id, **values, ) except DuplicateComponentAssetID as exc: raise DuplicateComponentAssetID(asset_id or "") from exc return self._map_component(component) def get_component(self, component_id: UUID) -> ComponentDetail: component = self.repository.get_component(component_id) if component is None: raise ComponentNotFound(component_id) return self._map_component(component)