from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase from sqlalchemy.sql import func import enum import datetime class Base(DeclarativeBase): pass class AnalysisStatus(str, enum.Enum): PENDING = "pending" IN_PROGRESS = "in_progress" COMPLETED = "completed" FAILED = "failed" class Report(Base): __tablename__ = "reports" id: Mapped[int] = mapped_column(primary_key=True, index=True) market: Mapped[str] = mapped_column(String(10), index=True) symbol: Mapped[str] = mapped_column(String(20), index=True) company_name: Mapped[str] = mapped_column(String(200)) status: Mapped[AnalysisStatus] = mapped_column(Enum(AnalysisStatus), default=AnalysisStatus.PENDING) ai_model: Mapped[str] = mapped_column(String(100), nullable=True, default="gemini-2.0-flash") created_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) sections: Mapped[list["ReportSection"]] = relationship(back_populates="report", cascade="all, delete-orphan") class ReportSection(Base): __tablename__ = "report_sections" id: Mapped[int] = mapped_column(primary_key=True, index=True) report_id: Mapped[int] = mapped_column(ForeignKey("reports.id")) section_name: Mapped[str] = mapped_column(String(50)) # e.g. company_profile, fundamental_analysis content: Mapped[str] = mapped_column(Text) # Markdown content created_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) report: Mapped["Report"] = relationship(back_populates="sections") class Setting(Base): __tablename__ = "settings" key: Mapped[str] = mapped_column(String(50), primary_key=True) value: Mapped[str] = mapped_column(Text)