import enum, uuid from sqlalchemy import String, Enum, ForeignKey, Integer, DateTime, JSON from sqlalchemy.orm import relationship, Mapped, mapped_column from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.sql import func from app.db import Base class JobStatus(str, enum.Enum): PENDING = "pending" QUEUED = "queued" RUNNING = "running" SUCCESS = "success" FAILED = "failed" class TaskStatus(str, enum.Enum): PENDING = "pending" QUEUED = "queued" RUNNING = "running" SUCCESS = "success" FAILED = "failed" class Job(Base): __tablename__ = "jobs" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) job_type: Mapped[str] = mapped_column(String(64), index=True) status: Mapped[JobStatus] = mapped_column(Enum(JobStatus), default=JobStatus.PENDING, index=True) domain: Mapped[str] = mapped_column(String(255), index=True) payload: Mapped[dict | None] = mapped_column(JSON, nullable=True) created_at: Mapped[str] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[str] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) tasks: Mapped[list["Task"]] = relationship("Task", back_populates="job", cascade="all, delete-orphan", lazy="selectin") class Task(Base): __tablename__ = "tasks" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) job_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(64), index=True) status: Mapped[TaskStatus] = mapped_column(Enum(TaskStatus), default=TaskStatus.PENDING, index=True) routing_key: Mapped[str] = mapped_column(String(128), index=True) retries: Mapped[int] = mapped_column(Integer, default=0) max_retries: Mapped[int] = mapped_column(Integer, default=3) worker_id: Mapped[str | None] = mapped_column(String(64), nullable=True) result: Mapped[dict | None] = mapped_column(JSON, nullable=True) error: Mapped[str | None] = mapped_column(String(1024), nullable=True) created_at: Mapped[str] = mapped_column(DateTime(timezone=True), server_default=func.now()) started_at: Mapped[str | None] = mapped_column(DateTime(timezone=True), nullable=True) finished_at: Mapped[str | None] = mapped_column(DateTime(timezone=True), nullable=True) job: Mapped["Job"] = relationship("Job", back_populates="tasks") class TaskDependency(Base): __tablename__ = "task_dependencies" task_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("tasks.id", ondelete="CASCADE"), primary_key=True) depends_on_task_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("tasks.id", ondelete="CASCADE"), primary_key=True)