use std::collections::{BTreeMap, BTreeSet};
use super::mutations::PreparedWrite;
use super::{Captured, Failure, Storage, identifier, reads};
use crate::serve::protocol::{Change, DocumentDelete, DocumentDeleteMany, Version};
impl Storage {
pub(super) fn prepare_delete_many(
&self,
at: &Captured,
delete: &DocumentDeleteMany,
next: Version,
) -> Result<Vec<PreparedWrite>, Failure> {
validate(&self.reader, at, delete)?;
let mut writes = BTreeMap::new();
for document_id in &delete.document_ids {
let change = Change::Delete(DocumentDelete {
collection: delete.collection.clone(),
document_id: document_id.clone(),
});
writes.extend(self.prepare_change(at, &change, next)?);
}
Ok(writes.into_iter().collect())
}
}
fn validate(
reader: &haematite::db::ReadOnlyDatabase,
at: &Captured,
delete: &DocumentDeleteMany,
) -> Result<(), Failure> {
if delete.document_ids.is_empty() {
return Err(Failure {
path: Some("/document_ids".to_owned()),
..Failure::new(
"import_empty",
"a delete batch must contain at least one document",
)
});
}
reads::collection(reader, at, &delete.collection)
.map_err(|failure| Failure {
path: Some("/collection".to_owned()),
..failure
})?
.ok_or_else(|| Failure {
path: Some("/collection".to_owned()),
..Failure::new("collection_missing", &delete.collection)
})?;
let mut ids = BTreeSet::new();
for (index, id) in delete.document_ids.iter().enumerate() {
let in_row = |failure: Failure| Failure {
path: Some(format!("/document_ids/{index}")),
..failure
};
identifier(id).map_err(in_row)?;
if !ids.insert(id) {
return Err(in_row(Failure::new(
"import_duplicate",
"repeated document_id in delete batch",
)));
}
if !reads::document_exists_for_constraint(reader, at, &delete.collection, id)
.map_err(in_row)?
{
return Err(in_row(Failure::new("document_missing", id)));
}
}
Ok(())
}