from __future__ import annotations from datetime import datetime, timezone from sqlalchemy import DateTime, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column def utc_now() -> datetime: return datetime.now(timezone.utc) class Base(DeclarativeBase): pass class RefreshRunRow(Base): __tablename__ = "refresh_runs" id: Mapped[str] = mapped_column(String(64), primary_key=True) mode: Mapped[str] = mapped_column(String(32), nullable=False) status: Mapped[str] = mapped_column(String(32), nullable=False, default="running") started_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) requested_entity_sets_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]") date_from: Mapped[str | None] = mapped_column(String(64), nullable=True) date_to: Mapped[str | None] = mapped_column(String(64), nullable=True) limit_per_set: Mapped[int] = mapped_column(Integer, nullable=False, default=200) records_read: Mapped[int] = mapped_column(Integer, nullable=False, default=0) entities_written: Mapped[int] = mapped_column(Integer, nullable=False, default=0) links_written: Mapped[int] = mapped_column(Integer, nullable=False, default=0) checkpoints_updated: Mapped[int] = mapped_column(Integer, nullable=False, default=0) details_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") error_message: Mapped[str | None] = mapped_column(Text, nullable=True) class CanonicalEntityRow(Base): __tablename__ = "canonical_entities" __table_args__ = ( UniqueConstraint("source_entity", "source_id", name="uq_canonical_entities_source"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) source_entity: Mapped[str] = mapped_column(String(255), nullable=False) source_id: Mapped[str] = mapped_column(String(255), nullable=False) display_name: Mapped[str] = mapped_column(Text, nullable=False, default="") attributes_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") first_seen_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) last_refresh_run_id: Mapped[str | None] = mapped_column(String(64), nullable=True) class CanonicalLinkRow(Base): __tablename__ = "canonical_links" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) source_entity: Mapped[str] = mapped_column(String(255), nullable=False) source_id: Mapped[str] = mapped_column(String(255), nullable=False) relation: Mapped[str] = mapped_column(String(128), nullable=False) target_entity: Mapped[str] = mapped_column(String(255), nullable=False) target_id: Mapped[str] = mapped_column(String(255), nullable=False) source_field: Mapped[str | None] = mapped_column(String(255), nullable=True) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) last_refresh_run_id: Mapped[str | None] = mapped_column(String(64), nullable=True) class RefreshCheckpointRow(Base): __tablename__ = "refresh_checkpoints" entity_set: Mapped[str] = mapped_column(String(255), primary_key=True) last_success_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) last_refresh_run_id: Mapped[str] = mapped_column(String(64), nullable=False) last_date_from: Mapped[str | None] = mapped_column(String(64), nullable=True) last_date_to: Mapped[str | None] = mapped_column(String(64), nullable=True) class FeatureRunRow(Base): __tablename__ = "feature_runs" id: Mapped[str] = mapped_column(String(64), primary_key=True) status: Mapped[str] = mapped_column(String(32), nullable=False, default="running") started_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) baseline_window_hours: Mapped[int] = mapped_column(Integer, nullable=False, default=24) entities_total: Mapped[int] = mapped_column(Integer, nullable=False, default=0) metrics_written: Mapped[int] = mapped_column(Integer, nullable=False, default=0) anomalies_written: Mapped[int] = mapped_column(Integer, nullable=False, default=0) details_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") error_message: Mapped[str | None] = mapped_column(Text, nullable=True) class FeatureMetricRow(Base): __tablename__ = "feature_metrics" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) feature_run_id: Mapped[str] = mapped_column(String(64), nullable=False) metric_key: Mapped[str] = mapped_column(String(128), nullable=False) scope: Mapped[str] = mapped_column(String(128), nullable=False) scope_id: Mapped[str] = mapped_column(String(255), nullable=False, default="") metric_type: Mapped[str] = mapped_column(String(32), nullable=False, default="gauge") metric_value: Mapped[float] = mapped_column(nullable=False, default=0.0) attributes_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") computed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) class AnomalySignalRow(Base): __tablename__ = "anomaly_signals" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) feature_run_id: Mapped[str] = mapped_column(String(64), nullable=False) signal_type: Mapped[str] = mapped_column(String(128), nullable=False) severity: Mapped[str] = mapped_column(String(32), nullable=False, default="medium") scope: Mapped[str] = mapped_column(String(128), nullable=False, default="global") scope_id: Mapped[str] = mapped_column(String(255), nullable=False, default="") score: Mapped[float] = mapped_column(nullable=False, default=0.0) details_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") detected_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) is_active: Mapped[int] = mapped_column(Integer, nullable=False, default=1) class RiskRunRow(Base): __tablename__ = "risk_runs" id: Mapped[str] = mapped_column(String(64), primary_key=True) status: Mapped[str] = mapped_column(String(32), nullable=False, default="running") started_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) source_feature_run_id: Mapped[str | None] = mapped_column(String(64), nullable=True) patterns_written: Mapped[int] = mapped_column(Integer, nullable=False, default=0) global_score: Mapped[float] = mapped_column(nullable=False, default=0.0) details_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") error_message: Mapped[str | None] = mapped_column(Text, nullable=True) class RiskPatternRow(Base): __tablename__ = "risk_patterns" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) risk_run_id: Mapped[str] = mapped_column(String(64), nullable=False) pattern_key: Mapped[str] = mapped_column(String(128), nullable=False) severity: Mapped[str] = mapped_column(String(32), nullable=False, default="low") scope: Mapped[str] = mapped_column(String(128), nullable=False, default="global") scope_id: Mapped[str] = mapped_column(String(255), nullable=False, default="") score: Mapped[float] = mapped_column(nullable=False, default=0.0) confidence: Mapped[float] = mapped_column(nullable=False, default=0.0) details_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") detected_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=utc_now) is_active: Mapped[int] = mapped_column(Integer, nullable=False, default=1)