pub mod hierarchical;
pub mod spatiotemporal;
pub use hierarchical::{HierarchicalIndex, HierarchicalIndexStats, HierarchicalQuery};
pub use spatiotemporal::{IndexStats, QueryOptions, SpatiotemporalIndex, TimeBucket};
use chrono::{DateTime, Utc};
use uuid::Uuid;
pub trait IndexableMemory {
fn build_hierarchical_index(
&self,
) -> impl std::future::Future<Output = HierarchicalIndex> + Send;
fn build_spatiotemporal_index(
&self,
) -> impl std::future::Future<Output = SpatiotemporalIndex> + Send;
fn query_by_time_range(
&self,
start: DateTime<Utc>,
end: DateTime<Utc>,
limit: usize,
) -> impl std::future::Future<Output = Vec<Uuid>> + Send;
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct QueryPerformance {
pub indexed_time_us: f64,
pub linear_time_us: f64,
pub speedup_factor: f64,
pub episodes_scanned: usize,
pub results_count: usize,
}
impl QueryPerformance {
#[must_use]
pub fn calculate_speedup(indexed_time_us: f64, linear_time_us: f64) -> f64 {
if indexed_time_us > 0.0 {
linear_time_us / indexed_time_us
} else {
1.0
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct IndexMetrics {
pub total_episodes: usize,
pub domain_count: usize,
pub task_type_count: usize,
pub memory_usage_bytes: usize,
pub avg_query_time_us: f64,
pub speedup_factor: f64,
pub cache_hit_rate: f64,
}
#[derive(Debug, Clone, PartialEq)]
pub struct BenchmarkResult {
pub episode_count: usize,
pub query_count: usize,
pub avg_indexed_time_us: f64,
pub avg_linear_time_us: f64,
pub overall_speedup: f64,
pub memory_overhead_percent: f64,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Episode;
use crate::types::{ComplexityLevel, TaskContext, TaskType};
use chrono::{Datelike, Timelike};
fn create_test_episode(domain: &str, task_type: TaskType) -> Episode {
let context = TaskContext {
domain: domain.to_string(),
complexity: ComplexityLevel::Simple,
tags: vec![],
..Default::default()
};
Episode::new("Test episode".to_string(), context, task_type)
}
#[test]
fn test_query_performance_calculation() {
let perf = QueryPerformance {
indexed_time_us: 10.0,
linear_time_us: 100.0,
speedup_factor: QueryPerformance::calculate_speedup(10.0, 100.0),
episodes_scanned: 1000,
results_count: 10,
};
assert_eq!(perf.speedup_factor, 10.0);
}
#[test]
fn test_hierarchical_query_builder() {
let query = HierarchicalQuery::new()
.with_domain("web-api")
.with_task_type(TaskType::CodeGeneration)
.with_limit(50);
assert_eq!(query.domain, Some("web-api".to_string()));
assert_eq!(query.task_type, Some(TaskType::CodeGeneration));
assert_eq!(query.limit, 50);
}
#[test]
fn test_time_bucket_variants() {
let year_bucket = TimeBucket::Year(2024);
assert_eq!(year_bucket, TimeBucket::Year(2024));
let month_bucket = TimeBucket::Month {
year: 2024,
month: 3,
};
assert_eq!(
month_bucket,
TimeBucket::Month {
year: 2024,
month: 3
}
);
let day_bucket = TimeBucket::Day {
year: 2024,
month: 3,
day: 15,
};
assert_eq!(
day_bucket,
TimeBucket::Day {
year: 2024,
month: 3,
day: 15,
}
);
let hour_bucket = TimeBucket::Hour {
year: 2024,
month: 3,
day: 15,
hour: 10,
};
assert_eq!(
hour_bucket,
TimeBucket::Hour {
year: 2024,
month: 3,
day: 15,
hour: 10,
}
);
}
#[test]
fn test_index_metrics() {
let metrics = IndexMetrics {
total_episodes: 1000,
domain_count: 5,
task_type_count: 10,
memory_usage_bytes: 102_400,
avg_query_time_us: 5.5,
speedup_factor: 10.0,
cache_hit_rate: 0.85,
};
assert_eq!(metrics.total_episodes, 1000);
assert_eq!(metrics.speedup_factor, 10.0);
assert!((metrics.cache_hit_rate - 0.85).abs() < f64::EPSILON);
}
#[test]
fn test_benchmark_result() {
let result = BenchmarkResult {
episode_count: 10000,
query_count: 100,
avg_indexed_time_us: 5.0,
avg_linear_time_us: 100.0,
overall_speedup: 20.0,
memory_overhead_percent: 8.5,
};
assert_eq!(result.episode_count, 10000);
assert_eq!(result.overall_speedup, 20.0);
assert!((result.memory_overhead_percent - 8.5).abs() < f64::EPSILON);
}
#[test]
fn test_spatiotemporal_index_basic() {
let mut index = SpatiotemporalIndex::new();
let episode = create_test_episode("web-api", TaskType::CodeGeneration);
index.insert(&episode);
assert_eq!(index.len(), 1);
assert!(!index.is_empty());
let year = episode.start_time.year() as u32;
let month = episode.start_time.month() as u8;
let day = episode.start_time.day() as u8;
let hour = episode.start_time.hour() as u8;
let results = index.query_hour(year, month, day, hour);
assert_eq!(results.len(), 1);
assert_eq!(results[0], episode.episode_id);
}
#[test]
fn test_hierarchical_index_basic() {
let mut index = HierarchicalIndex::new();
let episode = create_test_episode("web-api", TaskType::CodeGeneration);
index.insert(&episode);
assert_eq!(index.len(), 1);
assert_eq!(index.domain_count(), 1);
let results = index.query_by_domain("web-api", 10);
assert_eq!(results.len(), 1);
assert_eq!(results[0], episode.episode_id);
}
}