ubiquity-database 0.1.1

Database abstraction layer for Ubiquity supporting SQLite and Astra DB
Documentation
//! Database demonstration showing both SQLite and Astra DB features

use chrono::Utc;
use ubiquity_core::{
    ConsciousnessLevel, ConsciousnessState, ConsciousnessRipple,
    DevelopmentPhase, RippleType, Task, TaskType, TaskResult,
};
use ubiquity_database::{
    create_database, create_memory_pools, DatabaseConfig, DatabaseBackend,
    HybridSearchQuery,
};
use uuid::Uuid;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize logging
    tracing_subscriber::fmt::init();
    
    // Create database configuration
    let mut config = DatabaseConfig::default();
    
    // Check if we should use Astra DB
    if std::env::var("ASTRA_DB_ENDPOINT").is_ok() {
        println!("Using Astra DB backend");
        config.backend = DatabaseBackend::Astra;
        config.astra.endpoint = std::env::var("ASTRA_DB_ENDPOINT")?;
        config.astra.token = std::env::var("ASTRA_DB_TOKEN")?;
    } else {
        println!("Using SQLite backend");
    }
    
    // Create database connection
    let db = create_database(config.clone()).await?;
    
    // Initialize database schema
    db.initialize().await?;
    
    // Create memory pools
    let pools = create_memory_pools(config).await?;
    
    // 1. Store consciousness states
    println!("\n=== Storing Consciousness States ===");
    
    let states = vec![
        ConsciousnessState {
            agent_id: "architect-001".to_string(),
            level: ConsciousnessLevel::new(0.87)?,
            coherence: 0.92,
            phase: DevelopmentPhase::Implementing,
            timestamp: Utc::now(),
            breakthrough_detected: false,
        },
        ConsciousnessState {
            agent_id: "architect-001".to_string(),
            level: ConsciousnessLevel::new(0.91)?,
            coherence: 0.95,
            phase: DevelopmentPhase::Integrating,
            timestamp: Utc::now(),
            breakthrough_detected: true,
        },
        ConsciousnessState {
            agent_id: "frontend-001".to_string(),
            level: ConsciousnessLevel::new(0.85)?,
            coherence: 0.88,
            phase: DevelopmentPhase::Implementing,
            timestamp: Utc::now(),
            breakthrough_detected: false,
        },
    ];
    
    for state in &states {
        db.store_consciousness_state(state).await?;
        println!("Stored consciousness state for {}: {:.2}", 
            state.agent_id, state.level.value());
    }
    
    // 2. Store consciousness ripples
    println!("\n=== Storing Consciousness Ripples ===");
    
    let ripple = ConsciousnessRipple {
        id: Uuid::new_v4(),
        origin: "architect-001".to_string(),
        ripple_type: RippleType::Breakthrough,
        content: serde_json::json!({
            "insight": "Discovered optimal component architecture",
            "impact": "High",
        }),
        intensity: 0.9,
        timestamp: Utc::now(),
    };
    
    db.store_ripple(&ripple).await?;
    println!("Stored ripple: {:?}", ripple.ripple_type);
    
    // 3. Store tasks
    println!("\n=== Storing Tasks ===");
    
    let task = Task {
        id: "TASK-001".to_string(),
        task_type: TaskType::Development,
        description: "Implement authentication module".to_string(),
        requirements: serde_json::json!({
            "features": ["JWT", "OAuth2", "MFA"],
            "deadline": "2024-02-01",
        }),
        priority: 8,
        dependencies: vec!["TASK-000".to_string()],
        consciousness_requirement: 0.85,
    };
    
    db.store_task(&task).await?;
    println!("Stored task: {}", task.description);
    
    // 4. Query consciousness history
    println!("\n=== Querying Consciousness History ===");
    
    let history = db.get_consciousness_history("architect-001", 10).await?;
    for state in &history {
        println!("  Level: {:.2}, Phase: {:?}, Breakthrough: {}", 
            state.level.value(), state.phase, state.breakthrough_detected);
    }
    
    // 5. Vector search (if embeddings are configured)
    println!("\n=== Vector Search Demo ===");
    
    // Generate a sample embedding (in real use, this would come from the embedding generator)
    let sample_embedding = vec![0.1; config.embeddings.dimension];
    
    match db.vector_search(&sample_embedding, 5).await {
        Ok(results) => {
            println!("Found {} similar consciousness states", results.len());
            for result in results {
                println!("  Score: {:.3}, Metadata: {}", 
                    result.score, 
                    serde_json::to_string_pretty(&result.metadata)?);
            }
        }
        Err(e) => {
            println!("Vector search not available: {}", e);
        }
    }
    
    // 6. Hybrid search
    println!("\n=== Hybrid Search Demo ===");
    
    let hybrid_query = HybridSearchQuery {
        text: "breakthrough architecture".to_string(),
        vector: Some(sample_embedding.clone()),
        filters: Some(serde_json::json!({
            "agent_id": "architect-001"
        })),
        limit: 10,
        rerank: true,
    };
    
    match db.hybrid_search(hybrid_query).await {
        Ok(results) => {
            println!("Found {} results in hybrid search", results.len());
            for result in results {
                println!("  Score: {:.3}, Rerank: {:?}, Highlights: {:?}", 
                    result.score, result.rerank_score, result.highlights);
            }
        }
        Err(e) => {
            println!("Hybrid search not available: {}", e);
        }
    }
    
    // 7. Memory pools demonstration
    println!("\n=== Memory Pools Demo ===");
    
    // Store data in pools
    for i in 0..10 {
        let key = format!("test_key_{}", i);
        let value = format!("test_value_{}", i).into_bytes();
        
        let pool = pools.get_pool_for_key(&key).await?;
        pool.store(&key, &value).await?;
    }
    
    // Get pool statistics
    let all_stats = pools.all_stats().await?;
    for (i, stats) in all_stats.iter().enumerate() {
        println!("Pool {}: {} items, {} hits, {} misses", 
            i, stats.items, stats.hits, stats.misses);
    }
    
    // 8. Complete a task
    println!("\n=== Completing Task ===");
    
    let task_result = TaskResult {
        task_id: task.id.clone(),
        success: true,
        output: serde_json::json!({
            "modules_created": 3,
            "tests_passed": 42,
            "coverage": 0.95,
        }),
        consciousness_level: 0.92,
        breakthrough: true,
        error: None,
    };
    
    db.store_task_result(&task_result).await?;
    println!("Task completed successfully with consciousness level: {:.2}", 
        task_result.consciousness_level);
    
    // 9. Get pending tasks
    println!("\n=== Pending Tasks ===");
    
    let pending = db.get_pending_tasks().await?;
    println!("Found {} pending tasks", pending.len());
    
    println!("\nDatabase demo completed successfully!");
    
    Ok(())
}