Browse Source

chore: config cell filter operation

appflowy 2 years ago
parent
commit
5b504740ef

+ 2 - 2
frontend/rust-lib/flowy-grid/src/macros.rs

@@ -30,7 +30,7 @@ macro_rules! impl_type_option {
     ($target: ident, $field_type:expr) => {
         impl std::convert::From<&FieldRevision> for $target {
             fn from(field_rev: &FieldRevision) -> $target {
-                match field_rev.get_type_option_entry::<$target, _>(&$field_type) {
+                match field_rev.get_type_option_entry::<$target>($field_type.into()) {
                     None => $target::default(),
                     Some(target) => target,
                 }
@@ -39,7 +39,7 @@ macro_rules! impl_type_option {
 
         impl std::convert::From<&std::sync::Arc<FieldRevision>> for $target {
             fn from(field_rev: &std::sync::Arc<FieldRevision>) -> $target {
-                match field_rev.get_type_option_entry::<$target, _>(&$field_type) {
+                match field_rev.get_type_option_entry::<$target>($field_type.into()) {
                     None => $target::default(),
                     Some(target) => target,
                 }

+ 27 - 19
frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs

@@ -1,7 +1,9 @@
 use crate::entities::{FieldType, GridCheckboxFilter};
 use crate::impl_type_option;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData};
+use crate::services::row::{
+    AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -40,12 +42,18 @@ impl_type_option!(CheckboxTypeOption, FieldType::Checkbox);
 const YES: &str = "Yes";
 const NO: &str = "No";
 
-impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
+impl CellFilterOperation<GridCheckboxFilter, CheckboxCellData> for CheckboxTypeOption {
+    fn apply_filter(&self, cell_data: CheckboxCellData, filter: &GridCheckboxFilter) -> bool {
+        return false;
+    }
+}
+
+impl CellDataOperation<String> for CheckboxTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<String>,
@@ -54,7 +62,7 @@ impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
             return Ok(DecodedCellData::default());
         }
 
-        let encoded_data = encoded_data.into();
+        let encoded_data = cell_data.into();
         if encoded_data == YES || encoded_data == NO {
             return Ok(DecodedCellData::new(encoded_data));
         }
@@ -62,13 +70,6 @@ impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
         Ok(DecodedCellData::default())
     }
 
-    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridCheckboxFilter) -> bool
-    where
-        T: Into<String>,
-    {
-        todo!()
-    }
-
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,
@@ -95,12 +96,19 @@ fn string_to_bool(bool_str: &str) -> bool {
     }
 }
 
+pub struct CheckboxCellData(String);
+impl std::convert::From<AnyCellData> for CheckboxCellData {
+    fn from(any_cell_data: AnyCellData) -> Self {
+        CheckboxCellData(any_cell_data.cell_data)
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::services::field::type_options::checkbox_type_option::{NO, YES};
 
     use crate::services::field::FieldBuilder;
-    use crate::services::row::{apply_cell_data_changeset, decode_cell_data};
+    use crate::services::row::{apply_cell_data_changeset, decode_any_cell_data};
 
     use crate::entities::FieldType;
 
@@ -108,21 +116,21 @@ mod tests {
     fn checkout_box_description_test() {
         let field_rev = FieldBuilder::from_field_type(&FieldType::Checkbox).build();
         let data = apply_cell_data_changeset("true", None, &field_rev).unwrap();
-        assert_eq!(decode_cell_data(data, &field_rev).to_string(), YES);
+        assert_eq!(decode_any_cell_data(data, &field_rev).to_string(), YES);
 
         let data = apply_cell_data_changeset("1", None, &field_rev).unwrap();
-        assert_eq!(decode_cell_data(data, &field_rev,).to_string(), YES);
+        assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES);
 
         let data = apply_cell_data_changeset("yes", None, &field_rev).unwrap();
-        assert_eq!(decode_cell_data(data, &field_rev,).to_string(), YES);
+        assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES);
 
         let data = apply_cell_data_changeset("false", None, &field_rev).unwrap();
-        assert_eq!(decode_cell_data(data, &field_rev,).to_string(), NO);
+        assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO);
 
         let data = apply_cell_data_changeset("no", None, &field_rev).unwrap();
-        assert_eq!(decode_cell_data(data, &field_rev,).to_string(), NO);
+        assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO);
 
         let data = apply_cell_data_changeset("12", None, &field_rev).unwrap();
-        assert_eq!(decode_cell_data(data, &field_rev,).to_string(), NO);
+        assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO);
     }
 }

+ 13 - 11
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs

@@ -2,7 +2,9 @@ use crate::entities::{CellChangeset, FieldType, GridDateFilter};
 use crate::entities::{CellIdentifier, CellIdentifierPayload};
 use crate::impl_type_option;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData};
+use crate::services::row::{
+    AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use bytes::Bytes;
 use chrono::format::strftime::StrftimeItems;
 use chrono::{NaiveDateTime, Timelike};
@@ -115,12 +117,18 @@ impl DateTypeOption {
     }
 }
 
-impl CellDataOperation<String, GridDateFilter> for DateTypeOption {
+impl CellFilterOperation<GridDateFilter, AnyCellData> for DateTypeOption {
+    fn apply_filter(&self, cell_data: AnyCellData, filter: &GridDateFilter) -> bool {
+        return false;
+    }
+}
+
+impl CellDataOperation<String> for DateTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<String>,
@@ -133,16 +141,10 @@ impl CellDataOperation<String, GridDateFilter> for DateTypeOption {
             return Ok(DecodedCellData::default());
         }
 
-        let timestamp = encoded_data.into().parse::<i64>().unwrap_or(0);
+        let timestamp = cell_data.into().parse::<i64>().unwrap_or(0);
         let date = self.today_desc_from_timestamp(timestamp);
         DecodedCellData::try_from_bytes(date)
     }
-    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridDateFilter) -> bool
-    where
-        T: Into<String>,
-    {
-        todo!()
-    }
 
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where

