# ================================================================ # services/data/app/schemas/weather.py # ================================================================ """Weather data schemas""" from pydantic import BaseModel, Field, validator from datetime import datetime from typing import Optional, List from uuid import UUID class WeatherDataBase(BaseModel): """Base weather data schema""" location_id: str = Field(..., max_length=100, description="Weather monitoring location ID") date: datetime = Field(..., description="Date and time of weather measurement") temperature: Optional[float] = Field(None, ge=-50, le=60, description="Temperature in Celsius") precipitation: Optional[float] = Field(None, ge=0, description="Precipitation in mm") humidity: Optional[float] = Field(None, ge=0, le=100, description="Humidity percentage") wind_speed: Optional[float] = Field(None, ge=0, le=200, description="Wind speed in km/h") pressure: Optional[float] = Field(None, ge=800, le=1200, description="Atmospheric pressure in hPa") description: Optional[str] = Field(None, max_length=200, description="Weather description") source: str = Field("aemet", max_length=50, description="Data source") raw_data: Optional[str] = Field(None, description="Raw data from source") class WeatherDataCreate(WeatherDataBase): """Schema for creating weather data""" pass class WeatherDataUpdate(BaseModel): """Schema for updating weather data""" temperature: Optional[float] = Field(None, ge=-50, le=60) precipitation: Optional[float] = Field(None, ge=0) humidity: Optional[float] = Field(None, ge=0, le=100) wind_speed: Optional[float] = Field(None, ge=0, le=200) pressure: Optional[float] = Field(None, ge=800, le=1200) description: Optional[str] = Field(None, max_length=200) raw_data: Optional[str] = None class WeatherDataResponse(WeatherDataBase): """Schema for weather data responses""" id: str = Field(..., description="Unique identifier") created_at: datetime = Field(..., description="Creation timestamp") updated_at: datetime = Field(..., description="Last update timestamp") @validator('id', pre=True) 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 WeatherForecastBase(BaseModel): """Base weather forecast schema""" location_id: str = Field(..., max_length=100, description="Location ID") forecast_date: datetime = Field(..., description="Date for forecast") temperature: Optional[float] = Field(None, ge=-50, le=60, description="Forecasted temperature") precipitation: Optional[float] = Field(None, ge=0, description="Forecasted precipitation") humidity: Optional[float] = Field(None, ge=0, le=100, description="Forecasted humidity") wind_speed: Optional[float] = Field(None, ge=0, le=200, description="Forecasted wind speed") description: Optional[str] = Field(None, max_length=200, description="Forecast description") source: str = Field("aemet", max_length=50, description="Data source") raw_data: Optional[str] = Field(None, description="Raw forecast data") class WeatherForecastCreate(WeatherForecastBase): """Schema for creating weather forecasts""" pass class WeatherForecastResponse(WeatherForecastBase): """Schema for weather forecast responses""" id: str = Field(..., description="Unique identifier") generated_at: datetime = Field(..., description="When forecast was generated") created_at: datetime = Field(..., description="Creation timestamp") updated_at: datetime = Field(..., description="Last update timestamp") @validator('id', pre=True) 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 WeatherDataList(BaseModel): """Schema for paginated weather data responses""" data: List[WeatherDataResponse] 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 WeatherForecastList(BaseModel): """Schema for paginated weather forecast responses""" forecasts: List[WeatherForecastResponse] total: int = Field(..., description="Total number of forecasts") page: int = Field(..., description="Current page number") per_page: int = Field(..., description="Forecasts per page") class WeatherAnalytics(BaseModel): """Schema for weather analytics""" location_id: str period_start: datetime period_end: datetime avg_temperature: Optional[float] = None min_temperature: Optional[float] = None max_temperature: Optional[float] = None total_precipitation: Optional[float] = None avg_humidity: Optional[float] = None avg_wind_speed: Optional[float] = None avg_pressure: Optional[float] = None weather_conditions: dict = Field(default_factory=dict) rainy_days: int = 0 sunny_days: int = 0