Skip to main content

kaizen/search/
reindex.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2//! Drop and rebuild search index from persisted events.
3
4use crate::core::config::try_team_salt;
5use crate::core::event::{Event, SessionRecord};
6use crate::search::extract_doc;
7use crate::search::writer::{PendingWriter, index_dir};
8use anyhow::Result;
9use std::collections::BTreeMap;
10use std::path::Path;
11
12#[derive(Debug, Clone, Copy, serde::Serialize)]
13pub struct ReindexStats {
14    pub events_seen: u64,
15    pub docs_indexed: u64,
16}
17
18pub fn reindex_workspace(
19    root: &Path,
20    workspace: &Path,
21    sessions: &[SessionRecord],
22    events: Vec<(SessionRecord, Event)>,
23    cfg: &crate::core::config::Config,
24) -> Result<ReindexStats> {
25    drop_index(root)?;
26    let salt = try_team_salt(&cfg.sync).unwrap_or([0; 32]);
27    let session_map = sessions
28        .iter()
29        .map(|s| (s.id.clone(), s.clone()))
30        .collect::<BTreeMap<_, _>>();
31    let mut writer = PendingWriter::open(root)?;
32    let mut stats = ReindexStats {
33        events_seen: events.len() as u64,
34        docs_indexed: 0,
35    };
36    for (_, event) in events {
37        let Some(session) = session_map.get(&event.session_id) else {
38            continue;
39        };
40        if let Some(doc) = extract_doc(&event, session, workspace, &salt) {
41            writer.add(&doc)?;
42            stats.docs_indexed += 1;
43        }
44    }
45    writer.commit()?;
46    Ok(stats)
47}
48
49fn drop_index(root: &Path) -> Result<()> {
50    let dir = index_dir(root);
51    if dir.exists() {
52        std::fs::remove_dir_all(&dir)?;
53    }
54    Ok(())
55}