tiny-counter 0.1.0

Track event counts across time windows with fixed memory and fast queries
Documentation
// User engagement and analytics.
//
// This example shows how to:
// - Track Daily/Weekly/Monthly Active Users (DAU/WAU/MAU)
// - Calculate conversion rates
// - Score user engagement
// - Count active days

use chrono::Duration;
use tiny_counter::{EventId, EventStore};

// User engagement events
#[derive(Debug, Clone, Copy)]
enum UserEvent {
    Launch,
    FeatureUse,
    SettingsVisit,
    Purchase,
}

impl AsRef<str> for UserEvent {
    fn as_ref(&self) -> &str {
        match self {
            UserEvent::Launch => "user:launch",
            UserEvent::FeatureUse => "user:feature_use",
            UserEvent::SettingsVisit => "user:settings_visit",
            UserEvent::Purchase => "user:purchase",
        }
    }
}

impl EventId for UserEvent {}

fn main() {
    println!("=== User Analytics Examples ===\n");

    let store = EventStore::new();

    // Simulate user activity over time
    println!("Simulating user activity...");

    // Today: High engagement
    for _ in 0..10 {
        store.record(UserEvent::Launch);
        store.record(UserEvent::FeatureUse);
    }
    store.record_count(UserEvent::Purchase, 2);

    // Yesterday: Moderate engagement
    for _ in 0..5 {
        store.record_ago(UserEvent::Launch, Duration::days(1));
        store.record_ago(UserEvent::SettingsVisit, Duration::days(1));
    }

    // 2 days ago: Light engagement
    for _ in 0..2 {
        store.record_ago(UserEvent::Launch, Duration::days(2));
    }

    println!("  Recorded activity across 3 days\n");

    // 1. Daily/Weekly/Monthly Active Users
    println!("1. Active Users (DAU/WAU/MAU):");

    let dau = store
        .query(UserEvent::Launch)
        .last_days(1)
        .count_nonzero()
        .unwrap_or(0);

    let wau = store
        .query(UserEvent::Launch)
        .last_days(7)
        .count_nonzero()
        .unwrap_or(0);

    let mau = store
        .query(UserEvent::Launch)
        .last_days(30)
        .count_nonzero()
        .unwrap_or(0);

    println!("  DAU (active days in last 1 day): {}", dau);
    println!("  WAU (active days in last 7 days): {}", wau);
    println!("  MAU (active days in last 30 days): {}", mau);

    // 2. Engagement intensity
    println!("\n2. Engagement intensity:");

    let launches_today = store
        .query(UserEvent::Launch)
        .last_days(1)
        .sum()
        .unwrap_or(0);

    let launches_week = store
        .query(UserEvent::Launch)
        .last_days(7)
        .sum()
        .unwrap_or(0);

    let avg_per_day = store
        .query(UserEvent::Launch)
        .last_days(7)
        .average()
        .unwrap_or(0.0);

    let avg_on_active_days = store
        .query(UserEvent::Launch)
        .last_days(7)
        .average_nonzero()
        .unwrap_or(0.0);

    println!("  Launches today: {}", launches_today);
    println!("  Launches this week: {}", launches_week);
    println!("  Average per day: {:.2}", avg_per_day);
    println!("  Average on active days: {:.2}", avg_on_active_days);

    // 3. Conversion rates
    println!("\n3. Conversion rates:");

    let conversion_rate = store
        .query_ratio(UserEvent::Purchase, UserEvent::Launch)
        .last_days(7);

    if let Some(rate) = conversion_rate {
        println!("  Purchase conversion rate: {:.1}%", rate * 100.0);
    }

    let feature_adoption = store
        .query_ratio(UserEvent::FeatureUse, UserEvent::Launch)
        .last_days(7);

    if let Some(rate) = feature_adoption {
        println!("  Feature adoption rate: {:.1}%", rate * 100.0);
    }

    // 4. Engagement scoring
    println!("\n4. Engagement scoring:");

    let launches = store
        .query(UserEvent::Launch)
        .last_days(30)
        .sum()
        .unwrap_or(0);

    let feature_uses = store
        .query(UserEvent::FeatureUse)
        .last_days(30)
        .sum()
        .unwrap_or(0);

    let active_days = store
        .query(UserEvent::Launch)
        .last_days(30)
        .count_nonzero()
        .unwrap_or(0);

    // Score: launches×1 + features×5 + active_days×10
    let score = launches + (feature_uses * 5) + (active_days as u32 * 10);

    let segment = match score {
        0..=50 => "dormant",
        51..=200 => "casual",
        201..=500 => "regular",
        _ => "power_user",
    };

    println!("  Launches: {} (weight: 1)", launches);
    println!("  Feature uses: {} (weight: 5)", feature_uses);
    println!("  Active days: {} (weight: 10)", active_days);
    println!("  Total score: {}", score);
    println!("  User segment: {}", segment);

    // 5. Time-based patterns
    println!("\n5. Activity patterns:");

    if let Some(last_seen) = store.query(UserEvent::Launch).last_seen() {
        let hours_ago = last_seen.num_hours();
        let days_ago = last_seen.num_days();

        println!("  Last activity: {} hours ago", hours_ago);

        let status = if days_ago == 0 {
            "Active today"
        } else if days_ago <= 3 {
            "Regular user"
        } else if days_ago <= 7 {
            "Occasional user"
        } else if days_ago <= 30 {
            "At risk"
        } else {
            "Churned"
        };

        println!("  User status: {}", status);
    }

    // 6. Multi-event analysis
    println!("\n6. Overall engagement:");

    let total_events = store
        .query_many(&[
            UserEvent::Launch,
            UserEvent::FeatureUse,
            UserEvent::SettingsVisit,
            UserEvent::Purchase,
        ])
        .last_days(7)
        .sum()
        .unwrap_or(0);

    println!("  Total engagement events this week: {}", total_events);

    println!("\n✓ Analytics complete!");
}