| """SQLAlchemy models for persisted RAG documents, chunks, queries, and citations.""" |
|
|
| from __future__ import annotations |
|
|
| import uuid |
| from datetime import datetime |
| from typing import List, Optional |
|
|
| from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Index, Integer, JSON, String, Text, UniqueConstraint, func |
| from sqlalchemy.orm import Mapped, mapped_column, relationship |
|
|
| from persistence.db import Base |
|
|
|
|
| def _new_id() -> str: |
| return str(uuid.uuid4()) |
|
|
|
|
| class User(Base): |
| __tablename__ = "users" |
|
|
| id: Mapped[str] = mapped_column(String(128), primary_key=True) |
| email: Mapped[Optional[str]] = mapped_column(String(320), nullable=True) |
| display_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) |
| auth_provider: Mapped[Optional[str]] = mapped_column(String(64), nullable=True) |
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) |
| updated_at: Mapped[datetime] = mapped_column( |
| DateTime(timezone=True), |
| server_default=func.now(), |
| onupdate=func.now(), |
| nullable=False, |
| ) |
|
|
| documents: Mapped[List["Document"]] = relationship(back_populates="user") |
| chunks: Mapped[List["Chunk"]] = relationship(back_populates="user") |
| queries: Mapped[List["Query"]] = relationship(back_populates="user") |
| citations: Mapped[List["Citation"]] = relationship(back_populates="user") |
|
|
|
|
| class Document(Base): |
| __tablename__ = "documents" |
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id) |
| user_id: Mapped[str] = mapped_column(String(128), ForeignKey("users.id"), nullable=False) |
| source_type: Mapped[str] = mapped_column(String(32), nullable=False) |
| filename: Mapped[Optional[str]] = mapped_column(String(512), nullable=True) |
| source_url: Mapped[Optional[str]] = mapped_column(Text, nullable=True) |
| source_hash: Mapped[Optional[str]] = mapped_column(String(128), nullable=True) |
| cache_key: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) |
| status: Mapped[str] = mapped_column(String(32), nullable=False, default="processing") |
| error_message: Mapped[Optional[str]] = mapped_column(Text, nullable=True) |
| embedding_model: Mapped[str] = mapped_column(String(255), nullable=False) |
| embedding_format: Mapped[str] = mapped_column(String(64), nullable=False) |
| retrieval_mode: Mapped[str] = mapped_column(String(64), nullable=False) |
| reranker_model: Mapped[str] = mapped_column(String(255), nullable=False) |
| k_initial: Mapped[int] = mapped_column(Integer, nullable=False) |
| k_final: Mapped[int] = mapped_column(Integer, nullable=False) |
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) |
| updated_at: Mapped[datetime] = mapped_column( |
| DateTime(timezone=True), |
| server_default=func.now(), |
| onupdate=func.now(), |
| nullable=False, |
| ) |
|
|
| user: Mapped["User"] = relationship(back_populates="documents") |
| chunks: Mapped[List["Chunk"]] = relationship(back_populates="document", cascade="all, delete-orphan") |
| queries: Mapped[List["Query"]] = relationship(back_populates="document", cascade="all, delete-orphan") |
| citations: Mapped[List["Citation"]] = relationship(back_populates="document", cascade="all, delete-orphan") |
|
|
| __table_args__ = ( |
| Index("ix_documents_user_id_created_at", "user_id", "created_at"), |
| ) |
|
|
|
|
| class Chunk(Base): |
| __tablename__ = "chunks" |
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id) |
| user_id: Mapped[str] = mapped_column(String(128), ForeignKey("users.id"), nullable=False) |
| document_id: Mapped[str] = mapped_column(String(36), ForeignKey("documents.id"), nullable=False) |
| chunk_id: Mapped[int] = mapped_column(Integer, nullable=False) |
| chunk_index: Mapped[int] = mapped_column(Integer, nullable=False) |
| page_number: Mapped[int] = mapped_column(Integer, nullable=False) |
| text: Mapped[str] = mapped_column(Text, nullable=False) |
| text_hash: Mapped[Optional[str]] = mapped_column(String(128), nullable=True) |
| char_count: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) |
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) |
|
|
| user: Mapped["User"] = relationship(back_populates="chunks") |
| document: Mapped["Document"] = relationship(back_populates="chunks") |
| citations: Mapped[List["Citation"]] = relationship(back_populates="chunk") |
|
|
| __table_args__ = ( |
| Index("ix_chunks_user_id_document_id", "user_id", "document_id"), |
| UniqueConstraint("document_id", "chunk_id", name="uq_chunks_document_id_chunk_id"), |
| ) |
|
|
|
|
| class Query(Base): |
| __tablename__ = "queries" |
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id) |
| user_id: Mapped[str] = mapped_column(String(128), ForeignKey("users.id"), nullable=False) |
| document_id: Mapped[str] = mapped_column(String(36), ForeignKey("documents.id"), nullable=False) |
| question: Mapped[str] = mapped_column(Text, nullable=False) |
| answer: Mapped[str] = mapped_column(Text, nullable=False) |
| status: Mapped[str] = mapped_column(String(32), nullable=False) |
| is_abstained: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) |
| claim_verifications_json: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True) |
| embedding_model: Mapped[str] = mapped_column(String(255), nullable=False) |
| retrieval_mode: Mapped[str] = mapped_column(String(64), nullable=False) |
| reranker_model: Mapped[str] = mapped_column(String(255), nullable=False) |
| k_initial: Mapped[int] = mapped_column(Integer, nullable=False) |
| k_final: Mapped[int] = mapped_column(Integer, nullable=False) |
| latency_ms: Mapped[Optional[float]] = mapped_column(Float, nullable=True) |
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) |
|
|
| user: Mapped["User"] = relationship(back_populates="queries") |
| document: Mapped["Document"] = relationship(back_populates="queries") |
| citations: Mapped[List["Citation"]] = relationship(back_populates="query", cascade="all, delete-orphan") |
|
|
| __table_args__ = ( |
| Index("ix_queries_user_id_document_id_created_at", "user_id", "document_id", "created_at"), |
| ) |
|
|
|
|
| class Citation(Base): |
| __tablename__ = "citations" |
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id) |
| user_id: Mapped[str] = mapped_column(String(128), ForeignKey("users.id"), nullable=False) |
| query_id: Mapped[str] = mapped_column(String(36), ForeignKey("queries.id"), nullable=False) |
| document_id: Mapped[str] = mapped_column(String(36), ForeignKey("documents.id"), nullable=False) |
| chunk_db_id: Mapped[Optional[str]] = mapped_column(String(36), ForeignKey("chunks.id"), nullable=True) |
| chunk_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) |
| rank: Mapped[int] = mapped_column(Integer, nullable=False) |
| page_number: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) |
| excerpt: Mapped[str] = mapped_column(Text, nullable=False) |
| retrieval_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True) |
| reranker_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True) |
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) |
|
|
| user: Mapped["User"] = relationship(back_populates="citations") |
| query: Mapped["Query"] = relationship(back_populates="citations") |
| document: Mapped["Document"] = relationship(back_populates="citations") |
| chunk: Mapped[Optional["Chunk"]] = relationship(back_populates="citations") |
|
|
| __table_args__ = ( |
| Index("ix_citations_user_id_query_id", "user_id", "query_id"), |
| Index("ix_citations_query_id_rank", "query_id", "rank"), |
| ) |
|
|