use anyhow::Result;
use serde_json::Value;
use super::{mutation::Mutation, HmsCore};
pub(crate) const DELETE_BATCH: usize = 4096;
pub(crate) struct DocumentParts {
pub metadata: Value,
pub text: Option<String>,
pub source_uri: Option<String>,
pub version: String,
pub embedding: Option<Vec<f64>>,
}
pub(crate) struct DocumentView<'a> {
pub id: &'a str,
pub version: &'a str,
pub metadata: &'a Value,
text: &'a dyn Fn() -> Option<String>,
}
impl DocumentView<'_> {
pub(crate) fn text(&self) -> Option<String> {
(self.text)()
}
}
impl HmsCore {
pub fn revision(&self) -> u64 {
self.revision.load(std::sync::atomic::Ordering::Acquire)
}
pub(crate) fn scan_documents(&self, mut visit: impl FnMut(DocumentView<'_>)) -> u64 {
let _transaction = self.mutation_gate.read();
let revision = self.revision();
let store = self.documents();
for document in store.shared_values() {
let text = || {
document
.chunks
.first()
.and_then(|chunk| store.chunk_text(chunk))
};
visit(DocumentView {
id: &document.id,
version: &document.version,
metadata: &document.metadata,
text: &text,
});
}
revision
}
pub(crate) fn document_snapshot(&self, id: &str) -> Option<(String, Value, Option<String>)> {
self.document_parts(id)
.map(|parts| (parts.version, parts.metadata, parts.text))
}
pub(crate) fn document_parts(&self, id: &str) -> Option<DocumentParts> {
let _transaction = self.mutation_gate.read();
let store = self.documents();
let document = store.get(id)?;
let chunk = document.chunks.first();
Some(DocumentParts {
metadata: document.metadata.clone(),
text: chunk.and_then(|chunk| store.chunk_text(chunk)),
source_uri: document.source_uri.clone(),
version: document.version.clone(),
embedding: chunk.and_then(|chunk| chunk.embedding.as_ref().map(|e| e.to_f64())),
})
}
pub(crate) fn delete_documents(&self, ids: &[String]) -> Result<(usize, u64)> {
let mut deleted = 0;
let mut commits = 0;
for batch in ids.chunks(DELETE_BATCH) {
let mutations: Vec<Mutation> = {
let store = self.documents.read();
batch
.iter()
.filter(|id| store.contains_key(id))
.map(|id| Mutation::DeleteDocument { id: id.clone() })
.collect()
};
if mutations.is_empty() {
continue;
}
self.commit(&mutations)?;
deleted += mutations.len();
commits += 1;
}
Ok((deleted, commits))
}
}