use chrono::{Duration, Utc}; use heromodels::db::{Collection, Db}; use heromodels::models::User; use heromodels::models::calendar::{AttendanceStatus, Attendee, Calendar, Event, EventStatus}; use heromodels_core::Model; fn main() { // Create a new DB instance, reset before every run let db_path = "/tmp/ourdb_calendar_example"; let db = heromodels::db::hero::OurDB::new(db_path, true).expect("Can create DB"); println!("Hero Models - Calendar Usage Example"); println!("===================================="); // --- Create Users First --- println!("\n--- Creating Users ---"); let user1 = User::new() .username("alice_johnson") .email("alice.johnson@company.com") .full_name("Alice Johnson") .is_active(true) .build(); let user2 = User::new() .username("bob_smith") .email("bob.smith@company.com") .full_name("Bob Smith") .is_active(true) .build(); let user3 = User::new() .username("carol_davis") .email("carol.davis@company.com") .full_name("Carol Davis") .is_active(true) .build(); // Store users in database and get their IDs let user_collection = db.collection::().expect("can open user collection"); let (user1_id, stored_user1) = user_collection.set(&user1).expect("can set user1"); let (user2_id, stored_user2) = user_collection.set(&user2).expect("can set user2"); let (user3_id, stored_user3) = user_collection.set(&user3).expect("can set user3"); println!("Created users:"); println!("- User 1 (ID: {}): {}", user1_id, stored_user1.full_name); println!("- User 2 (ID: {}): {}", user2_id, stored_user2.full_name); println!("- User 3 (ID: {}): {}", user3_id, stored_user3.full_name); // --- Create Attendees --- println!("\n--- Creating Attendees ---"); let attendee1 = Attendee::new(user1_id).status(AttendanceStatus::Accepted); let attendee2 = Attendee::new(user2_id).status(AttendanceStatus::Tentative); let attendee3 = Attendee::new(user3_id); // Default NoResponse // Store attendees in database and get their IDs let attendee_collection = db .collection::() .expect("can open attendee collection"); let (attendee1_id, stored_attendee1) = attendee_collection .set(&attendee1) .expect("can set attendee1"); let (attendee2_id, stored_attendee2) = attendee_collection .set(&attendee2) .expect("can set attendee2"); let (attendee3_id, stored_attendee3) = attendee_collection .set(&attendee3) .expect("can set attendee3"); println!("Created attendees:"); println!( "- Attendee 1 (ID: {}): Contact ID {}, Status: {:?}", attendee1_id, stored_attendee1.contact_id, stored_attendee1.status ); println!( "- Attendee 2 (ID: {}): Contact ID {}, Status: {:?}", attendee2_id, stored_attendee2.contact_id, stored_attendee2.status ); println!( "- Attendee 3 (ID: {}): Contact ID {}, Status: {:?}", attendee3_id, stored_attendee3.contact_id, stored_attendee3.status ); // --- Create Events with Attendees --- println!("\n--- Creating Events with Enhanced Features ---"); let now = Utc::now(); let event1 = Event::new( "Team Meeting", now + Duration::hours(1), now + Duration::hours(2), ) .description("Weekly sync-up meeting to discuss project progress.") .location("Conference Room A") .color("#FF5722") // Red-orange color .created_by(user1_id) .status(EventStatus::Published) .category("Work") .reminder_minutes(15) .timezone("UTC") .add_attendee(attendee1_id) .add_attendee(attendee2_id); let event2 = Event::new( "Project Brainstorm", now + Duration::days(1), now + Duration::days(1) + Duration::minutes(90), ) .description("Brainstorming session for new project features.") .location("Innovation Lab") .color("#4CAF50") // Green color .created_by(user2_id) .status(EventStatus::Draft) .category("Planning") .reminder_minutes(30) .is_recurring(true) .add_attendee(attendee1_id) .add_attendee(attendee3_id); let event3 = Event::new( "Client Call", now + Duration::days(2), now + Duration::days(2) + Duration::hours(1), ) .description("Quarterly review with key client.") .color("#9C27B0") // Purple color .created_by(user3_id) .status(EventStatus::Published) .category("Client") .reminder_minutes(60) .add_attendee(attendee2_id); // Create an all-day event let event4 = Event::new( "Company Holiday", now + Duration::days(7), now + Duration::days(7) + Duration::hours(24), ) .description("National holiday - office closed.") .color("#FFC107") // Amber color .all_day(true) .created_by(user1_id) .status(EventStatus::Published) .category("Holiday"); println!("Created events with enhanced features:"); println!( "- Event 1: '{}' at {} with {} attendees", event1.title, event1.start_time.format("%Y-%m-%d %H:%M"), event1.attendees.len() ); println!( " Location: {}", event1 .location .as_ref() .unwrap_or(&"Not specified".to_string()) ); println!( " Color: {}", event1.color.as_ref().unwrap_or(&"Default".to_string()) ); println!( " Category: {}", event1.category.as_ref().unwrap_or(&"None".to_string()) ); println!(" Status: {:?}", event1.status); println!(" Created by: User ID {}", event1.created_by.unwrap_or(0)); println!( " Reminder: {} minutes before", event1.reminder_minutes.unwrap_or(0) ); println!(" All-day: {}", event1.all_day); println!(" Recurring: {}", event1.is_recurring); println!(" Attendee IDs: {:?}", event1.attendees); println!( "- Event 2: '{}' at {} with {} attendees", event2.title, event2.start_time.format("%Y-%m-%d %H:%M"), event2.attendees.len() ); println!( " Location: {}", event2 .location .as_ref() .unwrap_or(&"Not specified".to_string()) ); println!( " Color: {}", event2.color.as_ref().unwrap_or(&"Default".to_string()) ); println!( " Category: {}", event2.category.as_ref().unwrap_or(&"None".to_string()) ); println!(" Status: {:?}", event2.status); println!(" Created by: User ID {}", event2.created_by.unwrap_or(0)); println!( " Reminder: {} minutes before", event2.reminder_minutes.unwrap_or(0) ); println!(" All-day: {}", event2.all_day); println!(" Recurring: {}", event2.is_recurring); println!(" Attendee IDs: {:?}", event2.attendees); println!( "- Event 3: '{}' at {} with {} attendees", event3.title, event3.start_time.format("%Y-%m-%d %H:%M"), event3.attendees.len() ); println!( " Location: {}", event3 .location .as_ref() .unwrap_or(&"Not specified".to_string()) ); println!( " Color: {}", event3.color.as_ref().unwrap_or(&"Default".to_string()) ); println!( " Category: {}", event3.category.as_ref().unwrap_or(&"None".to_string()) ); println!(" Status: {:?}", event3.status); println!(" Created by: User ID {}", event3.created_by.unwrap_or(0)); println!( " Reminder: {} minutes before", event3.reminder_minutes.unwrap_or(0) ); println!(" All-day: {}", event3.all_day); println!(" Recurring: {}", event3.is_recurring); println!(" Attendee IDs: {:?}", event3.attendees); println!( "- Event 4: '{}' at {} (All-day: {})", event4.title, event4.start_time.format("%Y-%m-%d"), event4.all_day ); println!( " Color: {}", event4.color.as_ref().unwrap_or(&"Default".to_string()) ); println!( " Category: {}", event4.category.as_ref().unwrap_or(&"None".to_string()) ); println!(" Status: {:?}", event4.status); println!(" Created by: User ID {}", event4.created_by.unwrap_or(0)); // --- Demonstrate Event Manipulation --- println!("\n--- Demonstrating Event Manipulation ---"); // Reschedule an event let new_start = now + Duration::hours(2); let new_end = now + Duration::hours(3); let mut updated_event1 = event1.clone(); updated_event1 = updated_event1.reschedule(new_start, new_end); println!( "Rescheduled '{}' to {}", updated_event1.title, new_start.format("%Y-%m-%d %H:%M") ); // Remove an attendee updated_event1 = updated_event1.remove_attendee(attendee1_id); println!( "Removed attendee {} from '{}'. Remaining attendee IDs: {:?}", attendee1_id, updated_event1.title, updated_event1.attendees ); // Add a new attendee updated_event1 = updated_event1.add_attendee(attendee3_id); println!( "Added attendee {} to '{}'. Current attendee IDs: {:?}", attendee3_id, updated_event1.title, updated_event1.attendees ); // --- Demonstrate Event Status Changes --- println!("\n--- Demonstrating Event Status Changes ---"); // Change event status from Draft to Published let mut updated_event2 = event2.clone(); updated_event2 = updated_event2.status(EventStatus::Published); println!( "Changed '{}' status from Draft to Published", updated_event2.title ); // Cancel an event let mut cancelled_event = event3.clone(); cancelled_event = cancelled_event.status(EventStatus::Cancelled); println!("Cancelled event: '{}'", cancelled_event.title); // Update event with new features let enhanced_event = Event::new( "Enhanced Meeting", now + Duration::days(5), now + Duration::days(5) + Duration::hours(2), ) .description("Meeting with all new features demonstrated.") .location("Virtual - Zoom") .color("#673AB7") // Deep purple .created_by(user1_id) .status(EventStatus::Published) .category("Demo") .reminder_minutes(45) .timezone("America/New_York") .is_recurring(true) .add_attendee(attendee1_id) .add_attendee(attendee2_id) .add_attendee(attendee3_id); println!("Created enhanced event with all features:"); println!(" Title: {}", enhanced_event.title); println!(" Status: {:?}", enhanced_event.status); println!(" Category: {}", enhanced_event.category.as_ref().unwrap()); println!(" Color: {}", enhanced_event.color.as_ref().unwrap()); println!(" Timezone: {}", enhanced_event.timezone.as_ref().unwrap()); println!(" Recurring: {}", enhanced_event.is_recurring); println!( " Reminder: {} minutes", enhanced_event.reminder_minutes.unwrap() ); println!(" Attendees: {} people", enhanced_event.attendees.len()); // --- Store Events in Database --- // Now that Event is a proper database model, we need to store events first println!("\n--- Storing Events in Database ---"); let event_collection = db.collection::().expect("can open event collection"); // Store events and get their auto-generated IDs let (event1_id, stored_event1) = event_collection.set(&event1).expect("can set event1"); let (event2_id, stored_event2) = event_collection.set(&event2).expect("can set event2"); let (event3_id, stored_event3) = event_collection.set(&event3).expect("can set event3"); let (event4_id, stored_event4) = event_collection.set(&event4).expect("can set event4"); println!("Stored events in database:"); println!( "- Event ID {}: '{}' (Status: {:?})", event1_id, stored_event1.title, stored_event1.status ); println!( "- Event ID {}: '{}' (Status: {:?})", event2_id, stored_event2.title, stored_event2.status ); println!( "- Event ID {}: '{}' (Status: {:?})", event3_id, stored_event3.title, stored_event3.status ); println!( "- Event ID {}: '{}' (All-day: {})", event4_id, stored_event4.title, stored_event4.all_day ); // --- Create Calendars --- // Now calendars store the actual database IDs of the events println!("\n--- Creating Enhanced Calendars ---"); // Create a work calendar with enhanced features let calendar1 = Calendar::new(None, "Work Calendar") .description("Calendar for all work-related events.") .owner_id(user1_id) .is_public(false) .color("#2196F3") // Blue color .add_event(event1_id as i64) .add_event(event2_id as i64); // Create a personal calendar let calendar2 = Calendar::new(None, "Personal Calendar") .description("Personal events and appointments.") .owner_id(user2_id) .is_public(false) .color("#E91E63") // Pink color .add_event(event3_id as i64); // Create a company-wide calendar let calendar3 = Calendar::new(None, "Company Events") .description("Company-wide events and holidays.") .owner_id(user1_id) .is_public(true) .color("#FF9800") // Orange color .add_event(event4_id as i64); println!("Created calendars with enhanced features:"); println!( "- Calendar 1: '{}' with {} events", calendar1.name, calendar1.events.len() ); println!(" Owner: User ID {}", calendar1.owner_id.unwrap_or(0)); println!(" Public: {}", calendar1.is_public); println!( " Color: {}", calendar1.color.as_ref().unwrap_or(&"Default".to_string()) ); println!(" Events: {:?}", calendar1.events); println!( "- Calendar 2: '{}' with {} events", calendar2.name, calendar2.events.len() ); println!(" Owner: User ID {}", calendar2.owner_id.unwrap_or(0)); println!(" Public: {}", calendar2.is_public); println!( " Color: {}", calendar2.color.as_ref().unwrap_or(&"Default".to_string()) ); println!(" Events: {:?}", calendar2.events); println!( "- Calendar 3: '{}' with {} events", calendar3.name, calendar3.events.len() ); println!(" Owner: User ID {}", calendar3.owner_id.unwrap_or(0)); println!(" Public: {}", calendar3.is_public); println!( " Color: {}", calendar3.color.as_ref().unwrap_or(&"Default".to_string()) ); println!(" Events: {:?}", calendar3.events); // --- Store Calendars in DB --- let cal_collection = db .collection::() .expect("can open calendar collection"); let (_, calendar1) = cal_collection.set(&calendar1).expect("can set calendar1"); let (_, calendar2) = cal_collection.set(&calendar2).expect("can set calendar2"); let (_, calendar3) = cal_collection.set(&calendar3).expect("can set calendar3"); println!( "Created calendar1 (ID: {}): Name - '{}' (Owner: {}, Public: {})", calendar1.get_id(), calendar1.name, calendar1.owner_id.unwrap_or(0), calendar1.is_public ); println!( "Created calendar2 (ID: {}): Name - '{}' (Owner: {}, Public: {})", calendar2.get_id(), calendar2.name, calendar2.owner_id.unwrap_or(0), calendar2.is_public ); println!( "Created calendar3 (ID: {}): Name - '{}' (Owner: {}, Public: {})", calendar3.get_id(), calendar3.name, calendar3.owner_id.unwrap_or(0), calendar3.is_public ); // --- Retrieve a Calendar by ID --- let stored_calendar1_opt = cal_collection .get_by_id(calendar1.get_id()) .expect("can try to load calendar1"); assert!( stored_calendar1_opt.is_some(), "Calendar1 should be found in DB" ); let mut stored_calendar1 = stored_calendar1_opt.unwrap(); println!( "\nRetrieved calendar1 from DB: Name - '{}', Events count: {}", stored_calendar1.name, stored_calendar1.events.len() ); assert_eq!(stored_calendar1.name, "Work Calendar"); assert_eq!(stored_calendar1.events.len(), 2); assert_eq!(stored_calendar1.events[0], event1_id as i64); // Check event ID // --- Modify a Calendar (Add/Remove Events) --- // Since events are just IDs, we can add and remove them easily println!("\n--- Modifying Calendar ---"); // Create and store a new event let new_event = Event::new( "1-on-1 Meeting", now + Duration::days(3), now + Duration::days(3) + Duration::minutes(30), ) .description("One-on-one meeting with team member.") .location("Office"); let (new_event_id, _stored_new_event) = event_collection.set(&new_event).expect("can set new event"); println!("Created new event with ID: {}", new_event_id); // Add the new event ID to the calendar stored_calendar1 = stored_calendar1.add_event(new_event_id as i64); assert_eq!(stored_calendar1.events.len(), 3); println!( "Added event ID {} to calendar1. Total events: {}", new_event_id, stored_calendar1.events.len() ); // Remove an event ID from the calendar stored_calendar1 = stored_calendar1.remove_event(event2_id as i64); // Remove "Project Brainstorm" assert_eq!(stored_calendar1.events.len(), 2); println!( "Removed event ID {} from calendar1. Total events: {}", event2_id, stored_calendar1.events.len() ); // --- Store the modified calendar --- let (_, _stored_calendar1) = cal_collection .set(&stored_calendar1) .expect("can set modified calendar1"); // Verify the changes were persisted let re_retrieved_calendar1_opt = cal_collection .get_by_id(calendar1.get_id()) .expect("can try to load modified calendar1"); let re_retrieved_calendar1 = re_retrieved_calendar1_opt.unwrap(); assert_eq!(re_retrieved_calendar1.events.len(), 2); assert!(re_retrieved_calendar1.events.contains(&(event1_id as i64))); // Team Meeting still there assert!( re_retrieved_calendar1 .events .contains(&(new_event_id as i64)) ); // New event added assert!(!re_retrieved_calendar1.events.contains(&(event2_id as i64))); // Project Brainstorm removed println!( "\nModified and re-saved calendar1. Final events: {:?}", re_retrieved_calendar1.events ); // --- Delete a Calendar --- cal_collection .delete_by_id(calendar2.get_id()) .expect("can delete calendar2"); let deleted_calendar2_opt = cal_collection .get_by_id(calendar2.get_id()) .expect("can try to load deleted calendar2"); assert!( deleted_calendar2_opt.is_none(), "Calendar2 should be deleted from DB" ); println!("\nDeleted calendar2 (ID: {}) from DB.", calendar2.get_id()); println!("Calendar model DB Prefix: {}", Calendar::db_prefix()); // --- Demonstrate Event Retrieval --- println!("\n--- Retrieving Events from Database ---"); // Get all events let all_events = event_collection.get_all().expect("can list all events"); println!("All events in database:"); for event in &all_events { println!( "- Event ID: {}, Title: '{}', Start: {}, Attendees: {}", event.get_id(), event.title, event.start_time.format("%Y-%m-%d %H:%M"), event.attendees.len() ); } println!("Total events in DB: {}", all_events.len()); // Retrieve specific events by ID and show attendee details println!("\nRetrieving specific events:"); if let Some(retrieved_event1) = event_collection .get_by_id(event1_id) .expect("can try to get event1") { println!( "Retrieved Event 1: '{}' with {} attendees", retrieved_event1.title, retrieved_event1.attendees.len() ); // Look up attendee details for each attendee ID for &attendee_id in &retrieved_event1.attendees { if let Some(attendee) = attendee_collection .get_by_id(attendee_id) .expect("can try to get attendee") { // Look up user details for the attendee's contact_id if let Some(user) = user_collection .get_by_id(attendee.contact_id) .expect("can try to get user") { println!( " - Attendee ID {}: {} (User: {}, Status: {:?})", attendee_id, user.full_name, attendee.contact_id, attendee.status ); } } } } // --- List All Calendars --- println!("\n--- Listing All Enhanced Calendars ---"); let all_calendars = cal_collection.get_all().expect("can list all calendars"); for calendar in &all_calendars { println!( "- Calendar ID: {}, Name: '{}', Owner: {}, Public: {}, Color: {}", calendar.get_id(), calendar.name, calendar.owner_id.unwrap_or(0), calendar.is_public, calendar.color.as_ref().unwrap_or(&"Default".to_string()) ); println!( " Description: {}", calendar.description.as_ref().unwrap_or(&"None".to_string()) ); println!(" Events: {:?}", calendar.events); // Show which events are in this calendar with their details for &event_id in &calendar.events { if let Some(event) = event_collection .get_by_id(event_id as u32) .expect("can try to get event") { println!( " * Event: '{}' (Status: {:?}, Category: {}, All-day: {})", event.title, event.status, event.category.as_ref().unwrap_or(&"None".to_string()), event.all_day ); } } } println!("Total calendars in DB: {}", all_calendars.len()); println!("\nExample finished. DB stored at {}", db_path); println!( "To clean up, you can manually delete the directory: {}", db_path ); }