From 6a01a44cc26d0877a31a00931e8110877720b895 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 8 Jul 2022 16:08:39 +0800 Subject: [PATCH 1/6] refactor: rm filter login from eneities mod --- .../filter_entities/checkbox_filter.rs | 27 ------ .../entities/filter_entities/number_filter.rs | 74 ---------------- .../filter_entities/select_option_filter.rs | 63 -------------- .../entities/filter_entities/text_filter.rs | 86 ------------------ .../src/services/filter/checkbox_filter.rs | 29 +++++++ .../src/services/filter/date_filter.rs | 3 + .../flowy-grid/src/services/filter/mod.rs | 5 ++ .../src/services/filter/number_filter.rs | 78 +++++++++++++++++ .../services/filter/select_option_filter.rs | 64 ++++++++++++++ .../src/services/filter/text_filter.rs | 87 +++++++++++++++++++ 10 files changed, 266 insertions(+), 250 deletions(-) create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs index c13cad33e8..42b0bfe1cc 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs @@ -10,16 +10,6 @@ pub struct GridCheckboxFilter { pub condition: CheckboxCondition, } -impl GridCheckboxFilter { - pub fn apply(&self, cell_data: &CheckboxCellData) -> bool { - let is_check = cell_data.is_check(); - match self.condition { - CheckboxCondition::IsChecked => is_check, - CheckboxCondition::IsUnChecked => !is_check, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] pub enum CheckboxCondition { @@ -58,20 +48,3 @@ impl std::convert::From> for GridCheckboxFilter { } } } - -#[cfg(test)] -mod tests { - use crate::entities::{CheckboxCondition, GridCheckboxFilter}; - use crate::services::field::CheckboxCellData; - - #[test] - fn checkbox_filter_is_check_test() { - let checkbox_filter = GridCheckboxFilter { - condition: CheckboxCondition::IsChecked, - }; - for (value, r) in [("true", true), ("yes", true), ("false", false), ("no", false)] { - let data = CheckboxCellData(value.to_owned()); - assert_eq!(checkbox_filter.apply(&data), r); - } - } -} diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs index b54f94972d..2db980de04 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs @@ -16,31 +16,6 @@ pub struct GridNumberFilter { pub content: Option, } -impl GridNumberFilter { - pub fn apply(&self, num_cell_data: &NumberCellData) -> bool { - if self.content.is_none() { - return false; - } - - let content = self.content.as_ref().unwrap(); - let zero_decimal = Decimal::zero(); - let cell_decimal = num_cell_data.decimal().as_ref().unwrap_or(&zero_decimal); - match Decimal::from_str(content) { - Ok(decimal) => match self.condition { - NumberFilterCondition::Equal => cell_decimal == &decimal, - NumberFilterCondition::NotEqual => cell_decimal != &decimal, - NumberFilterCondition::GreaterThan => cell_decimal > &decimal, - NumberFilterCondition::LessThan => cell_decimal < &decimal, - NumberFilterCondition::GreaterThanOrEqualTo => cell_decimal >= &decimal, - NumberFilterCondition::LessThanOrEqualTo => cell_decimal <= &decimal, - NumberFilterCondition::NumberIsEmpty => num_cell_data.is_empty(), - NumberFilterCondition::NumberIsNotEmpty => !num_cell_data.is_empty(), - }, - Err(_) => false, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] pub enum NumberFilterCondition { @@ -91,52 +66,3 @@ impl std::convert::From> for GridNumberFilter { } } } - -#[cfg(test)] -mod tests { - use crate::entities::{GridNumberFilter, NumberFilterCondition}; - - use crate::services::field::{NumberCellData, NumberFormat}; - use std::str::FromStr; - #[test] - fn number_filter_equal_test() { - let number_filter = GridNumberFilter { - condition: NumberFilterCondition::Equal, - content: Some("123".to_owned()), - }; - - for (num_str, r) in [("123", true), ("1234", false), ("", false)] { - let data = NumberCellData::from_str(num_str).unwrap(); - assert_eq!(number_filter.apply(&data), r); - } - - let format = NumberFormat::USD; - for (num_str, r) in [("$123", true), ("1234", false), ("", false)] { - let data = NumberCellData::from_format_str(num_str, true, &format).unwrap(); - assert_eq!(number_filter.apply(&data), r); - } - } - #[test] - fn number_filter_greater_than_test() { - let number_filter = GridNumberFilter { - condition: NumberFilterCondition::GreaterThan, - content: Some("12".to_owned()), - }; - for (num_str, r) in [("123", true), ("10", false), ("30", true), ("", false)] { - let data = NumberCellData::from_str(num_str).unwrap(); - assert_eq!(number_filter.apply(&data), r); - } - } - - #[test] - fn number_filter_less_than_test() { - let number_filter = GridNumberFilter { - condition: NumberFilterCondition::LessThan, - content: Some("100".to_owned()), - }; - for (num_str, r) in [("12", true), ("1234", false), ("30", true), ("", true)] { - let data = NumberCellData::from_str(num_str).unwrap(); - assert_eq!(number_filter.apply(&data), r); - } - } -} diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs index 15edec0707..ad215dfd45 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs @@ -1,4 +1,3 @@ -#![allow(clippy::needless_collect)] use crate::services::field::select_option::{SelectOptionIds, SelectedSelectOptions}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; @@ -13,36 +12,6 @@ pub struct GridSelectOptionFilter { #[pb(index = 2)] pub option_ids: Vec, } - -impl GridSelectOptionFilter { - pub fn apply(&self, selected_options: &SelectedSelectOptions) -> bool { - let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect(); - match self.condition { - SelectOptionCondition::OptionIs => { - // if selected options equal to filter's options, then the required_options will be empty. - let required_options = self - .option_ids - .iter() - .filter(|id| !selected_option_ids.contains(id)) - .collect::>(); - - // https://stackoverflow.com/questions/69413164/how-to-fix-this-clippy-warning-needless-collect - !required_options.is_empty() - } - SelectOptionCondition::OptionIsNot => { - for option_id in selected_option_ids { - if self.option_ids.contains(option_id) { - return true; - } - } - false - } - SelectOptionCondition::OptionIsEmpty => selected_option_ids.is_empty(), - SelectOptionCondition::OptionIsNotEmpty => !selected_option_ids.is_empty(), - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] pub enum SelectOptionCondition { @@ -87,35 +56,3 @@ impl std::convert::From> for GridSelectOptionFilter { } } } - -#[cfg(test)] -mod tests { - #![allow(clippy::all)] - use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; - use crate::services::field::select_option::{SelectOption, SelectedSelectOptions}; - - #[test] - fn select_option_filter_is_test() { - let option_1 = SelectOption::new("A"); - let option_2 = SelectOption::new("B"); - - let filter_1 = GridSelectOptionFilter { - condition: SelectOptionCondition::OptionIs, - option_ids: vec![option_1.id.clone(), option_2.id.clone()], - }; - - assert_eq!( - filter_1.apply(&SelectedSelectOptions { - options: vec![option_1.clone(), option_2.clone()], - }), - false - ); - - assert_eq!( - filter_1.apply(&SelectedSelectOptions { - options: vec![option_1.clone()], - }), - true, - ); - } -} diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs index 65253d2faa..7335e89129 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs @@ -12,27 +12,6 @@ pub struct GridTextFilter { pub content: Option, } -impl GridTextFilter { - pub fn apply>(&self, cell_data: T) -> bool { - let cell_data = cell_data.as_ref(); - let s = cell_data.to_lowercase(); - if let Some(content) = self.content.as_ref() { - match self.condition { - TextFilterCondition::Is => &s == content, - TextFilterCondition::IsNot => &s != content, - TextFilterCondition::Contains => s.contains(content), - TextFilterCondition::DoesNotContain => !s.contains(content), - TextFilterCondition::StartsWith => s.starts_with(content), - TextFilterCondition::EndsWith => s.ends_with(content), - TextFilterCondition::TextIsEmpty => s.is_empty(), - TextFilterCondition::TextIsNotEmpty => !s.is_empty(), - } - } else { - false - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] pub enum TextFilterCondition { @@ -83,68 +62,3 @@ impl std::convert::From> for GridTextFilter { } } } - -#[cfg(test)] -mod tests { - #![allow(clippy::all)] - use crate::entities::{GridTextFilter, TextFilterCondition}; - - #[test] - fn text_filter_equal_test() { - let text_filter = GridTextFilter { - condition: TextFilterCondition::Is, - content: Some("appflowy".to_owned()), - }; - - assert!(text_filter.apply("AppFlowy")); - assert_eq!(text_filter.apply("appflowy"), true); - assert_eq!(text_filter.apply("Appflowy"), true); - assert_eq!(text_filter.apply("AppFlowy.io"), false); - } - #[test] - fn text_filter_start_with_test() { - let text_filter = GridTextFilter { - condition: TextFilterCondition::StartsWith, - content: Some("appflowy".to_owned()), - }; - - assert_eq!(text_filter.apply("AppFlowy.io"), true); - assert_eq!(text_filter.apply(""), false); - assert_eq!(text_filter.apply("https"), false); - } - - #[test] - fn text_filter_end_with_test() { - let text_filter = GridTextFilter { - condition: TextFilterCondition::EndsWith, - content: Some("appflowy".to_owned()), - }; - - assert_eq!(text_filter.apply("https://github.com/appflowy"), true); - assert_eq!(text_filter.apply("App"), false); - assert_eq!(text_filter.apply("appflowy.io"), false); - } - #[test] - fn text_filter_empty_test() { - let text_filter = GridTextFilter { - condition: TextFilterCondition::TextIsEmpty, - content: Some("appflowy".to_owned()), - }; - - assert_eq!(text_filter.apply(""), true); - assert_eq!(text_filter.apply("App"), false); - } - #[test] - fn text_filter_contain_test() { - let text_filter = GridTextFilter { - condition: TextFilterCondition::Contains, - content: Some("appflowy".to_owned()), - }; - - assert_eq!(text_filter.apply("https://github.com/appflowy"), true); - assert_eq!(text_filter.apply("AppFlowy"), true); - assert_eq!(text_filter.apply("App"), false); - assert_eq!(text_filter.apply(""), false); - assert_eq!(text_filter.apply("github"), false); - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs new file mode 100644 index 0000000000..ee2a352b65 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs @@ -0,0 +1,29 @@ +use crate::entities::{CheckboxCondition, GridCheckboxFilter}; +use crate::services::field::CheckboxCellData; + +impl GridCheckboxFilter { + pub fn apply(&self, cell_data: &CheckboxCellData) -> bool { + let is_check = cell_data.is_check(); + match self.condition { + CheckboxCondition::IsChecked => is_check, + CheckboxCondition::IsUnChecked => !is_check, + } + } +} + +#[cfg(test)] +mod tests { + use crate::entities::{CheckboxCondition, GridCheckboxFilter}; + use crate::services::field::CheckboxCellData; + + #[test] + fn checkbox_filter_is_check_test() { + let checkbox_filter = GridCheckboxFilter { + condition: CheckboxCondition::IsChecked, + }; + for (value, r) in [("true", true), ("yes", true), ("false", false), ("no", false)] { + let data = CheckboxCellData(value.to_owned()); + assert_eq!(checkbox_filter.apply(&data), r); + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs new file mode 100644 index 0000000000..e1dc1d6b47 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs @@ -0,0 +1,3 @@ +use crate::entities::GridDateFilter; + +impl GridDateFilter {} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs b/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs index 39ae6ba462..336e045249 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs @@ -1,4 +1,9 @@ +mod checkbox_filter; +mod date_filter; mod filter_cache; mod filter_service; +mod number_filter; +mod select_option_filter; +mod text_filter; pub(crate) use filter_service::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs new file mode 100644 index 0000000000..67e39bfa0d --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs @@ -0,0 +1,78 @@ +use crate::entities::{GridNumberFilter, NumberFilterCondition}; +use crate::services::field::NumberCellData; +use rust_decimal::prelude::Zero; +use rust_decimal::Decimal; +use std::str::FromStr; + +impl GridNumberFilter { + pub fn apply(&self, num_cell_data: &NumberCellData) -> bool { + if self.content.is_none() { + return false; + } + + let content = self.content.as_ref().unwrap(); + let zero_decimal = Decimal::zero(); + let cell_decimal = num_cell_data.decimal().as_ref().unwrap_or(&zero_decimal); + match Decimal::from_str(content) { + Ok(decimal) => match self.condition { + NumberFilterCondition::Equal => cell_decimal == &decimal, + NumberFilterCondition::NotEqual => cell_decimal != &decimal, + NumberFilterCondition::GreaterThan => cell_decimal > &decimal, + NumberFilterCondition::LessThan => cell_decimal < &decimal, + NumberFilterCondition::GreaterThanOrEqualTo => cell_decimal >= &decimal, + NumberFilterCondition::LessThanOrEqualTo => cell_decimal <= &decimal, + NumberFilterCondition::NumberIsEmpty => num_cell_data.is_empty(), + NumberFilterCondition::NumberIsNotEmpty => !num_cell_data.is_empty(), + }, + Err(_) => false, + } + } +} +#[cfg(test)] +mod tests { + use crate::entities::{GridNumberFilter, NumberFilterCondition}; + + use crate::services::field::{NumberCellData, NumberFormat}; + use std::str::FromStr; + #[test] + fn number_filter_equal_test() { + let number_filter = GridNumberFilter { + condition: NumberFilterCondition::Equal, + content: Some("123".to_owned()), + }; + + for (num_str, r) in [("123", true), ("1234", false), ("", false)] { + let data = NumberCellData::from_str(num_str).unwrap(); + assert_eq!(number_filter.apply(&data), r); + } + + let format = NumberFormat::USD; + for (num_str, r) in [("$123", true), ("1234", false), ("", false)] { + let data = NumberCellData::from_format_str(num_str, true, &format).unwrap(); + assert_eq!(number_filter.apply(&data), r); + } + } + #[test] + fn number_filter_greater_than_test() { + let number_filter = GridNumberFilter { + condition: NumberFilterCondition::GreaterThan, + content: Some("12".to_owned()), + }; + for (num_str, r) in [("123", true), ("10", false), ("30", true), ("", false)] { + let data = NumberCellData::from_str(num_str).unwrap(); + assert_eq!(number_filter.apply(&data), r); + } + } + + #[test] + fn number_filter_less_than_test() { + let number_filter = GridNumberFilter { + condition: NumberFilterCondition::LessThan, + content: Some("100".to_owned()), + }; + for (num_str, r) in [("12", true), ("1234", false), ("30", true), ("", true)] { + let data = NumberCellData::from_str(num_str).unwrap(); + assert_eq!(number_filter.apply(&data), r); + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs new file mode 100644 index 0000000000..2195463524 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs @@ -0,0 +1,64 @@ +#![allow(clippy::needless_collect)] +use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; +use crate::services::field::select_option::SelectedSelectOptions; + +impl GridSelectOptionFilter { + pub fn apply(&self, selected_options: &SelectedSelectOptions) -> bool { + let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect(); + match self.condition { + SelectOptionCondition::OptionIs => { + // if selected options equal to filter's options, then the required_options will be empty. + let required_options = self + .option_ids + .iter() + .filter(|id| !selected_option_ids.contains(id)) + .collect::>(); + + // https://stackoverflow.com/questions/69413164/how-to-fix-this-clippy-warning-needless-collect + !required_options.is_empty() + } + SelectOptionCondition::OptionIsNot => { + for option_id in selected_option_ids { + if self.option_ids.contains(option_id) { + return true; + } + } + false + } + SelectOptionCondition::OptionIsEmpty => selected_option_ids.is_empty(), + SelectOptionCondition::OptionIsNotEmpty => !selected_option_ids.is_empty(), + } + } +} + +#[cfg(test)] +mod tests { + #![allow(clippy::all)] + use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; + use crate::services::field::select_option::{SelectOption, SelectedSelectOptions}; + + #[test] + fn select_option_filter_is_test() { + let option_1 = SelectOption::new("A"); + let option_2 = SelectOption::new("B"); + + let filter_1 = GridSelectOptionFilter { + condition: SelectOptionCondition::OptionIs, + option_ids: vec![option_1.id.clone(), option_2.id.clone()], + }; + + assert_eq!( + filter_1.apply(&SelectedSelectOptions { + options: vec![option_1.clone(), option_2.clone()], + }), + false + ); + + assert_eq!( + filter_1.apply(&SelectedSelectOptions { + options: vec![option_1.clone()], + }), + true, + ); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs new file mode 100644 index 0000000000..a0ed6b6976 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs @@ -0,0 +1,87 @@ +use crate::entities::{GridTextFilter, TextFilterCondition}; + +impl GridTextFilter { + pub fn apply>(&self, cell_data: T) -> bool { + let cell_data = cell_data.as_ref(); + let s = cell_data.to_lowercase(); + if let Some(content) = self.content.as_ref() { + match self.condition { + TextFilterCondition::Is => &s == content, + TextFilterCondition::IsNot => &s != content, + TextFilterCondition::Contains => s.contains(content), + TextFilterCondition::DoesNotContain => !s.contains(content), + TextFilterCondition::StartsWith => s.starts_with(content), + TextFilterCondition::EndsWith => s.ends_with(content), + TextFilterCondition::TextIsEmpty => s.is_empty(), + TextFilterCondition::TextIsNotEmpty => !s.is_empty(), + } + } else { + false + } + } +} + +#[cfg(test)] +mod tests { + #![allow(clippy::all)] + use crate::entities::{GridTextFilter, TextFilterCondition}; + + #[test] + fn text_filter_equal_test() { + let text_filter = GridTextFilter { + condition: TextFilterCondition::Is, + content: Some("appflowy".to_owned()), + }; + + assert!(text_filter.apply("AppFlowy")); + assert_eq!(text_filter.apply("appflowy"), true); + assert_eq!(text_filter.apply("Appflowy"), true); + assert_eq!(text_filter.apply("AppFlowy.io"), false); + } + #[test] + fn text_filter_start_with_test() { + let text_filter = GridTextFilter { + condition: TextFilterCondition::StartsWith, + content: Some("appflowy".to_owned()), + }; + + assert_eq!(text_filter.apply("AppFlowy.io"), true); + assert_eq!(text_filter.apply(""), false); + assert_eq!(text_filter.apply("https"), false); + } + + #[test] + fn text_filter_end_with_test() { + let text_filter = GridTextFilter { + condition: TextFilterCondition::EndsWith, + content: Some("appflowy".to_owned()), + }; + + assert_eq!(text_filter.apply("https://github.com/appflowy"), true); + assert_eq!(text_filter.apply("App"), false); + assert_eq!(text_filter.apply("appflowy.io"), false); + } + #[test] + fn text_filter_empty_test() { + let text_filter = GridTextFilter { + condition: TextFilterCondition::TextIsEmpty, + content: Some("appflowy".to_owned()), + }; + + assert_eq!(text_filter.apply(""), true); + assert_eq!(text_filter.apply("App"), false); + } + #[test] + fn text_filter_contain_test() { + let text_filter = GridTextFilter { + condition: TextFilterCondition::Contains, + content: Some("appflowy".to_owned()), + }; + + assert_eq!(text_filter.apply("https://github.com/appflowy"), true); + assert_eq!(text_filter.apply("AppFlowy"), true); + assert_eq!(text_filter.apply("App"), false); + assert_eq!(text_filter.apply(""), false); + assert_eq!(text_filter.apply("github"), false); + } +} From 4f30f8e2cd52247e76fa55f574f186f1ef2c8467 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 8 Jul 2022 16:32:11 +0800 Subject: [PATCH 2/6] refactor: separate filter operation from filter_entities mod --- .../filter_entities/checkbox_filter.rs | 1 - .../entities/filter_entities/number_filter.rs | 5 +- .../filter_entities/select_option_filter.rs | 2 +- .../type_options/checkbox_type_option.rs | 16 +------ .../type_options/multi_select_type_option.rs | 17 ++----- .../number_type_option/number_type_option.rs | 20 ++------ .../type_options/single_select_type_option.rs | 16 +------ .../field/type_options/text_type_option.rs | 16 +------ .../field/type_options/url_type_option.rs | 17 ++----- .../src/services/filter/checkbox_filter.rs | 25 +++++++++- .../flowy-grid/src/services/filter/mod.rs | 1 + .../src/services/filter/number_filter.rs | 18 ++++++- .../services/filter/select_option_filter.rs | 47 ++++++++++++++++++- .../src/services/filter/text_filter.rs | 13 +++++ .../src/services/filter/url_filter.rs | 15 ++++++ 15 files changed, 133 insertions(+), 96 deletions(-) create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs index 42b0bfe1cc..bb31b7a3be 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs @@ -1,4 +1,3 @@ -use crate::services::field::CheckboxCellData; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::revision::GridFilterRevision; diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs index 2db980de04..097ff5330a 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs @@ -1,10 +1,7 @@ -use crate::services::field::NumberCellData; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::revision::GridFilterRevision; -use rust_decimal::prelude::Zero; -use rust_decimal::Decimal; -use std::str::FromStr; + use std::sync::Arc; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs index ad215dfd45..73c39cb657 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs @@ -1,4 +1,4 @@ -use crate::services::field::select_option::{SelectOptionIds, SelectedSelectOptions}; +use crate::services::field::select_option::SelectOptionIds; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::revision::GridFilterRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs index 12361e3fcb..1808f0dc82 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -1,8 +1,6 @@ -use crate::entities::{FieldType, GridCheckboxFilter}; +use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, -}; +use crate::services::cell::{AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -42,16 +40,6 @@ impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); const YES: &str = "Yes"; const NO: &str = "No"; -impl CellFilterOperation for CheckboxTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridCheckboxFilter) -> FlowyResult { - if !any_cell_data.is_checkbox() { - return Ok(true); - } - let checkbox_cell_data: CheckboxCellData = any_cell_data.try_into()?; - Ok(filter.apply(&checkbox_cell_data)) - } -} - impl CellDataOperation for CheckboxTypeOption { fn decode_cell_data( &self, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs index 9d27b0f468..209ed234f7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs @@ -1,12 +1,10 @@ -use crate::entities::{FieldType, GridSelectOptionFilter}; +use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, -}; +use crate::services::cell::{AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; use crate::services::field::select_option::{ make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, - SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR, + SelectOptionOperation, SELECTION_IDS_SEPARATOR, }; use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; @@ -46,16 +44,7 @@ impl SelectOptionOperation for MultiSelectTypeOption { &mut self.options } } -impl CellFilterOperation for MultiSelectTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult { - if !any_cell_data.is_multi_select() { - return Ok(true); - } - let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); - Ok(filter.apply(&selected_options)) - } -} impl CellDataOperation for MultiSelectTypeOption { fn decode_cell_data( &self, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index 690fd10841..c8f79df20c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -1,9 +1,7 @@ use crate::impl_type_option; -use crate::entities::{FieldType, GridNumberFilter}; -use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, -}; +use crate::entities::FieldType; +use crate::services::cell::{CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; use crate::services::field::number_currency::Currency; use crate::services::field::type_options::number_type_option::format::*; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; @@ -79,7 +77,7 @@ impl NumberTypeOption { Self::default() } - fn format_cell_data(&self, s: &str) -> FlowyResult { + pub(crate) fn format_cell_data(&self, s: &str) -> FlowyResult { match self.format { NumberFormat::Num | NumberFormat::Percent => match Decimal::from_str(s) { Ok(value, ..) => Ok(NumberCellData::from_decimal(value)), @@ -105,18 +103,6 @@ pub(crate) fn strip_currency_symbol(s: T) -> String { } s } -impl CellFilterOperation for NumberTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridNumberFilter) -> FlowyResult { - if !any_cell_data.is_number() { - return Ok(true); - } - - let cell_data = any_cell_data.cell_data; - let num_cell_data = self.format_cell_data(&cell_data)?; - - Ok(filter.apply(&num_cell_data)) - } -} impl CellDataOperation for NumberTypeOption { fn decode_cell_data( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs index b1e72d24a7..6094f8567b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs @@ -1,8 +1,6 @@ -use crate::entities::{FieldType, GridSelectOptionFilter}; +use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, -}; +use crate::services::cell::{AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; use crate::services::field::select_option::{ make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, SelectOptionOperation, @@ -43,16 +41,6 @@ impl SelectOptionOperation for SingleSelectTypeOption { } } -impl CellFilterOperation for SingleSelectTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, _filter: &GridSelectOptionFilter) -> FlowyResult { - if !any_cell_data.is_single_select() { - return Ok(true); - } - let _ids: SelectOptionIds = any_cell_data.try_into()?; - Ok(false) - } -} - impl CellDataOperation for SingleSelectTypeOption { fn decode_cell_data( &self, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index 0a727afb56..e26c7d3b16 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -1,8 +1,7 @@ -use crate::entities::{FieldType, GridTextFilter}; +use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{ - try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, - DecodedCellData, + try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -33,17 +32,6 @@ pub struct RichTextTypeOption { } impl_type_option!(RichTextTypeOption, FieldType::RichText); -impl CellFilterOperation for RichTextTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridTextFilter) -> FlowyResult { - if !any_cell_data.is_text() { - return Ok(true); - } - - let text_cell_data: TextCellData = any_cell_data.try_into()?; - Ok(filter.apply(text_cell_data)) - } -} - impl CellDataOperation for RichTextTypeOption { fn decode_cell_data( &self, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs index 490d9dfaa1..5b1fa2319f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs @@ -1,9 +1,9 @@ -use crate::entities::{FieldType, GridTextFilter}; +use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, FromCellString, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, FromCellString, }; -use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder}; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; use fancy_regex::Regex; use flowy_derive::ProtoBuf; @@ -34,17 +34,6 @@ pub struct URLTypeOption { } impl_type_option!(URLTypeOption, FieldType::URL); -impl CellFilterOperation for URLTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridTextFilter) -> FlowyResult { - if !any_cell_data.is_url() { - return Ok(true); - } - - let text_cell_data: TextCellData = any_cell_data.try_into()?; - Ok(filter.apply(&text_cell_data)) - } -} - impl CellDataOperation for URLTypeOption { fn decode_cell_data( &self, diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs index ee2a352b65..4037227fa7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs @@ -1,5 +1,7 @@ use crate::entities::{CheckboxCondition, GridCheckboxFilter}; -use crate::services::field::CheckboxCellData; +use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::field::{CheckboxCellData, CheckboxTypeOption}; +use flowy_error::FlowyResult; impl GridCheckboxFilter { pub fn apply(&self, cell_data: &CheckboxCellData) -> bool { @@ -11,6 +13,16 @@ impl GridCheckboxFilter { } } +impl CellFilterOperation for CheckboxTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridCheckboxFilter) -> FlowyResult { + if !any_cell_data.is_checkbox() { + return Ok(true); + } + let checkbox_cell_data: CheckboxCellData = any_cell_data.try_into()?; + Ok(filter.apply(&checkbox_cell_data)) + } +} + #[cfg(test)] mod tests { use crate::entities::{CheckboxCondition, GridCheckboxFilter}; @@ -26,4 +38,15 @@ mod tests { assert_eq!(checkbox_filter.apply(&data), r); } } + + #[test] + fn checkbox_filter_is_uncheck_test() { + let checkbox_filter = GridCheckboxFilter { + condition: CheckboxCondition::IsUnChecked, + }; + for (value, r) in [("false", true), ("no", true), ("true", false), ("yes", false)] { + let data = CheckboxCellData(value.to_owned()); + assert_eq!(checkbox_filter.apply(&data), r); + } + } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs b/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs index 336e045249..3e78977bfc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs @@ -5,5 +5,6 @@ mod filter_service; mod number_filter; mod select_option_filter; mod text_filter; +mod url_filter; pub(crate) use filter_service::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs index 67e39bfa0d..d3db1974d8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs @@ -1,5 +1,7 @@ use crate::entities::{GridNumberFilter, NumberFilterCondition}; -use crate::services::field::NumberCellData; +use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::field::{NumberCellData, NumberTypeOption}; +use flowy_error::FlowyResult; use rust_decimal::prelude::Zero; use rust_decimal::Decimal; use std::str::FromStr; @@ -28,6 +30,20 @@ impl GridNumberFilter { } } } + +impl CellFilterOperation for NumberTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridNumberFilter) -> FlowyResult { + if !any_cell_data.is_number() { + return Ok(true); + } + + let cell_data = any_cell_data.cell_data; + let num_cell_data = self.format_cell_data(&cell_data)?; + + Ok(filter.apply(&num_cell_data)) + } +} + #[cfg(test)] mod tests { use crate::entities::{GridNumberFilter, NumberFilterCondition}; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs index 2195463524..a4e848705f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs @@ -1,12 +1,20 @@ #![allow(clippy::needless_collect)] + use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; -use crate::services::field::select_option::SelectedSelectOptions; +use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::field::select_option::{SelectOptionOperation, SelectedSelectOptions}; +use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; +use flowy_error::FlowyResult; impl GridSelectOptionFilter { pub fn apply(&self, selected_options: &SelectedSelectOptions) -> bool { let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect(); match self.condition { SelectOptionCondition::OptionIs => { + if self.option_ids.len() != selected_option_ids.len() { + return true; + } + // if selected options equal to filter's options, then the required_options will be empty. let required_options = self .option_ids @@ -31,6 +39,27 @@ impl GridSelectOptionFilter { } } +impl CellFilterOperation for MultiSelectTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult { + if !any_cell_data.is_multi_select() { + return Ok(true); + } + + let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); + Ok(filter.apply(&selected_options)) + } +} + +impl CellFilterOperation for SingleSelectTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult { + if !any_cell_data.is_single_select() { + return Ok(true); + } + let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); + Ok(filter.apply(&selected_options)) + } +} + #[cfg(test)] mod tests { #![allow(clippy::all)] @@ -41,6 +70,7 @@ mod tests { fn select_option_filter_is_test() { let option_1 = SelectOption::new("A"); let option_2 = SelectOption::new("B"); + let option_3 = SelectOption::new("C"); let filter_1 = GridSelectOptionFilter { condition: SelectOptionCondition::OptionIs, @@ -54,6 +84,21 @@ mod tests { false ); + assert_eq!( + filter_1.apply(&SelectedSelectOptions { + options: vec![option_1.clone(), option_2.clone(), option_3.clone()], + }), + true + ); + + assert_eq!( + filter_1.apply(&SelectedSelectOptions { + options: vec![option_1.clone(), option_3.clone()], + }), + true + ); + + assert_eq!(filter_1.apply(&SelectedSelectOptions { options: vec![] }), true); assert_eq!( filter_1.apply(&SelectedSelectOptions { options: vec![option_1.clone()], diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs index a0ed6b6976..9e88be4289 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs @@ -1,4 +1,7 @@ use crate::entities::{GridTextFilter, TextFilterCondition}; +use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::field::{RichTextTypeOption, TextCellData}; +use flowy_error::FlowyResult; impl GridTextFilter { pub fn apply>(&self, cell_data: T) -> bool { @@ -21,6 +24,16 @@ impl GridTextFilter { } } +impl CellFilterOperation for RichTextTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridTextFilter) -> FlowyResult { + if !any_cell_data.is_text() { + return Ok(true); + } + + let text_cell_data: TextCellData = any_cell_data.try_into()?; + Ok(filter.apply(text_cell_data)) + } +} #[cfg(test)] mod tests { #![allow(clippy::all)] diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs new file mode 100644 index 0000000000..18c955cb16 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs @@ -0,0 +1,15 @@ +use crate::entities::GridTextFilter; +use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::field::{TextCellData, URLTypeOption}; +use flowy_error::FlowyResult; + +impl CellFilterOperation for URLTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridTextFilter) -> FlowyResult { + if !any_cell_data.is_url() { + return Ok(true); + } + + let text_cell_data: TextCellData = any_cell_data.try_into()?; + Ok(filter.apply(&text_cell_data)) + } +} From ec1113b13492da076c1a61665f531cc8b5ea53a9 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 9 Jul 2022 11:19:17 +0800 Subject: [PATCH 3/6] chore: add date filter tests --- .../entities/filter_entities/date_filter.rs | 47 +++++++- .../field/type_options/date_type_option.rs | 47 +++++--- .../src/services/filter/date_filter.rs | 3 - .../src/services/filter/filter_cache.rs | 3 - .../src/services/filter/filter_service.rs | 4 +- .../filter/{ => impls}/checkbox_filter.rs | 12 +- .../src/services/filter/impls/date_filter.rs | 107 ++++++++++++++++++ .../src/services/filter/impls/mod.rs | 13 +++ .../filter/{ => impls}/number_filter.rs | 20 ++-- .../{ => impls}/select_option_filter.rs | 16 +-- .../filter/{ => impls}/text_filter.rs | 38 +++---- .../services/filter/{ => impls}/url_filter.rs | 2 +- .../flowy-grid/src/services/filter/mod.rs | 7 +- 13 files changed, 239 insertions(+), 80 deletions(-) delete mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs rename frontend/rust-lib/flowy-grid/src/services/filter/{ => impls}/checkbox_filter.rs (75%) create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/filter/impls/mod.rs rename frontend/rust-lib/flowy-grid/src/services/filter/{ => impls}/number_filter.rs (80%) rename frontend/rust-lib/flowy-grid/src/services/filter/{ => impls}/select_option_filter.rs (87%) rename frontend/rust-lib/flowy-grid/src/services/filter/{ => impls}/text_filter.rs (68%) rename frontend/rust-lib/flowy-grid/src/services/filter/{ => impls}/url_filter.rs (91%) diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs index f892c8b10d..6df4c03f7d 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs @@ -1,6 +1,8 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::revision::GridFilterRevision; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; use std::sync::Arc; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] @@ -9,7 +11,30 @@ pub struct GridDateFilter { pub condition: DateFilterCondition, #[pb(index = 2, one_of)] - pub content: Option, + pub start: Option, + + #[pb(index = 3, one_of)] + pub end: Option, +} + +#[derive(Serialize, Deserialize, Default)] +struct DateRange { + start: Option, + end: Option, +} + +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 { + serde_json::from_str(s) + } } #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] @@ -48,9 +73,21 @@ impl std::convert::TryFrom for DateFilterCondition { } impl std::convert::From> for GridDateFilter { fn from(rev: Arc) -> Self { - GridDateFilter { - condition: DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs), - content: rev.content.clone(), - } + let condition = DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs); + let mut filter = GridDateFilter { + 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 } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 34b354b060..fb9844441b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -1,9 +1,8 @@ -use crate::entities::{CellChangeset, FieldType, GridDateFilter}; +use crate::entities::{CellChangeset, FieldType}; use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::impl_type_option; use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, - FromCellChangeset, FromCellString, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, FromCellChangeset, FromCellString, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -110,6 +109,10 @@ impl DateTypeOption { fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime { let native = NaiveDateTime::from_timestamp(timestamp, 0); + let native2 = NaiveDateTime::from_timestamp(timestamp, 0); + + if native > native2 {} + self.utc_date_time_from_native(native) } @@ -118,19 +121,10 @@ impl DateTypeOption { } } -impl CellFilterOperation for DateTypeOption { - fn apply_filter(&self, any_cell_data: AnyCellData, _filter: &GridDateFilter) -> FlowyResult { - if !any_cell_data.is_date() { - return Ok(true); - } - Ok(false) - } -} - -impl CellDataOperation for DateTypeOption { +impl CellDataOperation for DateTypeOption { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -168,17 +162,36 @@ impl CellDataOperation for DateTypeOption { } } -pub struct TimestampParser(i64); +pub struct DateTimestamp(i64); +impl AsRef for DateTimestamp { + fn as_ref(&self) -> &i64 { + &self.0 + } +} -impl FromCellString for TimestampParser { +impl std::convert::From for i64 { + fn from(timestamp: DateTimestamp) -> Self { + timestamp.0 + } +} + +impl FromCellString for DateTimestamp { fn from_cell_str(s: &str) -> FlowyResult where Self: Sized, { let num = s.parse::().unwrap_or(0); - Ok(TimestampParser(num)) + Ok(DateTimestamp(num)) } } + +impl std::convert::From for DateTimestamp { + fn from(data: AnyCellData) -> Self { + let num = data.cell_data.parse::().unwrap_or(0); + DateTimestamp(num) + } +} + #[derive(Default)] pub struct DateTypeOptionBuilder(DateTypeOption); impl_into_box_type_option_builder!(DateTypeOptionBuilder); diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs deleted file mode 100644 index e1dc1d6b47..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/filter/date_filter.rs +++ /dev/null @@ -1,3 +0,0 @@ -use crate::entities::GridDateFilter; - -impl GridDateFilter {} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs index 9f381e2874..5dcd16e448 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs @@ -1,12 +1,9 @@ use crate::entities::{ FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter, GridTextFilter, }; - use dashmap::DashMap; - use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use flowy_sync::client_grid::GridRevisionPad; - use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index 67dac70b6a..261b5c251f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -179,7 +179,7 @@ fn filter_cell( field_type, }; 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| { Some( 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) { None => { if is_visible { diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs similarity index 75% rename from frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs rename to frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs index 4037227fa7..c5cf95d34b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs @@ -4,7 +4,7 @@ use crate::services::field::{CheckboxCellData, CheckboxTypeOption}; use flowy_error::FlowyResult; 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(); match self.condition { CheckboxCondition::IsChecked => is_check, @@ -19,7 +19,7 @@ impl CellFilterOperation for CheckboxTypeOption { return Ok(true); } 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 { 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()); - 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 { 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()); - assert_eq!(checkbox_filter.apply(&data), r); + assert_eq!(checkbox_filter.is_visible(&data), visible); } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs new file mode 100644 index 0000000000..512dbe2aff --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs @@ -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>(&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 for DateTypeOption { + fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridDateFilter) -> FlowyResult { + 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); + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/mod.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/mod.rs new file mode 100644 index 0000000000..6fe93ae58c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/mod.rs @@ -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::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs similarity index 80% rename from frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs rename to frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs index d3db1974d8..7b4c12d7cf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs @@ -7,7 +7,7 @@ use rust_decimal::Decimal; use std::str::FromStr; 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() { return false; } @@ -40,7 +40,7 @@ impl CellFilterOperation for NumberTypeOption { let cell_data = any_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()), }; - 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(); - assert_eq!(number_filter.apply(&data), r); + assert_eq!(number_filter.is_visible(&data), visible); } 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(); - assert_eq!(number_filter.apply(&data), r); + assert_eq!(number_filter.is_visible(&data), visible); } } #[test] @@ -74,9 +74,9 @@ mod tests { condition: NumberFilterCondition::GreaterThan, 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(); - assert_eq!(number_filter.apply(&data), r); + assert_eq!(number_filter.is_visible(&data), visible); } } @@ -86,9 +86,9 @@ mod tests { condition: NumberFilterCondition::LessThan, 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(); - assert_eq!(number_filter.apply(&data), r); + assert_eq!(number_filter.is_visible(&data), visible); } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs similarity index 87% rename from frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs rename to frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs index a4e848705f..cd25bfef0e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs @@ -7,7 +7,7 @@ use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; use flowy_error::FlowyResult; 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(); match self.condition { SelectOptionCondition::OptionIs => { @@ -46,7 +46,7 @@ impl CellFilterOperation for MultiSelectTypeOption { } 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 for SingleSelectTypeOption { return Ok(true); } 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!( - filter_1.apply(&SelectedSelectOptions { + filter_1.is_visible(&SelectedSelectOptions { options: vec![option_1.clone(), option_2.clone()], }), false ); assert_eq!( - filter_1.apply(&SelectedSelectOptions { + filter_1.is_visible(&SelectedSelectOptions { options: vec![option_1.clone(), option_2.clone(), option_3.clone()], }), true ); assert_eq!( - filter_1.apply(&SelectedSelectOptions { + filter_1.is_visible(&SelectedSelectOptions { options: vec![option_1.clone(), option_3.clone()], }), true ); - assert_eq!(filter_1.apply(&SelectedSelectOptions { options: vec![] }), true); + assert_eq!(filter_1.is_visible(&SelectedSelectOptions { options: vec![] }), true); assert_eq!( - filter_1.apply(&SelectedSelectOptions { + filter_1.is_visible(&SelectedSelectOptions { options: vec![option_1.clone()], }), true, diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs similarity index 68% rename from frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs rename to frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs index 9e88be4289..45165e35e2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/text_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs @@ -4,7 +4,7 @@ use crate::services::field::{RichTextTypeOption, TextCellData}; use flowy_error::FlowyResult; impl GridTextFilter { - pub fn apply>(&self, cell_data: T) -> bool { + pub fn is_visible>(&self, cell_data: T) -> bool { let cell_data = cell_data.as_ref(); let s = cell_data.to_lowercase(); if let Some(content) = self.content.as_ref() { @@ -31,7 +31,7 @@ impl CellFilterOperation for RichTextTypeOption { } 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)] @@ -46,10 +46,10 @@ mod tests { content: Some("appflowy".to_owned()), }; - assert!(text_filter.apply("AppFlowy")); - assert_eq!(text_filter.apply("appflowy"), true); - assert_eq!(text_filter.apply("Appflowy"), true); - assert_eq!(text_filter.apply("AppFlowy.io"), false); + assert!(text_filter.is_visible("AppFlowy")); + assert_eq!(text_filter.is_visible("appflowy"), true); + assert_eq!(text_filter.is_visible("Appflowy"), true); + assert_eq!(text_filter.is_visible("AppFlowy.io"), false); } #[test] fn text_filter_start_with_test() { @@ -58,9 +58,9 @@ mod tests { content: Some("appflowy".to_owned()), }; - assert_eq!(text_filter.apply("AppFlowy.io"), true); - assert_eq!(text_filter.apply(""), false); - assert_eq!(text_filter.apply("https"), false); + assert_eq!(text_filter.is_visible("AppFlowy.io"), true); + assert_eq!(text_filter.is_visible(""), false); + assert_eq!(text_filter.is_visible("https"), false); } #[test] @@ -70,9 +70,9 @@ mod tests { content: Some("appflowy".to_owned()), }; - assert_eq!(text_filter.apply("https://github.com/appflowy"), true); - assert_eq!(text_filter.apply("App"), false); - assert_eq!(text_filter.apply("appflowy.io"), false); + assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true); + assert_eq!(text_filter.is_visible("App"), false); + assert_eq!(text_filter.is_visible("appflowy.io"), false); } #[test] fn text_filter_empty_test() { @@ -81,8 +81,8 @@ mod tests { content: Some("appflowy".to_owned()), }; - assert_eq!(text_filter.apply(""), true); - assert_eq!(text_filter.apply("App"), false); + assert_eq!(text_filter.is_visible(""), true); + assert_eq!(text_filter.is_visible("App"), false); } #[test] fn text_filter_contain_test() { @@ -91,10 +91,10 @@ mod tests { content: Some("appflowy".to_owned()), }; - assert_eq!(text_filter.apply("https://github.com/appflowy"), true); - assert_eq!(text_filter.apply("AppFlowy"), true); - assert_eq!(text_filter.apply("App"), false); - assert_eq!(text_filter.apply(""), false); - assert_eq!(text_filter.apply("github"), false); + assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true); + assert_eq!(text_filter.is_visible("AppFlowy"), true); + assert_eq!(text_filter.is_visible("App"), false); + assert_eq!(text_filter.is_visible(""), false); + assert_eq!(text_filter.is_visible("github"), false); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs similarity index 91% rename from frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs rename to frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs index 18c955cb16..50f9c815fc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/url_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs @@ -10,6 +10,6 @@ impl CellFilterOperation for URLTypeOption { } let text_cell_data: TextCellData = any_cell_data.try_into()?; - Ok(filter.apply(&text_cell_data)) + Ok(filter.is_visible(&text_cell_data)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs b/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs index 3e78977bfc..8a0067ff96 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/mod.rs @@ -1,10 +1,5 @@ -mod checkbox_filter; -mod date_filter; mod filter_cache; mod filter_service; -mod number_filter; -mod select_option_filter; -mod text_filter; -mod url_filter; +mod impls; pub(crate) use filter_service::*; From 24f2bf398e1eba1d3a05c687d99d2cd1e7f1fe16 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 9 Jul 2022 23:28:15 +0800 Subject: [PATCH 4/6] chore: add filter feature flag & enable filter tests --- frontend/rust-lib/flowy-grid/Cargo.toml | 3 +- .../entities/filter_entities/date_filter.rs | 49 ++++++++++ .../src/services/filter/filter_cache.rs | 9 +- .../src/services/filter/filter_service.rs | 10 +- .../flowy-grid/tests/grid/filter_test/mod.rs | 2 + .../tests/grid/filter_test/script.rs | 91 +++++++++++++++++++ .../{filter_test.rs => filter_test/test.rs} | 31 ++++--- .../rust-lib/flowy-grid/tests/grid/mod.rs | 2 +- .../rust-lib/flowy-grid/tests/grid/script.rs | 6 +- .../lib-dispatch/src/request/payload.rs | 2 +- .../lib-dispatch/src/response/response.rs | 4 +- .../src/revision/grid_rev.rs | 5 + .../src/revision/grid_setting_rev.rs | 4 +- .../src/client_grid/grid_revision_pad.rs | 11 +-- 14 files changed, 195 insertions(+), 34 deletions(-) create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs rename frontend/rust-lib/flowy-grid/tests/grid/{filter_test.rs => filter_test/test.rs} (54%) diff --git a/frontend/rust-lib/flowy-grid/Cargo.toml b/frontend/rust-lib/flowy-grid/Cargo.toml index ba3702038e..e09e156772 100644 --- a/frontend/rust-lib/flowy-grid/Cargo.toml +++ b/frontend/rust-lib/flowy-grid/Cargo.toml @@ -50,6 +50,7 @@ lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file [features] -default = [] +default = ["filter"] dart = ["lib-infra/dart"] +filter = [] flowy_unit_test = ["flowy-revision/flowy_unit_test"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs index 6df4c03f7d..eed2fa56bd 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs @@ -1,5 +1,7 @@ +use crate::entities::FieldType; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::GridFilterRevision; use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -17,6 +19,53 @@ pub struct GridDateFilter { pub end: Option, } +#[derive(ProtoBuf, Default, Clone, Debug)] +pub struct CreateGridDateFilterPayload { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub field_type: FieldType, + + #[pb(index = 3)] + pub condition: DateFilterCondition, + + #[pb(index = 4, one_of)] + pub start: Option, + + #[pb(index = 5, one_of)] + pub end: Option, +} + +pub struct CreateGridDateFilterParams { + pub field_id: String, + + pub field_type: FieldType, + + pub condition: DateFilterCondition, + + pub start: Option, + + pub end: Option, +} + +impl TryInto for CreateGridDateFilterPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let field_id = NotEmptyStr::parse(self.field_id) + .map_err(|_| ErrorCode::FieldIdIsEmpty)? + .0; + Ok(CreateGridDateFilterParams { + field_id, + condition: self.condition, + start: self.start, + field_type: self.field_type, + end: self.end, + }) + } +} + #[derive(Serialize, Deserialize, Default)] struct DateRange { start: Option, diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs index 5dcd16e448..a1f6d4cbbf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs @@ -8,10 +8,12 @@ use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; +type RowId = String; + #[derive(Default)] pub(crate) struct FilterResultCache { // key: row id - inner: DashMap, + inner: DashMap, } impl FilterResultCache { @@ -67,7 +69,7 @@ pub(crate) struct FilterCache { impl FilterCache { pub(crate) async fn from_grid_pad(grid_pad: &Arc>) -> Arc { let this = Arc::new(Self::default()); - let _ = reload_filter_cache(this.clone(), None, grid_pad).await; + let _ = refresh_filter_cache(this.clone(), None, grid_pad).await; this } @@ -98,7 +100,8 @@ impl FilterCache { } } -pub(crate) async fn reload_filter_cache( +/// Refresh the filter according to the field id. +pub(crate) async fn refresh_filter_cache( cache: Arc, field_ids: Option>, grid_pad: &Arc>, diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index 261b5c251f..6442dd4710 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -7,7 +7,7 @@ use crate::services::field::{ SingleSelectTypeOption, URLTypeOption, }; use crate::services::filter::filter_cache::{ - reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache, + refresh_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache, }; use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::row::GridBlockSnapshot; @@ -62,6 +62,7 @@ impl GridFilterService { let mut changesets = vec![]; for (index, block) in task_context.blocks.into_iter().enumerate() { + // The row_ids contains the row that its visibility was changed. let row_ids = block .row_revs .par_iter() @@ -74,6 +75,8 @@ impl GridFilterService { let mut visible_rows = vec![]; let mut hide_rows = vec![]; + + // Query the filter result from the cache for row_id in row_ids { if self .filter_result_cache @@ -93,8 +96,11 @@ impl GridFilterService { visible_rows, ..Default::default() }; + + // Save the changeset for each block changesets.push(changeset); } + self.notify(changesets).await; Ok(()) } @@ -106,7 +112,7 @@ impl GridFilterService { if let Some(filter_id) = &changeset.insert_filter { let field_ids = Some(vec![filter_id.field_id.clone()]); - reload_filter_cache(self.filter_cache.clone(), field_ids, &self.grid_pad).await; + refresh_filter_cache(self.filter_cache.clone(), field_ids, &self.grid_pad).await; } if let Some(filter_id) = &changeset.delete_filter { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs new file mode 100644 index 0000000000..63d424afaf --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs @@ -0,0 +1,2 @@ +mod script; +mod test; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs new file mode 100644 index 0000000000..c63ebc0d9c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -0,0 +1,91 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +#![allow(clippy::all)] +#![allow(dead_code)] +#![allow(unused_imports)] + +use flowy_grid::entities::{CreateGridFilterPayload, GridLayoutType, GridSetting}; +use flowy_grid::services::setting::GridSettingChangesetBuilder; +use flowy_grid_data_model::revision::FieldTypeRevision; +use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; +use crate::grid::script::GridEditorTest; + +pub enum FilterScript { + #[allow(dead_code)] + UpdateGridSetting { + params: GridSettingChangesetParams, + }, + InsertGridTableFilter { + payload: CreateGridFilterPayload, + }, + AssertTableFilterCount { + count: i32, + }, + DeleteGridTableFilter { + filter_id: String, + field_type_rev: FieldTypeRevision, + }, + #[allow(dead_code)] + AssertGridSetting { + expected_setting: GridSetting, + }, +} + +pub struct GridFilterTest { + pub editor_test: GridEditorTest, +} + +impl GridFilterTest { + pub async fn new() -> Self { + let editor_test = GridEditorTest::new().await; + Self { + editor_test + } + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub async fn run_script(&mut self, script: FilterScript) { + + match script { + FilterScript::UpdateGridSetting { params } => { + let _ = self.editor.update_grid_setting(params).await.unwrap(); + } + FilterScript::InsertGridTableFilter { payload } => { + let params: CreateGridFilterParams = payload.try_into().unwrap(); + let layout_type = GridLayoutType::Table; + let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) + .insert_filter(params) + .build(); + let _ = self.editor.update_grid_setting(params).await.unwrap(); + } + FilterScript::AssertTableFilterCount { count } => { + let layout_type = GridLayoutType::Table; + let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); + assert_eq!(count as usize, filters.len()); + } + FilterScript::DeleteGridTableFilter { filter_id ,field_type_rev} => { + let layout_type = GridLayoutType::Table; + let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) + .delete_filter(DeleteFilterParams { filter_id, field_type_rev }) + .build(); + let _ = self.editor.update_grid_setting(params).await.unwrap(); + } + FilterScript::AssertGridSetting { expected_setting } => { + let setting = self.editor.get_grid_setting().await.unwrap(); + assert_eq!(expected_setting, setting); + } + } + } +} + +impl std::ops::Deref for GridFilterTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.editor_test + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/test.rs similarity index 54% rename from frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/filter_test/test.rs index aad4cb1e7d..34e1ef69b0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/test.rs @@ -1,41 +1,41 @@ -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; -use flowy_grid::entities::CreateGridFilterPayload; +use crate::grid::filter_test::script::FilterScript::*; +use crate::grid::filter_test::script::*; +use flowy_grid::entities::{CreateGridFilterPayload, TextFilterCondition}; +use flowy_grid_data_model::revision::FieldRevision; #[tokio::test] async fn grid_filter_create_test() { - let test = GridEditorTest::new().await; + let mut test = GridFilterTest::new().await; let field_rev = test.text_field(); let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; - GridEditorTest::new().await.run_scripts(scripts).await; + test.run_scripts(scripts).await; } #[tokio::test] #[should_panic] async fn grid_filter_invalid_condition_panic_test() { - let test = GridEditorTest::new().await; - let field_rev = test.text_field(); + let mut test = GridFilterTest::new().await; // 100 is not a valid condition, so this test should be panic. - let payload = CreateGridFilterPayload::new(field_rev, 100, Some("abc".to_owned())); + let payload = create_filter(&test, "abc"); let scripts = vec![InsertGridTableFilter { payload }]; - GridEditorTest::new().await.run_scripts(scripts).await; + test.run_scripts(scripts).await; } #[tokio::test] async fn grid_filter_delete_test() { - let mut test = GridEditorTest::new().await; - let field_rev = test.text_field().clone(); - let payload = CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); + let mut test = GridFilterTest::new().await; + let payload = create_filter(&test, "abc"); let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; test.run_scripts(scripts).await; let filter = test.grid_filters().await.pop().unwrap(); + test.run_scripts(vec![ DeleteGridTableFilter { filter_id: filter.id, - field_type: field_rev.field_type.clone(), + field_type_rev: field_rev.field_type_rev.clone(), }, AssertTableFilterCount { count: 0 }, ]) @@ -44,3 +44,8 @@ async fn grid_filter_delete_test() { #[tokio::test] async fn grid_filter_get_rows_test() {} + +fn create_filter(grid_filter_test: &GridFilterTest, s: &str) -> CreateGridFilterPayload { + let field_rev = grid_filter_test.text_field(); + CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some(s.to_owned())) +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs index 38cdb25b99..4d746661eb 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs @@ -2,7 +2,7 @@ mod block_test; mod cell_test; mod field_test; mod field_util; -// mod filter_test; +mod filter_test; mod row_test; mod row_util; mod script; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs index e0ec211ba3..f25e859450 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -82,7 +82,7 @@ pub enum EditorScript { }, DeleteGridTableFilter { filter_id: String, - field_type: FieldType, + field_type_rev: FieldTypeRevision, }, #[allow(dead_code)] AssertGridSetting { @@ -271,10 +271,10 @@ impl GridEditorTest { let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); assert_eq!(count as usize, filters.len()); } - EditorScript::DeleteGridTableFilter { filter_id ,field_type} => { + EditorScript::DeleteGridTableFilter { filter_id ,field_type_rev} => { let layout_type = GridLayoutType::Table; let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .delete_filter(DeleteFilterParams { filter_id, field_type_rev: field_type.into() }) + .delete_filter(DeleteFilterParams { filter_id, field_type_rev }) .build(); let _ = self.editor.update_grid_setting(params).await.unwrap(); } diff --git a/frontend/rust-lib/lib-dispatch/src/request/payload.rs b/frontend/rust-lib/lib-dispatch/src/request/payload.rs index c5d67e8413..59edcf79d2 100644 --- a/frontend/rust-lib/lib-dispatch/src/request/payload.rs +++ b/frontend/rust-lib/lib-dispatch/src/request/payload.rs @@ -5,7 +5,7 @@ pub enum PayloadError {} // TODO: support stream data #[derive(Clone)] -#[cfg_attr(feature = "user_serde", derive(serde::Serialize))] +#[cfg_attr(feature = "use_serde", derive(serde::Serialize))] pub enum Payload { None, Bytes(Bytes), diff --git a/frontend/rust-lib/lib-dispatch/src/response/response.rs b/frontend/rust-lib/lib-dispatch/src/response/response.rs index cfad0e6f85..a745f8ee1a 100644 --- a/frontend/rust-lib/lib-dispatch/src/response/response.rs +++ b/frontend/rust-lib/lib-dispatch/src/response/response.rs @@ -9,7 +9,7 @@ use derivative::*; use std::{convert::TryFrom, fmt, fmt::Formatter}; #[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "user_serde", derive(serde::Serialize))] +#[cfg_attr(feature = "use_serde", derive(serde::Serialize))] pub enum StatusCode { Ok = 0, Err = 1, @@ -18,7 +18,7 @@ pub enum StatusCode { // serde user guide: https://serde.rs/field-attrs.html #[derive(Debug, Clone, Derivative)] -#[cfg_attr(feature = "user_serde", derive(serde::Serialize))] +#[cfg_attr(feature = "use_serde", derive(serde::Serialize))] pub struct EventResponse { #[derivative(Debug = "ignore")] pub payload: Payload, diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs index 1350f6acf5..edceb25d9c 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs @@ -31,6 +31,11 @@ pub struct GridRevision { pub fields: Vec>, pub blocks: Vec>, + #[cfg(feature = "filter")] + #[serde(default)] + pub setting: GridSettingRevision, + + #[cfg(not(feature = "filter"))] #[serde(default, skip)] pub setting: GridSettingRevision, } diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs index 3ffcedb1c4..7bd18024ca 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs @@ -56,12 +56,12 @@ impl GridSettingRevision { &self, layout: &GridLayoutRevision, field_id: &str, - field_type: &FieldTypeRevision, + field_type_rev: &FieldTypeRevision, ) -> Option>> { self.filters .get(layout) .and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get(field_id)) - .and_then(|filter_rev_map| filter_rev_map.get(field_type)) + .and_then(|filter_rev_map| filter_rev_map.get(field_type_rev)) .cloned() } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 8b724d8133..839102c1fb 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -17,8 +17,8 @@ pub type GridRevisionDelta = PlainTextDelta; pub type GridRevisionDeltaBuilder = PlainTextDeltaBuilder; pub struct GridRevisionPad { - pub(crate) grid_rev: Arc, - pub(crate) delta: GridRevisionDelta, + grid_rev: Arc, + delta: GridRevisionDelta, } pub trait JsonDeserializer { @@ -358,10 +358,9 @@ impl GridRevisionPad { if is_contain { // Only return the filters for the current fields' type. - if let Some(mut t_filter_revs) = - self.grid_rev - .setting - .get_filters(layout_ty, &field_rev.id, &field_rev.field_type_rev) + let field_id = &field_rev.id; + let field_type_rev = &field_rev.field_type_rev; + if let Some(mut t_filter_revs) = self.grid_rev.setting.get_filters(layout_ty, field_id, &field_type_rev) { filter_revs.append(&mut t_filter_revs); } From 8fa7a203263f5ba9c33befa7793412a55d1c6138 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 10 Jul 2022 17:06:36 +0800 Subject: [PATCH 5/6] chore: make grid setting from revision --- .../src/entities/filter_entities/util.rs | 10 +-- .../flowy-grid/src/entities/group_entities.rs | 7 +- .../src/entities/setting_entities.rs | 68 +++++++++--------- .../flowy-grid/src/entities/sort_entities.rs | 7 +- .../flowy-grid/src/services/grid_editor.rs | 15 ++-- .../src/services/setting/setting_builder.rs | 52 +++++++++++++- .../src/revision/grid_setting_rev.rs | 72 ++++++++++++++++--- 7 files changed, 167 insertions(+), 64 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs index 32ac38f986..4a67d7ff52 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs @@ -22,16 +22,16 @@ pub struct RepeatedGridFilter { pub items: Vec, } -impl std::convert::From<&Arc> for GridFilter { - fn from(rev: &Arc) -> Self { +impl std::convert::From<&GridFilterRevision> for GridFilter { + fn from(rev: &GridFilterRevision) -> Self { Self { id: rev.id.clone() } } } -impl std::convert::From<&Vec>> for RepeatedGridFilter { - fn from(revs: &Vec>) -> Self { +impl std::convert::From>> for RepeatedGridFilter { + fn from(revs: Vec>) -> Self { RepeatedGridFilter { - items: revs.iter().map(|rev| rev.into()).collect(), + items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(), } } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs index dc090e6ea1..53d20bbc57 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs @@ -4,6 +4,7 @@ use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::GridGroupRevision; use flowy_sync::entities::grid::CreateGridGroupParams; use std::convert::TryInto; +use std::sync::Arc; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridGroup { @@ -39,10 +40,10 @@ impl std::convert::From> for RepeatedGridGroup { } } -impl std::convert::From<&Vec> for RepeatedGridGroup { - fn from(revs: &Vec) -> Self { +impl std::convert::From>> for RepeatedGridGroup { + fn from(revs: Vec>) -> Self { RepeatedGridGroup { - items: revs.iter().map(|rev| rev.into()).collect(), + items: revs.iter().map(|rev| rev.as_ref().into()).collect(), } } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index ce2d623b0c..4440b88bb7 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -1,57 +1,53 @@ use crate::entities::{ - CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, RepeatedGridFilter, - RepeatedGridGroup, RepeatedGridSort, + CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, GridFilter, GridGroup, + GridSort, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort, }; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; -use flowy_grid_data_model::revision::GridLayoutRevision; +use flowy_grid_data_model::revision::{GridLayoutRevision, GridSettingRevision}; use flowy_sync::entities::grid::GridSettingChangesetParams; use std::collections::HashMap; use std::convert::TryInto; +use strum::IntoEnumIterator; +use strum_macros::EnumIter; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridSetting { #[pb(index = 1)] - pub filters_by_layout_ty: HashMap, + pub layouts: Vec, #[pb(index = 2)] - pub groups_by_layout_ty: HashMap, + pub current_layout_type: GridLayoutType, #[pb(index = 3)] - pub sorts_by_layout_ty: HashMap, + pub filters_by_field_id: HashMap, + + #[pb(index = 4)] + pub groups_by_field_id: HashMap, + + #[pb(index = 5)] + pub sorts_by_field_id: HashMap, } -// -// impl std::convert::From<&GridSettingRevision> for GridSetting { -// fn from(rev: &GridSettingRevision) -> Self { -// let filters_by_layout_ty: HashMap = rev -// .filters -// .iter() -// .map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into())) -// .collect(); -// -// let groups_by_layout_ty: HashMap = rev -// .groups -// .iter() -// .map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into())) -// .collect(); -// -// let sorts_by_layout_ty: HashMap = rev -// .sorts -// .iter() -// .map(|(layout_rev, sort_revs)| (layout_rev.to_string(), sort_revs.into())) -// .collect(); -// -// GridSetting { -// filters_by_layout_ty, -// groups_by_layout_ty, -// sorts_by_layout_ty, -// } -// } -// } -// -#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] +#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] +pub struct GridLayout { + #[pb(index = 1)] + ty: GridLayoutType, +} + +impl GridLayout { + pub fn all() -> Vec { + let mut layouts = vec![]; + for layout_ty in GridLayoutType::iter() { + layouts.push(GridLayout { ty: layout_ty }) + } + + layouts + } +} + +#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum, EnumIter)] #[repr(u8)] pub enum GridLayoutType { Table = 0, diff --git a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs index 1f03808fa8..3a560460fe 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs @@ -4,6 +4,7 @@ use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::GridSortRevision; use flowy_sync::entities::grid::CreateGridSortParams; use std::convert::TryInto; +use std::sync::Arc; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridSort { @@ -30,10 +31,10 @@ pub struct RepeatedGridSort { pub items: Vec, } -impl std::convert::From<&Vec> for RepeatedGridSort { - fn from(revs: &Vec) -> Self { +impl std::convert::From>> for RepeatedGridSort { + fn from(revs: Vec>) -> Self { RepeatedGridSort { - items: revs.iter().map(|rev| rev.into()).collect(), + items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(), } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 152c9a8d2a..1d63b6dd69 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -11,6 +11,7 @@ use crate::services::row::{ make_grid_blocks, make_row_from_row_rev, make_row_rev_from_context, make_rows_from_row_revs, CreateRowRevisionBuilder, CreateRowRevisionPayload, GridBlockSnapshot, }; +use crate::services::setting::make_grid_setting; use bytes::Bytes; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::*; @@ -453,17 +454,21 @@ impl GridRevisionEditor { } pub async fn get_grid_setting(&self) -> FlowyResult { - // let read_guard = self.grid_pad.read().await; - // let grid_setting_rev = read_guard.get_grid_setting_rev(); - // Ok(grid_setting_rev.into()) - todo!() + let read_guard = self.grid_pad.read().await; + let grid_setting_rev = read_guard.get_grid_setting_rev(); + let field_revs = read_guard.get_field_revs(None)?; + let grid_setting = make_grid_setting(grid_setting_rev, &field_revs); + Ok(grid_setting) } pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult> { let read_guard = self.grid_pad.read().await; let layout_rev = layout_type.clone().into(); match read_guard.get_filters(Some(&layout_rev), None) { - Some(filter_revs) => Ok(filter_revs.iter().map(GridFilter::from).collect::>()), + Some(filter_revs) => Ok(filter_revs + .iter() + .map(|filter_rev| filter_rev.as_ref().into()) + .collect::>()), None => Ok(vec![]), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs index 866b0a51e6..744d319976 100644 --- a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs @@ -1,5 +1,10 @@ -use crate::entities::GridLayoutType; +use crate::entities::{ + GridLayout, GridLayoutType, GridSetting, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort, +}; +use flowy_grid_data_model::revision::{FieldRevision, GridSettingRevision}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; +use std::collections::HashMap; +use std::sync::Arc; pub struct GridSettingChangesetBuilder { params: GridSettingChangesetParams, @@ -34,3 +39,48 @@ impl GridSettingChangesetBuilder { self.params } } + +pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc]) -> GridSetting { + let current_layout_type: GridLayoutType = grid_setting_rev.layout.clone().into(); + let filters_by_field_id = grid_setting_rev + .get_all_filter(&field_revs) + .and_then(|filters_by_field_id| { + Some( + filters_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>(), + ) + }) + .unwrap_or(HashMap::default()); + let groups_by_field_id = grid_setting_rev + .get_all_group() + .and_then(|groups_by_field_id| { + Some( + groups_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>(), + ) + }) + .unwrap_or(HashMap::default()); + let sorts_by_field_id = grid_setting_rev + .get_all_sort() + .and_then(|sorts_by_field_id| { + Some( + sorts_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>(), + ) + }) + .unwrap_or(HashMap::default()); + + GridSetting { + layouts: GridLayout::all(), + current_layout_type, + filters_by_field_id, + groups_by_field_id, + sorts_by_field_id, + } +} diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs index 7bd18024ca..5cd6fc287e 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs @@ -1,8 +1,9 @@ -use crate::revision::FieldTypeRevision; +use crate::revision::{FieldRevision, FieldTypeRevision}; use indexmap::IndexMap; use nanoid::nanoid; use serde::{Deserialize, Serialize}; use serde_repr::*; +use std::collections::HashMap; use std::sync::Arc; pub fn gen_grid_filter_id() -> String { @@ -17,20 +18,33 @@ pub fn gen_grid_sort_id() -> String { nanoid!(6) } +/// Each layout contains multiple key/value. +/// Key: field_id +/// Value: this value also contains key/value. +/// Key: FieldType, +/// Value: the corresponding filter. +/// +/// This overall struct is described below: +/// GridSettingRevision +/// layout: +/// field_id: +/// FieldType: GridFilterRevision +/// FieldType: GridFilterRevision +/// field_id: +/// FieldType: GridFilterRevision +/// FieldType: GridFilterRevision +/// layout: +/// field_id: +/// FieldType: GridFilterRevision +/// FieldType: GridFilterRevision +/// +/// Group and sorts will be the same structure as filters. #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] pub struct GridSettingRevision { pub layout: GridLayoutRevision, - // layout: - // field_id: - // FieldType: GridFilterRevision - // FieldType: GridFilterRevision - // layout: - // field_id: - // FieldType: GridFilterRevision - // field_id: - // FieldType: GridFilterRevision + #[serde(with = "indexmap::serde_seq")] - pub filters: IndexMap>, + filters: IndexMap>, #[serde(skip, with = "indexmap::serde_seq")] pub groups: IndexMap>, @@ -39,7 +53,43 @@ pub struct GridSettingRevision { pub sorts: IndexMap>, } +pub type FiltersByFieldId = HashMap>>; +pub type GroupsByFieldId = HashMap>>; +pub type SortsByFieldId = HashMap>>; impl GridSettingRevision { + pub fn get_all_group(&self) -> Option { + None + } + + pub fn get_all_sort(&self) -> Option { + None + } + + /// Return the Filters of the current layout + pub fn get_all_filter(&self, field_revs: &[Arc]) -> Option { + let layout = &self.layout; + // Acquire the read lock of the filters. + let filter_rev_map_by_field_id = self.filters.get(layout)?; + // Get the filters according to the FieldType, so we need iterate the field_revs. + let filters_by_field_id = field_revs + .iter() + .flat_map(|field_rev| { + let field_type = &field_rev.field_type_rev; + let field_id = &field_rev.id; + + let filter_rev_map: &GridFilterRevisionMap = filter_rev_map_by_field_id.get(field_id)?; + let filters: Vec> = filter_rev_map.get(field_type)?.clone(); + Some((field_rev.id.clone(), filters)) + }) + .collect::(); + Some(filters_by_field_id) + } + + fn get_filter_rev_map(&self, layout: &GridLayoutRevision, field_id: &str) -> Option<&GridFilterRevisionMap> { + let filter_rev_map_by_field_id = self.filters.get(layout)?; + filter_rev_map_by_field_id.get(field_id) + } + pub fn get_mut_filters( &mut self, layout: &GridLayoutRevision, From 5bfbda5606e2139df03192a930978282a6509f78 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 10 Jul 2022 22:17:44 +0800 Subject: [PATCH 6/6] fix: decode cell revision into AnyCellData --- .../entities/filter_entities/date_filter.rs | 2 +- .../src/entities/filter_entities/util.rs | 9 +++- .../src/entities/setting_entities.rs | 6 +-- .../rust-lib/flowy-grid/src/event_handler.rs | 9 +++- .../src/services/cell/any_cell_data.rs | 19 ++------ .../src/services/cell/cell_operation.rs | 5 ++- .../src/services/field/select_option.rs | 4 +- .../field/type_options/date_type_option.rs | 2 +- .../field/type_options/text_type_option.rs | 2 +- .../field/type_options/url_type_option.rs | 2 +- .../field/type_options/util/cell_data_util.rs | 2 +- .../src/services/filter/impls/date_filter.rs | 2 +- .../services/filter/impls/number_filter.rs | 2 +- .../src/services/setting/setting_builder.rs | 44 ++++++++----------- .../flowy-grid/tests/grid/filter_test/mod.rs | 2 +- .../tests/grid/filter_test/script.rs | 8 ++-- .../{test.rs => text_filter_test.rs} | 14 +++--- .../rust-lib/flowy-grid/tests/grid/script.rs | 30 +++++++------ .../src/revision/grid_setting_rev.rs | 1 + .../src/client_grid/grid_revision_pad.rs | 4 +- shared-lib/flowy-sync/src/entities/grid.rs | 1 + .../src/code_gen/protobuf_file/mod.rs | 10 ++--- 22 files changed, 93 insertions(+), 87 deletions(-) rename frontend/rust-lib/flowy-grid/tests/grid/filter_test/{test.rs => text_filter_test.rs} (75%) diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs index eed2fa56bd..936b95216c 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs @@ -74,7 +74,7 @@ struct DateRange { impl ToString for DateRange { fn to_string(&self) -> String { - serde_json::to_string(self).unwrap_or("".to_string()) + serde_json::to_string(self).unwrap_or_else(|_| "".to_string()) } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs index 4a67d7ff52..bc520dea54 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs @@ -45,9 +45,12 @@ impl std::convert::From> for RepeatedGridFilter { #[derive(ProtoBuf, Debug, Default, Clone)] pub struct DeleteFilterPayload { #[pb(index = 1)] - pub filter_id: String, + pub field_id: String, #[pb(index = 2)] + pub filter_id: String, + + #[pb(index = 3)] pub field_type: FieldType, } @@ -55,10 +58,14 @@ impl TryInto for DeleteFilterPayload { type Error = ErrorCode; fn try_into(self) -> Result { + let field_id = NotEmptyStr::parse(self.field_id) + .map_err(|_| ErrorCode::FieldIdIsEmpty)? + .0; let filter_id = NotEmptyStr::parse(self.filter_id) .map_err(|_| ErrorCode::UnexpectedEmptyString)? .0; Ok(DeleteFilterParams { + field_id, filter_id, field_type_rev: self.field_type.into(), }) diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 4440b88bb7..740ab38def 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -1,11 +1,11 @@ use crate::entities::{ - CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, GridFilter, GridGroup, - GridSort, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort, + CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, RepeatedGridFilter, + RepeatedGridGroup, RepeatedGridSort, }; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; -use flowy_grid_data_model::revision::{GridLayoutRevision, GridSettingRevision}; +use flowy_grid_data_model::revision::GridLayoutRevision; use flowy_sync::entities::grid::GridSettingChangesetParams; use std::collections::HashMap; use std::convert::TryInto; diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index d45d5e31c7..7d470bdfb9 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -363,9 +363,16 @@ pub(crate) async fn get_select_option_handler( data_result(SelectOptionCellData::default()) } Some(field_rev) => { + // let cell_rev = editor.get_cell_rev(¶ms.row_id, ¶ms.field_id).await?; let type_option = select_option_operation(&field_rev)?; - let any_cell_data: AnyCellData = cell_rev.try_into()?; + let any_cell_data: AnyCellData = match cell_rev { + None => AnyCellData { + data: "".to_string(), + field_type: field_rev.field_type_rev.clone().into(), + }, + Some(cell_rev) => cell_rev.try_into()?, + }; let option_context = type_option.selected_select_option(any_cell_data); data_result(option_context) } diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs index 8caeafd1ac..259fcc79ef 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs @@ -9,7 +9,7 @@ use std::str::FromStr; /// So it will return an empty data. You could check the CellDataOperation trait for more information. #[derive(Debug, Serialize, Deserialize)] pub struct AnyCellData { - pub cell_data: String, + pub data: String, pub field_type: FieldType, } @@ -38,21 +38,10 @@ impl std::convert::TryFrom<&CellRevision> for AnyCellData { } } -impl std::convert::TryFrom<&Option> for AnyCellData { +impl std::convert::TryFrom for AnyCellData { type Error = FlowyError; - fn try_from(value: &Option) -> Result { - match value { - None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")), - Some(cell_rev) => AnyCellData::try_from(cell_rev), - } - } -} - -impl std::convert::TryFrom> for AnyCellData { - type Error = FlowyError; - - fn try_from(value: Option) -> Result { + fn try_from(value: CellRevision) -> Result { Self::try_from(&value) } } @@ -60,7 +49,7 @@ impl std::convert::TryFrom> for AnyCellData { impl AnyCellData { pub fn new(content: String, field_type: FieldType) -> Self { AnyCellData { - cell_data: content, + data: content, field_type, } } diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index c866f2a167..5b74c26aa4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -51,7 +51,10 @@ pub fn apply_cell_data_changeset>( pub fn decode_any_cell_data>(data: T, field_rev: &FieldRevision) -> DecodedCellData { if let Ok(any_cell_data) = data.try_into() { - let AnyCellData { cell_data, field_type } = any_cell_data; + let AnyCellData { + data: cell_data, + field_type, + } = any_cell_data; let to_field_type = field_rev.field_type_rev.into(); match try_decode_cell_data(CellData(Some(cell_data)), field_rev, &field_type, &to_field_type) { Ok(cell_data) => cell_data, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs index e4b3d0f3d6..3e974e9f56 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs @@ -65,7 +65,7 @@ pub fn make_selected_select_options>( options: &[SelectOption], ) -> Vec { if let Ok(type_option_cell_data) = any_cell_data.try_into() { - let ids = SelectOptionIds::from(type_option_cell_data.cell_data); + let ids = SelectOptionIds::from(type_option_cell_data.data); ids.iter() .flat_map(|option_id| options.iter().find(|option| &option.id == option_id).cloned()) .collect() @@ -151,7 +151,7 @@ impl std::convert::TryFrom for SelectOptionIds { type Error = FlowyError; fn try_from(value: AnyCellData) -> Result { - Ok(Self::from(value.cell_data)) + Ok(Self::from(value.data)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index fb9844441b..2200dad63c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -187,7 +187,7 @@ impl FromCellString for DateTimestamp { impl std::convert::From for DateTimestamp { fn from(data: AnyCellData) -> Self { - let num = data.cell_data.parse::().unwrap_or(0); + let num = data.data.parse::().unwrap_or(0); DateTimestamp(num) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index e26c7d3b16..a23366e2a4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -76,7 +76,7 @@ impl std::convert::TryFrom for TextCellData { type Error = FlowyError; fn try_from(value: AnyCellData) -> Result { - Ok(TextCellData(value.cell_data)) + Ok(TextCellData(value.data)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs index 5b1fa2319f..74fc9fc26b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs @@ -114,7 +114,7 @@ impl std::convert::TryFrom for URLCellData { type Error = FlowyError; fn try_from(data: AnyCellData) -> Result { - serde_json::from_str::(&data.cell_data).map_err(internal_error) + serde_json::from_str::(&data.data).map_err(internal_error) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs index c8170e5fad..549f502bb0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs @@ -4,7 +4,7 @@ use std::str::FromStr; pub fn get_cell_data(cell_rev: &CellRevision) -> String { match AnyCellData::from_str(&cell_rev.data) { - Ok(type_option) => type_option.cell_data, + Ok(type_option) => type_option.data, Err(_) => String::new(), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs index 512dbe2aff..ae920c4edb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs @@ -24,7 +24,7 @@ impl GridDateFilter { false } } - DateFilterCondition::DateIsEmpty => cell_timestamp == (0 as i64), + DateFilterCondition::DateIsEmpty => cell_timestamp == 0_i64, } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs index 7b4c12d7cf..7f3a5dd212 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs @@ -37,7 +37,7 @@ impl CellFilterOperation for NumberTypeOption { return Ok(true); } - let cell_data = any_cell_data.cell_data; + let cell_data = any_cell_data.data; let num_cell_data = self.format_cell_data(&cell_data)?; Ok(filter.is_visible(&num_cell_data)) diff --git a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs index 744d319976..6880db5277 100644 --- a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs @@ -43,38 +43,32 @@ impl GridSettingChangesetBuilder { pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc]) -> GridSetting { let current_layout_type: GridLayoutType = grid_setting_rev.layout.clone().into(); let filters_by_field_id = grid_setting_rev - .get_all_filter(&field_revs) - .and_then(|filters_by_field_id| { - Some( - filters_by_field_id - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::>(), - ) + .get_all_filter(field_revs) + .map(|filters_by_field_id| { + filters_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>() }) - .unwrap_or(HashMap::default()); + .unwrap_or_default(); let groups_by_field_id = grid_setting_rev .get_all_group() - .and_then(|groups_by_field_id| { - Some( - groups_by_field_id - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::>(), - ) + .map(|groups_by_field_id| { + groups_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>() }) - .unwrap_or(HashMap::default()); + .unwrap_or_default(); let sorts_by_field_id = grid_setting_rev .get_all_sort() - .and_then(|sorts_by_field_id| { - Some( - sorts_by_field_id - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::>(), - ) + .map(|sorts_by_field_id| { + sorts_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::>() }) - .unwrap_or(HashMap::default()); + .unwrap_or_default(); GridSetting { layouts: GridLayout::all(), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs index 63d424afaf..4c6980c527 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs @@ -1,2 +1,2 @@ mod script; -mod test; +mod text_filter_test; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs index c63ebc0d9c..d89b6a66a1 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -5,7 +5,7 @@ use flowy_grid::entities::{CreateGridFilterPayload, GridLayoutType, GridSetting}; use flowy_grid::services::setting::GridSettingChangesetBuilder; -use flowy_grid_data_model::revision::FieldTypeRevision; +use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; use crate::grid::script::GridEditorTest; @@ -22,7 +22,7 @@ pub enum FilterScript { }, DeleteGridTableFilter { filter_id: String, - field_type_rev: FieldTypeRevision, + field_rev: FieldRevision, }, #[allow(dead_code)] AssertGridSetting { @@ -67,10 +67,10 @@ impl GridFilterTest { let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); assert_eq!(count as usize, filters.len()); } - FilterScript::DeleteGridTableFilter { filter_id ,field_type_rev} => { + FilterScript::DeleteGridTableFilter { filter_id, field_rev} => { let layout_type = GridLayoutType::Table; let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .delete_filter(DeleteFilterParams { filter_id, field_type_rev }) + .delete_filter(DeleteFilterParams { field_id: field_rev.id, filter_id, field_type_rev: field_rev.field_type_rev }) .build(); let _ = self.editor.update_grid_setting(params).await.unwrap(); } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs similarity index 75% rename from frontend/rust-lib/flowy-grid/tests/grid/filter_test/test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs index 34e1ef69b0..29614b21b2 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs @@ -16,9 +16,10 @@ async fn grid_filter_create_test() { #[should_panic] async fn grid_filter_invalid_condition_panic_test() { let mut test = GridFilterTest::new().await; + let field_rev = test.text_field().clone(); // 100 is not a valid condition, so this test should be panic. - let payload = create_filter(&test, "abc"); + let payload = CreateGridFilterPayload::new(&field_rev, 100, Some("".to_owned())); let scripts = vec![InsertGridTableFilter { payload }]; test.run_scripts(scripts).await; } @@ -26,16 +27,16 @@ async fn grid_filter_invalid_condition_panic_test() { #[tokio::test] async fn grid_filter_delete_test() { let mut test = GridFilterTest::new().await; - let payload = create_filter(&test, "abc"); + let field_rev = test.text_field().clone(); + let payload = create_filter(&field_rev, TextFilterCondition::TextIsEmpty, "abc"); let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; test.run_scripts(scripts).await; let filter = test.grid_filters().await.pop().unwrap(); - test.run_scripts(vec![ DeleteGridTableFilter { filter_id: filter.id, - field_type_rev: field_rev.field_type_rev.clone(), + field_rev, }, AssertTableFilterCount { count: 0 }, ]) @@ -45,7 +46,6 @@ async fn grid_filter_delete_test() { #[tokio::test] async fn grid_filter_get_rows_test() {} -fn create_filter(grid_filter_test: &GridFilterTest, s: &str) -> CreateGridFilterPayload { - let field_rev = grid_filter_test.text_field(); - CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some(s.to_owned())) +fn create_filter(field_rev: &FieldRevision, condition: TextFilterCondition, s: &str) -> CreateGridFilterPayload { + CreateGridFilterPayload::new(field_rev, condition, Some(s.to_owned())) } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs index f25e859450..915749fb0e 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -1,16 +1,19 @@ -#![cfg_attr(rustfmt, rustfmt::skip)] #![allow(clippy::all)] #![allow(dead_code)] #![allow(unused_imports)] use bytes::Bytes; +use flowy_grid::entities::*; +use flowy_grid::services::field::select_option::SelectOption; use flowy_grid::services::field::*; use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; use flowy_grid::services::row::CreateRowRevisionPayload; use flowy_grid::services::setting::GridSettingChangesetBuilder; -use flowy_grid::entities::*; use flowy_grid_data_model::revision::*; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; use flowy_sync::client_grid::GridBuilder; +use flowy_sync::entities::grid::{ + CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams, +}; use flowy_test::helper::ViewTest; use flowy_test::FlowySDKTest; use std::collections::HashMap; @@ -18,8 +21,6 @@ use std::sync::Arc; use std::time::Duration; use strum::EnumCount; use tokio::time::sleep; -use flowy_grid::services::field::select_option::SelectOption; -use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams}; pub enum EditorScript { CreateField { @@ -82,7 +83,7 @@ pub enum EditorScript { }, DeleteGridTableFilter { filter_id: String, - field_type_rev: FieldTypeRevision, + field_rev: FieldRevision, }, #[allow(dead_code)] AssertGridSetting { @@ -170,10 +171,7 @@ impl GridEditorTest { assert_eq!(self.field_count, self.field_revs.len()); } EditorScript::AssertFieldCount(count) => { - assert_eq!( - self.editor.get_field_revs(None).await.unwrap().len(), - count - ); + assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count); } EditorScript::AssertFieldEqual { field_index, field_rev } => { let field_revs = self.editor.get_field_revs(None).await.unwrap(); @@ -204,14 +202,16 @@ impl GridEditorTest { } EditorScript::CreateEmptyRow => { let row_order = self.editor.create_row(None).await.unwrap(); - self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order); + self.row_order_by_row_id + .insert(row_order.row_id().to_owned(), row_order); self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); } EditorScript::CreateRow { payload: context } => { let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); for row_order in row_orders { - self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order); + self.row_order_by_row_id + .insert(row_order.row_id().to_owned(), row_order); } self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); @@ -271,10 +271,14 @@ impl GridEditorTest { let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); assert_eq!(count as usize, filters.len()); } - EditorScript::DeleteGridTableFilter { filter_id ,field_type_rev} => { + EditorScript::DeleteGridTableFilter { filter_id, field_rev } => { let layout_type = GridLayoutType::Table; let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .delete_filter(DeleteFilterParams { filter_id, field_type_rev }) + .delete_filter(DeleteFilterParams { + field_id: field_rev.id, + filter_id, + field_type_rev: field_rev.field_type_rev, + }) .build(); let _ = self.editor.update_grid_setting(params).await.unwrap(); } diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs index 5cd6fc287e..d29d9d767b 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs @@ -85,6 +85,7 @@ impl GridSettingRevision { Some(filters_by_field_id) } + #[allow(dead_code)] fn get_filter_rev_map(&self, layout: &GridLayoutRevision, field_id: &str) -> Option<&GridFilterRevisionMap> { let filter_rev_map_by_field_id = self.filters.get(layout)?; filter_rev_map_by_field_id.get(field_id) diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 839102c1fb..e47305f7fa 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -360,7 +360,7 @@ impl GridRevisionPad { // Only return the filters for the current fields' type. let field_id = &field_rev.id; let field_type_rev = &field_rev.field_type_rev; - if let Some(mut t_filter_revs) = self.grid_rev.setting.get_filters(layout_ty, field_id, &field_type_rev) + if let Some(mut t_filter_revs) = self.grid_rev.setting.get_filters(layout_ty, field_id, field_type_rev) { filter_revs.append(&mut t_filter_revs); } @@ -395,7 +395,7 @@ impl GridRevisionPad { if let Some(params) = changeset.delete_filter { match grid_rev .setting - .get_mut_filters(&layout_rev, ¶ms.filter_id, ¶ms.field_type_rev) + .get_mut_filters(&layout_rev, ¶ms.field_id, ¶ms.field_type_rev) { Some(filters) => { filters.retain(|filter| filter.id != params.filter_id); diff --git a/shared-lib/flowy-sync/src/entities/grid.rs b/shared-lib/flowy-sync/src/entities/grid.rs index 866562ccd6..fc3c14b4fb 100644 --- a/shared-lib/flowy-sync/src/entities/grid.rs +++ b/shared-lib/flowy-sync/src/entities/grid.rs @@ -24,6 +24,7 @@ pub struct CreateGridFilterParams { } pub struct DeleteFilterParams { + pub field_id: String, pub filter_id: String, pub field_type_rev: FieldTypeRevision, } diff --git a/shared-lib/lib-infra/src/code_gen/protobuf_file/mod.rs b/shared-lib/lib-infra/src/code_gen/protobuf_file/mod.rs index 3641b4729f..5f293e5e2c 100644 --- a/shared-lib/lib-infra/src/code_gen/protobuf_file/mod.rs +++ b/shared-lib/lib-infra/src/code_gen/protobuf_file/mod.rs @@ -114,12 +114,12 @@ fn generate_dart_protobuf_files( check_pb_dart_plugin(); let protoc_bin_path = protoc_bin_path.to_str().unwrap().to_owned(); paths.iter().for_each(|path| { - if cmd_lib::run_cmd! { + let result = cmd_lib::run_cmd! { ${protoc_bin_path} --dart_out=${output} --proto_path=${proto_file_output_path} ${path} - } - .is_err() - { - panic!("Generate dart pb file failed with: {}", path) + }; + + if result.is_err() { + panic!("Generate dart pb file failed with: {}, {:?}", path, result) }; });