contextquery-api / app /models.py
RamshaAnwar's picture
feat(hubs): tenant-safe list, get, and delete (#5)
3d08a7e unverified
Raw History Blame Contribute Delete
4.37 kB
import uuid
from datetime import datetime
from sqlalchemy import Column, String, Boolean, Integer, DateTime, ForeignKey, UniqueConstraint, LargeBinary
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship
from pgvector.sqlalchemy import Vector
from app.db import Base
class User(Base):
__tablename__ = "users"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
email = Column(String(320), nullable=False)
password_hash = Column(String(255), nullable=False)
role = Column(String(20), nullable=False, default="owner")
is_active = Column(Boolean, nullable=False, default=True)
created_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
class Hub(Base):
__tablename__ = "hubs"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
owner_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
name = Column(String(120), nullable=False)
description = Column(String(500), nullable=True)
ai_summary = Column(String, nullable=True)
suggested_questions = Column(JSONB, nullable=False, default=list)
created_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
updated_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
# These relationships belong in Hub, not User!
documents = relationship("Document", back_populates="hub", cascade="all, delete-orphan")
chunks = relationship("Chunk", back_populates="hub", cascade="all, delete-orphan")
__table_args__ = (
UniqueConstraint("owner_id", "name", name="uq_hub_name_per_owner"),
)
class Document(Base):
__tablename__ = "documents"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
hub_id = Column(UUID(as_uuid=True), ForeignKey("hubs.id", ondelete="CASCADE"), nullable=False)
owner_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
origin = Column(String(20), nullable=False)
filename = Column(String(255), nullable=False)
mime_type = Column(String(100), nullable=False)
size_bytes = Column(Integer, nullable=False)
checksum_sha256 = Column(String(64), nullable=False)
status = Column(String(20), nullable=False, default="pending")
error_message = Column(String, nullable=True)
file_bytes = Column(LargeBinary, nullable=True)
process_claim = Column(UUID(as_uuid=True), nullable=True)
created_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
updated_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
hub = relationship("Hub", back_populates="documents")
__table_args__ = (
UniqueConstraint("hub_id", "checksum_sha256", name="uq_doc_checksum_per_hub"),
)
class Chunk(Base):
__tablename__ = "chunks"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
document_id = Column(UUID(as_uuid=True), ForeignKey("documents.id", ondelete="CASCADE"), nullable=False)
hub_id = Column(UUID(as_uuid=True), ForeignKey("hubs.id", ondelete="CASCADE"), nullable=False)
owner_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
chunk_index = Column(Integer, nullable=False)
text = Column(String, nullable=False)
token_count = Column(Integer, nullable=False)
embedding = Column(Vector(768), nullable=False)
created_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
hub = relationship("Hub", back_populates="chunks")
class IdempotencyKey(Base):
__tablename__ = "idempotency_keys"
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), primary_key=True)
key = Column(UUID(as_uuid=True), primary_key=True)
request_method = Column(String(10), nullable=False)
request_path = Column(String(255), nullable=False)
request_hash = Column(String(64), nullable=False)
status = Column(String(20), nullable=False, default="in_progress")
response_status = Column(Integer, nullable=True)
response_body = Column(JSONB, nullable=True)
created_at = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
expires_at = Column(DateTime(timezone=True), nullable=False)