use tracing::info;
use crate::document::{DocumentTree, NodeId};
use crate::error::Result;
use crate::index::parse::RawNode;
use super::detector::ChangeDetector;
#[derive(Debug)]
pub struct UpdateResult {
pub nodes_added: usize,
pub nodes_removed: usize,
pub nodes_modified: usize,
pub summaries_regenerated: usize,
}
impl Default for UpdateResult {
fn default() -> Self {
Self {
nodes_added: 0,
nodes_removed: 0,
nodes_modified: 0,
summaries_regenerated: 0,
}
}
}
pub struct PartialUpdater {
detector: ChangeDetector,
}
impl PartialUpdater {
pub fn new() -> Self {
Self {
detector: ChangeDetector::new(),
}
}
pub fn detector(&self) -> &ChangeDetector {
&self.detector
}
pub fn detector_mut(&mut self) -> &mut ChangeDetector {
&mut self.detector
}
pub fn update(
&self,
old_tree: &DocumentTree,
new_raw_nodes: Vec<RawNode>,
) -> Result<(DocumentTree, UpdateResult)> {
let mut result = UpdateResult::default();
let new_tree = self.build_tree_from_raw(new_raw_nodes)?;
let changes = self.detector.detect_changes(old_tree, &new_tree);
info!(
"Detected changes: {} added, {} removed, {} modified",
changes.added.len(),
changes.removed.len(),
changes.modified.len()
);
result.nodes_added = changes.added.len();
result.nodes_removed = changes.removed.len();
result.nodes_modified = changes.modified.len();
Ok((new_tree, result))
}
fn build_tree_from_raw(&self, raw_nodes: Vec<RawNode>) -> Result<DocumentTree> {
let mut tree = DocumentTree::new("Document", "");
let mut level_stack: Vec<Option<NodeId>> = vec![Some(tree.root())];
for raw in raw_nodes {
let level = raw.level;
while level_stack.len() <= level {
level_stack.push(None);
}
let parent_id = (0..level)
.rev()
.find_map(|l| level_stack.get(l).copied().flatten())
.unwrap_or(tree.root());
let content = if raw.content.is_empty() {
""
} else {
&raw.content
};
let node_id = tree.add_child(parent_id, &raw.title, content);
tree.set_line_indices(node_id, raw.line_start, raw.line_end);
if let Some(page) = raw.page {
tree.set_page_boundaries(node_id, page, page);
}
if let Some(count) = raw.token_count {
if count > 0 {
tree.set_token_count(node_id, count);
}
}
if level < level_stack.len() {
level_stack[level] = Some(node_id);
}
for i in (level + 1)..level_stack.len() {
level_stack[i] = None;
}
}
Ok(tree)
}
pub fn needs_reindex(&self, doc_id: &str, content: &str) -> bool {
self.detector.needs_reindex_by_hash(doc_id, content)
}
pub fn record(&mut self, doc_id: &str, content: &str) {
self.detector.record(doc_id, content, None);
}
}
impl Default for PartialUpdater {
fn default() -> Self {
Self::new()
}
}