pub(in crate::data::executor) struct UniqueCheck<'a> {
pub sparse: &'a crate::engine::sparse::btree::SparseEngine,
pub database_id: u64,
pub tid: u64,
pub collection: &'a str,
pub doc: &'a serde_json::Value,
pub document_id: &'a str,
pub paths: &'a [crate::engine::document::store::IndexPath],
pub bitemporal: bool,
}
pub(in crate::data::executor) fn check_unique_constraints(c: UniqueCheck<'_>) -> crate::Result<()> {
use crate::engine::document::store::extract_index_values;
let UniqueCheck {
sparse,
database_id,
tid,
collection,
doc,
document_id,
paths,
bitemporal,
} = c;
let doc_engine = crate::engine::document::store::DocumentEngine::new(sparse, database_id, tid);
for path in paths {
if !path.unique {
continue;
}
if let Some(ref p) = path.predicate
&& !p.evaluate_json(doc)
{
continue;
}
for raw in extract_index_values(doc, &path.path, path.is_array) {
let needle = if path.case_insensitive {
raw.to_lowercase()
} else {
raw
};
let existing = doc_engine
.index_lookup(collection, &path.path, &needle, bitemporal)
.unwrap_or_default();
if existing.iter().any(|id| id != document_id) {
return Err(crate::Error::RejectedConstraint {
collection: collection.to_string(),
constraint: "unique".to_string(),
detail: format!(
"unique index '{}' violation on field '{}' (value '{}')",
path.name, path.path, needle
),
});
}
}
}
Ok(())
}