""" Schemas base y utilidades comunes para Pydantic. """ from datetime import datetime from typing import Generic, List, Optional, TypeVar from pydantic import BaseModel, ConfigDict class BaseSchema(BaseModel): """Schema base con configuración común.""" model_config = ConfigDict( from_attributes=True, populate_by_name=True, use_enum_values=True, json_encoders={datetime: lambda v: v.isoformat()}, ) class TimestampSchema(BaseSchema): """Schema con campos de timestamp.""" creado_en: datetime actualizado_en: datetime # Type variable para paginación genérica T = TypeVar("T") class PaginatedResponse(BaseModel, Generic[T]): """Respuesta paginada genérica.""" items: List[T] total: int page: int page_size: int pages: int @property def has_next(self) -> bool: return self.page < self.pages @property def has_prev(self) -> bool: return self.page > 1 class MessageResponse(BaseModel): """Respuesta simple con mensaje.""" message: str success: bool = True class ErrorResponse(BaseModel): """Respuesta de error.""" error: dict class GeoJSONPoint(BaseModel): """Schema para punto GeoJSON.""" type: str = "Point" coordinates: List[float] # [lng, lat] class GeoJSONFeature(BaseModel): """Schema para feature GeoJSON.""" type: str = "Feature" geometry: dict properties: dict class GeoJSONFeatureCollection(BaseModel): """Schema para colección de features GeoJSON.""" type: str = "FeatureCollection" features: List[GeoJSONFeature] class CoordenadasSchema(BaseModel): """Schema para coordenadas simples.""" lat: float lng: float class RangoFechasSchema(BaseModel): """Schema para filtros de rango de fechas.""" desde: Optional[datetime] = None hasta: Optional[datetime] = None