use std::sync::Arc;
use std::time::Instant;
use super::{build_typed_registry, search_stats, typed};
use crate::core::item::AnyItem;
pub struct SearchIndex {
registry: typed::SearchRegistry,
}
impl SearchIndex {
pub fn new() -> Self {
let registry = build_typed_registry();
log::info!(
"SearchIndex: initialized with {} typed entity indexes",
registry.len()
);
Self { registry }
}
pub fn index_item(&self, item: &Arc<dyn AnyItem>) {
static DISABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
if *DISABLED.get_or_init(|| std::env::var("MYKO_SEARCH_INDEX_DISABLED").is_ok()) {
return;
}
self.registry.insert(item.as_ref());
}
pub fn remove_entity(&self, entity_type: &str, entity_id: &str) {
self.registry.remove(entity_type, entity_id);
}
pub fn commit(&self) {}
pub fn search(&self, entity_type: &str, query: &str, limit: usize) -> Vec<Arc<str>> {
let opts = typed::SearchOptions {
limit,
..typed::SearchOptions::default()
};
let started = Instant::now();
let hits: Vec<Arc<str>> = self
.registry
.search(entity_type, query, opts)
.into_iter()
.map(|h| h.id)
.collect();
search_stats::record_search(entity_type, hits.len(), started.elapsed());
hits
}
pub fn is_searchable(&self, entity_type: &str) -> bool {
self.registry.entity_types().any(|t| t == entity_type)
}
pub fn build_from_registry(&self, registry: &crate::store::StoreRegistry) {
use hyphae::Gettable;
let mut count = 0;
let entity_types: Vec<&'static str> = self.registry.entity_types().collect();
for entity_type in entity_types {
let Some(store) = registry.get(entity_type) else {
continue;
};
let entries = store.entries().get();
for (_, item) in entries.iter() {
self.registry.insert(item.as_ref());
count += 1;
}
}
log::info!("SearchIndex: built initial index with {} entities", count);
}
}
impl Default for SearchIndex {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_search_index_is_empty_for_unknown_types() {
let index = SearchIndex::new();
let hits = index.search("UnknownType", "anything", 10);
assert!(hits.is_empty());
}
}