use std::{any::Any, fmt::Display, sync::OnceLock};
use crate::{
collection::Document,
errors::{ErrorKind, NitriteError, NitriteResult},
index::IndexMap,
Value,
};
use super::{Filter, FilterProvider};
pub(crate) struct AllFilter;
impl FilterProvider for AllFilter {
fn apply(&self, _entry: &Document) -> NitriteResult<bool> {
Ok(true)
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Display for AllFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "AllFilter")
}
}
pub(crate) struct EqualsFilter {
field_name: OnceLock<String>,
field_value: OnceLock<Value>,
collection_name: OnceLock<String>,
}
impl EqualsFilter {
#[inline]
pub(crate) fn new(field_name: String, field_value: Value) -> Self {
let name = OnceLock::new();
let _ = name.set(field_name);
let value = OnceLock::new();
let _ = value.set(field_value);
EqualsFilter {
field_name: name,
field_value: value,
collection_name: OnceLock::new(),
}
}
}
impl Display for EqualsFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match (self.field_name.get(), self.field_value.get()) {
(Some(name), Some(value)) => write!(f, "({} == {})", name, value),
(Some(name), None) => write!(f, "({} == unknown)", name),
(None, Some(value)) => write!(f, "(unknown == {})", value),
(None, None) => write!(f, "(unknown == unknown)"),
}
}
}
impl FilterProvider for EqualsFilter {
#[inline]
fn apply(&self, entry: &Document) -> NitriteResult<bool> {
let field_name = self.field_name.get()
.ok_or_else(|| NitriteError::new(
"Equals filter error: field name not set - filter must be properly initialized before applying",
ErrorKind::InvalidOperation
))?;
let value = entry.get(field_name)?;
let field_value = self.field_value.get()
.ok_or_else(|| NitriteError::new(
"Equals filter error: field value not set - filter must be properly initialized before applying",
ErrorKind::InvalidOperation
))?;
Ok(&value == field_value)
}
fn apply_on_index(&self, index_map: &IndexMap) -> NitriteResult<Vec<Value>> {
let field_value = self.field_value.get().cloned().unwrap_or(Value::Null);
let val = index_map.get(&field_value)?;
match val {
Some(Value::Array(array)) => Ok(array.clone()),
Some(v) => Ok(vec![v]),
None => Ok(vec![]),
}
}
fn get_collection_name(&self) -> NitriteResult<String> {
self.collection_name.get()
.cloned()
.ok_or_else(|| {
log::error!("Collection name is not set for filter");
NitriteError::new(
"Collection name is not set",
ErrorKind::InvalidOperation,
)
})
}
fn set_collection_name(&self, collection_name: String) -> NitriteResult<()> {
self.collection_name.get_or_init(|| collection_name);
Ok(())
}
fn has_field(&self) -> bool {
true
}
fn get_field_name(&self) -> NitriteResult<String> {
self.field_name.get()
.cloned()
.ok_or_else(|| NitriteError::new("Field name not initialized", ErrorKind::InvalidOperation))
}
fn set_field_name(&self, field_name: String) -> NitriteResult<()> {
self.field_name.get_or_init(|| field_name);
Ok(())
}
fn get_field_value(&self) -> NitriteResult<Option<Value>> {
if self.field_value.get().is_none() {
Ok(None)
} else {
Ok(self.field_value.get().cloned())
}
}
fn set_field_value(&self, field_value: Value) -> NitriteResult<()> {
self.field_value.get_or_init(|| field_value);
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct NotEqualsFilter {
field_name: OnceLock<String>,
field_value: OnceLock<Value>,
collection_name: OnceLock<String>,
}
impl NotEqualsFilter {
#[inline]
pub(crate) fn new(field_name: String, field_value: Value) -> Self {
let name = OnceLock::new();
let _ = name.set(field_name);
let value = OnceLock::new();
let _ = value.set(field_value);
NotEqualsFilter {
field_name: name,
field_value: value,
collection_name: OnceLock::new(),
}
}
}
impl Display for NotEqualsFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match (self.field_name.get(), self.field_value.get()) {
(Some(name), Some(value)) => write!(f, "({} != {})", name, value),
(Some(name), None) => write!(f, "({} != unknown)", name),
(None, Some(value)) => write!(f, "(unknown != {})", value),
(None, None) => write!(f, "(unknown != unknown)"),
}
}
}
impl FilterProvider for NotEqualsFilter {
#[inline]
fn apply(&self, entry: &Document) -> NitriteResult<bool> {
let field_name = self.field_name.get()
.ok_or_else(|| NitriteError::new(
"Not-equals filter error: field name not set - filter must be properly initialized before applying",
ErrorKind::InvalidOperation
))?;
let value = entry.get(field_name)?;
let field_value = self.field_value.get().unwrap_or(&Value::Null);
Ok(&value != field_value)
}
fn apply_on_index(&self, index_map: &IndexMap) -> NitriteResult<Vec<Value>> {
let mut sub_map = Vec::new();
let mut nitrite_ids = Vec::new();
let cmp_value = self.field_value.get().unwrap_or(&Value::Null).clone();
let entries = index_map.entries()?;
for result in entries {
let (key, value) = result?;
if key != cmp_value {
self.process_index_value(Some(value), &mut sub_map, &mut nitrite_ids);
}
}
if sub_map.is_empty() {
Ok(nitrite_ids)
} else {
Ok(sub_map)
}
}
fn get_collection_name(&self) -> NitriteResult<String> {
self.collection_name.get()
.cloned()
.ok_or_else(|| {
log::error!("Collection name is not set for filter");
NitriteError::new(
"Collection name is not set",
ErrorKind::InvalidOperation,
)
})
}
fn set_collection_name(&self, collection_name: String) -> NitriteResult<()> {
self.collection_name.get_or_init(|| collection_name);
Ok(())
}
fn has_field(&self) -> bool {
true
}
fn get_field_name(&self) -> NitriteResult<String> {
self.field_name.get()
.cloned()
.ok_or_else(|| NitriteError::new(
"Not-equals filter error: field name not set - filter must be properly initialized before accessing",
ErrorKind::InvalidOperation
))
}
fn set_field_name(&self, field_name: String) -> NitriteResult<()> {
self.field_name.get_or_init(|| field_name);
Ok(())
}
fn get_field_value(&self) -> NitriteResult<Option<Value>> {
if self.field_value.get().is_none() {
Ok(None)
} else {
Ok(self.field_value.get().cloned())
}
}
fn set_field_value(&self, field_value: Value) -> NitriteResult<()> {
self.field_value.get_or_init(|| field_value);
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::collection::Document;
#[test]
fn test_all_filter_apply() {
let filter = AllFilter;
let doc = Document::new();
assert!(filter.apply(&doc).unwrap());
}
#[test]
fn test_equals_filter_apply() {
let filter = EqualsFilter::new("field".to_string(), Value::I32(42));
let mut doc = Document::new();
doc.put("field", Value::I32(42)).unwrap();
assert!(filter.apply(&doc).unwrap());
}
#[test]
fn test_equals_filter_apply_negative() {
let filter = EqualsFilter::new("field".to_string(), Value::I32(42));
let mut doc = Document::new();
doc.put("field", Value::I32(43)).unwrap();
assert!(!filter.apply(&doc).unwrap());
}
#[test]
fn test_not_equals_filter_apply() {
let filter = NotEqualsFilter::new("field".to_string(), Value::I32(42));
let mut doc = Document::new();
doc.put("field", Value::I32(43)).unwrap();
assert!(filter.apply(&doc).unwrap());
}
#[test]
fn test_not_equals_filter_apply_negative() {
let filter = NotEqualsFilter::new("field".to_string(), Value::I32(42));
let mut doc = Document::new();
doc.put("field", Value::I32(42)).unwrap();
assert!(!filter.apply(&doc).unwrap());
}
#[test]
fn test_equals_filter_display_with_initialized_values() {
let filter = EqualsFilter::new("field".to_string(), Value::I32(42));
let display_str = format!("{}", filter);
assert_eq!(display_str, "(field == 42)");
}
#[test]
fn test_equals_filter_display_with_uninitialized_collection_name() {
let filter = EqualsFilter::new("field".to_string(), Value::I32(42));
let display_str = format!("{}", filter);
assert!(display_str.contains("field") && display_str.contains("42"));
}
#[test]
fn test_equals_filter_get_field_name_after_initialization() {
let filter = EqualsFilter::new("test_field".to_string(), Value::I32(42));
let field_name = filter.get_field_name().unwrap();
assert_eq!(field_name, "test_field");
}
#[test]
fn test_equals_filter_get_field_value_initialization() {
let filter =
EqualsFilter::new("field".to_string(), Value::String("test_value".to_string()));
let field_value = filter.get_field_value().unwrap();
assert_eq!(field_value, Some(Value::String("test_value".to_string())));
}
#[test]
fn test_not_equals_filter_display_with_initialized_values() {
let filter =
NotEqualsFilter::new("status".to_string(), Value::String("inactive".to_string()));
let display_str = format!("{}", filter);
assert_eq!(display_str, "(status != \"inactive\")");
}
#[test]
fn test_not_equals_filter_get_collection_name_fails_when_not_set() {
let filter = NotEqualsFilter::new("field".to_string(), Value::I32(1));
let result = filter.get_collection_name();
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Collection name is not set"));
}
#[test]
fn test_not_equals_filter_set_and_get_collection_name() {
let filter = NotEqualsFilter::new("field".to_string(), Value::I32(1));
filter
.set_collection_name("my_collection".to_string())
.unwrap();
let name = filter.get_collection_name().unwrap();
assert_eq!(name, "my_collection");
}
#[test]
fn test_not_equals_filter_get_field_name_after_initialization() {
let filter =
NotEqualsFilter::new("my_field".to_string(), Value::String("value".to_string()));
let field_name = filter.get_field_name().unwrap();
assert_eq!(field_name, "my_field");
}
#[test]
fn test_not_equals_filter_apply_with_missing_field() {
let filter = NotEqualsFilter::new("missing_field".to_string(), Value::I32(42));
let doc = Document::new();
let result = filter.apply(&doc);
assert!(result.is_ok());
assert!(result.unwrap()); }
#[test]
fn test_equals_filter_apply_with_uninitialized_field_name_fails() {
let filter = EqualsFilter::new("field".to_string(), Value::I32(42));
let mut doc = Document::new();
doc.put("field", Value::I32(42)).unwrap();
assert!(filter.apply(&doc).unwrap());
}
#[test]
fn test_equals_filter_once_lock_initialization_efficiency() {
let filter = EqualsFilter::new("perf_field".to_string(), Value::I32(100));
assert_eq!(filter.get_field_name().unwrap(), "perf_field");
assert_eq!(filter.get_field_value().unwrap(), Some(Value::I32(100)));
}
#[test]
fn test_not_equals_filter_value_comparison_optimization() {
let filter = NotEqualsFilter::new("test_field".to_string(), Value::I32(99));
let mut doc = Document::new();
doc.put("test_field", Value::I32(100)).unwrap();
for _ in 0..100 {
assert!(filter.apply(&doc).unwrap());
}
}
#[test]
fn test_equals_filter_multiple_applies() {
let filter = EqualsFilter::new("field".to_string(), Value::I32(42));
let mut doc = Document::new();
doc.put("field", Value::I32(42)).unwrap();
for _ in 0..1000 {
assert!(filter.apply(&doc).unwrap());
}
}
#[test]
fn test_not_equals_filter_apply_on_index_efficiency() {
let filter = NotEqualsFilter::new("field".to_string(), Value::I32(42));
let mut map = std::collections::BTreeMap::new();
map.insert(Value::I32(1), Value::Array(vec![Value::I32(10)]));
map.insert(Value::I32(2), Value::Array(vec![Value::I32(20)]));
map.insert(Value::I32(42), Value::Array(vec![Value::I32(30)]));
let index_map = IndexMap::new(None, Some(map));
let result = filter.apply_on_index(&index_map).unwrap();
assert_eq!(result.len(), 2);
}
}