import uuid from datetime import date, datetime from sqlalchemy import Boolean, Date, DateTime, ForeignKey, Index, Integer, String, Text, UniqueConstraint, func from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from api.models.base import Base, TimestampMixin, new_uuid class LegacyInterface(Base, TimestampMixin): __tablename__ = "legacy_interfaces" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=new_uuid ) interface_key: Mapped[str] = mapped_column(String(300), nullable=False, unique=True, index=True) interface_kind: Mapped[str] = mapped_column(String(40), nullable=False, index=True) legacy_since: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, index=True ) replacement_ref: Mapped[str] = mapped_column(Text, nullable=False) owner_component: Mapped[str] = mapped_column( String(100), nullable=False, default="state-hub", server_default="state-hub", index=True ) status: Mapped[str] = mapped_column( String(30), nullable=False, default="legacy", server_default="legacy", index=True ) replacement_verified: Mapped[bool] = mapped_column( Boolean, nullable=False, default=False, server_default="false" ) manual_hold: Mapped[bool] = mapped_column( Boolean, nullable=False, default=False, server_default="false" ) hold_reason: Mapped[str | None] = mapped_column(Text, nullable=True) notes: Mapped[str | None] = mapped_column(Text, nullable=True) retired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) usage_buckets: Mapped[list["LegacyInterfaceUsageBucket"]] = relationship( # noqa: F821 "LegacyInterfaceUsageBucket", back_populates="legacy_interface", cascade="all, delete-orphan", lazy="selectin", ) class LegacyInterfaceUsageBucket(Base, TimestampMixin): __tablename__ = "legacy_interface_usage_buckets" __table_args__ = ( UniqueConstraint( "legacy_interface_id", "period_start", "bucket_kind", "bucket_key", name="uq_legacy_usage_bucket", ), Index("ix_legacy_usage_interface_period", "legacy_interface_id", "period_start"), Index("ix_legacy_usage_bucket_kind_key", "bucket_kind", "bucket_key"), ) id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=new_uuid ) legacy_interface_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("legacy_interfaces.id", ondelete="CASCADE"), nullable=False, index=True, ) period_start: Mapped[date] = mapped_column(Date, nullable=False, index=True) bucket_kind: Mapped[str] = mapped_column(String(30), nullable=False) bucket_key: Mapped[str] = mapped_column(String(200), nullable=False) call_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") first_seen_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) last_seen_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, index=True) legacy_interface: Mapped["LegacyInterface"] = relationship( # noqa: F821 "LegacyInterface", back_populates="usage_buckets" )