from datetime import datetime from sqlalchemy import JSON, DateTime, ForeignKey, Integer, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.constants import ActorValue from app.core.database import Base from app.core.utils.time import utc_now from app.modules.workflows.constants import WorkflowStatus class WorkflowInstance(Base): __tablename__ = "workflow_instances" __table_args__ = ( UniqueConstraint( "workflow_type", "aggregate_type", "aggregate_id", name="uq_workflow_aggregate", ), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), unique=True, index=True) workflow_type: Mapped[str] = mapped_column(String(128), index=True) aggregate_type: Mapped[str] = mapped_column(String(128), index=True) aggregate_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) status: Mapped[str] = mapped_column(String(32), default=WorkflowStatus.RUNNING, index=True) actor: Mapped[str] = mapped_column(String(128), default=ActorValue.SYSTEM, index=True) current_step: Mapped[str | None] = mapped_column(String(128), nullable=True) payload: Mapped[dict | None] = mapped_column(JSON, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=utc_now, index=True) updated_at: Mapped[datetime] = mapped_column( DateTime, default=utc_now, onupdate=utc_now, ) completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True) class WorkflowAction(Base): __tablename__ = "workflow_actions" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), unique=True, index=True) workflow_code: Mapped[str] = mapped_column( ForeignKey("workflow_instances.code", ondelete="RESTRICT"), index=True, ) action: Mapped[str] = mapped_column(String(128), index=True) actor: Mapped[str] = mapped_column(String(128), default=ActorValue.SYSTEM, index=True) from_status: Mapped[str | None] = mapped_column(String(32), nullable=True) to_status: Mapped[str | None] = mapped_column(String(32), nullable=True) payload: Mapped[dict | None] = mapped_column(JSON, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=utc_now, index=True)