use std::collections::HashMap;
use nodedb_types::filter::MetadataFilter;
use nodedb_types::result::SearchResult;
use nodedb_vector::rerank::Ranked;
use crate::engine::crdt::CrdtEngine;
use crate::engine::vector::IndexIdMap;
use super::filter::{fields_match, row_fields};
pub(super) struct Hydration<'a> {
pub ids: Option<&'a IndexIdMap>,
pub crdt: &'a CrdtEngine,
pub collection: &'a str,
pub filter: Option<&'a MetadataFilter>,
pub exclude_fields: &'a [&'a str],
pub skip_payload_fetch: bool,
}
impl Hydration<'_> {
pub(super) fn results(&self, ranked: Vec<Ranked>) -> Vec<SearchResult> {
ranked.into_iter().filter_map(|r| self.result(r)).collect()
}
fn result(&self, r: Ranked) -> Option<SearchResult> {
let doc_id = self
.ids
.and_then(|ids| ids.doc_id(r.id))
.map_or_else(|| r.id.to_string(), str::to_owned);
let needs_payload = !self.skip_payload_fetch || self.filter.is_some();
let metadata = if needs_payload {
row_fields(self.crdt, self.collection, &doc_id, self.exclude_fields).unwrap_or_default()
} else {
HashMap::new()
};
if let Some(f) = self.filter
&& !fields_match(&metadata, f)
{
return None;
}
let metadata = if self.skip_payload_fetch {
HashMap::new()
} else {
metadata
};
Some(SearchResult {
id: doc_id,
node_id: None,
distance: r.distance,
metadata,
})
}
}