use anyhow::Result;
use rusqlite::Connection;
use std::collections::HashMap;
use crate::graph::schema::SymbolNode;
#[allow(
dead_code,
reason = "Future optimization: O(1) SymbolId lookup, not yet integrated into main query path"
)]
pub struct SymbolIndex {
index: HashMap<String, i64>,
}
#[allow(
dead_code,
reason = "Associated items used in module tests and reserved for future integration"
)]
impl SymbolIndex {
pub fn new() -> Self {
Self {
index: HashMap::new(),
}
}
pub fn build_index(&mut self, conn: &Connection) -> Result<()> {
let mut stmt = conn
.prepare_cached(
"SELECT id, data
FROM graph_entities
WHERE kind = 'Symbol'
AND json_extract(data, '$.symbol_id') IS NOT NULL",
)
.map_err(|e| anyhow::anyhow!("Failed to prepare SymbolIndex build query: {}", e))?;
let rows = stmt
.query_map([], |row| {
let id: i64 = row.get(0)?;
let data: String = row.get(1)?;
Ok((id, data))
})
.map_err(|e| anyhow::anyhow!("Failed to execute SymbolIndex build query: {}", e))?;
for row in rows {
let (id, data) =
row.map_err(|e| anyhow::anyhow!("Failed to read SymbolIndex row: {}", e))?;
if let Ok(node) = serde_json::from_str::<SymbolNode>(&data) {
if let Some(symbol_id) = node.symbol_id {
self.index.insert(symbol_id, id);
}
}
}
Ok(())
}
pub fn lookup(&self, symbol_id: &str) -> Option<i64> {
self.index.get(symbol_id).copied()
}
pub fn len(&self) -> usize {
self.index.len()
}
pub fn is_empty(&self) -> bool {
self.index.is_empty()
}
pub fn clear(&mut self) {
self.index.clear();
}
}
impl Default for SymbolIndex {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_index_new_is_empty() {
let index = SymbolIndex::new();
assert!(index.is_empty());
assert_eq!(index.len(), 0);
}
#[test]
fn test_symbol_index_lookup_returns_none_when_empty() {
let index = SymbolIndex::new();
assert!(index.lookup("nonexistent").is_none());
}
#[test]
fn test_symbol_index_lookup_after_insert() {
let mut index = SymbolIndex::new();
index.index.insert("test_id".to_string(), 42);
assert_eq!(index.lookup("test_id"), Some(42));
assert_eq!(index.lookup("other"), None);
}
#[test]
fn test_symbol_index_clear() {
let mut index = SymbolIndex::new();
index.index.insert("test_id".to_string(), 42);
assert_eq!(index.len(), 1);
index.clear();
assert!(index.is_empty());
}
#[test]
fn test_symbol_index_default() {
let index = SymbolIndex::default();
assert!(index.is_empty());
}
}