""" GT 2.0 Base Model Classes - Service-Based Architecture Provides Pydantic models for data serialization with the DuckDB service. No SQLAlchemy ORM dependency - pure Python/Pydantic models. """ from typing import Any, Dict, Optional, List, Type, TypeVar from datetime import datetime import uuid from pydantic import BaseModel, Field, ConfigDict # Generic type for model classes T = TypeVar('T', bound='BaseServiceModel') class BaseServiceModel(BaseModel): """ Base model for all GT 2.0 entities using service-based architecture. Replaces SQLAlchemy models with Pydantic models + DuckDB service. """ # Pydantic v2 configuration model_config = ConfigDict( from_attributes=True, validate_assignment=True, arbitrary_types_allowed=True, use_enum_values=True ) # Standard fields for all models id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique identifier") created_at: datetime = Field(default_factory=datetime.utcnow, description="Creation timestamp") updated_at: datetime = Field(default_factory=datetime.utcnow, description="Last update timestamp") def to_dict(self) -> Dict[str, Any]: """Convert model to dictionary""" return self.model_dump() @classmethod def from_dict(cls: Type[T], data: Dict[str, Any]) -> T: """Create model instance from dictionary""" return cls(**data) @classmethod def from_row(cls: Type[T], row: Dict[str, Any]) -> T: """Create model instance from database row""" # Convert database row to model, handling type conversions model_data = {} for field_name, field_info in cls.model_fields.items(): if field_name in row: value = row[field_name] # Handle datetime conversion if field_info.annotation == datetime and isinstance(value, str): try: value = datetime.fromisoformat(value) except ValueError: value = datetime.utcnow() model_data[field_name] = value return cls(**model_data) def update_timestamp(self): """Update the updated_at timestamp""" self.updated_at = datetime.utcnow() class BaseCreateModel(BaseModel): """Base model for creation requests""" model_config = ConfigDict(from_attributes=True) class BaseUpdateModel(BaseModel): """Base model for update requests""" model_config = ConfigDict(from_attributes=True) updated_at: datetime = Field(default_factory=datetime.utcnow) class BaseResponseModel(BaseServiceModel): """Base model for API responses""" pass # Legacy compatibility - some files might still import Base Base = BaseServiceModel # For backwards compatibility during migration # Database service integration helpers class DatabaseMixin: """Mixin providing database service integration methods""" @classmethod async def get_table_name(cls) -> str: """Get the database table name for this model""" # Convert CamelCase to snake_case and pluralize name = cls.__name__.lower() if name.endswith('y'): name = name[:-1] + 'ies' elif name.endswith('s'): name = name + 'es' else: name = name + 's' return name @classmethod async def create_sql(cls) -> str: """Generate CREATE TABLE SQL for this model""" # This would generate SQL based on Pydantic field types # For now, return placeholder - actual schemas are in DuckDB service table_name = await cls.get_table_name() return f"-- CREATE TABLE {table_name} generated by DuckDB service" async def to_sql_values(self) -> Dict[str, Any]: """Convert model to SQL-safe values""" data = self.to_dict() # Convert datetime objects to ISO strings for key, value in data.items(): if isinstance(value, datetime): data[key] = value.isoformat() return data