+ 45 - 11
frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs

@@ -3,7 +3,9 @@ use crate::impl_type_option;
 use crate::entities::{FieldType, GridNumberFilter};
 use crate::services::field::type_options::number_type_option::format::*;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData};
+use crate::services::row::{
+    AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -138,13 +140,19 @@ impl NumberTypeOption {
         s
     }
 }
+impl CellFilterOperation<GridNumberFilter, AnyCellData> for NumberTypeOption {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridNumberFilter) -> bool {
+        let number_cell_data = NumberCellData::from_number_type_option(self, any_cell_data);
+        return false;
+    }
+}
 
-impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
+impl CellDataOperation<String> for NumberTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<String>,
@@ -153,7 +161,7 @@ impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
             return Ok(DecodedCellData::default());
         }
 
-        let cell_data = encoded_data.into();
+        let cell_data = cell_data.into();
         match self.format {
             NumberFormat::Num => {
                 if let Ok(v) = cell_data.parse::<f64>() {
@@ -178,12 +186,6 @@ impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
             }
         }
     }
-    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridNumberFilter) -> bool
-    where
-        T: Into<String>,
-    {
-        todo!()
-    }
 
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
@@ -210,6 +212,38 @@ impl std::default::Default for NumberTypeOption {
     }
 }
 
