chore: add date filter tests

This commit is contained in:
appflowy 2022-07-09 11:19:17 +08:00
parent 4f30f8e2cd
commit ec1113b134
13 changed files with 239 additions and 80 deletions

View File

@ -1,6 +1,8 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use flowy_grid_data_model::revision::GridFilterRevision; use flowy_grid_data_model::revision::GridFilterRevision;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
@ -9,7 +11,30 @@ pub struct GridDateFilter {
pub condition: DateFilterCondition, pub condition: DateFilterCondition,
#[pb(index = 2, one_of)] #[pb(index = 2, one_of)]
pub content: Option<String>, pub start: Option<i64>,
#[pb(index = 3, one_of)]
pub end: Option<i64>,
}
#[derive(Serialize, Deserialize, Default)]
struct DateRange {
start: Option<i64>,
end: Option<i64>,
}
impl ToString for DateRange {
fn to_string(&self) -> String {
serde_json::to_string(self).unwrap_or("".to_string())
}
}
impl FromStr for DateRange {
type Err = serde_json::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
serde_json::from_str(s)
}
} }
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
@ -48,9 +73,21 @@ impl std::convert::TryFrom<u8> for DateFilterCondition {
} }
impl std::convert::From<Arc<GridFilterRevision>> for GridDateFilter { impl std::convert::From<Arc<GridFilterRevision>> for GridDateFilter {
fn from(rev: Arc<GridFilterRevision>) -> Self { fn from(rev: Arc<GridFilterRevision>) -> Self {
GridDateFilter { let condition = DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs);
condition: DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs), let mut filter = GridDateFilter {
content: rev.content.clone(), condition,
} ..Default::default()
};
if let Some(range) = rev
.content
.as_ref()
.and_then(|content| DateRange::from_str(content).ok())
{
filter.start = range.start;
filter.end = range.end;
};
filter
} }
} }

View File

@ -1,9 +1,8 @@
use crate::entities::{CellChangeset, FieldType, GridDateFilter}; use crate::entities::{CellChangeset, FieldType};
use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::entities::{CellIdentifier, CellIdentifierPayload};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::cell::{ use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, FromCellChangeset, FromCellString,
FromCellChangeset, FromCellString,
}; };
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use bytes::Bytes; use bytes::Bytes;
@ -110,6 +109,10 @@ impl DateTypeOption {
fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime<chrono::Utc> { fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime<chrono::Utc> {
let native = NaiveDateTime::from_timestamp(timestamp, 0); let native = NaiveDateTime::from_timestamp(timestamp, 0);
let native2 = NaiveDateTime::from_timestamp(timestamp, 0);
if native > native2 {}
self.utc_date_time_from_native(native) self.utc_date_time_from_native(native)
} }
@ -118,19 +121,10 @@ impl DateTypeOption {
} }
} }
impl CellFilterOperation<GridDateFilter> for DateTypeOption { impl CellDataOperation<DateTimestamp, DateCellChangeset> for DateTypeOption {
fn apply_filter(&self, any_cell_data: AnyCellData, _filter: &GridDateFilter) -> FlowyResult<bool> {
if !any_cell_data.is_date() {
return Ok(true);
}
Ok(false)
}
}
impl CellDataOperation<TimestampParser, DateCellChangeset> for DateTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<TimestampParser>, cell_data: CellData<DateTimestamp>,
decoded_field_type: &FieldType, decoded_field_type: &FieldType,
_field_rev: &FieldRevision, _field_rev: &FieldRevision,
) -> FlowyResult<DecodedCellData> { ) -> FlowyResult<DecodedCellData> {
@ -168,17 +162,36 @@ impl CellDataOperation<TimestampParser, DateCellChangeset> for DateTypeOption {
} }
} }
pub struct TimestampParser(i64); pub struct DateTimestamp(i64);
impl AsRef<i64> for DateTimestamp {
fn as_ref(&self) -> &i64 {
&self.0
}
}
impl FromCellString for TimestampParser { impl std::convert::From<DateTimestamp> for i64 {
fn from(timestamp: DateTimestamp) -> Self {
timestamp.0
}
}
impl FromCellString for DateTimestamp {
fn from_cell_str(s: &str) -> FlowyResult<Self> fn from_cell_str(s: &str) -> FlowyResult<Self>
where where
Self: Sized, Self: Sized,
{ {
let num = s.parse::<i64>().unwrap_or(0); let num = s.parse::<i64>().unwrap_or(0);
Ok(TimestampParser(num)) Ok(DateTimestamp(num))
} }
} }
impl std::convert::From<AnyCellData> for DateTimestamp {
fn from(data: AnyCellData) -> Self {
let num = data.cell_data.parse::<i64>().unwrap_or(0);
DateTimestamp(num)
}
}
#[derive(Default)] #[derive(Default)]
pub struct DateTypeOptionBuilder(DateTypeOption); pub struct DateTypeOptionBuilder(DateTypeOption);
impl_into_box_type_option_builder!(DateTypeOptionBuilder); impl_into_box_type_option_builder!(DateTypeOptionBuilder);

