use super::{ ContactId, DateTime, Event, EventId, NaiveDate, NewEvent, ProjectId, Result, TaskId, UserId, Utc, async_trait, }; /// Repository for calendar event operations. /// /// Events can be standalone or linked to tasks (for time-blocking). /// /// # Ordering Contract /// /// All methods returning `Vec` **MUST** return results sorted by /// `start_time ASC`. This is enforced at the SQL level (`ORDER BY e.start_time ASC`) /// and callers rely on this guarantee, no post-fetch sorting is needed. #[async_trait] pub trait EventRepository: Send + Sync { /// Lists all events for a user, ordered by `start_time ASC`. async fn list_all(&self, user_id: UserId) -> Result>; /// Lists events belonging to a specific project, ordered by `start_time ASC`. async fn list_by_project(&self, user_id: UserId, project_id: ProjectId) -> Result>; /// Lists events linked to a specific contact, ordered by `start_time DESC`. async fn list_by_contact(&self, user_id: UserId, contact_id: ContactId) -> Result>; /// Retrieves an event by ID. async fn get_by_id(&self, id: EventId, user_id: UserId) -> Result>; /// Creates a new event. async fn create(&self, user_id: UserId, event: NewEvent) -> Result; /// Restores an event verbatim from a backup, preserving its original ID and /// all metadata the normal create path never sets, `block_type`, /// `external_source`/`external_id`, `recurrence_parent_id`, `is_read_only`, /// `snoozed_until`, and reminder offsets. Idempotent (`INSERT OR IGNORE`). async fn restore(&self, user_id: UserId, event: &Event) -> Result<()>; /// Updates an existing event. async fn update( &self, id: EventId, user_id: UserId, event: crate::models::UpdateEvent, ) -> Result>; /// Deletes an event. async fn delete(&self, id: EventId, user_id: UserId) -> Result; /// Records the external source/id for an event (e.g. after an iCal import), /// used to dedup on re-import. async fn set_external_ref( &self, id: EventId, user_id: UserId, source: &str, external_id: &str, ) -> Result<()>; /// Deletes multiple events by ID, returning the number deleted. async fn delete_many(&self, ids: &[EventId], user_id: UserId) -> Result; /// Gets events starting within the next N days, ordered by `start_time ASC`. async fn get_upcoming(&self, user_id: UserId, days: i64) -> Result>; /// Finds the event linked to a specific task (for time-blocking). async fn get_by_linked_task(&self, user_id: UserId, task_id: TaskId) -> Result>; /// Deletes the event linked to a task. async fn delete_by_linked_task(&self, user_id: UserId, task_id: TaskId) -> Result; /// Lists events occurring on a specific date, ordered by `start_time ASC`. async fn list_for_date(&self, user_id: UserId, date: NaiveDate) -> Result>; /// Lists events within a date range (for weekly review), ordered by `start_time ASC`. async fn list_between( &self, user_id: UserId, start: DateTime, end: DateTime, ) -> Result>; /// Lists all recurring events (recurrence != 'None' or recurrence_rule is set). async fn list_recurring(&self, user_id: UserId) -> Result>; /// Finds an event by external source and ID (for dedup during import). async fn find_by_external_id( &self, source: &str, ext_id: &str, user_id: UserId, ) -> Result>; /// Snoozes an event until `until`. Returns the updated event, or `None` if not found. async fn snooze( &self, id: EventId, user_id: UserId, until: DateTime, ) -> Result>; /// Clears any snooze on an event. Returns the updated event, or `None` if not found. async fn unsnooze(&self, id: EventId, user_id: UserId) -> Result>; /// Lists currently snoozed events (snoozed_until is in the future). async fn list_snoozed(&self, user_id: UserId) -> Result>; }