from datetime import datetime, timezone from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, Integer, String, Text, func from sqlalchemy.orm import Mapped, declared_attr, mapped_column from app.db.session import Base def utc_now() -> datetime: return datetime.now(timezone.utc) class Versioned: version: Mapped[int] = mapped_column(Integer, nullable=False, default=1) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=utc_now, onupdate=utc_now ) is_deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) @declared_attr.directive def __mapper_args__(cls): return {"version_id_col": cls.version} class Source(Versioned, Base): __tablename__ = "sources" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(250), nullable=False) source_url: Mapped[str | None] = mapped_column(String(1000)) notes: Mapped[str] = mapped_column(Text, nullable=False, default="") class Document(Versioned, Base): __tablename__ = "documents" id: Mapped[int] = mapped_column(primary_key=True) source_id: Mapped[int] = mapped_column(ForeignKey("sources.id"), index=True) title: Mapped[str] = mapped_column(String(250), nullable=False) category: Mapped[str] = mapped_column(String(80), nullable=False) content: Mapped[str] = mapped_column(Text, nullable=False) collected_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) notes: Mapped[str] = mapped_column(Text, nullable=False, default="") class AuditEvent(Base): __tablename__ = "audit_events" id: Mapped[int] = mapped_column(primary_key=True) entity_type: Mapped[str] = mapped_column(String(30), nullable=False, index=True) entity_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True) action: Mapped[str] = mapped_column(String(30), nullable=False) actor: Mapped[str | None] = mapped_column(String(100)) notes: Mapped[str] = mapped_column(Text, nullable=False, default="") snapshot: Mapped[dict] = mapped_column(JSON, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())