use std::collections::HashMap;
use anyhow::{Context, Result};
use crate::storage::VectorStore;
use crate::types::{Chunk, ChunkEdge, ChunkEdgeType};
#[derive(Debug, Clone)]
pub struct SimilarEdgeCandidate {
pub edge: ChunkEdge,
pub similarity: f32,
pub repo: String,
}
pub fn edge_candidate(
a: &Chunk,
a_repo: &str,
b: &Chunk,
b_repo: &str,
similarity: f32,
) -> SimilarEdgeCandidate {
let (src, src_repo, dst) = if a.id <= b.id {
(a, a_repo, b)
} else {
(b, b_repo, a)
};
SimilarEdgeCandidate {
edge: ChunkEdge {
source_chunk: src.id.clone(),
target_chunk: dst.id.clone(),
source_name: src.name.clone().unwrap_or_default(),
target_name: dst.name.clone().unwrap_or_default(),
edge_type: ChunkEdgeType::SimilarTo,
file_path: src.file_path.clone(),
},
similarity,
repo: src_repo.to_string(),
}
}
pub async fn persist_similar_edges(
store: &mut VectorStore,
candidates: &[SimilarEdgeCandidate],
repo_scope: Option<&str>,
) -> Result<usize> {
store
.clear_chunk_edges_by_type(ChunkEdgeType::SimilarTo, repo_scope)
.await
.context("Failed to clear previous similar_to edges")?;
let mut by_repo: HashMap<&str, Vec<ChunkEdge>> = HashMap::new();
for c in candidates {
by_repo
.entry(c.repo.as_str())
.or_default()
.push(c.edge.clone());
}
let mut written = 0;
for (repo, edges) in by_repo {
store
.upsert_chunk_edges(&edges, repo)
.await
.with_context(|| format!("Failed to persist similar_to edges for repo '{repo}'"))?;
written += edges.len();
}
Ok(written)
}
#[cfg(test)]
#[path = "similar_edges_tests.rs"]
mod tests;