from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, UniqueConstraint from sqlalchemy.dialects.postgresql import UUID, JSONB from sqlalchemy.orm import relationship import uuid from datetime import datetime from app.db.session import Base class Researcher(Base): __tablename__ = "researchers" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) orcid_id = Column(String, unique=True, index=True, nullable=False) name = Column(String, nullable=True) authenticated = Column(Boolean, default=False) last_sync_at = Column(DateTime, nullable=True) publications = relationship("Publication", back_populates="researcher", cascade="all, delete-orphan") class Publication(Base): __tablename__ = "publications" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) researcher_id = Column(UUID(as_uuid=True), ForeignKey("researchers.id"), nullable=False) researcher = relationship("Researcher", back_populates="publications") # ORCID core put_code = Column(Integer, index=True, nullable=False) title = Column(String, nullable=True) subtitle = Column(String, nullable=True) type = Column(String, nullable=True) # Journal / container journal = Column(String, nullable=True) # Dates pub_year = Column(Integer, nullable=True) pub_month = Column(Integer, nullable=True) pub_day = Column(Integer, nullable=True) # Identifiers / links doi = Column(String, nullable=True) url = Column(String, nullable=True) # Description / citation short_description = Column(String, nullable=True) citation_type = Column(String, nullable=True) citation_value = Column(String, nullable=True) # Language / country language_code = Column(String, nullable=True) country = Column(String, nullable=True) # Extra structured data external_ids = Column(JSONB, nullable=True) # lista de external-id normalizados contributors = Column(JSONB, nullable=True) # lista de autores/roles # Tu campo existente hash_fingerprint = Column(String, nullable=True) last_modified = Column(DateTime, nullable=True, default=None) # Legacy: descargado global (deprecado). Mantener por compatibilidad de DB. downloaded = Column(Boolean, nullable=False, default=False) class PublicationDownload(Base): """ Marca de descarga por usuario (researcher) sobre cualquier publicación. Una fila por (researcher_id, publication_id). """ __tablename__ = "publication_downloads" __table_args__ = ( UniqueConstraint("researcher_id", "publication_id", name="uq_publication_download"), ) id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) researcher_id = Column(UUID(as_uuid=True), ForeignKey("researchers.id"), nullable=False, index=True) publication_id = Column(UUID(as_uuid=True), ForeignKey("publications.id"), nullable=False, index=True) downloaded_at = Column(DateTime, nullable=False, default=datetime.utcnow)