use std::sync::Arc;
use nodedb_types::Surrogate;
use nodedb_types::result::QueryResult;
use crate::error::LiteError;
use crate::query::engine::LiteQueryEngine;
use crate::storage::engine::StorageEngine;
use super::super::adapter::LitePhysicalFut;
fn affected(rows_affected: u64) -> QueryResult {
QueryResult {
columns: vec![],
rows: vec![],
rows_affected,
command: None,
}
}
pub(super) fn fts_index_doc<'a, S: StorageEngine + 'a>(
engine: &'a LiteQueryEngine<S>,
permit: Option<&'a crate::engine::fts::coordinator::TextMutationPermit>,
collection: &str,
surrogate: Surrogate,
fields: &[(String, String)],
) -> LitePhysicalFut<'a> {
let document = nodedb_fts::DocumentText::from_fields(fields.iter().cloned());
if document.is_empty() {
return fts_delete_doc(engine, permit, collection, Some(surrogate));
}
let collection = collection.to_owned();
let text = document.whole();
let fts_state = Arc::clone(&engine.fts_state);
Box::pin(async move {
let guard = if permit.is_none() {
Some(fts_state.admit_mutation().await)
} else {
None
};
let result = async {
let mut mgr = fts_state
.manager
.lock()
.map_err(|_| LiteError::LockPoisoned)?;
if mgr.declaration_for(&collection).is_some() {
return Err(LiteError::Unsupported {
detail: format!("unstructured text mutation on '{collection}' retains an active SEARCH INDEX: use source document writes or DROP SEARCH INDEX first"),
});
}
mgr.index_document(&collection, &text, &text)?;
mgr.register_origin_surrogate(surrogate, &text);
drop(mgr);
Ok(affected(1))
}.await;
match guard {
Some(guard) => guard.finish(result),
None => result,
}
})
}
pub(super) fn fts_delete_doc<'a, S: StorageEngine + 'a>(
engine: &'a LiteQueryEngine<S>,
permit: Option<&'a crate::engine::fts::coordinator::TextMutationPermit>,
collection: &str,
surrogate: Option<Surrogate>,
) -> LitePhysicalFut<'a> {
let Some(surrogate) = surrogate else {
return Box::pin(async { Ok(affected(0)) });
};
let collection = collection.to_owned();
let fts_state = Arc::clone(&engine.fts_state);
Box::pin(async move {
let guard = if permit.is_none() {
Some(fts_state.admit_mutation().await)
} else {
None
};
let result = async {
let mut mgr = fts_state
.manager
.lock()
.map_err(|_| LiteError::LockPoisoned)?;
if mgr.declaration_for(&collection).is_some() {
return Err(LiteError::Unsupported {
detail: format!("unstructured text mutation on '{collection}' retains an active SEARCH INDEX: use source document writes or DROP SEARCH INDEX first"),
});
}
let removed_doc_id = mgr.remove_by_origin_surrogate(&collection, surrogate)?;
drop(mgr);
Ok(affected(u64::from(removed_doc_id.is_some())))
}.await;
match guard {
Some(guard) => guard.finish(result),
None => result,
}
})
}