from __future__ import annotations from datetime import datetime from sqlalchemy import BigInteger, CheckConstraint, DateTime, Float, ForeignKey, Index, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.models.base import Base, TimestampMixin class VideoUpscaleTask(Base, TimestampMixin): __tablename__ = "video_upscale_tasks" __table_args__ = ( CheckConstraint( "(chat_generation_task_id IS NOT NULL AND generation_record_id IS NULL) OR " "(chat_generation_task_id IS NULL AND generation_record_id IS NOT NULL)", name="ck_video_upscale_tasks_exactly_one_owner", ), Index("uq_video_upscale_tasks_chat_task", "chat_generation_task_id", unique=True), Index("uq_video_upscale_tasks_generation_record", "generation_record_id", unique=True), Index("idx_video_upscale_tasks_provider_task_id", "provider_task_id"), Index("idx_video_upscale_tasks_status_next_retry", "status", "next_retry_at"), Index("idx_video_upscale_tasks_status_lease", "status", "lease_until"), ) id: Mapped[str] = mapped_column(String(32), primary_key=True) chat_generation_task_id: Mapped[str | None] = mapped_column( String(32), ForeignKey("chat_generation_tasks.id", ondelete="CASCADE"), nullable=True, ) generation_record_id: Mapped[str | None] = mapped_column( String(32), ForeignKey("generation_records.id", ondelete="CASCADE"), nullable=True, ) status: Mapped[str] = mapped_column(String(32), nullable=False, default="pending", server_default="pending") stage: Mapped[str] = mapped_column(String(48), nullable=False, default="upscale_queued", server_default="upscale_queued") processor_key: Mapped[str] = mapped_column(String(64), nullable=False) attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") failure_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") manual_retry_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") next_retry_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) last_error: Mapped[str | None] = mapped_column(Text, nullable=True) source_local_path: Mapped[str | None] = mapped_column(Text, nullable=True) source_file_size_bytes: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0, server_default="0") source_width: Mapped[int | None] = mapped_column(Integer, nullable=True) source_height: Mapped[int | None] = mapped_column(Integer, nullable=True) source_duration_seconds: Mapped[float | None] = mapped_column(Float, nullable=True) source_deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) source_delete_error: Mapped[str | None] = mapped_column(Text, nullable=True) source_remote_url: Mapped[str | None] = mapped_column(Text, nullable=True) source_remote_url_signed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) source_remote_url_expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) source_remote_url_last_probe_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) source_remote_url_probe_status: Mapped[str | None] = mapped_column(String(32), nullable=True) input_source_type: Mapped[str | None] = mapped_column(String(32), nullable=True) input_source_fallback_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") target_width: Mapped[int] = mapped_column(Integer, nullable=False) target_height: Mapped[int] = mapped_column(Integer, nullable=False) effective_target_width: Mapped[int | None] = mapped_column(Integer, nullable=True) effective_target_height: Mapped[int | None] = mapped_column(Integer, nullable=True) provider_task_id: Mapped[str | None] = mapped_column(String(160), nullable=True) provider_request_json: Mapped[str | None] = mapped_column(Text, nullable=True) provider_response_json: Mapped[str | None] = mapped_column(Text, nullable=True) provider_output_url: Mapped[str | None] = mapped_column(Text, nullable=True) provider_output_url_expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) provider_submitted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) final_local_path: Mapped[str | None] = mapped_column(Text, nullable=True) final_resource_url: Mapped[str | None] = mapped_column(Text, nullable=True) final_file_size_bytes: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0, server_default="0") celery_task_id: Mapped[str | None] = mapped_column(String(160), nullable=True) lease_token: Mapped[str | None] = mapped_column(String(64), nullable=True) lease_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) failed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)