Something went wrong. Try again.
Highly ambitious ATProtocol AppView service and sdks forked from slices.network/slices
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788//! Analytics and time-series data queries.//!//! This module handles database operations for generating analytics data,//! including sparkline time-series data for record indexing activity.
use super::client::Database;use crate::errors::DatabaseError;use crate::models::SparklinePoint;use std::collections::HashMap;
impl Database { /// Gets sparkline data for multiple slices in a single query batch. /// /// Generates time-bucketed counts of indexed records for visualization. /// /// # Arguments /// * `slice_uris` - Array of slice URIs to get data for /// * `interval` - Time bucket size: "minute", "hour", or "day" /// * `duration_hours` - How many hours of history to include /// /// # Returns /// HashMap mapping slice_uri -> array of (timestamp, count) data points pub async fn get_batch_sparkline_data( &self, slice_uris: &[String], interval: &str, duration_hours: i32, ) -> Result<HashMap<String, Vec<SparklinePoint>>, DatabaseError> { use chrono::{Duration, Utc}; let cutoff_time = Utc::now() - Duration::hours(duration_hours as i64);
let mut sparklines = HashMap::new();
for slice_uri in slice_uris { let interval_validated = match interval { "minute" => "minute", "day" => "day", _ => "hour", };
// Generate a complete series of time buckets with zero-filled gaps let query = format!( r#" WITH time_series AS ( SELECT generate_series( date_trunc('{}', $1::timestamptz), date_trunc('{}', NOW()), '1 {}'::interval ) AS bucket ) SELECT ts.bucket, COALESCE(COUNT(r.cid), 0) as count FROM time_series ts LEFT JOIN record r ON date_trunc('{}', r.indexed_at) = ts.bucket AND r.indexed_at >= $1 AND r.slice_uri = $2 GROUP BY ts.bucket ORDER BY ts.bucket "#, interval_validated, interval_validated, interval_validated, interval_validated );
let rows = sqlx::query_as::<_, (Option<chrono::DateTime<chrono::Utc>>, Option<i64>)>(&query) .bind(cutoff_time) .bind(slice_uri) .fetch_all(&self.pool) .await?;
let data_points = rows .into_iter() .map(|(bucket, count)| SparklinePoint { timestamp: bucket.unwrap().to_rfc3339(), count: count.unwrap_or(0), }) .collect();
sparklines.insert(slice_uri.clone(), data_points); }
Ok(sparklines) }}