use crate::AletheiaDB;
use crate::core::error::{Error, Result};
use crate::core::id::NodeId;
use crate::semantic_search::semantic_navigator::SemanticNavigator;
pub struct TapestryEngine<'a> {
db: &'a AletheiaDB,
}
impl<'a> TapestryEngine<'a> {
pub fn new(db: &'a AletheiaDB) -> Self {
Self { db }
}
pub fn weave(
&self,
start_node: NodeId,
waypoints: &[NodeId],
end_node: NodeId,
vector_property: &str,
) -> Result<Vec<NodeId>> {
let navigator = SemanticNavigator::new(self.db);
let mut full_path = Vec::new();
let mut sequence = Vec::with_capacity(waypoints.len() + 2);
sequence.push(start_node);
sequence.extend_from_slice(waypoints);
sequence.push(end_node);
for window in sequence.windows(2) {
let from = window[0];
let to = window[1];
let segment = navigator.find_path(from, to, vector_property)?;
if full_path.is_empty() {
full_path.extend(segment);
} else {
full_path.extend(segment.into_iter().skip(1));
}
}
if full_path.is_empty() {
if start_node == end_node && waypoints.is_empty() {
return Ok(vec![start_node]);
} else {
return Err(Error::other("Failed to weave path"));
}
}
Ok(full_path)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::AletheiaDBConfig;
use crate::config::WalConfigBuilder;
use crate::core::property::PropertyMapBuilder;
use tempfile::tempdir;
fn create_test_db() -> (AletheiaDB, tempfile::TempDir) {
let dir = tempdir().unwrap();
let wal_path = dir.path().join("wal");
let data_path = dir.path().join("data");
std::fs::create_dir_all(&wal_path).unwrap();
std::fs::create_dir_all(&data_path).unwrap();
let persistence_config = crate::storage::index_persistence::PersistenceConfig {
data_dir: data_path,
enabled: false,
..Default::default()
};
let config = AletheiaDBConfig::builder()
.wal(WalConfigBuilder::new().wal_dir(wal_path).build())
.persistence(persistence_config)
.build();
let db = AletheiaDB::with_unified_config(config).unwrap();
(db, dir)
}
#[test]
fn test_tapestry_weave() {
let (db, _dir) = create_test_db();
let props = PropertyMapBuilder::new()
.insert_vector("vec", &[1.0, 0.0]) .build();
let a = db.create_node("Node", props.clone()).unwrap();
let b = db.create_node("Node", props.clone()).unwrap();
let c = db.create_node("Node", props.clone()).unwrap();
let d = db.create_node("Node", props.clone()).unwrap();
let e = db.create_node("Node", props.clone()).unwrap();
db.create_edge(a, b, "NEXT", PropertyMapBuilder::new().build())
.unwrap();
db.create_edge(b, c, "NEXT", PropertyMapBuilder::new().build())
.unwrap();
db.create_edge(c, d, "NEXT", PropertyMapBuilder::new().build())
.unwrap();
db.create_edge(d, e, "NEXT", PropertyMapBuilder::new().build())
.unwrap();
let tapestry = TapestryEngine::new(&db);
let path = tapestry.weave(a, &[c], e, "vec").unwrap();
assert_eq!(path, vec![a, b, c, d, e]);
}
}