# services/external/app/schemas/traffic.py """ Traffic Service Pydantic Schemas """ from pydantic import BaseModel, Field, field_validator from datetime import datetime from typing import Optional, List from uuid import UUID class TrafficDataBase(BaseModel): """Base traffic data schema""" location_id: str = Field(..., max_length=100, description="Traffic monitoring location ID") date: datetime = Field(..., description="Date and time of traffic measurement") traffic_volume: Optional[int] = Field(None, ge=0, description="Vehicles per hour") pedestrian_count: Optional[int] = Field(None, ge=0, description="Pedestrians per hour") congestion_level: Optional[str] = Field(None, pattern="^(low|medium|high)$", description="Traffic congestion level") average_speed: Optional[float] = Field(None, ge=0, le=200, description="Average speed in km/h") source: str = Field("madrid_opendata", max_length=50, description="Data source") raw_data: Optional[str] = Field(None, description="Raw data from source") class TrafficDataCreate(TrafficDataBase): """Schema for creating traffic data""" pass class TrafficDataUpdate(BaseModel): """Schema for updating traffic data""" traffic_volume: Optional[int] = Field(None, ge=0) pedestrian_count: Optional[int] = Field(None, ge=0) congestion_level: Optional[str] = Field(None, pattern="^(low|medium|high)$") average_speed: Optional[float] = Field(None, ge=0, le=200) raw_data: Optional[str] = None class TrafficDataResponseDB(TrafficDataBase): """Schema for traffic data responses from database""" id: str = Field(..., description="Unique identifier") created_at: datetime = Field(..., description="Creation timestamp") updated_at: datetime = Field(..., description="Last update timestamp") @field_validator('id', mode='before') @classmethod def convert_uuid_to_string(cls, v): if isinstance(v, UUID): return str(v) return v class Config: from_attributes = True json_encoders = { datetime: lambda v: v.isoformat() } class TrafficDataList(BaseModel): """Schema for paginated traffic data responses""" data: List[TrafficDataResponseDB] total: int = Field(..., description="Total number of records") page: int = Field(..., description="Current page number") per_page: int = Field(..., description="Records per page") has_next: bool = Field(..., description="Whether there are more pages") has_prev: bool = Field(..., description="Whether there are previous pages") class TrafficAnalytics(BaseModel): """Schema for traffic analytics""" location_id: str period_start: datetime period_end: datetime avg_traffic_volume: Optional[float] = None avg_pedestrian_count: Optional[float] = None peak_traffic_hour: Optional[int] = None peak_pedestrian_hour: Optional[int] = None congestion_distribution: dict = Field(default_factory=dict) avg_speed: Optional[float] = None class TrafficDataResponse(BaseModel): """Schema for API traffic data responses""" date: datetime = Field(..., description="Date and time of traffic measurement") traffic_volume: Optional[int] = Field(None, ge=0, description="Vehicles per hour") pedestrian_count: Optional[int] = Field(None, ge=0, description="Pedestrians per hour") congestion_level: Optional[str] = Field(None, pattern="^(low|medium|high)$", description="Traffic congestion level") average_speed: Optional[float] = Field(None, ge=0, le=200, description="Average speed in km/h") source: str = Field(..., description="Data source") class Config: json_encoders = { datetime: lambda v: v.isoformat() } class LocationRequest(BaseModel): latitude: float longitude: float address: Optional[str] = None class DateRangeRequest(BaseModel): start_date: datetime end_date: datetime class HistoricalTrafficRequest(BaseModel): latitude: float longitude: float start_date: datetime end_date: datetime class TrafficForecastRequest(BaseModel): latitude: float longitude: float hours: int = 24