use crate::collection::{FindPlan, NitriteId};
use crate::common::{Fields, NitritePlugin};
use crate::errors::NitriteResult;
use crate::index::IndexDescriptor;
use crate::nitrite_config::NitriteConfig;
use crate::{FieldValues, NitritePluginProvider};
use std::ops::Deref;
use std::sync::Arc;
#[derive(Clone)]
pub struct NitriteIndexer {
inner: Arc<dyn NitriteIndexerProvider>,
}
pub trait NitriteIndexerProvider: NitritePluginProvider + Send + Sync {
fn index_type(&self) -> String;
fn is_unique(&self) -> bool;
fn validate_index(&self, fields: &Fields) -> NitriteResult<()>;
fn drop_index(
&self,
index_descriptor: &IndexDescriptor,
nitrite_config: &NitriteConfig,
) -> NitriteResult<()>;
fn write_index_entry(
&self,
field_values: &FieldValues,
index_descriptor: &IndexDescriptor,
nitrite_config: &NitriteConfig,
) -> NitriteResult<()>;
fn remove_index_entry(
&self,
field_values: &FieldValues,
index_descriptor: &IndexDescriptor,
nitrite_config: &NitriteConfig,
) -> NitriteResult<()>;
fn find_by_filter(
&self,
find_plan: &FindPlan,
nitrite_config: &NitriteConfig,
) -> NitriteResult<Vec<NitriteId>>;
}
impl NitriteIndexer {
pub fn new<T: NitriteIndexerProvider + 'static>(inner: T) -> Self {
NitriteIndexer { inner: Arc::new(inner) }
}
}
impl Deref for NitriteIndexer {
type Target = Arc<dyn NitriteIndexerProvider>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::{Convertible, Fields, NitritePlugin};
use crate::errors::{ErrorKind, NitriteError};
use crate::index::IndexDescriptor;
use crate::nitrite_config::NitriteConfig;
use std::any::{Any, TypeId};
#[derive(Copy, Clone)]
struct MockNitriteIndexer;
impl NitriteIndexerProvider for MockNitriteIndexer {
fn index_type(&self) -> String {
"MockIndex".to_string()
}
fn is_unique(&self) -> bool {
true
}
fn validate_index(&self, _fields: &Fields) -> NitriteResult<()> {
Ok(())
}
fn drop_index(
&self,
_index_descriptor: &IndexDescriptor,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<()> {
Ok(())
}
fn write_index_entry(
&self,
_field_values: &FieldValues,
_index_descriptor: &IndexDescriptor,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<()> {
Ok(())
}
fn remove_index_entry(
&self,
_field_values: &FieldValues,
_index_descriptor: &IndexDescriptor,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<()> {
Ok(())
}
fn find_by_filter(
&self,
_find_plan: &FindPlan,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<Vec<NitriteId>> {
Ok(vec![NitriteId::new()])
}
}
impl NitritePluginProvider for MockNitriteIndexer {
fn initialize(&self, _config: NitriteConfig) -> NitriteResult<()> {
Ok(())
}
fn close(&self) -> NitriteResult<()> {
Ok(())
}
fn as_plugin(&self) -> NitritePlugin {
NitritePlugin::new(*self)
}
}
#[test]
fn test_index_type() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
assert_eq!(indexer.index_type(), "MockIndex");
}
#[test]
fn test_is_unique() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
assert!(indexer.is_unique());
}
#[test]
fn test_validate_index() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
let fields = Fields::with_names(vec!["test_field"]).unwrap();
assert!(indexer.validate_index(&fields).is_ok());
}
#[test]
fn test_drop_index() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
let index_descriptor = IndexDescriptor::new(
"test_index",
Fields::with_names(vec!["test_field"]).unwrap(),
"test",
);
let config = NitriteConfig::default();
assert!(indexer.drop_index(&index_descriptor, &config).is_ok());
}
#[test]
fn test_write_index_entry() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let index_descriptor = IndexDescriptor::new(
"test_index",
Fields::with_names(vec!["test_field"]).unwrap(),
"test",
);
let config = NitriteConfig::default();
assert!(indexer.write_index_entry(&field_values, &index_descriptor, &config).is_ok());
}
#[test]
fn test_remove_index_entry() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let index_descriptor = IndexDescriptor::new(
"test_index",
Fields::with_names(vec!["test_field"]).unwrap(),
"test",
);
let config = NitriteConfig::default();
assert!(indexer.remove_index_entry(&field_values, &index_descriptor, &config).is_ok());
}
#[test]
fn test_find_by_filter() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
let find_plan = FindPlan::new();
let config = NitriteConfig::default();
assert!(indexer.find_by_filter(&find_plan, &config).is_ok());
}
#[test]
fn test_initialize() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
let config = NitriteConfig::default();
assert!(indexer.initialize(config).is_ok());
}
#[test]
fn test_close() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
assert!(indexer.close().is_ok());
}
#[test]
fn test_as_plugin() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
assert_eq!(indexer.as_plugin().type_id(), TypeId::of::<NitritePlugin>());
}
#[test]
fn test_validate_index_error() {
#[derive(Copy, Clone)]
struct ErrorMockNitriteIndexer;
impl NitriteIndexerProvider for ErrorMockNitriteIndexer {
fn index_type(&self) -> String {
"ErrorMockIndex".to_string()
}
fn is_unique(&self) -> bool {
false
}
fn validate_index(&self, _fields: &Fields) -> NitriteResult<()> {
Err(NitriteError::new("Validation error", ErrorKind::IndexingError))
}
fn drop_index(
&self,
_index_descriptor: &IndexDescriptor,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<()> {
Err(NitriteError::new("Drop index error", ErrorKind::IndexingError))
}
fn write_index_entry(
&self,
_field_values: &FieldValues,
_index_descriptor: &IndexDescriptor,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<()> {
Err(NitriteError::new("Write index entry error", ErrorKind::IndexingError))
}
fn remove_index_entry(
&self,
_field_values: &FieldValues,
_index_descriptor: &IndexDescriptor,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<()> {
Err(NitriteError::new("Remove index entry error", ErrorKind::IndexingError))
}
fn find_by_filter(
&self,
_find_plan: &FindPlan,
_nitrite_config: &NitriteConfig,
) -> NitriteResult<Vec<NitriteId>> {
Err(NitriteError::new("Find by filter error", ErrorKind::IndexingError))
}
}
impl NitritePluginProvider for ErrorMockNitriteIndexer {
fn initialize(&self, _config: NitriteConfig) -> NitriteResult<()> {
Err(NitriteError::new("Initialize error", ErrorKind::IndexingError))
}
fn close(&self) -> NitriteResult<()> {
Err(NitriteError::new("Close error", ErrorKind::IndexingError))
}
fn as_plugin(&self) -> NitritePlugin {
NitritePlugin::new(*self)
}
}
let indexer = NitriteIndexer::new(ErrorMockNitriteIndexer);
let fields = Fields::with_names(vec!["test_field"]).unwrap();
let index_descriptor = IndexDescriptor::new(
"test_index",
Fields::with_names(vec!["test_field"]).unwrap(),
"test",
);
let config = NitriteConfig::default();
let field_values = FieldValues::new(
vec![(String::from("test_field"), 1.to_value().unwrap())],
NitriteId::new(),
Fields::with_names(vec!["test_field"]).unwrap(),
);
let find_plan = FindPlan::new();
assert!(indexer.validate_index(&fields).is_err());
assert!(indexer.drop_index(&index_descriptor, &config).is_err());
assert!(indexer.write_index_entry(&field_values, &index_descriptor, &config).is_err());
assert!(indexer.remove_index_entry(&field_values, &index_descriptor, &config).is_err());
assert!(indexer.find_by_filter(&find_plan, &config).is_err());
assert!(indexer.initialize(config).is_err());
assert!(indexer.close().is_err());
}
#[test]
fn test_indexer_get_method_efficiency() {
let indexer = NitriteIndexer::new(MockNitriteIndexer);
assert_eq!(indexer.index_type(), "MockIndex");
assert_eq!(indexer.index_type(), "MockIndex");
assert!(indexer.is_unique());
}
#[test]
fn test_indexer_arc_sharing() {
let indexer1 = NitriteIndexer::new(MockNitriteIndexer);
let indexer2 = indexer1.clone();
assert_eq!(indexer1.index_type(), indexer2.index_type());
}
#[test]
fn test_indexer_error_propagation_efficiency() {
#[derive(Copy, Clone)]
struct MinimalErrorMockIndexer;
impl NitriteIndexerProvider for MinimalErrorMockIndexer {
fn index_type(&self) -> String { "MinimalError".to_string() }
fn is_unique(&self) -> bool { false }
fn validate_index(&self, _fields: &Fields) -> NitriteResult<()> {
Err(NitriteError::new("Quick error", ErrorKind::IndexingError))
}
fn drop_index(&self, _: &IndexDescriptor, _: &NitriteConfig) -> NitriteResult<()> { Ok(()) }
fn write_index_entry(&self, _: &FieldValues, _: &IndexDescriptor, _: &NitriteConfig) -> NitriteResult<()> { Ok(()) }
fn remove_index_entry(&self, _: &FieldValues, _: &IndexDescriptor, _: &NitriteConfig) -> NitriteResult<()> { Ok(()) }
fn find_by_filter(&self, _: &FindPlan, _: &NitriteConfig) -> NitriteResult<Vec<NitriteId>> { Ok(vec![]) }
}
impl NitritePluginProvider for MinimalErrorMockIndexer {
fn initialize(&self, _config: NitriteConfig) -> NitriteResult<()> { Ok(()) }
fn close(&self) -> NitriteResult<()> { Ok(()) }
fn as_plugin(&self) -> NitritePlugin { NitritePlugin::new(*self) }
}
let indexer = NitriteIndexer::new(MinimalErrorMockIndexer);
let fields = Fields::with_names(vec!["test"]).unwrap();
let result = indexer.validate_index(&fields);
assert!(result.is_err());
if let Err(e) = result {
assert!(e.to_string().contains("Quick error"));
}
}
}