pixeluvw_supabase 0.1.0

A production-ready, high-performance Supabase SDK for Rust with middleware, retry logic, and Arc<Inner> architecture
Documentation
//! Comprehensive example demonstrating all pixeluvw_supabase features.
//!
//! Run with: cargo run --example usage_demo
//!
//! Requires a `.env` file with:
//! ```
//! SUPABASE_URL=https://your-project.supabase.co
//! SUPABASE_KEY=your-anon-key
//! ```

use dotenv::dotenv;
use pixeluvw_supabase::{ClientConfig, Middleware, RequestContext, SupabaseClient};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

// =============================================================================
// Data Models
// =============================================================================

#[derive(Debug, Serialize, Deserialize)]
#[allow(dead_code)]
struct User {
    id: Option<i32>,
    name: String,
    email: String,
}

// =============================================================================
// Custom Middleware Example
// =============================================================================

struct LoggingMiddleware;

impl Middleware for LoggingMiddleware {
    fn on_request(&self, ctx: &RequestContext) {
        println!(
            "📤 Request: {} {} (table: {})",
            ctx.method, ctx.url, ctx.table
        );
    }

    fn on_response(&self, ctx: &RequestContext, status: u16, duration_ms: u64) {
        let emoji = if status < 400 { "" } else { "" };
        println!(
            "{} Response: {} {} -> {} ({}ms)",
            emoji, ctx.method, ctx.table, status, duration_ms
        );
    }

    fn on_error(&self, ctx: &RequestContext, error: &str) {
        eprintln!("💥 Error on {}: {}", ctx.table, error);
    }
}

// =============================================================================
// Main Demo
// =============================================================================

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load .env file for credentials
    // Note: from_env() does NOT load .env automatically, so we do it here.
    dotenv().ok();

    println!("🚀 pixeluvw_supabase Usage Demo\n");
    println!("{}", "=".repeat(50));

    // -------------------------------------------------------------------------
    // 1. Basic Client Creation (using from_env - RECOMMENDED)
    // -------------------------------------------------------------------------
    println!("\n1️⃣ Creating client from environment variables (RECOMMENDED)...");
    let client = SupabaseClient::from_env()?;
    println!("   ✅ Client created: {:?}", client);

    // -------------------------------------------------------------------------
    // 2. Client with Custom Configuration
    // -------------------------------------------------------------------------
    println!("\n2️⃣ Creating client with custom config...");
    let config = ClientConfig {
        timeout_secs: 60,
        max_retries: 5,
        retry_base_delay_ms: 200,
    };
    let _custom_client = SupabaseClient::from_env_with_config(config)?;
    println!("   ✅ Custom client created with 60s timeout and 5 retries");

    // -------------------------------------------------------------------------
    // 3. Client with Middleware
    // -------------------------------------------------------------------------
    println!("\n3️⃣ Adding middleware...");
    let client_with_logging =
        SupabaseClient::from_env()?.with_middleware(Arc::new(LoggingMiddleware));
    println!("   ✅ Logging middleware attached");

    // -------------------------------------------------------------------------
    // 4. Cheap Cloning (Arc<Inner> demonstration)
    // -------------------------------------------------------------------------
    println!("\n4️⃣ Demonstrating cheap cloning...");
    let client1 = SupabaseClient::from_env()?;
    let _client2 = client1.clone();
    println!("   ✅ Cloned client shares connection pool (Arc::ptr_eq = true)");

    // -------------------------------------------------------------------------
    // 5. Query Examples (using middleware client for logging)
    // -------------------------------------------------------------------------
    println!("\n5️⃣ Query Examples:\n");

    // SELECT
    println!("   📖 SELECT query:");
    let result: Result<Vec<serde_json::Value>, _> = client_with_logging
        .from("users")
        .select("id,name,email")
        .limit(5)
        .execute()
        .await;

    match result {
        Ok(users) => println!("   Found {} users", users.len()),
        Err(e) => println!("   Query failed (table might not exist): {}", e),
    }

    // COUNT
    println!("\n   🔢 COUNT query:");
    let count_result = client_with_logging
        .from("users")
        .count("exact")
        .execute_count()
        .await;

    match count_result {
        Ok(count) => println!("   Total users: {}", count),
        Err(e) => println!("   Count failed: {}", e),
    }

    // -------------------------------------------------------------------------
    // 6. Storage Example
    // -------------------------------------------------------------------------
    println!("\n6️⃣ Storage Example:");
    let storage = client.storage();
    match storage.list_buckets().await {
        Ok(buckets) => {
            println!("   Found {} buckets:", buckets.len());
            for b in &buckets {
                println!("     - {}", b.id);
            }
        }
        Err(e) => println!("   Could not list buckets: {}", e),
    }

    // -------------------------------------------------------------------------
    // 7. Auth Example
    // -------------------------------------------------------------------------
    println!("\n7️⃣ Auth Example:");
    println!("   Attempting sign-in with invalid credentials (expected to fail)...");

    // Auth operations
    let auth_result = client
        .auth()
        .sign_in_with_password("test@example.com", "test123")
        .await;

    match auth_result {
        Ok(session) => {
            println!("   Signed in! Token: {}...", &session.access_token[..20]);
            // To make authenticated requests, we would update the client:
            // let mut client = client;
            // client.set_auth_token(&session.access_token);
        }
        Err(_) => println!("   ✅ Auth correctly rejected invalid credentials"),
    }

    // -------------------------------------------------------------------------
    // Summary
    // -------------------------------------------------------------------------
    println!("\n{}", "=".repeat(50));
    println!("🎉 Demo complete!\n");
    println!("Features demonstrated:");
    println!("  ✅ Basic client creation");
    println!("  ✅ Custom configuration (timeout, retries)");
    println!("  ✅ Middleware system");
    println!("  ✅ Cheap cloning with Arc<Inner>");
    println!("  ✅ SELECT queries");
    println!("  ✅ COUNT queries");
    println!("  ✅ Storage bucket listing");
    println!("  ✅ Authentication");

    Ok(())
}