from __future__ import annotations from datetime import datetime from typing import Any from sqlalchemy import DateTime, ForeignKey, Index, JSON, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from iti.db import Base, IdMixin, TimestampMixin class ExchangeTemplateModel(Base, IdMixin, TimestampMixin): __tablename__ = "exchange_templates" code: Mapped[str] = mapped_column(String(128), unique=True, index=True, comment="模板编码") name: Mapped[str] = mapped_column(String(255), comment="模板名称") template_kind: Mapped[str] = mapped_column(String(32), index=True, comment="模板类型") entity: Mapped[str] = mapped_column(String(128), index=True, comment="业务实体") status: Mapped[str] = mapped_column(String(32), default="draft", index=True, comment="状态") description: Mapped[str | None] = mapped_column(Text, nullable=True, comment="说明") current_version: Mapped[str | None] = mapped_column( String(64), nullable=True, index=True, comment="当前版本" ) meta: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="扩展配置") versions: Mapped[list["ExchangeTemplateVersionModel"]] = relationship( back_populates="template", cascade="all, delete-orphan", ) class ExchangeTemplateVersionModel(Base, IdMixin, TimestampMixin): __tablename__ = "exchange_template_versions" __table_args__ = ( UniqueConstraint("template_id", "version", name="uq_exchange_template_versions_template_version"), Index("ix_exchange_template_versions_template_id_version", "template_id", "version"), ) template_id: Mapped[str] = mapped_column( String(36), ForeignKey("exchange_templates.id", ondelete="CASCADE"), index=True, comment="模板ID", ) version: Mapped[str] = mapped_column(String(64), comment="版本号") template_kind: Mapped[str] = mapped_column(String(32), index=True, comment="模板类型") published_at: Mapped[datetime | None] = mapped_column( DateTime, nullable=True, comment="发布时间", ) file_key: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="模板文件") checksum: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="校验值") bindings: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list, comment="绑定配置") fields: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list, comment="字段定义") placeholders: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list, comment="占位符定义") meta: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="扩展配置") template: Mapped["ExchangeTemplateModel"] = relationship(back_populates="versions") class ExchangeTaskModel(Base, IdMixin, TimestampMixin): __tablename__ = "exchange_tasks" __table_args__ = ( Index("ix_exchange_tasks_template_id_kind_status", "template_id", "task_kind", "status"), Index("ix_exchange_tasks_version_id", "template_version_id"), ) template_id: Mapped[str | None] = mapped_column( String(36), ForeignKey("exchange_templates.id", ondelete="SET NULL"), nullable=True, index=True, comment="模板ID", ) template_version_id: Mapped[str | None] = mapped_column( String(36), ForeignKey("exchange_template_versions.id", ondelete="SET NULL"), nullable=True, index=True, comment="模板版本ID", ) task_kind: Mapped[str] = mapped_column(String(32), index=True, comment="任务类型") status: Mapped[str] = mapped_column(String(32), default="pending", index=True, comment="状态") requested_by: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True, comment="发起人") storage_key: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="任务文件") checksum: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="校验值") error_count: Mapped[int] = mapped_column(default=0, comment="错误数") success_count: Mapped[int] = mapped_column(default=0, comment="成功数") failed_count: Mapped[int] = mapped_column(default=0, comment="失败数") message: Mapped[str | None] = mapped_column(Text, nullable=True, comment="消息") input_payload: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="输入参数") result_payload: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="输出结果") started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, comment="开始时间") finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, comment="结束时间") meta: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="扩展配置") template: Mapped["ExchangeTemplateModel"] = relationship( foreign_keys=[template_id] ) version: Mapped["ExchangeTemplateVersionModel"] = relationship( foreign_keys=[template_version_id] ) rows: Mapped[list["ExchangeTaskRowModel"]] = relationship( back_populates="task", cascade="all, delete-orphan", ) class ExchangeTaskRowModel(Base, IdMixin, TimestampMixin): __tablename__ = "exchange_task_rows" __table_args__ = ( UniqueConstraint("task_id", "row_index", name="uq_exchange_task_rows_task_row"), Index("ix_exchange_task_rows_task_id_status", "task_id", "status"), ) task_id: Mapped[str] = mapped_column( String(36), ForeignKey("exchange_tasks.id", ondelete="CASCADE"), index=True, comment="任务ID", ) row_index: Mapped[int] = mapped_column(comment="行号") status: Mapped[str] = mapped_column(String(32), default="pending", index=True, comment="状态") data: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="原始数据") message: Mapped[str | None] = mapped_column(Text, nullable=True, comment="错误信息") result: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, comment="结果数据") task: Mapped["ExchangeTaskModel"] = relationship(back_populates="rows")