use crate::collection::Document;
use crate::collection::NitriteId;
use crate::errors::ErrorKind;
use crate::errors::NitriteError;
use crate::errors::NitriteResult;
use crate::index::IndexMap;
use crate::Value;
use crate::DOC_ID;
use std::any::Any;
use std::fmt::Display;
use std::ops::Deref;
use std::sync::Arc;
use super::AllFilter;
use super::AndFilter;
use super::BetweenFilter;
use super::ElementMatchFilter;
use super::EqualsFilter;
use super::NotFilter;
use super::OrFilter;
use super::TextFilter;
pub trait FilterProvider: Any + Send + Sync + Display {
fn apply(&self, entry: &Document) -> NitriteResult<bool>;
fn apply_on_index(&self, _index_map: &IndexMap) -> NitriteResult<Vec<Value>> {
log::error!("Filter {} does not support index scan", self);
Err(NitriteError::new(
"Filter does not support index scan",
ErrorKind::FilterError,
))
}
fn get_collection_name(&self) -> NitriteResult<String> {
log::error!("Filter {} does not have collection name", self);
Err(NitriteError::new(
"Filter does not have collection name",
ErrorKind::FilterError,
))
}
fn set_collection_name(&self, _collection_name: String) -> NitriteResult<()> {
Ok(())
}
#[inline]
fn has_field(&self) -> bool {
false
}
fn get_field_name(&self) -> NitriteResult<String> {
log::error!("Filter {} does not have field name", self);
Err(NitriteError::new(
"Filter does not have field name",
ErrorKind::FilterError,
))
}
fn set_field_name(&self, _field_name: String) -> NitriteResult<()> {
Ok(())
}
fn get_field_value(&self) -> NitriteResult<Option<Value>> {
log::debug!("Filter {} does not have field value", self);
Err(NitriteError::new(
"Filter does not have field value",
ErrorKind::FilterError,
))
}
fn set_field_value(&self, _field_value: Value) -> NitriteResult<()> {
Ok(())
}
fn get_reverse_scan(&self) -> NitriteResult<bool> {
log::error!("Filter {} does not have reverse scan", self);
Err(NitriteError::new(
"Filter does not have reverse scan",
ErrorKind::FilterError,
))
}
fn set_reverse_scan(&self, _reverse_scan: bool) -> NitriteResult<()> {
Ok(())
}
#[inline]
fn is_reverse_scan_supported(&self) -> bool {
false
}
#[inline]
fn is_index_only_filter(&self) -> bool {
false
}
fn supported_index_type(&self) -> NitriteResult<String> {
log::error!("Filter {} does not specify supported index type", self);
Err(NitriteError::new(
"Filter does not specify supported index type",
ErrorKind::FilterError,
))
}
fn can_be_grouped(&self, other: Filter) -> NitriteResult<bool> {
let _ = other;
Ok(false)
}
#[inline]
fn process_index_value(
&self,
value: Option<Value>,
sub_map: &mut Vec<Value>,
nitrite_ids: &mut Vec<Value>,
) {
match value {
Some(Value::Array(array)) => {
nitrite_ids.extend(array.iter().cloned());
}
Some(Value::Map(map)) => {
sub_map.push(Value::Map(map));
}
Some(_) | None => {}
}
}
fn validate_array_search_term(&self, field: String, value: &Value) -> NitriteResult<()> {
match value {
Value::Array(array) => {
for v in array {
match v {
Value::Null => continue,
Value::Array(_) => {
log::error!("Nested array field {} is not supported", field);
return Err(NitriteError::new(
"Nested array is not supported",
ErrorKind::FilterError,
))
}
_ => {
if !v.is_comparable() {
log::error!("Cannot filter using non comparable values {}", field);
return Err(NitriteError::new(
&format!("Cannot filter using non comparable values {}", field),
ErrorKind::FilterError,
));
}
}
}
}
Ok(())
}
_ => Ok(()),
}
}
fn logical_filters(&self) -> NitriteResult<Vec<Filter>> {
Err(NitriteError::new(
"Filter is not a logical filters",
ErrorKind::FilterError,
))
}
fn as_any(&self) -> &dyn Any;
}
#[derive(Clone)]
pub struct Filter {
inner: Arc<dyn FilterProvider>,
}
impl Filter {
pub fn new<T: FilterProvider + 'static>(inner: T) -> Self {
Filter { inner: Arc::new(inner) }
}
pub fn and(&self, filter: Filter) -> Self {
Filter::new(AndFilter::new(vec![filter, self.clone()]))
}
pub fn or(&self, filter: Filter) -> Self {
Filter::new(OrFilter::new(vec![filter, self.clone()]))
}
pub fn not(&self) -> Self {
Filter::new(NotFilter::new(self.clone()))
}
}
impl Display for Filter {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.inner)
}
}
impl Deref for Filter {
type Target = Arc<dyn FilterProvider>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub fn all() -> Filter {
Filter::new(AllFilter {})
}
pub fn by_id(id: NitriteId) -> Filter {
Filter::new(EqualsFilter::new(
DOC_ID.to_string(),
Value::NitriteId(id),
))
}
pub fn and(filters: Vec<Filter>) -> Filter {
Filter::new(AndFilter::new(filters))
}
pub fn or(filters: Vec<Filter>) -> Filter {
Filter::new(OrFilter::new(filters))
}
pub fn not(filter: Filter) -> Filter {
Filter::new(NotFilter::new(filter))
}
#[derive(Clone)]
pub struct IndexScanFilter {
inner: Arc<IndexScanFilterInner>,
}
pub(crate) struct IndexScanFilterInner {
filters: Vec<Filter>,
}
impl IndexScanFilter {
pub(crate) fn new(filters: Vec<Filter>) -> Self {
IndexScanFilter {
inner: Arc::new(IndexScanFilterInner { filters }),
}
}
pub fn filters(&self) -> Vec<Filter> {
self.inner.filters.clone()
}
}
pub(crate) fn is_all_filter(filter: &Filter) -> bool {
filter.as_any().is::<AllFilter>()
}
pub(crate) fn is_and_filter(filter: &Filter) -> bool {
filter.as_any().is::<AndFilter>()
}
pub(crate) fn is_or_filter(filter: &Filter) -> bool {
filter.as_any().is::<OrFilter>()
}
pub(crate) fn is_text_filter(filter: &Filter) -> bool {
filter.as_any().is::<TextFilter>()
}
pub(crate) fn is_between_filter(filter: &Filter) -> bool {
filter.as_any().is::<BetweenFilter>()
}
pub(crate) fn is_equals_filter(filter: &Filter) -> bool {
filter.as_any().is::<EqualsFilter>()
}
pub(crate) fn is_element_match_filter(filter: &Filter) -> bool {
filter.as_any().is::<ElementMatchFilter>()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::collection::{Document, NitriteId};
use crate::common::Convertible;
use crate::filter::field;
use crate::index::IndexMap;
use crate::Value;
use std::collections::BTreeMap;
use std::fmt::Formatter;
struct MockFilter;
impl Display for MockFilter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "MockFilter")
}
}
impl FilterProvider for MockFilter {
fn apply(&self, _entry: &Document) -> NitriteResult<bool> {
Ok(true)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[test]
fn test_filter_apply() {
let filter = Filter::new(MockFilter);
let doc = Document::new();
assert!(filter.apply(&doc).unwrap());
}
#[test]
fn test_filter_apply_on_index() {
let filter = Filter::new(MockFilter);
let index_map = IndexMap::new(None, Some(BTreeMap::new()));
assert!(filter.apply_on_index(&index_map).is_err());
}
#[test]
fn test_filter_get_collection_name() {
let filter = Filter::new(MockFilter);
assert!(filter.get_collection_name().is_err());
}
#[test]
fn test_filter_set_collection_name() {
let filter = Filter::new(MockFilter);
assert!(filter.set_collection_name("test".to_string()).is_ok());
}
#[test]
fn test_filter_get_field_name() {
let filter = Filter::new(MockFilter);
assert!(filter.get_field_name().is_err());
}
#[test]
fn test_filter_set_field_name() {
let filter = Filter::new(MockFilter);
assert!(filter.set_field_name("test".to_string()).is_ok());
}
#[test]
fn test_filter_get_field_value() {
let filter = Filter::new(MockFilter);
assert!(filter.get_field_value().is_err());
}
#[test]
fn test_filter_set_field_value() {
let filter = Filter::new(MockFilter);
assert!(filter.set_field_value(Value::I32(42)).is_ok());
}
#[test]
fn test_filter_get_reverse_scan() {
let filter = Filter::new(MockFilter);
assert!(filter.get_reverse_scan().is_err());
}
#[test]
fn test_filter_set_reverse_scan() {
let filter = Filter::new(MockFilter);
assert!(filter.set_reverse_scan(true).is_ok());
}
#[test]
fn test_filter_is_reverse_scan_supported() {
let filter = Filter::new(MockFilter);
assert!(!filter.is_reverse_scan_supported());
}
#[test]
fn test_filter_is_index_only_filter() {
let filter = Filter::new(MockFilter);
assert!(!filter.is_index_only_filter());
}
#[test]
fn test_filter_supported_index_type() {
let filter = Filter::new(MockFilter);
assert!(filter.supported_index_type().is_err());
}
#[test]
fn test_filter_can_be_grouped() {
let filter1 = Filter::new(MockFilter);
let filter2 = Filter::new(MockFilter);
assert!(!filter1.can_be_grouped(filter2).unwrap());
}
#[test]
fn test_filter_process_index_value() {
let filter = Filter::new(MockFilter);
let mut sub_map = Vec::new();
let mut nitrite_ids = Vec::new();
filter.process_index_value(Some(Value::Array(vec![Value::I32(42)])), &mut sub_map, &mut nitrite_ids);
assert_eq!(nitrite_ids, vec![Value::I32(42)]);
}
#[test]
fn test_filter_validate_array_search_term() {
let filter = Filter::new(MockFilter);
let value = Value::Array(vec![Value::I32(42)]);
assert!(filter.validate_array_search_term("field".to_string(), &value).is_ok());
}
#[test]
fn test_filter_logical_filters() {
let filter = Filter::new(MockFilter);
assert!(filter.logical_filters().is_err());
}
#[test]
fn test_all_filter() {
let filter = all();
let doc = Document::new();
assert!(filter.apply(&doc).is_ok());
}
#[test]
fn test_by_id_filter() {
let id = NitriteId::new();
let filter = by_id(id);
let mut doc = Document::new();
doc.put(DOC_ID, Value::NitriteId(id)).expect("Failed to put value");
assert!(filter.apply(&doc).unwrap());
}
#[test]
fn test_and_filter() {
let filter = and(vec![all(), all()]);
let doc = Document::new();
assert!(filter.apply(&doc).is_ok());
}
#[test]
fn test_or_filter() {
let filter = or(vec![all(), all()]);
let doc = Document::new();
assert!(filter.apply(&doc).is_ok());
}
#[test]
fn test_not_filter() {
let filter = not(all());
let doc = Document::new();
assert!(filter.apply(&doc).is_ok());
}
#[test]
fn test_index_scan_filter() {
let filter = IndexScanFilter::new(vec![all()]);
assert_eq!(filter.filters().len(), 1);
}
#[test]
fn test_is_all_filter() {
let filter = all();
assert!(is_all_filter(&filter));
}
#[test]
fn test_is_and_filter() {
let filter = and(vec![all(), all()]);
assert!(is_and_filter(&filter));
}
#[test]
fn test_is_or_filter() {
let filter = or(vec![all(), all()]);
assert!(is_or_filter(&filter));
}
#[test]
fn test_is_text_filter() {
let filter = field("field").text("value");
assert!(is_text_filter(&filter));
}
#[test]
fn test_is_equals_filter() {
let filter = field("field").eq("value".to_value().unwrap());
assert!(is_equals_filter(&filter));
}
#[test]
fn test_is_element_match_filter() {
let filter = field("field").elem_match(all());
assert!(is_element_match_filter(&filter));
}
}