296 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			296 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
/// Custom Object Example
 | 
						|
/// 
 | 
						|
/// This example demonstrates how to create your own custom object types
 | 
						|
/// using the derive macro.
 | 
						|
/// 
 | 
						|
/// Run with:
 | 
						|
/// ```bash
 | 
						|
/// cargo run --example custom_object
 | 
						|
/// ```
 | 
						|
 | 
						|
use osiris::store::{BaseData, GenericStore, HeroDbClient};
 | 
						|
use osiris::{DeriveObject, Object};
 | 
						|
use serde::{Deserialize, Serialize};
 | 
						|
use std::collections::BTreeMap;
 | 
						|
use time::OffsetDateTime;
 | 
						|
 | 
						|
// ========================================
 | 
						|
// Custom Object: Task
 | 
						|
// ========================================
 | 
						|
 | 
						|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 | 
						|
pub enum TaskPriority {
 | 
						|
    Low,
 | 
						|
    Medium,
 | 
						|
    High,
 | 
						|
    Critical,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 | 
						|
pub enum TaskStatus {
 | 
						|
    Todo,
 | 
						|
    InProgress,
 | 
						|
    Done,
 | 
						|
    Blocked,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, Clone, Serialize, Deserialize, DeriveObject)]
 | 
						|
pub struct Task {
 | 
						|
    pub base_data: BaseData,
 | 
						|
    
 | 
						|
    /// Task title
 | 
						|
    #[index]
 | 
						|
    pub title: String,
 | 
						|
    
 | 
						|
    /// Task description
 | 
						|
    pub description: Option<String>,
 | 
						|
    
 | 
						|
    /// Priority level
 | 
						|
    #[index]
 | 
						|
    pub priority: TaskPriority,
 | 
						|
    
 | 
						|
    /// Current status
 | 
						|
    #[index]
 | 
						|
    pub status: TaskStatus,
 | 
						|
    
 | 
						|
    /// Assigned to user
 | 
						|
    #[index]
 | 
						|
    pub assignee: Option<String>,
 | 
						|
    
 | 
						|
    /// Due date
 | 
						|
    #[index]
 | 
						|
    #[serde(with = "time::serde::rfc3339::option")]
 | 
						|
    pub due_date: Option<OffsetDateTime>,
 | 
						|
    
 | 
						|
    /// Tags for categorization
 | 
						|
    #[index]
 | 
						|
    pub tags: BTreeMap<String, String>,
 | 
						|
    
 | 
						|
    /// Estimated hours
 | 
						|
    pub estimated_hours: Option<f32>,
 | 
						|
    
 | 
						|
    /// Actual hours spent
 | 
						|
    pub actual_hours: Option<f32>,
 | 
						|
}
 | 
						|
 | 
						|
