// Read-only access abstraction for the memory store use super::{capnp, index, types::*}; use super::Store; // --------------------------------------------------------------------------- // StoreView: read-only access trait for search and graph code. // --------------------------------------------------------------------------- pub trait StoreView { /// Iterate all nodes. Callback receives (key, content, weight). fn for_each_node(&self, f: F); /// Iterate all nodes with metadata. Callback receives (key, node_type, timestamp). fn for_each_node_meta(&self, f: F); /// Iterate all relations. Callback receives (source_key, target_key, strength, rel_type). fn for_each_relation(&self, f: F); /// Node weight by key, or the default weight if missing. fn node_weight(&self, key: &str) -> f64; } impl StoreView for Store { fn for_each_node(&self, mut f: F) { let db = match self.db.as_ref() { Some(db) => db, None => return, }; let keys = match index::all_keys(db) { Ok(keys) => keys, Err(_) => return, }; for key in keys { if let Ok(Some(offset)) = index::get_offset(db, &key) { if let Ok(node) = capnp::read_node_at_offset(offset) { f(&key, &node.content, node.weight); } } } } fn for_each_node_meta(&self, mut f: F) { let db = match self.db.as_ref() { Some(db) => db, None => return, }; let keys = match index::all_keys(db) { Ok(keys) => keys, Err(_) => return, }; for key in keys { if let Ok(Some(offset)) = index::get_offset(db, &key) { if let Ok(node) = capnp::read_node_at_offset(offset) { f(&key, node.node_type, node.timestamp); } } } } fn for_each_relation(&self, mut f: F) { let db = match self.db.as_ref() { Some(db) => db, None => return, }; // Build uuid → key map by iterating all nodes once let mut uuid_to_key: std::collections::HashMap<[u8; 16], String> = std::collections::HashMap::new(); let keys = match index::all_keys(db) { Ok(keys) => keys, Err(_) => return, }; for key in &keys { if let Ok(Some(uuid)) = index::get_uuid_for_key(db, key) { uuid_to_key.insert(uuid, key.clone()); } } // Iterate edges: only process outgoing to avoid duplicates for key in &keys { let uuid = match index::get_uuid_for_key(db, key) { Ok(Some(u)) => u, _ => continue, }; let edges = match index::edges_for_node(db, &uuid) { Ok(e) => e, Err(_) => continue, }; for (other_uuid, strength, rel_type_byte, is_outgoing) in edges { if !is_outgoing { continue; } // only process outgoing let target_key = match uuid_to_key.get(&other_uuid) { Some(k) => k, None => continue, // orphan edge }; let rel_type = RelationType::from_u8(rel_type_byte); f(key, target_key, strength, rel_type); } } } fn node_weight(&self, key: &str) -> f64 { let cfg = crate::config::get(); self.get_node(key) .ok() .flatten() .map(|n| n.weight as f64) .unwrap_or(cfg.default_node_weight) } }