from datetime import datetime from typing import Optional, Dict, Any from pydantic import BaseModel, Field, ConfigDict from bson import ObjectId from pydantic_core import core_schema class PyObjectId(str): """Custom ObjectId type for Pydantic v2""" @classmethod def __get_pydantic_core_schema__(cls, source_type, handler): return core_schema.union_schema([ core_schema.is_instance_schema(ObjectId), core_schema.chain_schema([ core_schema.str_schema(), core_schema.no_info_plain_validator_function(cls.validate), ]) ], serialization=core_schema.plain_serializer_function_ser_schema( lambda x: str(x) )) @classmethod def validate(cls, v): if not ObjectId.is_valid(v): raise ValueError("Invalid ObjectId") return ObjectId(v) class ServiceStatus: """Service status constants""" HEALTHY = "healthy" UNHEALTHY = "unhealthy" UNKNOWN = "unknown" class ServiceType: """Service type constants""" BACKEND = "backend" FRONTEND = "frontend" DATABASE = "database" CACHE = "cache" MESSAGE_QUEUE = "message_queue" OTHER = "other" class Service(BaseModel): """Service model for MongoDB""" id: Optional[PyObjectId] = Field(alias="_id", default=None) name: str = Field(..., min_length=1, max_length=100) description: Optional[str] = Field(default=None, max_length=500) service_type: str = Field(default=ServiceType.BACKEND) url: str = Field(..., min_length=1) health_endpoint: Optional[str] = Field(default="/health") status: str = Field(default=ServiceStatus.UNKNOWN) last_health_check: Optional[datetime] = None response_time_ms: Optional[float] = None created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow) metadata: Dict[str, Any] = Field(default_factory=dict) model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, json_encoders={ObjectId: str}, json_schema_extra={ "example": { "name": "News API", "description": "News generation and management API", "service_type": "backend", "url": "http://news-api:8050", "health_endpoint": "/health", "status": "healthy", "metadata": { "version": "1.0.0", "port": 8050 } } } )