impl Task {
 | 
						|
    pub fn new(ns: String, title: impl ToString) -> Self {
 | 
						|
        Self {
 | 
						|
            base_data: BaseData::new(ns),
 | 
						|
            title: title.to_string(),
 | 
						|
            description: None,
 | 
						|
            priority: TaskPriority::Medium,
 | 
						|
            status: TaskStatus::Todo,
 | 
						|
            assignee: None,
 | 
						|
            due_date: None,
 | 
						|
            tags: BTreeMap::new(),
 | 
						|
            estimated_hours: None,
 | 
						|
            actual_hours: None,
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn set_description(mut self, description: impl ToString) -> Self {
 | 
						|
        self.description = Some(description.to_string());
 | 
						|
        self
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn set_priority(mut self, priority: TaskPriority) -> Self {
 | 
						|
        self.priority = priority;
 | 
						|
        self
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn set_status(mut self, status: TaskStatus) -> Self {
 | 
						|
        self.status = status;
 | 
						|
        self
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn set_assignee(mut self, assignee: impl ToString) -> Self {
 | 
						|
        self.assignee = Some(assignee.to_string());
 | 
						|
        self
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn set_due_date(mut self, due_date: OffsetDateTime) -> Self {
 | 
						|
        self.due_date = Some(due_date);
 | 
						|
        self
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn add_tag(mut self, key: impl ToString, value: impl ToString) -> Self {
 | 
						|
        self.tags.insert(key.to_string(), value.to_string());
 | 
						|
        self
 | 
						|
    }
 | 
						|
    
 | 
						|
    pub fn set_estimated_hours(mut self, hours: f32) -> Self {
 | 
						|
        self.estimated_hours = Some(hours);
 | 
						|
        self
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// ========================================
 | 
						|
// Main Example
 | 
						|
// ========================================
 | 
						|
 | 
						|
#[tokio::main]
 | 
						|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
						|
    println!("🎯 OSIRIS Custom Object Example\n");
 | 
						|
    
 | 
						|
    // Connect to HeroDB
 | 
						|
    println!("📡 Connecting to HeroDB...");
 | 
						|
    let client = HeroDbClient::new("redis://localhost:6379", 2)?;
 | 
						|
    let store = GenericStore::new(client);
 | 
						|
    println!("✓ Connected to HeroDB (DB 2)\n");
 | 
						|
    
 | 
						|
    // ========================================
 | 
						|
    // Create Tasks
 | 
						|
    // ========================================
 | 
						|
    println!("📋 Creating Tasks");
 | 
						|
    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
 | 
						|
    
 | 
						|
    let now = OffsetDateTime::now_utc();
 | 
						|
    let tomorrow = now + time::Duration::days(1);
 | 
						|
    let next_week = now + time::Duration::days(7);
 | 
						|
    
 | 
						|
    // Task 1: High priority, assigned
 | 
						|
    let task1 = Task::new("tasks".to_string(), "Implement derive macro")
 | 
						|
        .set_description("Create proc macro for automatic Object trait implementation")
 | 
						|
        .set_priority(TaskPriority::High)
 | 
						|
        .set_status(TaskStatus::Done)
 | 
						|
        .set_assignee("alice")
 | 
						|
        .set_due_date(tomorrow)
 | 
						|
        .add_tag("component", "derive")
 | 
						|
        .add_tag("project", "osiris")
 | 
						|
        .set_estimated_hours(8.0);
 | 
						|
    
 | 
						|
    println!("Task 1: {}", task1.title);
 | 
						|
    println!("  Priority: {:?}", task1.priority);
 | 
						|
    println!("  Status: {:?}", task1.status);
 | 
						|
    println!("  Assignee: {}", task1.assignee.as_ref().unwrap());
 | 
						|
    store.put(&task1).await?;
 | 
						|
    println!("✓ Stored\n");
 | 
						|
    
 | 
						|
    // Task 2: Critical priority, blocked
 | 
						|
    let task2 = Task::new("tasks".to_string(), "Fix indexing bug")
 | 
						|
        .set_description("BTreeMap indexing has lifetime issues")
 | 
						|
        .set_priority(TaskPriority::Critical)
 | 
						|
        .set_status(TaskStatus::Blocked)
 | 
						|
        .set_assignee("bob")
 | 
						|
        .set_due_date(now)
 | 
						|
        .add_tag("type", "bug")
 | 
						|
        .add_tag("project", "osiris")
 | 
						|
        .set_estimated_hours(4.0);
 | 
						|
    
 | 
						|
    println!("Task 2: {}", task2.title);
 | 
						|
    println!("  Priority: {:?}", task2.priority);
 | 
						|
    println!("  Status: {:?}", task2.status);
 | 
						|
    store.put(&task2).await?;
 | 
						|
    println!("✓ Stored\n");
 | 
						|
    
 | 
						|
    // Task 3: In progress
 | 
						|
    let task3 = Task::new("tasks".to_string(), "Write documentation")
 | 
						|
        .set_description("Document the derive macro usage")
 | 
						|
        .set_priority(TaskPriority::Medium)
 | 
						|
        .set_status(TaskStatus::InProgress)
 | 
						|
        .set_assignee("alice")
 | 
						|
        .set_due_date(next_week)
 | 
						|
        .add_tag("type", "docs")
 | 
						|
        .add_tag("project", "osiris")
 | 
						|
        .set_estimated_hours(6.0);
 | 
						|
    
 | 
						|
    println!("Task 3: {}", task3.title);
 | 
						|
    println!("  Priority: {:?}", task3.priority);
 | 
						|
    println!("  Status: {:?}", task3.status);
 | 
						|
    store.put(&task3).await?;
 | 
						|
    println!("✓ Stored\n");
 | 
						|
    
 | 
						|
    // ========================================
 | 
						|
    // Query Tasks
 | 
						|
    // ========================================
 | 
						|
    println!("🔍 Querying Tasks");
 | 
						|
    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
 | 
						|
    
 | 
						|
    // Query by assignee
 | 
						|
    println!("Tasks assigned to Alice:");
 | 
						|
    let alice_tasks = store.get_ids_by_index("tasks", "assignee", "alice").await?;
 | 
						|
    for id in &alice_tasks {
 | 
						|
        let task: Task = store.get("tasks", id).await?;
 | 
						|
        println!("  - {} ({:?})", task.title, task.status);
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
    
 | 
						|
    // Query by priority
 | 
						|
    println!("High priority tasks:");
 | 
						|
    let high_priority = store.get_ids_by_index("tasks", "priority", "High").await?;
 | 
						|
    for id in &high_priority {
 | 
						|
        let task: Task = store.get("tasks", id).await?;
 | 
						|
        println!("  - {} (assigned to: {})", 
 | 
						|
            task.title, 
 | 
						|
            task.assignee.as_ref().unwrap_or(&"unassigned".to_string())
 | 
						|
        );
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
    
 | 
						|
    // Query by status
 | 
						|
    println!("Blocked tasks:");
 | 
						|
    let blocked = store.get_ids_by_index("tasks", "status", "Blocked").await?;
 | 
						|
    for id in &blocked {
 | 
						|
        let task: Task = store.get("tasks", id).await?;
 | 
						|
        println!("  - {} (priority: {:?})", task.title, task.priority);
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
    
 | 
						|
    // Query by tag
 | 
						|
    println!("Tasks tagged with project=osiris:");
 | 
						|
    let project_tasks = store.get_ids_by_index("tasks", "tags:tag", "project=osiris").await?;
 | 
						|
    println!("  Found {} tasks", project_tasks.len());
 | 
						|
    println!();
 | 
						|
    
 | 
						|
    // ========================================
 | 
						|
    // Show Auto-Generated Indexes
 | 
						|
    // ========================================
 | 
						|
    println!("📊 Auto-Generated Indexes");
 | 
						|
    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
 | 
						|
    
 | 
						|
    println!("Task indexed fields: {:?}", Task::indexed_fields());
 | 
						|
    println!();
 | 
						|
    
 | 
						|
    println!("Index keys for '{}':", task1.title);
 | 
						|
    for key in task1.index_keys() {
 | 
						|
        println!("  - {} = {}", key.name, key.value);
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
    
 | 
						|
    // ========================================
 | 
						|
    // Update Task Status
 | 
						|
    // ========================================
 | 
						|
    println!("✏️  Updating Task Status");
 | 
						|
    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
 | 
						|
    
 | 
						|
    // Retrieve, modify, and store
 | 
						|
    let mut task2_updated: Task = store.get("tasks", &task2.base_data.id).await?;
 | 
						|
    println!("Updating '{}' status from {:?} to {:?}", 
 | 
						|
        task2_updated.title, 
 | 
						|
        task2_updated.status, 
 | 
						|
        TaskStatus::InProgress
 | 
						|
    );
 | 
						|
    
 | 
						|
    task2_updated.status = TaskStatus::InProgress;
 | 
						|
    task2_updated.base_data.update_modified();
 | 
						|
    
 | 
						|
    store.put(&task2_updated).await?;
 | 
						|
    println!("✓ Task updated\n");
 | 
						|
    
 | 
						|
    // ========================================
 | 
						|
    // Cleanup
 | 
						|
    // ========================================
 | 
						|
    println!("🧹 Cleanup");
 | 
						|
    println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
 | 
						|
    
 | 
						|
    store.delete(&task1).await?;
 | 
						|
    store.delete(&task2_updated).await?;
 | 
						|
    store.delete(&task3).await?;
 | 
						|
    println!("✓ All tasks deleted\n");
 | 
						|
    
 | 
						|
    println!("✅ Example completed successfully!");
 | 
						|
    
 | 
						|
    Ok(())
 | 
						|
}
 |