View File

@ -1,3 +0,0 @@
use crate::entities::GridDateFilter;
impl GridDateFilter {}

View File

@ -1,12 +1,9 @@
use crate::entities::{ use crate::entities::{
FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter, GridTextFilter, FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter, GridTextFilter,
}; };
use dashmap::DashMap; use dashmap::DashMap;
use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
use flowy_sync::client_grid::GridRevisionPad; use flowy_sync::client_grid::GridRevisionPad;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;

View File

@ -179,7 +179,7 @@ fn filter_cell(
field_type, field_type,
}; };
let any_cell_data = AnyCellData::try_from(cell_rev).ok()?; let any_cell_data = AnyCellData::try_from(cell_rev).ok()?;
let is_hidden = match &filter_id.field_type { let is_visible = match &filter_id.field_type {
FieldType::RichText => filter_cache.text_filter.get(&filter_id).and_then(|filter| { FieldType::RichText => filter_cache.text_filter.get(&filter_id).and_then(|filter| {
Some( Some(
field_rev field_rev
@ -238,7 +238,7 @@ fn filter_cell(
}), }),
}?; }?;
let is_visible = !is_hidden.unwrap_or(false); let is_visible = !is_visible.unwrap_or(true);
match filter_result.visible_by_field_id.get(&filter_id) { match filter_result.visible_by_field_id.get(&filter_id) {
None => { None => {
if is_visible { if is_visible {

View File

@ -4,7 +4,7 @@ use crate::services::field::{CheckboxCellData, CheckboxTypeOption};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
impl GridCheckboxFilter { impl GridCheckboxFilter {
pub fn apply(&self, cell_data: &CheckboxCellData) -> bool { pub fn is_visible(&self, cell_data: &CheckboxCellData) -> bool {
let is_check = cell_data.is_check(); let is_check = cell_data.is_check();
match self.condition { match self.condition {
CheckboxCondition::IsChecked => is_check, CheckboxCondition::IsChecked => is_check,
@ -19,7 +19,7 @@ impl CellFilterOperation<GridCheckboxFilter> for CheckboxTypeOption {
return Ok(true); return Ok(true);
} }
let checkbox_cell_data: CheckboxCellData = any_cell_data.try_into()?; let checkbox_cell_data: CheckboxCellData = any_cell_data.try_into()?;
Ok(filter.apply(&checkbox_cell_data)) Ok(filter.is_visible(&checkbox_cell_data))
} }
} }
@ -33,9 +33,9 @@ mod tests {
let checkbox_filter = GridCheckboxFilter { let checkbox_filter = GridCheckboxFilter {
condition: CheckboxCondition::IsChecked, condition: CheckboxCondition::IsChecked,
}; };
for (value, r) in [("true", true), ("yes", true), ("false", false), ("no", false)] { for (value, visible) in [("true", true), ("yes", true), ("false", false), ("no", false)] {
let data = CheckboxCellData(value.to_owned()); let data = CheckboxCellData(value.to_owned());
assert_eq!(checkbox_filter.apply(&data), r); assert_eq!(checkbox_filter.is_visible(&data), visible);
} }
} }
@ -44,9 +44,9 @@ mod tests {
let checkbox_filter = GridCheckboxFilter { let checkbox_filter = GridCheckboxFilter {
condition: CheckboxCondition::IsUnChecked, condition: CheckboxCondition::IsUnChecked,
}; };
for (value, r) in [("false", true), ("no", true), ("true", false), ("yes", false)] { for (value, visible) in [("false", true), ("no", true), ("true", false), ("yes", false)] {
let data = CheckboxCellData(value.to_owned()); let data = CheckboxCellData(value.to_owned());
assert_eq!(checkbox_filter.apply(&data), r); assert_eq!(checkbox_filter.is_visible(&data), visible);
} }
} }
} }

View File

@ -0,0 +1,107 @@
use crate::entities::{DateFilterCondition, GridDateFilter};
use crate::services::cell::{AnyCellData, CellFilterOperation};
use crate::services::field::{DateTimestamp, DateTypeOption};
use flowy_error::FlowyResult;
impl GridDateFilter {
pub fn is_visible<T: Into<i64>>(&self, cell_timestamp: T) -> bool {
if self.start.is_none() {
return false;
}
let cell_timestamp = cell_timestamp.into();
let start_timestamp = *self.start.as_ref().unwrap();
// We assume that the cell_timestamp doesn't contain hours, just day.
match self.condition {
DateFilterCondition::DateIs => cell_timestamp == start_timestamp,
DateFilterCondition::DateBefore => cell_timestamp < start_timestamp,
DateFilterCondition::DateAfter => cell_timestamp > start_timestamp,
DateFilterCondition::DateOnOrBefore => cell_timestamp <= start_timestamp,
DateFilterCondition::DateOnOrAfter => cell_timestamp >= start_timestamp,
DateFilterCondition::DateWithIn => {
if let Some(end_timestamp) = self.end.as_ref() {
cell_timestamp >= start_timestamp && cell_timestamp <= *end_timestamp
} else {
false
}
}
DateFilterCondition::DateIsEmpty => cell_timestamp == (0 as i64),
}
}
}
impl CellFilterOperation<GridDateFilter> for DateTypeOption {
fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridDateFilter) -> FlowyResult<bool> {
if !any_cell_data.is_date() {
return Ok(true);
}
let timestamp: DateTimestamp = any_cell_data.into();
Ok(filter.is_visible(timestamp))
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::all)]
use crate::entities::{DateFilterCondition, GridDateFilter};
#[test]
fn date_filter_is_test() {
let filter = GridDateFilter {
condition: DateFilterCondition::DateIs,
start: Some(123),
end: None,
};
for (val, visible) in vec![(123, true), (12, false)] {
assert_eq!(filter.is_visible(val as i64), visible);
}
}
#[test]
fn date_filter_before_test() {
let filter = GridDateFilter {
condition: DateFilterCondition::DateBefore,
start: Some(123),
end: None,
};
for (val, visible) in vec![(123, false), (122, true)] {
assert_eq!(filter.is_visible(val as i64), visible);
}
}
#[test]
fn date_filter_before_or_on_test() {
let filter = GridDateFilter {
condition: DateFilterCondition::DateOnOrBefore,
start: Some(123),
end: None,
};
for (val, visible) in vec![(123, true), (122, true)] {
assert_eq!(filter.is_visible(val as i64), visible);
}
}
#[test]
fn date_filter_after_test() {
let filter = GridDateFilter {
condition: DateFilterCondition::DateAfter,
start: Some(123),
end: None,
};
for (val, visible) in vec![(1234, true), (122, false), (0, false)] {
assert_eq!(filter.is_visible(val as i64), visible);
}
}
#[test]
fn date_filter_within_test() {
let filter = GridDateFilter {
condition: DateFilterCondition::DateWithIn,
start: Some(123),
end: Some(130),
};
for (val, visible) in vec![(123, true), (130, true), (132, false)] {
assert_eq!(filter.is_visible(val as i64), visible);
}
}
}

View File

@ -0,0 +1,13 @@
mod checkbox_filter;
mod date_filter;
mod number_filter;
mod select_option_filter;
mod text_filter;
mod url_filter;
pub use checkbox_filter::*;
pub use date_filter::*;
pub use number_filter::*;
pub use select_option_filter::*;
pub use text_filter::*;
pub use url_filter::*;

View File

@ -7,7 +7,7 @@ use rust_decimal::Decimal;
use std::str::FromStr; use std::str::FromStr;
impl GridNumberFilter { impl GridNumberFilter {
pub fn apply(&self, num_cell_data: &NumberCellData) -> bool { pub fn is_visible(&self, num_cell_data: &NumberCellData) -> bool {
if self.content.is_none() { if self.content.is_none() {
return false; return false;
} }
@ -40,7 +40,7 @@ impl CellFilterOperation<GridNumberFilter> for NumberTypeOption {
let cell_data = any_cell_data.cell_data; let cell_data = any_cell_data.cell_data;
let num_cell_data = self.format_cell_data(&cell_data)?; let num_cell_data = self.format_cell_data(&cell_data)?;
Ok(filter.apply(&num_cell_data)) Ok(filter.is_visible(&num_cell_data))
} }
} }
@ -57,15 +57,15 @@ mod tests {
content: Some("123".to_owned()), content: Some("123".to_owned()),
}; };
for (num_str, r) in [("123", true), ("1234", false), ("", false)] { for (num_str, visible) in [("123", true), ("1234", false), ("", false)] {
let data = NumberCellData::from_str(num_str).unwrap(); let data = NumberCellData::from_str(num_str).unwrap();
assert_eq!(number_filter.apply(&data), r); assert_eq!(number_filter.is_visible(&data), visible);
} }
let format = NumberFormat::USD; let format = NumberFormat::USD;
for (num_str, r) in [("$123", true), ("1234", false), ("", false)] { for (num_str, visible) in [("$123", true), ("1234", false), ("", false)] {
let data = NumberCellData::from_format_str(num_str, true, &format).unwrap(); let data = NumberCellData::from_format_str(num_str, true, &format).unwrap();
assert_eq!(number_filter.apply(&data), r); assert_eq!(number_filter.is_visible(&data), visible);
} }
} }
#[test] #[test]
@ -74,9 +74,9 @@ mod tests {
condition: NumberFilterCondition::GreaterThan, condition: NumberFilterCondition::GreaterThan,
content: Some("12".to_owned()), content: Some("12".to_owned()),
}; };
for (num_str, r) in [("123", true), ("10", false), ("30", true), ("", false)] { for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] {
let data = NumberCellData::from_str(num_str).unwrap(); let data = NumberCellData::from_str(num_str).unwrap();
assert_eq!(number_filter.apply(&data), r); assert_eq!(number_filter.is_visible(&data), visible);
} }
} }
@ -86,9 +86,9 @@ mod tests {
condition: NumberFilterCondition::LessThan, condition: NumberFilterCondition::LessThan,
content: Some("100".to_owned()), content: Some("100".to_owned()),
}; };
for (num_str, r) in [("12", true), ("1234", false), ("30", true), ("", true)] { for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", true)] {
let data = NumberCellData::from_str(num_str).unwrap(); let data = NumberCellData::from_str(num_str).unwrap();
assert_eq!(number_filter.apply(&data), r); assert_eq!(number_filter.is_visible(&data), visible);
} }
} }
} }

