diff --git a/heromodels/examples/calendar_example/main.rs b/heromodels/examples/calendar_example/main.rs index 6afec70..0008d38 100644 --- a/heromodels/examples/calendar_example/main.rs +++ b/heromodels/examples/calendar_example/main.rs @@ -1,6 +1,7 @@ use chrono::{Duration, Utc}; use heromodels::db::{Collection, Db}; -use heromodels::models::calendar::{Attendee, AttendanceStatus, Calendar, Event}; +use heromodels::models::User; +use heromodels::models::calendar::{AttendanceStatus, Attendee, Calendar, Event}; use heromodels_core::Model; fn main() { @@ -11,122 +12,401 @@ fn main() { 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 --- - let attendee1 = Attendee::new("user_123".to_string()) - .status(AttendanceStatus::Accepted); - let attendee2 = Attendee::new("user_456".to_string()) - .status(AttendanceStatus::Tentative); - let attendee3 = Attendee::new("user_789".to_string()); // Default NoResponse + 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 - // --- Create Events --- - let now = Utc::now(); - let event1 = Event::new( - "event_alpha".to_string(), - "Team Meeting", - now + Duration::seconds(3600), // Using Duration::seconds for more explicit chrono 0.4 compatibility - now + Duration::seconds(7200), - ) - .description("Weekly sync-up meeting.") - .location("Conference Room A") - .add_attendee(attendee1.clone()) - .add_attendee(attendee2.clone()); + // Store attendees in database and get their IDs + let attendee_collection = db + .collection::() + .expect("can open attendee collection"); - let event2 = Event::new( - "event_beta".to_string(), - "Project Brainstorm", - now + Duration::days(1), - now + Duration::days(1) + Duration::seconds(5400), // 90 minutes - ) - .description("Brainstorming session for new project features.") - .add_attendee(attendee1.clone()) - .add_attendee(attendee3.clone()); + 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"); - let event3_for_calendar2 = Event::new( - "event_gamma".to_string(), - "Client Call", - now + Duration::days(2), - now + Duration::days(2) + Duration::seconds(3600) + 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 Calendars --- - // Note: Calendar::new directly returns Calendar, no separate .build() step like the user example. + // --- Create Events with Attendees --- + println!("\n--- Creating Events with Attendees ---"); + let now = Utc::now(); - // Create a calendar with auto-generated ID + 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") + .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") + .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.") + .add_attendee(attendee2_id); + + println!("Created events:"); + 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!(" 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!(" 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!(" Attendee IDs: {:?}", event3.attendees); + + // --- 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 + ); + + // --- 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"); + + println!("Stored events in database:"); + println!("- Event ID {}: '{}'", event1_id, stored_event1.title); + println!("- Event ID {}: '{}'", event2_id, stored_event2.title); + println!("- Event ID {}: '{}'", event3_id, stored_event3.title); + + // --- Create Calendars --- + // Now calendars store the actual database IDs of the events + println!("\n--- Creating Calendars ---"); + + // Create a calendar with auto-generated ID and the stored event IDs let calendar1 = Calendar::new(None, "Work Calendar") .description("Calendar for all work-related events.") - .add_event(event1.clone()) - .add_event(event2.clone()); + .add_event(event1_id as i64) + .add_event(event2_id as i64); - // Create a calendar with auto-generated ID (explicit IDs are no longer supported) - let calendar2 = Calendar::new(None, "Personal Calendar") - .add_event(event3_for_calendar2.clone()); + // Create another calendar with auto-generated ID + let calendar2 = Calendar::new(None, "Personal Calendar").add_event(event3_id as i64); + println!("Created calendars with event IDs:"); + println!( + "- Calendar 1: '{}' with events: {:?}", + calendar1.name, calendar1.events + ); + println!( + "- Calendar 2: '{}' with events: {:?}", + calendar2.name, calendar2.events + ); // --- Store Calendars in DB --- - let cal_collection = db.collection::().expect("can open calendar collection"); + 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"); - println!("Created calendar1 (ID: {}): Name - '{}'", calendar1.get_id(), calendar1.name); - println!("Created calendar2 (ID: {}): Name - '{}'", calendar2.get_id(), calendar2.name); + println!( + "Created calendar1 (ID: {}): Name - '{}'", + calendar1.get_id(), + calendar1.name + ); + println!( + "Created calendar2 (ID: {}): Name - '{}'", + calendar2.get_id(), + calendar2.name + ); // --- 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 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()); + 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].title, "Team Meeting"); + assert_eq!(stored_calendar1.events[0], event1_id as i64); // Check event ID - // --- Modify a Calendar (Reschedule an Event) --- - let event_id_to_reschedule = event1.id.as_str(); - let new_start_time = now + Duration::seconds(10800); // 3 hours from now - let new_end_time = now + Duration::seconds(14400); // 4 hours from now + // --- Modify a Calendar (Add/Remove Events) --- + // Since events are just IDs, we can add and remove them easily + println!("\n--- Modifying Calendar ---"); - stored_calendar1 = stored_calendar1.update_event(event_id_to_reschedule, |event_to_update| { - println!("Rescheduling event '{}'...", event_to_update.title); - event_to_update.reschedule(new_start_time, new_end_time) - }); + // 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 rescheduled_event = stored_calendar1.events.iter().find(|e| e.id == event_id_to_reschedule) - .expect("Rescheduled event should exist"); - assert_eq!(rescheduled_event.start_time, new_start_time); - assert_eq!(rescheduled_event.end_time, new_end_time); - println!("Event '{}' rescheduled in stored_calendar1.", rescheduled_event.title); + 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 (_, mut stored_calendar1) = cal_collection.set(&stored_calendar1).expect("can set modified calendar1"); - let re_retrieved_calendar1_opt = cal_collection.get_by_id(calendar1.get_id()).expect("can try to load modified calendar1"); + 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(); - let re_retrieved_event = re_retrieved_calendar1.events.iter().find(|e| e.id == event_id_to_reschedule) - .expect("Rescheduled event should exist in re-retrieved calendar"); - assert_eq!(re_retrieved_event.start_time, new_start_time, "Reschedule not persisted correctly"); + 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. Rescheduled event start time: {}", re_retrieved_event.start_time); - - // --- Add a new event to an existing calendar --- - let event4_new = Event::new( - "event_delta".to_string(), - "1-on-1", - now + Duration::days(3), - now + Duration::days(3) + Duration::seconds(1800) // 30 minutes + println!( + "\nModified and re-saved calendar1. Final events: {:?}", + re_retrieved_calendar1.events ); - stored_calendar1 = stored_calendar1.add_event(event4_new); - assert_eq!(stored_calendar1.events.len(), 3); - let (_, stored_calendar1) = cal_collection.set(&stored_calendar1).expect("can set calendar1 after adding new event"); - println!("Added new event '1-on-1' to stored_calendar1. Total events: {}", stored_calendar1.events.len()); // --- 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"); + 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 Calendars ---"); + let all_calendars = cal_collection.get_all().expect("can list all calendars"); + for calendar in &all_calendars { + println!( + "- Calendar ID: {}, Name: '{}', Events: {:?}", + calendar.get_id(), + calendar.name, + calendar.events + ); + + // Show which events are in this calendar + 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: '{}'", event.title); + } + } + } + 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); + println!( + "To clean up, you can manually delete the directory: {}", + db_path + ); } diff --git a/heromodels/src/models/calendar/calendar.rs b/heromodels/src/models/calendar/calendar.rs index 2ca849c..d883060 100644 --- a/heromodels/src/models/calendar/calendar.rs +++ b/heromodels/src/models/calendar/calendar.rs @@ -1,32 +1,50 @@ use chrono::{DateTime, Utc}; use heromodels_core::BaseModelData; use heromodels_derive::model; -use rhai_autobind_macros::rhai_model_export; use rhai::{CustomType, TypeBuilder}; +use rhai_autobind_macros::rhai_model_export; use serde::{Deserialize, Serialize}; /// Represents the status of an attendee for an event #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum AttendanceStatus { - Accepted, - Declined, - Tentative, - NoResponse, + Accepted = 0, + Declined = 1, + Tentative = 2, + NoResponse = 3, } /// Represents an attendee of an event -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] +#[model] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Attendee { + /// Base model data + pub base_data: BaseModelData, /// ID of the user attending - // Assuming user_id might be queryable pub contact_id: u32, /// Attendance status of the user for the event pub status: AttendanceStatus, } impl Attendee { + /// Creates a new attendee with auto-generated ID pub fn new(contact_id: u32) -> Self { Self { + base_data: BaseModelData::new(), // ID will be auto-generated by OurDB + contact_id, + status: AttendanceStatus::NoResponse, + } + } + + /// Creates a new attendee with optional ID (use None for auto-generated ID) + pub fn new_with_id(id: Option, contact_id: u32) -> Self { + let mut base_data = BaseModelData::new(); + if let Some(id) = id { + base_data.update_id(id); + } + + Self { + base_data, contact_id, status: AttendanceStatus::NoResponse, } @@ -39,10 +57,10 @@ impl Attendee { } /// Represents an event in a calendar +#[model] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] pub struct Event { /// Base model data - #[serde(flatten)] pub base_data: BaseModelData, /// Title of the event pub title: String, @@ -52,17 +70,40 @@ pub struct Event { pub start_time: DateTime, /// End time of the event pub end_time: DateTime, - /// List of attendees for the event - pub attendees: Vec, + /// List of attendee IDs for the event + pub attendees: Vec, /// Optional location of the event pub location: Option, } impl Event { - /// Creates a new event + /// Creates a new event with auto-generated ID pub fn new(title: impl ToString, start_time: DateTime, end_time: DateTime) -> Self { Self { - base_data: BaseModelData::new(), + base_data: BaseModelData::new(), // ID will be auto-generated by OurDB + title: title.to_string(), + description: None, + start_time, + end_time, + attendees: Vec::new(), + location: None, + } + } + + /// Creates a new event with optional ID (use None for auto-generated ID) + pub fn new_with_id( + id: Option, + title: impl ToString, + start_time: DateTime, + end_time: DateTime, + ) -> Self { + let mut base_data = BaseModelData::new(); + if let Some(id) = id { + base_data.update_id(id); + } + + Self { + base_data, title: title.to_string(), description: None, start_time, @@ -90,26 +131,18 @@ impl Event { self } - /// Adds an attendee to the event - pub fn add_attendee(mut self, attendee: Attendee) -> Self { - // Prevent duplicate attendees by contact_id - if !self.attendees.iter().any(|a| a.contact_id == attendee.contact_id) { - self.attendees.push(attendee); + /// Adds an attendee ID to the event + pub fn add_attendee(mut self, attendee_id: u32) -> Self { + // Prevent duplicate attendees by ID + if !self.attendees.iter().any(|&a_id| a_id == attendee_id) { + self.attendees.push(attendee_id); } self } - /// Removes an attendee from the event by user_id - pub fn remove_attendee(mut self, contact_id: u32) -> Self { - self.attendees.retain(|a| a.contact_id != contact_id); - self - } - - /// Updates the status of an existing attendee - pub fn update_attendee_status(mut self, contact_id: u32, status: AttendanceStatus) -> Self { - if let Some(attendee) = self.attendees.iter_mut().find(|a| a.contact_id == contact_id) { - attendee.status = status; - } + /// Removes an attendee from the event by attendee ID + pub fn remove_attendee(mut self, attendee_id: u32) -> Self { + self.attendees.retain(|&a_id| a_id != attendee_id); self } @@ -130,14 +163,11 @@ impl Event { } /// Represents a calendar with events -#[rhai_model_export( - db_type = "std::sync::Arc", -)] +#[rhai_model_export(db_type = "std::sync::Arc")] #[model] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] pub struct Calendar { /// Base model data - #[serde(flatten)] pub base_data: BaseModelData, /// Name of the calendar @@ -194,7 +224,8 @@ impl Calendar { /// Removes an event from the calendar by its ID pub fn remove_event(mut self, event_id_to_remove: i64) -> Self { - self.events.retain(|&event_id_in_vec| event_id_in_vec != event_id_to_remove); + self.events + .retain(|&event_id_in_vec| event_id_in_vec != event_id_to_remove); self } } diff --git a/heromodels/src/models/calendar/rhai.rs b/heromodels/src/models/calendar/rhai.rs index d4e1f12..b3415da 100644 --- a/heromodels/src/models/calendar/rhai.rs +++ b/heromodels/src/models/calendar/rhai.rs @@ -1,17 +1,16 @@ -use rhai::{Engine, EvalAltResult, NativeCallContext, ImmutableString}; +use rhai::{Engine, EvalAltResult, ImmutableString, NativeCallContext}; use std::sync::Arc; -use heromodels_core::BaseModelData; +use super::calendar::{AttendanceStatus, Attendee, Calendar, Event}; use crate::db::hero::OurDB; -use super::calendar::{Calendar, Event, Attendee, AttendanceStatus}; -use adapter_macros::{adapt_rhai_i64_input_fn, adapt_rhai_i64_input_method}; use adapter_macros::rhai_timestamp_helpers; +use adapter_macros::{adapt_rhai_i64_input_fn, adapt_rhai_i64_input_method}; +use heromodels_core::BaseModelData; // Helper function for get_all_calendars registration - fn new_calendar_rhai(name: String) -> Result> { - Ok(Calendar::new(None, name)) + Ok(Calendar::new(None, name)) } fn new_event_rhai( @@ -20,71 +19,113 @@ fn new_event_rhai( start_time_ts: i64, end_time_ts: i64, ) -> Result> { - let start_time = rhai_timestamp_helpers::rhai_timestamp_to_datetime(start_time_ts) - .map_err(|e_str| Box::new(EvalAltResult::ErrorRuntime( - format!("Failed to convert start_time for Event: {}", e_str).into(), - context.position(), - )))?; - - let end_time = rhai_timestamp_helpers::rhai_timestamp_to_datetime(end_time_ts) - .map_err(|e_str| Box::new(EvalAltResult::ErrorRuntime( - format!("Failed to convert end_time for Event: {}", e_str).into(), - context.position(), - )))?; - - Ok(Event::new(title_rhai.to_string(), start_time, end_time)) -} - -pub fn register_rhai_engine_functions(engine: &mut Engine, db: Arc) { - engine.register_fn("name", move |calendar: Calendar, name: String| Calendar::name(calendar, name)); - engine.register_fn("description", move |calendar: Calendar, description: String| Calendar::description(calendar, description)); - engine.register_fn("add_event", Calendar::add_event); - // Note: Event IDs are i64 in Calendar.events, but Event model's base_data.id is u32. - // This might require adjustment if events are fetched by ID from the DB via Calendar.events. - - engine.register_fn("new_event", |context: NativeCallContext, title_rhai: ImmutableString, start_time_ts: i64, end_time_ts: i64| -> Result> { - new_event_rhai(context, title_rhai, start_time_ts, end_time_ts) - }); - engine.register_fn("title", move |event: Event, title: String| Event::title(event, title)); - engine.register_fn("description", move |event: Event, description: String| Event::description(event, description)); - engine.register_fn("add_attendee", move |event: Event, attendee: Attendee| Event::add_attendee(event, attendee)); - engine.register_fn("remove_attendee", adapt_rhai_i64_input_method!(Event, remove_attendee, u32)); - engine.register_fn("update_attendee_status", move |context: NativeCallContext, event: Event, contact_id_i64: i64, status: AttendanceStatus| -> Result> { - let contact_id_u32: u32 = contact_id_i64.try_into().map_err(|_e| { - Box::new(EvalAltResult::ErrorArithmetic( - format!("Conversion error for contact_id in Event::update_attendee_status from i64 to u32"), + let start_time = + rhai_timestamp_helpers::rhai_timestamp_to_datetime(start_time_ts).map_err(|e_str| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Failed to convert start_time for Event: {}", e_str).into(), context.position(), )) })?; - Ok(event.update_attendee_status(contact_id_u32, status)) + + let end_time = + rhai_timestamp_helpers::rhai_timestamp_to_datetime(end_time_ts).map_err(|e_str| { + Box::new(EvalAltResult::ErrorRuntime( + format!("Failed to convert end_time for Event: {}", e_str).into(), + context.position(), + )) + })?; + + Ok(Event::new(title_rhai.to_string(), start_time, end_time)) +} + +pub fn register_rhai_engine_functions(engine: &mut Engine, db: Arc) { + engine.register_fn("name", move |calendar: Calendar, name: String| { + Calendar::name(calendar, name) }); + engine.register_fn( + "description", + move |calendar: Calendar, description: String| Calendar::description(calendar, description), + ); + engine.register_fn("add_event", Calendar::add_event); + // Note: Event IDs are i64 in Calendar.events, but Event model's base_data.id is u32. + // This might require adjustment if events are fetched by ID from the DB via Calendar.events. + + engine.register_fn( + "new_event", + |context: NativeCallContext, + title_rhai: ImmutableString, + start_time_ts: i64, + end_time_ts: i64| + -> Result> { + new_event_rhai(context, title_rhai, start_time_ts, end_time_ts) + }, + ); + engine.register_fn("title", move |event: Event, title: String| { + Event::title(event, title) + }); + engine.register_fn("description", move |event: Event, description: String| { + Event::description(event, description) + }); + engine.register_fn( + "add_attendee", + adapt_rhai_i64_input_method!(Event, add_attendee, u32), + ); + engine.register_fn( + "remove_attendee", + adapt_rhai_i64_input_method!(Event, remove_attendee, u32), + ); engine.register_fn("new_attendee", adapt_rhai_i64_input_fn!(Attendee::new, u32)); - engine.register_fn("new_calendar", |name: String| -> Result> { new_calendar_rhai(name) }); + engine.register_fn( + "new_calendar", + |name: String| -> Result> { new_calendar_rhai(name) }, + ); // Register a function to get the database instance engine.register_fn("get_db", move || db.clone()); - + // Register getters for Calendar - engine.register_get("id", |c: &mut Calendar| -> Result> { Ok(c.base_data.id as i64) }); - engine.register_get("name", |c: &mut Calendar| -> Result> { - // println!("Rhai attempting to get Calendar.name: {}", c.name); // Debug print - Ok(c.name.clone()) - }); - engine.register_get("description", |c: &mut Calendar| -> Result, Box> { Ok(c.description.clone()) }); + engine.register_get( + "id", + |c: &mut Calendar| -> Result> { Ok(c.base_data.id as i64) }, + ); + engine.register_get( + "name", + |c: &mut Calendar| -> Result> { + // println!("Rhai attempting to get Calendar.name: {}", c.name); // Debug print + Ok(c.name.clone()) + }, + ); + engine.register_get( + "description", + |c: &mut Calendar| -> Result, Box> { + Ok(c.description.clone()) + }, + ); // Register getter for Calendar.base_data - engine.register_get("base_data", |c: &mut Calendar| -> Result> { Ok(c.base_data.clone()) }); + engine.register_get( + "base_data", + |c: &mut Calendar| -> Result> { Ok(c.base_data.clone()) }, + ); // Register getters for BaseModelData - engine.register_get("id", |bmd: &mut BaseModelData| -> Result> { Ok(bmd.id.into()) }); + engine.register_get( + "id", + |bmd: &mut BaseModelData| -> Result> { Ok(bmd.id.into()) }, + ); // Database interaction functions for Calendar are expected to be provided by #[rhai_model_export(..)] on the Calendar struct. // Ensure that `db.rs` or similar correctly wires up the `OurDB` methods for these. // Getters for Event - engine.register_get("id", |e: &mut Event| -> Result> { Ok(e.base_data.id as i64) }); - engine.register_get("title", |e: &mut Event| -> Result> { Ok(e.title.clone()) }); + engine.register_get("id", |e: &mut Event| -> Result> { + Ok(e.base_data.id as i64) + }); + engine.register_get( + "title", + |e: &mut Event| -> Result> { Ok(e.title.clone()) }, + ); // Add more getters for Event fields as needed }