from datetime import datetime from typing import Optional from sqlalchemy import DateTime, ForeignKey, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from .base import Base class SnapshotContent(Base): """Stores unique file contents by SHA-256. One row per unique content.""" __tablename__ = "snapshot_contents" sha256: Mapped[str] = mapped_column(String(64), primary_key=True) content: Mapped[str] = mapped_column(Text(), nullable=False) size: Mapped[int] = mapped_column(Integer(), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) snapshots: Mapped[list["ConfigSnapshot"]] = relationship( "ConfigSnapshot", back_populates="snapshot_content" ) class ConfigSnapshot(Base): """Each capture event: device + path + timestamp + content reference.""" __tablename__ = "config_snapshots" id: Mapped[int] = mapped_column(Integer(), autoincrement=True, primary_key=True) device_id: Mapped[int] = mapped_column( Integer(), ForeignKey("devices.id", ondelete="CASCADE"), nullable=False ) sha256: Mapped[str] = mapped_column( String(64), ForeignKey("snapshot_contents.sha256"), nullable=False ) label: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) device: Mapped["Device"] = relationship("Device", back_populates="config_snapshots") snapshot_content: Mapped["SnapshotContent"] = relationship( "SnapshotContent", back_populates="snapshots" )