from __future__ import annotations from datetime import datetime, timedelta from typing import Optional, List, Dict, Any from sqlalchemy import select, delete, func from sqlalchemy.ext.asyncio import AsyncSession from app.models.host_metrics import HostMetrics class HostMetricsRepository: """Repository pour gérer les métriques des hôtes""" def __init__(self, session: AsyncSession): self.session = session async def create(self, **fields) -> HostMetrics: """Crée une nouvelle entrée de métriques""" metrics = HostMetrics(**fields) self.session.add(metrics) await self.session.flush() return metrics async def get(self, metrics_id: int) -> Optional[HostMetrics]: """Récupère une entrée de métriques par son ID""" stmt = select(HostMetrics).where(HostMetrics.id == metrics_id) result = await self.session.execute(stmt) return result.scalar_one_or_none() async def get_latest_for_host(self, host_id: str, metric_type: str = None) -> Optional[HostMetrics]: """Récupère les dernières métriques pour un hôte""" stmt = select(HostMetrics).where(HostMetrics.host_id == host_id) if metric_type: stmt = stmt.where(HostMetrics.metric_type == metric_type) stmt = stmt.order_by(HostMetrics.collected_at.desc()).limit(1) result = await self.session.execute(stmt) return result.scalar_one_or_none() async def list_for_host( self, host_id: str, metric_type: str = None, limit: int = 100, offset: int = 0 ) -> List[HostMetrics]: """Liste les métriques pour un hôte avec pagination""" stmt = select(HostMetrics).where(HostMetrics.host_id == host_id) if metric_type: stmt = stmt.where(HostMetrics.metric_type == metric_type) stmt = stmt.order_by(HostMetrics.collected_at.desc()).offset(offset).limit(limit) result = await self.session.execute(stmt) return list(result.scalars().all()) async def get_all_latest(self, metric_type: str = "system_info") -> Dict[str, HostMetrics]: """Récupère les dernières métriques pour tous les hôtes Returns: Dict mapping host_id to latest HostMetrics """ # Sous-requête pour obtenir la date max par host_id subq = ( select( HostMetrics.host_id, func.max(HostMetrics.collected_at).label("max_collected") ) .where(HostMetrics.metric_type == metric_type) .group_by(HostMetrics.host_id) .subquery() ) # Jointure pour récupérer les enregistrements complets stmt = ( select(HostMetrics) .join( subq, (HostMetrics.host_id == subq.c.host_id) & (HostMetrics.collected_at == subq.c.max_collected) ) .where(HostMetrics.metric_type == metric_type) ) result = await self.session.execute(stmt) metrics_list = result.scalars().all() return {m.host_id: m for m in metrics_list} async def cleanup_old_metrics(self, days_to_keep: int = 30) -> int: """Supprime les métriques plus anciennes que le nombre de jours spécifié Returns: Nombre d'entrées supprimées """ cutoff_date = datetime.utcnow() - timedelta(days=days_to_keep) stmt = delete(HostMetrics).where(HostMetrics.collected_at < cutoff_date) result = await self.session.execute(stmt) return result.rowcount async def get_metrics_history( self, host_id: str, metric_type: str = "system_info", hours: int = 24 ) -> List[HostMetrics]: """Récupère l'historique des métriques pour les dernières heures""" cutoff = datetime.utcnow() - timedelta(hours=hours) stmt = ( select(HostMetrics) .where(HostMetrics.host_id == host_id) .where(HostMetrics.metric_type == metric_type) .where(HostMetrics.collected_at >= cutoff) .order_by(HostMetrics.collected_at.asc()) ) result = await self.session.execute(stmt) return list(result.scalars().all()) async def count_for_host(self, host_id: str) -> int: """Compte le nombre d'entrées de métriques pour un hôte""" stmt = select(func.count(HostMetrics.id)).where(HostMetrics.host_id == host_id) result = await self.session.execute(stmt) return result.scalar() or 0