"""幂等键模型。""" from datetime import datetime from sqlalchemy import DateTime, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.ids import new_id from app.core.time import utc_now from app.db.base import Base def new_idempotency_id() -> str: return new_id("idempotency_") class IdempotencyKey(Base): __tablename__ = "idempotency_keys" __table_args__ = (UniqueConstraint("scope", "key", name="uq_idempotency_scope_key"),) id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_idempotency_id) key: Mapped[str] = mapped_column(String(200), nullable=False, index=True) scope: Mapped[str] = mapped_column(String(120), nullable=False, index=True) method: Mapped[str] = mapped_column(String(20), nullable=False) path: Mapped[str] = mapped_column(String(500), nullable=False) request_hash: Mapped[str] = mapped_column(String(128), nullable=False) status: Mapped[str] = mapped_column(String(40), nullable=False, default="completed") response_status_code: Mapped[int] = mapped_column(default=200) response_body_json: Mapped[str] = mapped_column(Text, nullable=False) resource_type: Mapped[str | None] = mapped_column(String(80)) resource_id: Mapped[str | None] = mapped_column(String(120)) trace_id: Mapped[str | None] = mapped_column(String(80), index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=utc_now, onupdate=utc_now ) expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True)