use super::IndexDescriptor;
use crate::{
collection::{FindPlan, NitriteId},
errors::{ErrorKind, NitriteError, NitriteResult},
FieldValues,
};
use std::ops::Deref;
use std::sync::Arc;
pub trait NitriteIndexProvider: Send + Sync {
fn index_descriptor(&self) -> NitriteResult<IndexDescriptor>;
fn write(&self, field_values: &FieldValues) -> NitriteResult<()>;
fn remove(&self, field_values: &FieldValues) -> NitriteResult<()>;
fn drop_index(&self) -> NitriteResult<()>;
fn find_nitrite_ids(&self, find_plan: &FindPlan) -> NitriteResult<Vec<NitriteId>>;
fn is_unique(&self) -> bool;
fn add_nitrite_ids(
&self,
nitrite_ids: &mut Vec<NitriteId>,
field_values: &FieldValues,
) -> NitriteResult<Vec<NitriteId>> {
if self.is_unique() && nitrite_ids.len() == 1 {
log::error!("Unique constraint violated for {:?}", field_values);
return Err(NitriteError::new(
&format!("Unique constraint violated for {:?}", field_values),
ErrorKind::IndexingError,
));
}
nitrite_ids.push(*field_values.nitrite_id());
Ok(std::mem::take(nitrite_ids))
}
fn remove_nitrite_ids(
&self,
nitrite_ids: &mut Vec<NitriteId>,
field_values: &FieldValues,
) -> NitriteResult<Vec<NitriteId>> {
if !nitrite_ids.is_empty() {
nitrite_ids.retain(|x| x != field_values.nitrite_id());
}
Ok(std::mem::take(nitrite_ids))
}
}
#[derive(Clone)]
pub struct NitriteIndex {
inner: Arc<dyn NitriteIndexProvider>,
}
impl NitriteIndex {
pub fn new<T: NitriteIndexProvider + 'static>(inner: T) -> Self {
NitriteIndex { inner: Arc::new(inner) }
}
}
impl Deref for NitriteIndex {
type Target = Arc<dyn NitriteIndexProvider>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::{Convertible, Fields, UNIQUE_INDEX};
use crate::errors::ErrorKind;
struct MockNitriteIndex;
impl NitriteIndexProvider for MockNitriteIndex {
fn index_descriptor(&self) -> NitriteResult<IndexDescriptor> {
Ok(IndexDescriptor::new(
UNIQUE_INDEX,
Fields::with_names(vec!["test_field"])?,
"test",
))
}
fn write(&self, _field_values: &FieldValues) -> NitriteResult<()> {
Ok(())
}
fn remove(&self, _field_values: &FieldValues) -> NitriteResult<()> {
Ok(())
}
fn drop_index(&self) -> NitriteResult<()> {
Ok(())
}
fn find_nitrite_ids(&self, _find_plan: &FindPlan) -> NitriteResult<Vec<NitriteId>> {
Ok(vec![NitriteId::new()])
}
fn is_unique(&self) -> bool {
true
}
}
#[test]
fn test_index_descriptor() {
let index = NitriteIndex::new(MockNitriteIndex);
assert!(index.index_descriptor().is_ok());
}
#[test]
fn test_write() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
assert!(index.write(&field_values).is_ok());
}
#[test]
fn test_remove() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
assert!(index.remove(&field_values).is_ok());
}
#[test]
fn test_drop_index() {
let index = NitriteIndex::new(MockNitriteIndex);
assert!(index.drop_index().is_ok());
}
#[test]
fn test_find_nitrite_ids() {
let index = NitriteIndex::new(MockNitriteIndex);
let find_plan = FindPlan::new();
assert!(index.find_nitrite_ids(&find_plan).is_ok());
}
#[test]
fn test_is_unique() {
let index = NitriteIndex::new(MockNitriteIndex);
assert!(index.is_unique());
}
#[test]
fn test_add_nitrite_ids_unique_violation() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![NitriteId::new()];
let result = index.add_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_err());
assert_eq!(result.unwrap_err().kind(), &ErrorKind::IndexingError);
}
#[test]
fn test_add_nitrite_ids() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![];
let result = index.add_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 1);
}
#[test]
fn test_remove_nitrite_ids() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![*field_values.nitrite_id()];
let result = index.remove_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
}
#[test]
fn test_remove_nitrite_ids_not_found() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![NitriteId::new()];
let result = index.remove_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 1);
}
#[test]
fn test_add_nitrite_ids_uses_mem_take() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![];
let result = index.add_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 1);
assert!(nitrite_ids.is_empty());
}
#[test]
fn test_remove_nitrite_ids_uses_mem_take() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![*field_values.nitrite_id()];
let result = index.remove_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
assert!(nitrite_ids.is_empty());
}
#[test]
fn test_add_nitrite_ids_multiple_entries() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids: Vec<NitriteId> = (0..10)
.map(|_| NitriteId::new())
.collect();
let original_len = nitrite_ids.len();
let result = index.add_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), original_len + 1);
}
#[test]
fn test_remove_nitrite_ids_batch_retention() {
let index = NitriteIndex::new(MockNitriteIndex);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let mut nitrite_ids = vec![
*field_values.nitrite_id(),
NitriteId::new(),
NitriteId::new(),
];
let result = index.remove_nitrite_ids(&mut nitrite_ids, &field_values);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 2);
}
}