"""BGP raw observation model for routing event ingestion.""" from sqlalchemy import Column, DateTime, ForeignKey, Index, Integer, JSON, String, Text from sqlalchemy.sql import func from app.core.time import to_iso8601_utc from app.db.session import Base class BGPObservation(Base): __tablename__ = "bgp_observations" id = Column(Integer, primary_key=True, index=True) snapshot_id = Column(Integer, ForeignKey("data_snapshots.id"), nullable=True, index=True) task_id = Column(Integer, ForeignKey("collection_tasks.id"), nullable=True, index=True) source = Column(String(100), nullable=False, index=True) ingest_batch_id = Column(String(100), nullable=True, index=True) source_event_id = Column(String(100), nullable=True, index=True) collector = Column(String(100), nullable=True, index=True) peer_asn = Column(Integer, nullable=True, index=True) peer_ip = Column(String(100), nullable=True) prefix = Column(String(64), nullable=True, index=True) event_type = Column(String(32), nullable=False, index=True) as_path = Column(JSON, default=list) origin_asn = Column(Integer, nullable=True, index=True) next_hop = Column(String(100), nullable=True) communities = Column(JSON, default=list) observed_at = Column(DateTime(timezone=True), nullable=False, index=True) collector_geo = Column(JSON, default=dict) raw_payload = Column(JSON, default=dict) created_at = Column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True) note = Column(Text, nullable=True) __table_args__ = ( Index("idx_bgp_obs_source_observed", "source", "observed_at"), Index("idx_bgp_obs_collector_prefix", "collector", "prefix"), Index("idx_bgp_obs_task_source_event", "task_id", "source_event_id"), ) def to_dict(self) -> dict: return { "id": self.id, "snapshot_id": self.snapshot_id, "task_id": self.task_id, "source": self.source, "ingest_batch_id": self.ingest_batch_id, "source_event_id": self.source_event_id, "collector": self.collector, "peer_asn": self.peer_asn, "peer_ip": self.peer_ip, "prefix": self.prefix, "event_type": self.event_type, "as_path": self.as_path or [], "origin_asn": self.origin_asn, "next_hop": self.next_hop, "communities": self.communities or [], "observed_at": to_iso8601_utc(self.observed_at), "collector_geo": self.collector_geo or {}, "raw_payload": self.raw_payload or {}, "created_at": to_iso8601_utc(self.created_at), "note": self.note, }