import uuid from datetime import date, datetime from sqlalchemy import Date, DateTime, ForeignKey, Index, String, Text from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from api.models.base import Base, TimestampMixin, new_uuid class InterfaceChange(Base, TimestampMixin): __tablename__ = "interface_changes" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=new_uuid ) repo_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("managed_repos.id", ondelete="CASCADE"), nullable=False, index=True, ) interface_type: Mapped[str] = mapped_column( String(40), nullable=False ) # rest_api | mcp_tool | cli | schema | capability change_type: Mapped[str] = mapped_column( String(40), nullable=False ) # breaking | additive | deprecation | removal title: Mapped[str] = mapped_column(String(300), nullable=False) description: Mapped[str] = mapped_column(Text, nullable=False) affected_paths: Mapped[list] = mapped_column( JSONB, nullable=False, default=list, server_default="[]" ) affected_repo_slugs: Mapped[list] = mapped_column( JSONB, nullable=False, default=list, server_default="[]" ) status: Mapped[str] = mapped_column( String(20), nullable=False, default="draft", index=True ) # draft | published | resolved planned_for: Mapped[date | None] = mapped_column(Date, nullable=True) published_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) resolved_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) author: Mapped[str] = mapped_column(String(100), nullable=False, default="custodian") repo: Mapped["ManagedRepo"] = relationship( # noqa: F821 "ManagedRepo", lazy="selectin" ) __table_args__ = ( Index("ix_interface_changes_repo_status", "repo_id", "status"), )