import uuid from sqlalchemy import Column, String, Text, DateTime, Integer, Float, ForeignKey, Index, create_engine, Boolean from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from datetime import datetime from app.config import settings Base = declarative_base() class User(Base): __tablename__ = "users" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email = Column(String(255), unique=True, nullable=False, index=True) hashed_password = Column(String(255), nullable=False) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) class Document(Base): __tablename__ = "documents" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) source = Column(String(50), nullable=False) ext_id = Column(String(200), nullable=True) title = Column(Text, nullable=False) url = Column(Text, nullable=True) lang = Column(String(2), nullable=True) minio_key = Column(Text, nullable=True) indexed_at = Column(DateTime, default=datetime.utcnow) class Fingerprint(Base): __tablename__ = "fingerprints" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) doc_id = Column(UUID(as_uuid=True), ForeignKey("documents.id"), nullable=False) hash = Column(String(64), nullable=False) # xxhash hex string position = Column(Integer, nullable=True) Index("ix_fingerprints_hash", Fingerprint.hash) Index("ix_fingerprints_doc_id", Fingerprint.doc_id) class AnalysisTask(Base): __tablename__ = "analysis_tasks" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True) status = Column(String(20), default="pending") overall_similarity = Column(Float, nullable=True) source_text = Column(Text, nullable=True) created_at = Column(DateTime, default=datetime.utcnow) completed_at = Column(DateTime, nullable=True) class Match(Base): __tablename__ = "matches" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) task_id = Column(UUID(as_uuid=True), ForeignKey("analysis_tasks.id"), nullable=False) doc_id = Column(UUID(as_uuid=True), ForeignKey("documents.id"), nullable=True) similarity = Column(Float, nullable=False) method = Column(String(20), nullable=False) fragment_start = Column(Integer, nullable=True) fragment_end = Column(Integer, nullable=True) fragment_text = Column(Text, nullable=True) engine = create_engine(settings.DATABASE_URL, echo=False) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) def get_db(): db = SessionLocal() try: yield db finally: db.close()