+#[derive(Default)]
+pub struct NumberCellData(String);
+
+impl NumberCellData {
+    fn from_number_type_option(type_option: &NumberTypeOption, any_cell_data: AnyCellData) -> Self {
+        let cell_data = any_cell_data.cell_data;
+        match type_option.format {
+            NumberFormat::Num => {
+                if let Ok(v) = cell_data.parse::<f64>() {
+                    return Self(v.to_string());
+                }
+
+                if let Ok(v) = cell_data.parse::<i64>() {
+                    return Self(v.to_string());
+                }
+
+                Self::default()
+            }
+            NumberFormat::Percent => {
+                let content = cell_data.parse::<f64>().map_or(String::new(), |v| v.to_string());
+                Self(content)
+            }
+            _ => {
+                let content = type_option
+                    .money_from_number_str(&cell_data)
+                    .unwrap_or_else(|_| "".to_string());
+                Self(content)
+            }
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;

+ 32 - 26
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs

@@ -3,7 +3,9 @@ use crate::entities::{CellIdentifier, CellIdentifierPayload};
 use crate::impl_type_option;
 use crate::services::field::type_options::util::get_cell_data;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData};
+use crate::services::row::{
+    AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
@@ -95,12 +97,18 @@ impl SelectOptionOperation for SingleSelectTypeOption {
     }
 }
 
-impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOption {
+impl CellFilterOperation<GridSelectOptionFilter, SelectOptionIds> for SingleSelectTypeOption {
+    fn apply_filter(&self, cell_data: SelectOptionIds, filter: &GridSelectOptionFilter) -> bool {
+        return false;
+    }
+}
+
+impl CellDataOperation<String> for SingleSelectTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<String>,
@@ -109,7 +117,7 @@ impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOptio
             return Ok(DecodedCellData::default());
         }
 
-        let encoded_data = encoded_data.into();
+        let encoded_data = cell_data.into();
         let mut cell_data = SelectOptionCellData {
             options: self.options.clone(),
             select_options: vec![],
@@ -123,13 +131,6 @@ impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOptio
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridSelectOptionFilter) -> bool
-    where
-        T: Into<String>,
-    {
-        todo!()
-    }
-
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,
@@ -199,13 +200,17 @@ impl SelectOptionOperation for MultiSelectTypeOption {
         &mut self.options
     }
 }
-
-impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption {
+impl CellFilterOperation<GridSelectOptionFilter, SelectOptionIds> for MultiSelectTypeOption {
+    fn apply_filter(&self, cell_data: SelectOptionIds, filter: &GridSelectOptionFilter) -> bool {
+        return false;
+    }
+}
+impl CellDataOperation<String> for MultiSelectTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<String>,
@@ -214,7 +219,7 @@ impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption
             return Ok(DecodedCellData::default());
         }
 
-        let encoded_data = encoded_data.into();
+        let encoded_data = cell_data.into();
         let select_options = select_option_ids(encoded_data)
             .into_iter()
             .flat_map(|option_id| self.options.iter().find(|option| option.id == option_id).cloned())
@@ -228,13 +233,6 @@ impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridSelectOptionFilter) -> bool
-    where
-        T: Into<String>,
-    {
-        todo!()
-    }
-
     fn apply_changeset<T>(&self, changeset: T, cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         T: Into<CellContentChangeset>,
@@ -292,6 +290,14 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
     }
 }
 