View File

@ -7,7 +7,7 @@ use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
impl GridSelectOptionFilter { impl GridSelectOptionFilter {
pub fn apply(&self, selected_options: &SelectedSelectOptions) -> bool { pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect(); let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect();
match self.condition { match self.condition {
SelectOptionCondition::OptionIs => { SelectOptionCondition::OptionIs => {
@ -46,7 +46,7 @@ impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOption {
} }
let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data));
Ok(filter.apply(&selected_options)) Ok(filter.is_visible(&selected_options))
} }
} }
@ -56,7 +56,7 @@ impl CellFilterOperation<GridSelectOptionFilter> for SingleSelectTypeOption {
return Ok(true); return Ok(true);
} }
let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data));
Ok(filter.apply(&selected_options)) Ok(filter.is_visible(&selected_options))
} }
} }
@ -78,29 +78,29 @@ mod tests {
}; };
assert_eq!( assert_eq!(
filter_1.apply(&SelectedSelectOptions { filter_1.is_visible(&SelectedSelectOptions {
options: vec![option_1.clone(), option_2.clone()], options: vec![option_1.clone(), option_2.clone()],
}), }),
false false
); );
assert_eq!( assert_eq!(
filter_1.apply(&SelectedSelectOptions { filter_1.is_visible(&SelectedSelectOptions {
options: vec![option_1.clone(), option_2.clone(), option_3.clone()], options: vec![option_1.clone(), option_2.clone(), option_3.clone()],
}), }),
true true
); );
assert_eq!( assert_eq!(
filter_1.apply(&SelectedSelectOptions { filter_1.is_visible(&SelectedSelectOptions {
options: vec![option_1.clone(), option_3.clone()], options: vec![option_1.clone(), option_3.clone()],
}), }),
true true
); );
assert_eq!(filter_1.apply(&SelectedSelectOptions { options: vec![] }), true); assert_eq!(filter_1.is_visible(&SelectedSelectOptions { options: vec![] }), true);
assert_eq!( assert_eq!(
filter_1.apply(&SelectedSelectOptions { filter_1.is_visible(&SelectedSelectOptions {
options: vec![option_1.clone()], options: vec![option_1.clone()],
}), }),
true, true,

View File

@ -4,7 +4,7 @@ use crate::services::field::{RichTextTypeOption, TextCellData};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
impl GridTextFilter { impl GridTextFilter {
pub fn apply<T: AsRef<str>>(&self, cell_data: T) -> bool { pub fn is_visible<T: AsRef<str>>(&self, cell_data: T) -> bool {
let cell_data = cell_data.as_ref(); let cell_data = cell_data.as_ref();
let s = cell_data.to_lowercase(); let s = cell_data.to_lowercase();
if let Some(content) = self.content.as_ref() { if let Some(content) = self.content.as_ref() {
@ -31,7 +31,7 @@ impl CellFilterOperation<GridTextFilter> for RichTextTypeOption {
} }
let text_cell_data: TextCellData = any_cell_data.try_into()?; let text_cell_data: TextCellData = any_cell_data.try_into()?;
Ok(filter.apply(text_cell_data)) Ok(filter.is_visible(text_cell_data))
} }
} }
#[cfg(test)] #[cfg(test)]
@ -46,10 +46,10 @@ mod tests {
content: Some("appflowy".to_owned()), content: Some("appflowy".to_owned()),
}; };
assert!(text_filter.apply("AppFlowy")); assert!(text_filter.is_visible("AppFlowy"));
assert_eq!(text_filter.apply("appflowy"), true); assert_eq!(text_filter.is_visible("appflowy"), true);
assert_eq!(text_filter.apply("Appflowy"), true); assert_eq!(text_filter.is_visible("Appflowy"), true);
assert_eq!(text_filter.apply("AppFlowy.io"), false); assert_eq!(text_filter.is_visible("AppFlowy.io"), false);
} }
#[test] #[test]
fn text_filter_start_with_test() { fn text_filter_start_with_test() {
@ -58,9 +58,9 @@ mod tests {
content: Some("appflowy".to_owned()), content: Some("appflowy".to_owned()),
}; };
assert_eq!(text_filter.apply("AppFlowy.io"), true); assert_eq!(text_filter.is_visible("AppFlowy.io"), true);
assert_eq!(text_filter.apply(""), false); assert_eq!(text_filter.is_visible(""), false);
assert_eq!(text_filter.apply("https"), false); assert_eq!(text_filter.is_visible("https"), false);
} }
#[test] #[test]
@ -70,9 +70,9 @@ mod tests {
content: Some("appflowy".to_owned()), content: Some("appflowy".to_owned()),
}; };
assert_eq!(text_filter.apply("https://github.com/appflowy"), true); assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true);
assert_eq!(text_filter.apply("App"), false); assert_eq!(text_filter.is_visible("App"), false);
assert_eq!(text_filter.apply("appflowy.io"), false); assert_eq!(text_filter.is_visible("appflowy.io"), false);
} }
#[test] #[test]
fn text_filter_empty_test() { fn text_filter_empty_test() {
@ -81,8 +81,8 @@ mod tests {
content: Some("appflowy".to_owned()), content: Some("appflowy".to_owned()),
}; };
assert_eq!(text_filter.apply(""), true); assert_eq!(text_filter.is_visible(""), true);
assert_eq!(text_filter.apply("App"), false); assert_eq!(text_filter.is_visible("App"), false);
} }
#[test] #[test]
fn text_filter_contain_test() { fn text_filter_contain_test() {
@ -91,10 +91,10 @@ mod tests {
content: Some("appflowy".to_owned()), content: Some("appflowy".to_owned()),
}; };
assert_eq!(text_filter.apply("https://github.com/appflowy"), true); assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true);
assert_eq!(text_filter.apply("AppFlowy"), true); assert_eq!(text_filter.is_visible("AppFlowy"), true);
assert_eq!(text_filter.apply("App"), false); assert_eq!(text_filter.is_visible("App"), false);
assert_eq!(text_filter.apply(""), false); assert_eq!(text_filter.is_visible(""), false);
assert_eq!(text_filter.apply("github"), false); assert_eq!(text_filter.is_visible("github"), false);
} }
} }

View File

@ -10,6 +10,6 @@ impl CellFilterOperation<GridTextFilter> for URLTypeOption {
} }
let text_cell_data: TextCellData = any_cell_data.try_into()?; let text_cell_data: TextCellData = any_cell_data.try_into()?;
Ok(filter.apply(&text_cell_data)) Ok(filter.is_visible(&text_cell_data))
} }
} }

View File

@ -1,10 +1,5 @@
mod checkbox_filter;
mod date_filter;
mod filter_cache; mod filter_cache;
mod filter_service; mod filter_service;
mod number_filter; mod impls;
mod select_option_filter;
mod text_filter;
mod url_filter;
pub(crate) use filter_service::*; pub(crate) use filter_service::*;