#[cfg(feature = "geometric")]
pub struct CodeGraphGeo {
inner: magellan::graph::geometric_backend::GeometricBackend,
db_path: std::path::PathBuf,
symbol_cache: HashMap<String, Vec<NodeId>>,
}
#[cfg(feature = "geometric")]
impl CodeGraphGeo {
pub fn open(path: &Path) -> Result<Self> {
use magellan::graph::geometric_backend::GeometricBackend;
let inner = GeometricBackend::open(path).map_err(|e| {
SpliceError::Other(format!(
"Failed to open geometric backend at {:?}: {}",
path, e
))
})?;
Ok(Self {
inner,
db_path: path.to_path_buf(),
symbol_cache: HashMap::new(),
})
}
pub fn db_path(&self) -> &Path {
&self.db_path
}
pub fn inner(&self) -> &magellan::graph::geometric_backend::GeometricBackend {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut magellan::graph::geometric_backend::GeometricBackend {
&mut self.inner
}
pub fn get_all_files(&self) -> Vec<String> {
self.inner
.get_all_files()
.into_iter()
.map(|(path, _, _)| path)
.collect()
}
pub fn get_code_chunk(
&self,
file_path: &Path,
byte_start: usize,
byte_end: usize,
) -> Result<Option<String>> {
let path_str = file_path
.to_str()
.ok_or_else(|| SpliceError::Other(format!("Invalid UTF-8 in path: {:?}", file_path)))?;
let chunks = self
.inner
.get_code_chunks(path_str)
.map_err(|e| SpliceError::Other(format!("Failed to get code chunks: {}", e)))?;
for chunk in chunks {
if chunk.byte_start == byte_start && chunk.byte_end == byte_end {
return Ok(Some(chunk.content));
}
}
Ok(None)
}
}
#[cfg(feature = "geometric")]
impl CodeGraphGeo {
pub fn find_symbol_in_file(&self, file_path: &str, name: &str) -> Option<NodeId> {
let cache_key = format!("{}::{}", file_path, name);
if let Some(ids) = self.symbol_cache.get(&cache_key) {
return ids.first().copied();
}
match self.inner.find_symbol_id_by_name_and_path(name, file_path) {
Some(id) => Some(NodeId(id as i64)),
None => None,
}
}
pub fn find_symbols_by_name(&self, name: &str) -> Vec<(NodeId, Option<String>)> {
let symbols = self.inner.find_symbols_by_name_info(name);
symbols
.into_iter()
.map(|info| (NodeId(info.id as i64), Some(info.file_path)))
.collect()
}
pub fn all_symbol_names(&self) -> Vec<String> {
use std::collections::HashSet;
let mut names = HashSet::new();
for key in self.symbol_cache.keys() {
if let Some(name) = key.split("::").last() {
names.insert(name.to_string());
} else {
names.insert(key.clone());
}
}
match self.inner.get_all_symbols() {
Ok(symbols) => {
for symbol in symbols {
names.insert(symbol.name);
}
}
Err(_) => {}
}
names.into_iter().collect()
}
pub fn get_span(&self, node_id: NodeId) -> Result<(usize, usize)> {
let entity_id = node_id.0 as u64;
match self.inner.find_symbol_by_id_info(entity_id) {
Some(info) => Ok((info.byte_start as usize, info.byte_end as usize)),
None => Err(SpliceError::SymbolNotFound {
message: format!("Symbol with entity_id {} not found", entity_id),
symbol: format!("entity_{}", entity_id),
file: None,
hint: "Symbol may have been deleted".to_string(),
}),
}
}
pub fn store_symbol(
&mut self,
_name: &str,
_kind: &str,
_language: Language,
_byte_start: usize,
_byte_end: usize,
_line_start: usize,
_line_end: usize,
_col_start: usize,
_col_end: usize,
) -> Result<NodeId> {
Err(SpliceError::Other(
"Direct symbol storage not supported on geometric backend. Use magellan watch to index files.".to_string()
))
}
pub fn store_symbol_with_file_and_language(
&mut self,
_file_path: &Path,
_name: &str,
_kind: &str,
_language: Language,
_byte_start: usize,
_byte_end: usize,
_line_start: usize,
_line_end: usize,
_col_start: usize,
_col_end: usize,
) -> Result<NodeId> {
Err(SpliceError::Other(
"Direct symbol storage not supported on geometric backend. Use magellan watch to index files.".to_string()
))
}
pub fn backend_type(&self) -> BackendType {
BackendType::Geometric
}
}