use chrono::{DateTime, Days, Utc}; use std::path::PathBuf; /// Public-facing metadata persisted in SQLite #[derive(Debug, Default, Clone)] pub struct WorkspaceMetadata { pub path: PathBuf, pub navigated_ts: Option>, pub modified_ts: Option>, pub queried_ts: Option>, } impl WorkspaceMetadata { /// Surface most recently navigated first pub fn most_recently_navigated(a: &Self, b: &Self) -> std::cmp::Ordering { match (a.navigated_ts, b.navigated_ts) { (Some(a_ts), Some(b_ts)) => b_ts.cmp(&a_ts), (Some(_), None) => std::cmp::Ordering::Less, (None, Some(_)) => std::cmp::Ordering::Greater, (None, None) => a.path.cmp(&b.path), } } /// Surface most recently touched first pub fn most_recently_touched(a: &Self, b: &Self) -> std::cmp::Ordering { match (a.last_touched(), b.last_touched()) { (Some(a_ts), Some(b_ts)) => b_ts.cmp(&a_ts), (Some(_), None) => std::cmp::Ordering::Less, (None, Some(_)) => std::cmp::Ordering::Greater, (None, None) => a.path.cmp(&b.path), } } /// The most recent time this codebase index was navigated to, queried or modified. pub fn last_touched(&self) -> Option> { let mut last_access_time: Option> = None; if let Some(nav_ts) = self.navigated_ts { last_access_time = last_access_time .map(|old_time| old_time.max(nav_ts)) .or(Some(nav_ts)); } if let Some(mod_ts) = self.modified_ts { last_access_time = last_access_time .map(|old_time| old_time.max(mod_ts)) .or(Some(mod_ts)); } if let Some(query_ts) = self.queried_ts { last_access_time = last_access_time .map(|old_time| old_time.max(query_ts)) .or(Some(query_ts)); } last_access_time } pub fn is_expired(&self, current_time: DateTime, shelf_life_days: u64) -> bool { let Some(last_touch) = self.last_touched() else { return true; }; last_touch .checked_add_days(Days::new(shelf_life_days)) .unwrap_or_default() < current_time } } /// An event to update the workspace metadata. #[derive(Debug, Clone, Copy)] pub enum WorkspaceMetadataEvent { Queried, Modified, Created, } impl From for persistence::model::NewWorkspaceMetadata { fn from(value: WorkspaceMetadata) -> Self { Self { repo_path: value.path.to_string_lossy().into_owned(), navigated_ts: value.navigated_ts.map(|utc_dt| utc_dt.naive_utc()), modified_ts: value.modified_ts.map(|utc_dt| utc_dt.naive_utc()), queried_ts: value.queried_ts.map(|utc_dt| utc_dt.naive_utc()), } } } impl From for WorkspaceMetadata { fn from(value: persistence::model::WorkspaceMetadata) -> Self { Self { path: PathBuf::from(value.repo_path), navigated_ts: value.navigated_ts.map(|naive_ts| naive_ts.and_utc()), modified_ts: value.modified_ts.map(|naive_ts| naive_ts.and_utc()), queried_ts: value.queried_ts.map(|naive_ts| naive_ts.and_utc()), } } }