+pub struct SelectOptionIds(Vec<String>);
+impl std::convert::From<AnyCellData> for SelectOptionIds {
+    fn from(any_cell_data: AnyCellData) -> Self {
+        let ids = select_option_ids(any_cell_data.cell_data);
+        Self(ids)
+    }
+}
+
 fn select_option_ids(data: String) -> Vec<String> {
     data.split(SELECTION_IDS_SEPARATOR)
         .map(|id| id.to_string())
@@ -503,8 +509,8 @@ fn make_select_context_from(cell_rev: &Option<CellRevision>, options: &[SelectOp
     match cell_rev {
         None => vec![],
         Some(cell_rev) => {
-            if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&cell_rev.data) {
-                select_option_ids(type_option_cell_data.data)
+            if let Ok(type_option_cell_data) = AnyCellData::from_str(&cell_rev.data) {
+                select_option_ids(type_option_cell_data.cell_data)
                     .into_iter()
                     .flat_map(|option_id| options.iter().find(|option| option.id == option_id).cloned())
                     .collect()

+ 20 - 12
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs

@@ -1,7 +1,9 @@
 use crate::entities::{FieldType, GridTextFilter};
 use crate::impl_type_option;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{try_decode_cell_data, CellContentChangeset, CellDataOperation, DecodedCellData};
+use crate::services::row::{
+    try_decode_cell_data, AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -30,10 +32,16 @@ pub struct RichTextTypeOption {
 }
 impl_type_option!(RichTextTypeOption, FieldType::RichText);
 
-impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
+impl CellFilterOperation<GridTextFilter, TextCellData> for RichTextTypeOption {
+    fn apply_filter(&self, cell_data: TextCellData, filter: &GridTextFilter) -> bool {
+        return false;
+    }
+}
+
+impl CellDataOperation<String> for RichTextTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
         field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
@@ -45,20 +53,13 @@ impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
             || decoded_field_type.is_multi_select()
             || decoded_field_type.is_number()
         {
-            try_decode_cell_data(encoded_data.into(), field_rev, decoded_field_type, decoded_field_type)
+            try_decode_cell_data(cell_data.into(), field_rev, decoded_field_type, decoded_field_type)
         } else {
-            let cell_data = encoded_data.into();
+            let cell_data = cell_data.into();
             Ok(DecodedCellData::new(cell_data))
         }
     }
 
-    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridTextFilter) -> bool
-    where
-        T: Into<String>,
-    {
-        todo!()
-    }
-
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,
@@ -72,6 +73,13 @@ impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
     }
 }
 
+pub struct TextCellData(String);
+impl std::convert::From<AnyCellData> for TextCellData {
+    fn from(any_data: AnyCellData) -> Self {
+        TextCellData(any_data.cell_data)
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;

+ 19 - 9
frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs

@@ -1,7 +1,9 @@
 use crate::entities::{FieldType, GridTextFilter};
 use crate::impl_type_option;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, EncodedCellData};
+use crate::services::row::{
+    AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, EncodedCellData,
+};
 use bytes::Bytes;
 use fancy_regex::Regex;
 use flowy_derive::ProtoBuf;
@@ -33,12 +35,18 @@ pub struct URLTypeOption {
 }
 impl_type_option!(URLTypeOption, FieldType::URL);
 
-impl CellDataOperation<EncodedCellData<URLCellData>, GridTextFilter> for URLTypeOption {
+impl CellFilterOperation<GridTextFilter, URLCellData> for URLTypeOption {
+    fn apply_filter(&self, cell_data: URLCellData, filter: &GridTextFilter) -> bool {
+        return false;
+    }
+}
+
+impl CellDataOperation<EncodedCellData<URLCellData>> for URLTypeOption {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
+        field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<EncodedCellData<URLCellData>>,
@@ -46,14 +54,10 @@ impl CellDataOperation<EncodedCellData<URLCellData>, GridTextFilter> for URLType
         if !decoded_field_type.is_url() {
             return Ok(DecodedCellData::default());
         }
-        let cell_data = encoded_data.into().try_into_inner()?;
+        let cell_data = cell_data.into().try_into_inner()?;
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_filter(&self, _filter: &GridTextFilter) -> bool {
-        todo!()
-    }
-
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,
@@ -117,6 +121,12 @@ impl FromStr for URLCellData {
     }
 }
 
+impl std::convert::From<AnyCellData> for URLCellData {
+    fn from(any_cell_data: AnyCellData) -> Self {
+        URLCellData::from_str(&any_cell_data.cell_data).unwrap_or(URLCellData::default())
+    }
+}
+
 lazy_static! {
     static ref URL_REGEX: Regex = Regex::new(
         "[(http(s)?):\\/\\/(www\\.)?a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)"

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/field/type_options/util.rs

@@ -1,10 +1,10 @@
-use crate::services::row::TypeOptionCellData;
+use crate::services::row::AnyCellData;
 use flowy_grid_data_model::revision::CellRevision;
 use std::str::FromStr;
 
 pub fn get_cell_data(cell_rev: &CellRevision) -> String {
-    match TypeOptionCellData::from_str(&cell_rev.data) {
-        Ok(type_option) => type_option.data,
+    match AnyCellData::from_str(&cell_rev.data) {
+        Ok(type_option) => type_option.cell_data,
         Err(_) => String::new(),
     }
 }

+ 8 - 8
frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs

@@ -37,7 +37,7 @@ impl std::ops::Deref for FilterResultCache {
 pub(crate) struct FilterResult {
     pub(crate) row_id: String,
     pub(crate) row_index: i32,
-    pub(crate) cell_by_field_id: HashMap<String, bool>,
+    pub(crate) visible_by_field_id: HashMap<FilterId, bool>,
 }
 
 impl FilterResult {
@@ -45,17 +45,17 @@ impl FilterResult {
         Self {
             row_index: index,
             row_id: row_rev.id.clone(),
-            cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
+            visible_by_field_id: HashMap::new(),
         }
     }
 
-    #[allow(dead_code)]
-    fn update_cell(&mut self, cell_id: &str, exist: bool) {
-        self.cell_by_field_id.insert(cell_id.to_owned(), exist);
-    }
-
     pub(crate) fn is_visible(&self) -> bool {
-        todo!()
+        for (_, visible) in &self.visible_by_field_id {
+            if visible == &false {
+                return false;
+            }
+        }
+        return true;
     }
 }
 

+ 102 - 39
frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs

@@ -1,12 +1,15 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::entities::{FieldType, GridBlockChangeset, GridTextFilter};
 use crate::services::block_manager::GridBlockManager;
-use crate::services::field::RichTextTypeOption;
+use crate::services::field::{
+    CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption,
+    SingleSelectTypeOption, URLTypeOption,
+};
 use crate::services::filter::filter_cache::{
     reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
 };
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::row::{CellDataOperation, GridBlockSnapshot};
+use crate::services::row::{AnyCellData, CellDataOperation, CellFilterOperation, GridBlockSnapshot};
 use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
 use dashmap::mapref::one::{Ref, RefMut};
 use flowy_error::FlowyResult;
@@ -60,23 +63,28 @@ impl GridFilterService {
 
         let mut changesets = vec![];
         for (index, block) in task_context.blocks.into_iter().enumerate() {
-            let results = block
+            let row_ids = block
                 .row_revs
                 .par_iter()
-                .map(|row_rev| {
+                .flat_map(|row_rev| {
                     let filter_result_cache = self.filter_result_cache.clone();
                     let filter_cache = self.filter_cache.clone();
                     filter_row(index, row_rev, filter_cache, filter_result_cache, &field_revs)
                 })
-                .collect::<Vec<FilterResult>>();
+                .collect::<Vec<String>>();
 
             let mut visible_rows = vec![];
             let mut hide_rows = vec![];
-            for result in results {
-                if result.is_visible() {
-                    visible_rows.push(result.row_id);
+            for row_id in row_ids {
+                if self
+                    .filter_result_cache
+                    .get(&row_id)
+                    .map(|result| result.is_visible())
+                    .unwrap_or(false)
+                {
+                    visible_rows.push(row_id);
                 } else {
-                    hide_rows.push(result.row_id);
+                    hide_rows.push(row_id);
                 }
             }
 
@@ -134,32 +142,31 @@ impl GridFilterService {
     }
 }
 
+// Return None if there is no change in this row after applying the filter
 fn filter_row(
     index: usize,
     row_rev: &Arc<RowRevision>,
     filter_cache: Arc<FilterCache>,
     filter_result_cache: Arc<FilterResultCache>,
     field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
-) -> FilterResult {
-    match filter_result_cache.get_mut(&row_rev.id) {
-        None => {
-            let mut filter_result = FilterResult::new(index as i32, row_rev);
-            for (field_id, cell_rev) in row_rev.cells.iter() {
-                let _ = update_filter_result(field_revs, &mut filter_result, &filter_cache, field_id, cell_rev);
-            }
-            filter_result_cache.insert(row_rev.id.clone(), filter_result);
-        }
-        Some(mut result) => {
-            for (field_id, cell_rev) in row_rev.cells.iter() {
-                let _ = update_filter_result(field_revs, result.value_mut(), &filter_cache, field_id, cell_rev);
+) -> Option<String> {
+    let mut result = filter_result_cache
+        .entry(row_rev.id.clone())
+        .or_insert(FilterResult::new(index as i32, row_rev));
+
+    for (field_id, cell_rev) in row_rev.cells.iter() {
+        match filter_cell(field_revs, result.value_mut(), &filter_cache, field_id, cell_rev) {
+            None => {}
+            Some(_) => {
+                return Some(row_rev.id.clone());
             }
         }
     }
-
-    todo!()
+    return None;
 }
 
-fn update_filter_result(
+// Return None if there is no change in this cell after applying the filter
+fn filter_cell(
     field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
     filter_result: &mut FilterResult,
     filter_cache: &Arc<FilterCache>,
@@ -168,27 +175,83 @@ fn update_filter_result(
 ) -> Option<()> {
     let field_rev = field_revs.get(field_id)?;
     let field_type = FieldType::from(field_rev.field_type_rev);
+    let field_type_rev = field_type.clone().into();
     let filter_id = FilterId {
         field_id: field_id.to_owned(),
         field_type,
     };
-    match &filter_id.field_type {
-        FieldType::RichText => match filter_cache.text_filter.get(&filter_id) {
-            None => {}
-            Some(filter) => {
-                // let v = field_rev
-                //     .get_type_option_entry::<RichTextTypeOption, _>(&filter_id.field_type)?
-                //     .apply_filter(cell_rev, &filter);
+    let any_cell_data = AnyCellData::try_from(cell_rev).ok()?;
+    let is_hidden = match &filter_id.field_type {
+        FieldType::RichText => filter_cache.text_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<RichTextTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+        FieldType::Number => filter_cache.number_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<NumberTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+        FieldType::DateTime => filter_cache.date_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<DateTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+        FieldType::SingleSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<SingleSelectTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+        FieldType::MultiSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<MultiSelectTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+        FieldType::Checkbox => filter_cache.checkbox_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<CheckboxTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+        FieldType::URL => filter_cache.url_filter.get(&filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option_entry::<URLTypeOption>(field_type_rev)?
+                    .apply_filter(any_cell_data.into(), filter.value()),
+            )
+        }),
+    }?;
+
+    let is_visible = !is_hidden;
+    match filter_result.visible_by_field_id.get(&filter_id) {
+        None => {
+            if is_visible {
+                return None;
+            } else {
+                filter_result.visible_by_field_id.insert(filter_id, is_visible);
+                Some(())
             }
-        },
-        FieldType::Number => {}
-        FieldType::DateTime => {}
-        FieldType::SingleSelect => {}
-        FieldType::MultiSelect => {}
-        FieldType::Checkbox => {}
-        FieldType::URL => {}
+        }
+        Some(old_is_visible) => {
+            if old_is_visible != &is_visible {
+                filter_result.visible_by_field_id.insert(filter_id, is_visible);
+                Some(())
+            } else {
+                None
+            }
+        }
     }
-    None
 }
 
 pub struct GridFilterChangeset {

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -352,7 +352,7 @@ impl GridRevisionEditor {
         let row_rev = self.block_manager.get_row_rev(&params.row_id).await.ok()??;
 
         let cell_rev = row_rev.cells.get(&params.field_id)?.clone();
-        let data = decode_cell_data(cell_rev.data, &field_rev).data;
+        let data = decode_any_cell_data(cell_rev.data, &field_rev).data;
         Some(Cell::new(&params.field_id, data))
     }
 

+ 41 - 39
frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs

@@ -2,25 +2,25 @@ use crate::entities::FieldType;
 use crate::services::field::*;
 use bytes::Bytes;
 use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision};
 use serde::{Deserialize, Serialize};
 use std::fmt::Formatter;
 use std::str::FromStr;
 
-pub trait CellDataOperation<D, F> {
+pub trait CellFilterOperation<T, C: From<AnyCellData>> {
+    fn apply_filter(&self, cell_data: C, filter: &T) -> bool;
+}
+
+pub trait CellDataOperation<D> {
     fn decode_cell_data<T>(
         &self,
-        encoded_data: T,
+        cell_data: T,
         decoded_field_type: &FieldType,
         field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
         T: Into<D>;
 
-    fn apply_filter<T>(&self, encoded_data: T, filter: &F) -> bool
-    where
-        T: Into<D>;
-
     fn apply_changeset<C: Into<CellContentChangeset>>(
         &self,
         changeset: C,
@@ -53,39 +53,40 @@ impl std::ops::Deref for CellContentChangeset {
 }
 
 #[derive(Debug, Serialize, Deserialize)]
-pub struct TypeOptionCellData {
-    pub data: String,
+pub struct AnyCellData {
+    pub cell_data: String,
     pub field_type: FieldType,
 }
 
-impl std::str::FromStr for TypeOptionCellData {
+impl std::str::FromStr for AnyCellData {
     type Err = FlowyError;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let type_option_cell_data: TypeOptionCellData = serde_json::from_str(s)?;
+        let type_option_cell_data: AnyCellData = serde_json::from_str(s)?;
         Ok(type_option_cell_data)
     }
 }
 
-impl std::convert::TryInto<TypeOptionCellData> for String {
+impl std::convert::TryInto<AnyCellData> for String {
     type Error = FlowyError;
 
-    fn try_into(self) -> Result<TypeOptionCellData, Self::Error> {
-        TypeOptionCellData::from_str(&self)
+    fn try_into(self) -> Result<AnyCellData, Self::Error> {
+        AnyCellData::from_str(&self)
     }
 }
 
-impl std::convert::TryFrom<&CellRevision> for TypeOptionCellData {
+impl std::convert::TryFrom<&CellRevision> for AnyCellData {
     type Error = FlowyError;
 
     fn try_from(value: &CellRevision) -> Result<Self, Self::Error> {
         Self::from_str(&value.data)
     }
 }
-impl TypeOptionCellData {
-    pub fn new<T: ToString>(data: T, field_type: FieldType) -> Self {
-        TypeOptionCellData {
-            data: data.to_string(),
+
+impl AnyCellData {
+    pub fn new(content: String, field_type: FieldType) -> Self {
+        AnyCellData {
+            cell_data: content,
             field_type,
         }
     }
@@ -142,14 +143,14 @@ pub fn apply_cell_data_changeset<C: Into<CellContentChangeset>, T: AsRef<FieldRe
         FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset, cell_rev),
     }?;
 
-    Ok(TypeOptionCellData::new(s, field_type).json())
+    Ok(AnyCellData::new(s, field_type).json())
 }
 
-pub fn decode_cell_data<T: TryInto<TypeOptionCellData>>(data: T, field_rev: &FieldRevision) -> DecodedCellData {
-    if let Ok(type_option_cell_data) = data.try_into() {
-        let TypeOptionCellData { data, field_type } = type_option_cell_data;
+pub fn decode_any_cell_data<T: TryInto<AnyCellData>>(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 to_field_type = field_rev.field_type_rev.into();
-        match try_decode_cell_data(data, field_rev, &field_type, &to_field_type) {
+        match try_decode_cell_data(cell_data, field_rev, &field_type, &to_field_type) {
             Ok(cell_data) => cell_data,
             Err(e) => {
                 tracing::error!("Decode cell data failed, {:?}", e);
@@ -163,34 +164,35 @@ pub fn decode_cell_data<T: TryInto<TypeOptionCellData>>(data: T, field_rev: &Fie
 }
 
 pub fn try_decode_cell_data(
-    encoded_data: String,
+    cell_data: String,
     field_rev: &FieldRevision,
     s_field_type: &FieldType,
     t_field_type: &FieldType,
 ) -> FlowyResult<DecodedCellData> {
     let get_cell_data = || {
+        let field_type: FieldTypeRevision = t_field_type.into();
         let data = match t_field_type {
             FieldType::RichText => field_rev
-                .get_type_option_entry::<RichTextTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<RichTextTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
             FieldType::Number => field_rev
-                .get_type_option_entry::<NumberTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<NumberTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
             FieldType::DateTime => field_rev
-                .get_type_option_entry::<DateTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<DateTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
             FieldType::SingleSelect => field_rev
-                .get_type_option_entry::<SingleSelectTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<SingleSelectTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
             FieldType::MultiSelect => field_rev
-                .get_type_option_entry::<MultiSelectTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<MultiSelectTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
             FieldType::Checkbox => field_rev
-                .get_type_option_entry::<CheckboxTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<CheckboxTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
             FieldType::URL => field_rev
-                .get_type_option_entry::<URLTypeOption, _>(t_field_type)?
-                .decode_cell_data(encoded_data, s_field_type, field_rev),
+                .get_type_option_entry::<URLTypeOption>(field_type)?
+                .decode_cell_data(cell_data, s_field_type, field_rev),
         };
         Some(data)
     };

+ 2 - 3
frontend/rust-lib/flowy-grid/tests/grid/field_util.rs

@@ -12,7 +12,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
     let cloned_field_rev = field_rev.clone();
 
     let type_option_data = field_rev
-        .get_type_option_entry::<RichTextTypeOption, _>(field_rev.field_type_rev)
+        .get_type_option_entry::<RichTextTypeOption>(field_rev.field_type_rev.clone())
         .unwrap()
         .protobuf_bytes()
         .to_vec();
@@ -44,9 +44,8 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
 
     let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
     let cloned_field_rev = field_rev.clone();
-    let field_type: FieldType = field_rev.field_type_rev.into();
     let type_option_data = field_rev
-        .get_type_option_entry::<SingleSelectTypeOption, _>(&field_type)
+        .get_type_option_entry::<SingleSelectTypeOption>(field_rev.field_type_rev.clone())
         .unwrap()
         .protobuf_bytes()
         .to_vec();

+ 2 - 2
frontend/rust-lib/flowy-grid/tests/grid/row_test.rs

@@ -7,7 +7,7 @@ use flowy_grid::entities::FieldType;
 use flowy_grid::services::field::{
     DateCellData, MultiSelectTypeOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
 };
-use flowy_grid::services::row::{decode_cell_data, CreateRowRevisionBuilder};
+use flowy_grid::services::row::{decode_any_cell_data, CreateRowRevisionBuilder};
 use flowy_grid_data_model::revision::RowMetaChangeset;
 
 #[tokio::test]
@@ -139,7 +139,7 @@ async fn grid_row_add_date_cell_test() {
     let date_field = date_field.unwrap();
     let cell_rev = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
     assert_eq!(
-        decode_cell_data(cell_rev, &date_field)
+        decode_any_cell_data(cell_rev, &date_field)
             .parse::<DateCellData>()
             .unwrap()
             .date,

+ 2 - 6
shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs

@@ -168,13 +168,9 @@ impl FieldRevision {
         self.type_options.insert(id, entry.json_str());
     }
 
-    pub fn get_type_option_entry<T1: TypeOptionDataDeserializer, T2: Into<FieldTypeRevision>>(
-        &self,
-        field_type: T2,
-    ) -> Option<T1> {
-        let field_type_rev = field_type.into();
+    pub fn get_type_option_entry<T: TypeOptionDataDeserializer>(&self, field_type_rev: FieldTypeRevision) -> Option<T> {
         let id = field_type_rev.to_string();
-        self.type_options.get(&id).map(|s| T1::from_json_str(s))
+        self.type_options.get(&id).map(|s| T::from_json_str(s))
     }
 
     pub fn insert_type_option_str(&mut self, field_type: &FieldTypeRevision, json_str: String) {