""" Post Metrics Model - Tracking engagement metrics per post. """ from datetime import datetime from sqlalchemy import Column, Integer, Float, String, DateTime, ForeignKey, Index from sqlalchemy.orm import relationship from app.core.database import Base class PostMetrics(Base): """ Stores engagement metrics for posts. Multiple records per post to track metrics over time. """ __tablename__ = "post_metrics" id = Column(Integer, primary_key=True, index=True) post_id = Column(Integer, ForeignKey("posts.id", ondelete="CASCADE"), nullable=False) platform = Column(String(50), nullable=False) # Core engagement metrics likes = Column(Integer, default=0) comments = Column(Integer, default=0) shares = Column(Integer, default=0) # retweets, reposts impressions = Column(Integer, default=0) reach = Column(Integer, default=0) saves = Column(Integer, default=0) # bookmarks clicks = Column(Integer, default=0) # link clicks replies = Column(Integer, default=0) quotes = Column(Integer, default=0) # quote tweets # Calculated metrics engagement_rate = Column(Float, default=0.0) engagement_total = Column(Integer, default=0) # Timestamps recorded_at = Column(DateTime, default=datetime.utcnow, index=True) created_at = Column(DateTime, default=datetime.utcnow) # Relationships post = relationship("Post", back_populates="metrics_history") # Indexes for efficient queries __table_args__ = ( Index("ix_post_metrics_post_platform", "post_id", "platform"), Index("ix_post_metrics_recorded", "recorded_at"), ) def calculate_engagement_rate(self): """Calculate engagement rate based on impressions.""" self.engagement_total = ( self.likes + self.comments + self.shares + self.saves + self.replies + self.quotes ) if self.impressions > 0: self.engagement_rate = (self.engagement_total / self.impressions) * 100 else: self.engagement_rate = 0.0 def to_dict(self): return { "id": self.id, "post_id": self.post_id, "platform": self.platform, "likes": self.likes, "comments": self.comments, "shares": self.shares, "impressions": self.impressions, "reach": self.reach, "saves": self.saves, "clicks": self.clicks, "replies": self.replies, "quotes": self.quotes, "engagement_rate": round(self.engagement_rate, 2), "engagement_total": self.engagement_total, "recorded_at": self.recorded_at.isoformat() if self.recorded_at else None }