scim-server 0.4.0

A comprehensive SCIM 2.0 server library for Rust with multi-tenant support and type-safe operations
Documentation
//! Basic SCIM Server Usage Example
//!
//! This example demonstrates the basic functionality of a SCIM server
//! using the StandardResourceProvider with in-memory storage.

use scim_server::{
    RequestContext, providers::StandardResourceProvider, resource::provider::ResourceProvider,
    storage::InMemoryStorage,
};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("๐Ÿš€ Starting SCIM Server Basic Usage Example");

    // Create the StandardResourceProvider with in-memory storage
    let storage = InMemoryStorage::new();
    let provider = StandardResourceProvider::new(storage);

    println!("โœ… StandardResourceProvider initialized with in-memory storage");

    // Create a request context for our operations
    let context = RequestContext::new("example-request-1".to_string());

    println!("\n๐Ÿ“ Creating users...");

    // Create first user
    let user1_data = json!({
        "userName": "john.doe@example.com",
        "name": {
            "formatted": "John Doe",
            "familyName": "Doe",
            "givenName": "John"
        },
        "emails": [
            {
                "value": "john.doe@example.com",
                "type": "work",
                "primary": true
            },
            {
                "value": "john.personal@example.com",
                "type": "home",
                "primary": false
            }
        ],
        "phoneNumbers": [
            {
                "value": "+1-555-555-1234",
                "type": "work"
            }
        ],
        "active": true
    });

    let user1 = provider
        .create_resource("User", user1_data, &context)
        .await?;
    println!(
        "โœ… Created user: {} (ID: {})",
        user1.get_username().unwrap_or("unknown"),
        user1.get_id().unwrap_or("unknown")
    );

    // Create second user
    let user2_data = json!({
        "userName": "jane.smith@example.com",
        "name": {
            "formatted": "Jane Smith",
            "familyName": "Smith",
            "givenName": "Jane"
        },
        "emails": [
            {
                "value": "jane.smith@example.com",
                "type": "work",
                "primary": true
            }
        ],
        "active": true
    });

    let user2 = provider
        .create_resource("User", user2_data, &context)
        .await?;
    println!(
        "โœ… Created user: {} (ID: {})",
        user2.get_username().unwrap_or("unknown"),
        user2.get_id().unwrap_or("unknown")
    );

    println!("\n๐Ÿ“‹ Listing all users...");

    // List all users
    let users = provider.list_resources("User", None, &context).await?;
    println!("๐Ÿ“Š Found {} users:", users.len());
    for user in &users {
        println!(
            "   - {} ({})",
            user.get_username().unwrap_or("unknown"),
            user.get_id().unwrap_or("unknown")
        );
    }

    println!("\n๐Ÿ” Finding users by attributes...");

    // Find user by username
    let found_user = provider
        .find_resource_by_attribute("User", "userName", &json!("john.doe@example.com"), &context)
        .await?;

    match found_user {
        Some(user) => {
            println!(
                "โœ… Found user by username: {} (ID: {})",
                user.get_username().unwrap_or("unknown"),
                user.get_id().unwrap_or("unknown")
            );
        }
        None => println!("โŒ User not found by username"),
    }

    // Find user by email
    let found_by_email = provider
        .find_resource_by_attribute(
            "User",
            "emails.value",
            &json!("jane.smith@example.com"),
            &context,
        )
        .await?;

    match found_by_email {
        Some(user) => {
            println!(
                "โœ… Found user by email: {} (ID: {})",
                user.get_username().unwrap_or("unknown"),
                user.get_id().unwrap_or("unknown")
            );
        }
        None => println!("โŒ User not found by email"),
    }

    println!("\nโœ๏ธ  Updating user...");

    // Update the first user
    let user1_id = user1.get_id().unwrap();
    let updated_data = json!({
        "id": user1_id,
        "userName": "john.doe@example.com",
        "name": {
            "formatted": "John Updated Doe",
            "familyName": "Doe",
            "givenName": "John",
            "middleName": "Updated"
        },
        "emails": [
            {
                "value": "john.doe@example.com",
                "type": "work",
                "primary": true
            },
            {
                "value": "john.personal@example.com",
                "type": "home",
                "primary": false
            }
        ],
        "phoneNumbers": [
            {
                "value": "+1-555-555-1234",
                "type": "work"
            },
            {
                "value": "+1-555-555-5678",
                "type": "mobile"
            }
        ],
        "active": true
    });

    let updated_user = provider
        .update_resource("User", user1_id, updated_data, &context)
        .await?;
    println!(
        "โœ… Updated user: {} (ID: {})",
        updated_user.get_username().unwrap_or("unknown"),
        updated_user.get_id().unwrap_or("unknown")
    );

    // Show the updated name
    if let Some(name) = updated_user.get_name() {
        if let Some(formatted) = name.formatted.as_ref() {
            println!("   ๐Ÿ“ New formatted name: {}", formatted);
        }
    }

    println!("\n๐Ÿ“ž Working with phone numbers...");

    // Demonstrate working with phone numbers
    if let Some(phone_numbers) = updated_user.get_phone_numbers() {
        println!("๐Ÿ“ฑ User has {} phone numbers:", phone_numbers.len());
        for phone in phone_numbers {
            let phone_type = phone.phone_type.as_ref().map_or("unknown", |v| v);
            println!("   - {}: {}", phone_type, phone.value);
        }
    }

    println!("\n๐Ÿ“ง Working with email addresses...");

    // Demonstrate working with emails
    if let Some(emails) = updated_user.get_emails() {
        println!("๐Ÿ“ง User has {} email addresses:", emails.len());
        for email in emails {
            let email_type = email.email_type.as_ref().map_or("unknown", |v| v);
            let is_primary = email.primary.unwrap_or(false);
            println!(
                "   - {}: {} (primary: {})",
                email_type, email.value, is_primary
            );
        }
    }

    println!("\n๐Ÿ—‘๏ธ  Testing resource existence and deletion...");

    // Check if user exists
    let user2_id = user2.get_id().unwrap();
    let exists = provider.resource_exists("User", user2_id, &context).await?;
    println!("โœ… User {} exists: {}", user2_id, exists);

    // Delete the second user
    provider.delete_resource("User", user2_id, &context).await?;
    println!("โœ… Deleted user");

    // Check if user still exists
    let exists_after = provider.resource_exists("User", user2_id, &context).await?;
    println!(
        "โœ… User {} exists after deletion: {}",
        user2_id, exists_after
    );

    // List users again to confirm deletion
    let users_after = provider.list_resources("User", None, &context).await?;
    println!("๐Ÿ“Š Users remaining after deletion: {}", users_after.len());

    println!("\n๐Ÿ“Š Provider statistics...");

    // Get provider statistics
    let stats = provider.get_stats().await;
    println!("๐Ÿ“ˆ Provider Statistics:");
    println!("   โ€ข Total tenants: {}", stats.tenant_count);
    println!("   โ€ข Total resources: {}", stats.total_resources);
    println!("   โ€ข Resource types: {:?}", stats.resource_types);
    println!("   โ€ข Resource type count: {}", stats.resource_type_count);

    println!("\n๐Ÿงน Testing clear functionality...");

    // Test clear functionality
    provider.clear().await;
    let stats_after_clear = provider.get_stats().await;
    println!("๐Ÿ“ˆ Statistics after clear:");
    println!("   โ€ข Total tenants: {}", stats_after_clear.tenant_count);
    println!(
        "   โ€ข Total resources: {}",
        stats_after_clear.total_resources
    );

    println!("\nโœ… Basic Usage Example Complete!");
    println!("๐ŸŽ‰ Successfully demonstrated:");
    println!("   โ€ข Creating resources with StandardResourceProvider");
    println!("   โ€ข Listing and searching resources");
    println!("   โ€ข Updating and deleting resources");
    println!("   โ€ข Working with complex attributes (emails, phone numbers)");
    println!("   โ€ข Provider statistics and resource existence checks");
    println!("   โ€ข Clear functionality for testing");

    Ok(())
}