use std::{collections::HashSet, path::Path};
use crate::{db::Document, error::GetDocumentError, DbError, Intersection, SearchError, Stats, DB};
use memmap2::Mmap;
use rkyv::{de::Pool, rancor::Strategy, Archive, Deserialize};
pub struct SearchResult<'a, D: Document>(pub Result<Vec<u32>, SearchError>, &'a Searcher<D>);
impl<D: Document> SearchResult<'_, D> {
pub fn len(&self) -> Option<usize> {
self.0.as_ref().map(|p| p.len()).ok()
}
pub fn get_internal_document_ids(&self) -> Option<&[u32]> {
self.0.as_ref().map(|p| p.as_slice()).ok()
}
pub fn get_archived_documents(
&self,
cb: impl FnOnce(Vec<&D::Archived>),
) -> Result<(), GetDocumentError> {
let Some(doc_ids) = self.get_internal_document_ids() else {
return Ok(());
};
self.1.get_archived_documents(doc_ids, cb)
}
pub fn get_documents(&self) -> Result<Vec<D>, GetDocumentError>
where
<D as Archive>::Archived: Deserialize<D, Strategy<Pool, rkyv::rancor::Error>>,
{
let Some(doc_ids) = self.get_internal_document_ids() else {
return Ok(Vec::new());
};
self.1.get_documents(doc_ids)
}
}
pub struct Searcher<D: Document> {
db: DB<D>,
common_tokens: HashSet<Box<str>>,
mmap: Mmap,
}
impl<D: Document> Searcher<D> {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, DbError> {
let (db, common_tokens, mmap) = DB::open(path)?;
Ok(Self {
db,
common_tokens,
mmap,
})
}
pub fn search<I: Intersection>(&self, q: &str) -> SearchResult<D> {
let stats = Stats::default();
self.search_with_stats::<I>(q, &stats)
}
pub fn search_with_stats<I: Intersection>(&self, q: &str, stats: &Stats) -> SearchResult<D> {
SearchResult(
self.db
.search::<I>(q, stats, &self.common_tokens, &self.mmap),
self,
)
}
pub fn get_archived_documents(
&self,
doc_ids: &[u32],
cb: impl FnOnce(Vec<&D::Archived>),
) -> Result<(), GetDocumentError> {
self.db.get_archived_documents(doc_ids, cb)
}
pub fn get_archived_document(
&self,
doc_id: u32,
cb: impl FnOnce(&D::Archived),
) -> Result<(), GetDocumentError> {
self.db.get_archived_document(doc_id, cb)
}
pub fn get_documents(&self, doc_ids: &[u32]) -> Result<Vec<D>, GetDocumentError>
where
<D as Archive>::Archived: Deserialize<D, Strategy<Pool, rkyv::rancor::Error>>,
{
self.db.get_documents(doc_ids)
}
pub fn get_document(&self, doc_id: u32) -> Result<D, GetDocumentError>
where
<D as Archive>::Archived: Deserialize<D, Strategy<Pool, rkyv::rancor::Error>>,
{
self.db.get_document(doc_id)
}
}