diff --git a/src/cli/journal.rs b/src/cli/journal.rs index b0a4fd9..67da9e3 100644 --- a/src/cli/journal.rs +++ b/src/cli/journal.rs @@ -90,48 +90,21 @@ pub fn find_current_transcript() -> Option { newest.map(|(_, p)| p.to_string_lossy().to_string()) } -fn journal_tail_entries(store: &crate::store::Store, n: usize, full: bool) -> Result<(), String> { - let date_re = regex::Regex::new(r"(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2})").unwrap(); - let key_date_re = regex::Regex::new(r"j-(\d{4}-\d{2}-\d{2}[t-]\d{2}-\d{2})").unwrap(); +fn journal_tail_query(store: &crate::store::Store, query: &str, n: usize, full: bool) -> Result<(), String> { + let graph = store.build_graph(); + let stages = crate::query_parser::parse_stages(query)?; + let results = crate::search::run_query(&stages, vec![], &graph, store, false, n); - let normalize_date = |s: &str| -> String { - let s = s.replace('t', "T"); - if s.len() >= 16 { - format!("{}T{}", &s[..10], s[11..].replace('-', ":")) + // Query sorts desc and limits, so reverse to show oldest-to-newest + for (key, _score) in results.into_iter().rev() { + let Some(node) = store.nodes.get(&key) else { continue }; + let ts = if node.created_at > 0 { + crate::store::format_datetime(node.created_at) + } else if node.timestamp > 0 { + crate::store::format_datetime(node.timestamp) } else { - s - } - }; - - let extract_sort = |node: &crate::store::Node| -> (i64, String) { - if node.created_at > 0 { - return (node.created_at, crate::store::format_datetime(node.created_at)); - } - if let Some(caps) = key_date_re.captures(&node.key) { - return (0, normalize_date(&caps[1])); - } - if let Some(caps) = date_re.captures(&node.content) { - return (0, normalize_date(&caps[1])); - } - (node.timestamp, crate::store::format_datetime(node.timestamp)) - }; - - let mut journal: Vec<_> = store.nodes.values() - .filter(|node| node.node_type == crate::store::NodeType::EpisodicSession) - .collect(); - journal.sort_by(|a, b| { - let (at, as_) = extract_sort(a); - let (bt, bs) = extract_sort(b); - if at > 0 && bt > 0 { - at.cmp(&bt) - } else { - as_.cmp(&bs) - } - }); - - let skip = if journal.len() > n { journal.len() - n } else { 0 }; - for node in journal.iter().skip(skip) { - let (_, ts) = extract_sort(node); + node.key.clone() + }; let title = extract_title(&node.content); if full { println!("--- [{}] {} ---\n{}\n", ts, title, node.content); @@ -142,44 +115,14 @@ fn journal_tail_entries(store: &crate::store::Store, n: usize, full: bool) -> Re Ok(()) } -fn journal_tail_digests(store: &crate::store::Store, node_type: crate::store::NodeType, n: usize, full: bool) -> Result<(), String> { - let mut digests: Vec<_> = store.nodes.values() - .filter(|node| node.node_type == node_type) - .collect(); - digests.sort_by(|a, b| { - if a.timestamp > 0 && b.timestamp > 0 { - a.timestamp.cmp(&b.timestamp) - } else { - a.key.cmp(&b.key) - } - }); - - let skip = if digests.len() > n { digests.len() - n } else { 0 }; - for node in digests.iter().skip(skip) { - let label = &node.key; - let title = extract_title(&node.content); - if full { - println!("--- [{}] {} ---\n{}\n", label, title, node.content); - } else { - println!("[{}] {}", label, title); - } - } - Ok(()) -} - pub fn cmd_journal_tail(n: usize, full: bool, level: u8) -> Result<(), String> { let store = crate::store::Store::load()?; - if level == 0 { - journal_tail_entries(&store, n, full) - } else { - let node_type = match level { - 1 => crate::store::NodeType::EpisodicDaily, - 2 => crate::store::NodeType::EpisodicWeekly, - _ => crate::store::NodeType::EpisodicMonthly, - }; - journal_tail_digests(&store, node_type, n, full) - } + let query = format!("all | type:{} | sort:timestamp | limit:{}", + match level { 0 => "episodic", 1 => "daily", 2 => "weekly", _ => "monthly" }, + n + ); + journal_tail_query(&store, &query, n, full) } pub fn cmd_journal_write(name: &str, text: &[String]) -> Result<(), String> {