pixeluvw_supabase 0.1.0

A production-ready, high-performance Supabase SDK for Rust with middleware, retry logic, and Arc<Inner> architecture
Documentation
//! Middleware examples for pixeluvw_supabase.
//!
//! This file demonstrates various middleware use cases:
//! - Logging
//! - Metrics collection
//! - Request timing
//! - Error tracking

use pixeluvw_supabase::{Middleware, RequestContext, SupabaseClient};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;

// =============================================================================
// 1. Simple Logging Middleware
// =============================================================================

/// A basic middleware that logs all requests and responses.
pub struct LoggingMiddleware {
    prefix: String,
}

impl LoggingMiddleware {
    pub fn new(prefix: &str) -> Self {
        Self {
            prefix: prefix.to_string(),
        }
    }
}

impl Middleware for LoggingMiddleware {
    fn on_request(&self, ctx: &RequestContext) {
        println!("[{}] → {} {}", self.prefix, ctx.method, ctx.table);
    }

    fn on_response(&self, ctx: &RequestContext, status: u16, duration_ms: u64) {
        println!(
            "[{}] ← {} {} -> {} ({}ms)",
            self.prefix, ctx.method, ctx.table, status, duration_ms
        );
    }

    fn on_error(&self, ctx: &RequestContext, error: &str) {
        eprintln!(
            "[{}] ✗ {} {}: {}",
            self.prefix, ctx.method, ctx.table, error
        );
    }
}

// =============================================================================
// 2. Metrics Middleware
// =============================================================================

/// A middleware that collects request/response metrics.
pub struct MetricsMiddleware {
    total_requests: AtomicU64,
    total_errors: AtomicU64,
    total_latency_ms: AtomicU64,
}

impl Default for MetricsMiddleware {
    fn default() -> Self {
        Self::new()
    }
}

impl MetricsMiddleware {
    pub fn new() -> Self {
        Self {
            total_requests: AtomicU64::new(0),
            total_errors: AtomicU64::new(0),
            total_latency_ms: AtomicU64::new(0),
        }
    }

    pub fn get_stats(&self) -> (u64, u64, u64) {
        (
            self.total_requests.load(Ordering::Relaxed),
            self.total_errors.load(Ordering::Relaxed),
            self.total_latency_ms.load(Ordering::Relaxed),
        )
    }

    pub fn avg_latency_ms(&self) -> f64 {
        let requests = self.total_requests.load(Ordering::Relaxed);
        if requests == 0 {
            return 0.0;
        }
        self.total_latency_ms.load(Ordering::Relaxed) as f64 / requests as f64
    }
}

impl Middleware for MetricsMiddleware {
    fn on_request(&self, _ctx: &RequestContext) {
        self.total_requests.fetch_add(1, Ordering::Relaxed);
    }

    fn on_response(&self, _ctx: &RequestContext, _status: u16, duration_ms: u64) {
        self.total_latency_ms
            .fetch_add(duration_ms, Ordering::Relaxed);
    }

    fn on_error(&self, _ctx: &RequestContext, _error: &str) {
        self.total_errors.fetch_add(1, Ordering::Relaxed);
    }
}

// =============================================================================
// 3. Rate Limit Tracker Middleware
// =============================================================================

/// A middleware that tracks rate limit responses.
pub struct RateLimitTracker {
    rate_limited_count: AtomicU64,
}

impl Default for RateLimitTracker {
    fn default() -> Self {
        Self::new()
    }
}

impl RateLimitTracker {
    pub fn new() -> Self {
        Self {
            rate_limited_count: AtomicU64::new(0),
        }
    }

    pub fn get_rate_limited_count(&self) -> u64 {
        self.rate_limited_count.load(Ordering::Relaxed)
    }
}

impl Middleware for RateLimitTracker {
    fn on_response(&self, _ctx: &RequestContext, status: u16, _duration_ms: u64) {
        if status == 429 {
            self.rate_limited_count.fetch_add(1, Ordering::Relaxed);
            eprintln!("⚠️ Rate limited! Total: {}", self.get_rate_limited_count());
        }
    }
}

// =============================================================================
// Example Usage
// =============================================================================

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load .env automatically via SupabaseClient::from_env
    // ensure .env exists with SUPABASE_URL and SUPABASE_KEY

    println!("🔌 Middleware Examples\n");
    println!("   Note: Ensure .env is set with SUPABASE_URL and SUPABASE_KEY\n");

    // Create metrics middleware (keep reference to check stats later)
    let metrics = Arc::new(MetricsMiddleware::new());

    // Create client with multiple middlewares using from_env (which auto-loads .env)
    let client = SupabaseClient::from_env()?
        .with_middleware(Arc::new(LoggingMiddleware::new("SUPABASE")))
        .with_middleware(metrics.clone())
        .with_middleware(Arc::new(RateLimitTracker::new()));

    println!("Client created with 3 middlewares attached.\n");

    // Make some requests
    println!("Making test query...\n");
    let _: Result<Vec<serde_json::Value>, _> =
        client.from("test").select("*").limit(1).execute().await;

    // Check metrics
    let (requests, errors, _latency) = metrics.get_stats();
    println!("\n📊 Metrics Summary:");
    println!("   Total requests: {}", requests);
    println!("   Total errors: {}", errors);
    println!("   Avg latency: {:.2}ms", metrics.avg_latency_ms());

    Ok(())
}