"""Logic for the /participant-metrics endpoint.""" from typing import Any, Mapping from ddtrace import tracer from analytics.constants import cache from analytics.queries.format import format_row from analytics.queries.participant_metrics import ( PARTICIPANT_METRICS_FIELDS, ParticipantMetrics, ) from analytics.schemas.participants import ParticipantMetricsSchema from analytics.utils import store_availability from analytics.utils.cache import cache_in_redis @cache_in_redis(ttl=cache.ONE_DAY) @tracer.wrap(name="get_participant_metrics") def get_participant_metrics( query_params: Mapping[str, Any], permissions: Mapping[str, Any] ): """Fetch participant metrics.""" available_store_ids = store_availability.get_query_store_ids( query_params.get("store_ids") or [] ) if not available_store_ids: return ParticipantMetricsSchema.normalized_response( {"metrics": [], "total_participants": 0} ) rows = ParticipantMetrics( { **permissions, **query_params, "store_ids": available_store_ids, "order_dir": (query_params.get("order_dir") or "DESC").upper(), "is_feed_data_available": store_availability.is_apple_spotify_data_in_sync(), # METRICS_BY_TRACK_PARTICIPANT_*_ROLLUP is widened by the # transfer-product-ownership dbt PR; rollup_grain dedups former-owner # rows that would otherwise inflate SUM()s post-transfer. "rollup_grain": True, } ).execute() metrics = [format_row(row) for row in rows] total_participants = metrics[0].pop("total_participants", 0) if metrics else 0 for row in metrics[1:]: row.pop("total_participants", None) items = [ {key: row[key] for key in PARTICIPANT_METRICS_FIELDS if key in row} for row in metrics ] return ParticipantMetricsSchema.normalized_response( {"metrics": items, "total_participants": total_participants} )