Browse Source

chore: cache filter result

appflowy 2 years ago
parent
commit
50d0eff039
23 changed files with 620 additions and 202 deletions
  1. 30 32
      frontend/rust-lib/flowy-grid/src/services/block_manager.rs
  2. 6 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs
  3. 6 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs
  4. 6 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
  5. 11 3
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs
  6. 7 3
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs
  7. 6 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs
  8. 217 28
      frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
  9. 14 18
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  10. 4 4
      frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs
  11. 16 7
      frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs
  12. 5 3
      frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs
  13. 1 1
      frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs
  14. 9 9
      frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs
  15. 4 4
      frontend/rust-lib/flowy-grid/src/services/tasks/store.rs
  16. 9 8
      frontend/rust-lib/flowy-grid/src/services/tasks/task.rs
  17. 6 3
      frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs
  18. 3 2
      frontend/rust-lib/flowy-grid/tests/grid/script.rs
  19. 2 2
      shared-lib/flowy-grid-data-model/src/entities/field.rs
  20. 96 20
      shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs
  21. 35 33
      shared-lib/flowy-grid-data-model/src/entities/grid_setting.rs
  22. 85 3
      shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs
  23. 42 11
      shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

+ 30 - 32
frontend/rust-lib/flowy-grid/src/services/block_manager.rs

@@ -9,7 +9,7 @@ use flowy_grid_data_model::entities::{
     CellChangeset, GridRowsChangeset, IndexRowOrder, Row, RowOrder, UpdatedRowOrder,
 };
 use flowy_grid_data_model::revision::{
-    CellRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision,
+    GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision,
 };
 use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence;
 use flowy_revision::{RevisionManager, RevisionPersistence};
@@ -23,7 +23,7 @@ pub(crate) struct GridBlockManager {
     grid_id: String,
     user: Arc<dyn GridUser>,
     persistence: Arc<BlockIndexCache>,
-    block_editor_map: DashMap<BlockId, Arc<GridBlockRevisionEditor>>,
+    block_editors: DashMap<BlockId, Arc<GridBlockRevisionEditor>>,
 }
 
 impl GridBlockManager {
@@ -33,13 +33,13 @@ impl GridBlockManager {
         block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
         persistence: Arc<BlockIndexCache>,
     ) -> FlowyResult<Self> {
-        let editor_map = make_block_meta_editor_map(user, block_meta_revs).await?;
+        let block_editors = make_block_editors(user, block_meta_revs).await?;
         let user = user.clone();
         let grid_id = grid_id.to_owned();
         let manager = Self {
             grid_id,
             user,
-            block_editor_map: editor_map,
+            block_editors,
             persistence,
         };
         Ok(manager)
@@ -48,11 +48,11 @@ impl GridBlockManager {
     // #[tracing::instrument(level = "trace", skip(self))]
     pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<GridBlockRevisionEditor>> {
         debug_assert!(!block_id.is_empty());
-        match self.block_editor_map.get(block_id) {
+        match self.block_editors.get(block_id) {
             None => {
                 tracing::error!("This is a fatal error, block with id:{} is not exist", block_id);
-                let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?);
-                self.block_editor_map.insert(block_id.to_owned(), editor.clone());
+                let editor = Arc::new(make_block_editor(&self.user, block_id).await?);
+                self.block_editors.insert(block_id.to_owned(), editor.clone());
                 Ok(editor)
             }
             Some(editor) => Ok(editor.clone()),
@@ -222,33 +222,31 @@ impl GridBlockManager {
         editor.get_row_orders::<&str>(None).await
     }
 
-    pub(crate) async fn make_block_snapshots(&self, block_ids: Vec<String>) -> FlowyResult<Vec<GridBlockSnapshot>> {
+    pub(crate) async fn get_block_snapshots(
+        &self,
+        block_ids: Option<Vec<String>>,
+    ) -> FlowyResult<Vec<GridBlockSnapshot>> {
         let mut snapshots = vec![];
-        for block_id in block_ids {
-            let editor = self.get_editor(&block_id).await?;
-            let row_revs = editor.get_row_revs::<&str>(None).await?;
-            snapshots.push(GridBlockSnapshot { block_id, row_revs });
+        match block_ids {
+            None => {
+                for iter in self.block_editors.iter() {
+                    let editor = iter.value();
+                    let block_id = editor.block_id.clone();
+                    let row_revs = editor.get_row_revs::<&str>(None).await?;
+                    snapshots.push(GridBlockSnapshot { block_id, row_revs });
+                }
+            }
+            Some(block_ids) => {
+                for block_id in block_ids {
+                    let editor = self.get_editor(&block_id).await?;
+                    let row_revs = editor.get_row_revs::<&str>(None).await?;
+                    snapshots.push(GridBlockSnapshot { block_id, row_revs });
+                }
+            }
         }
         Ok(snapshots)
     }
 
-    // Optimization: Using the shared memory(Arc, Cow,etc.) to reduce memory usage.
-    #[allow(dead_code)]
-    pub async fn get_cell_revs(
-        &self,
-        block_ids: Vec<String>,
-        field_id: &str,
-        row_ids: Option<Vec<Cow<'_, String>>>,
-    ) -> FlowyResult<Vec<CellRevision>> {
-        let mut block_cell_revs = vec![];
-        for block_id in block_ids {
-            let editor = self.get_editor(&block_id).await?;
-            let cell_revs = editor.get_cell_revs(field_id, row_ids.clone()).await?;
-            block_cell_revs.extend(cell_revs);
-        }
-        Ok(block_cell_revs)
-    }
-
     async fn notify_did_update_block(&self, block_id: &str, changeset: GridRowsChangeset) -> FlowyResult<()> {
         send_dart_notification(block_id, GridNotification::DidUpdateGridBlock)
             .payload(changeset)
@@ -263,20 +261,20 @@ impl GridBlockManager {
     }
 }
 
-async fn make_block_meta_editor_map(
+async fn make_block_editors(
     user: &Arc<dyn GridUser>,
     block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
 ) -> FlowyResult<DashMap<String, Arc<GridBlockRevisionEditor>>> {
     let editor_map = DashMap::new();
     for block_meta_rev in block_meta_revs {
-        let editor = make_block_meta_editor(user, &block_meta_rev.block_id).await?;
+        let editor = make_block_editor(user, &block_meta_rev.block_id).await?;
         editor_map.insert(block_meta_rev.block_id.clone(), Arc::new(editor));
     }
 
     Ok(editor_map)
 }
 
-async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
+async fn make_block_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
     tracing::trace!("Open block:{} meta editor", block_id);
     let token = user.token()?;
     let user_id = user.user_id()?;

+ 6 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs

@@ -4,7 +4,7 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::FieldType;
+use flowy_grid_data_model::entities::{FieldType, GridCheckboxFilter};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
 use serde::{Deserialize, Serialize};
 
@@ -40,7 +40,7 @@ impl_type_option!(CheckboxTypeOption, FieldType::Checkbox);
 const YES: &str = "Yes";
 const NO: &str = "No";
 
-impl CellDataOperation<String> for CheckboxTypeOption {
+impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -62,6 +62,10 @@ impl CellDataOperation<String> for CheckboxTypeOption {
         Ok(DecodedCellData::default())
     }
 
+    fn apply_filter(&self, _filter: GridCheckboxFilter) -> bool {
+        todo!()
+    }
+
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,

+ 6 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs

@@ -7,7 +7,7 @@ use chrono::format::strftime::StrftimeItems;
 use chrono::{NaiveDateTime, Timelike};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::{CellChangeset, FieldType};
+use flowy_grid_data_model::entities::{CellChangeset, FieldType, GridDateFilter};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
 use serde::{Deserialize, Serialize};
 use strum_macros::EnumIter;
@@ -115,7 +115,7 @@ impl DateTypeOption {
     }
 }
 
-impl CellDataOperation<String> for DateTypeOption {
+impl CellDataOperation<String, GridDateFilter> for DateTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -138,6 +138,10 @@ impl CellDataOperation<String> for DateTypeOption {
         DecodedCellData::try_from_bytes(date)
     }
 
+    fn apply_filter(&self, _filter: GridDateFilter) -> bool {
+        todo!()
+    }
+
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,

+ 6 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs

@@ -6,7 +6,7 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::FieldType;
+use flowy_grid_data_model::entities::{FieldType, GridNumberFilter};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
 use rust_decimal::Decimal;
 use serde::{Deserialize, Serialize};
@@ -139,7 +139,7 @@ impl NumberTypeOption {
     }
 }
 
-impl CellDataOperation<String> for NumberTypeOption {
+impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -179,6 +179,10 @@ impl CellDataOperation<String> for NumberTypeOption {
         }
     }
 
+    fn apply_filter(&self, _filter: GridNumberFilter) -> bool {
+        todo!()
+    }
+
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,

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

@@ -6,7 +6,7 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD
 use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::{CellChangeset, FieldType};
+use flowy_grid_data_model::entities::{CellChangeset, FieldType, GridSelectOptionFilter};
 use flowy_grid_data_model::parser::NotEmptyStr;
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
 use nanoid::nanoid;
@@ -94,7 +94,7 @@ impl SelectOptionOperation for SingleSelectTypeOption {
     }
 }
 
-impl CellDataOperation<String> for SingleSelectTypeOption {
+impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -122,6 +122,10 @@ impl CellDataOperation<String> for SingleSelectTypeOption {
         DecodedCellData::try_from_bytes(cell_data)
     }
 
+    fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
+        todo!()
+    }
+
     fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         C: Into<CellContentChangeset>,
@@ -192,7 +196,7 @@ impl SelectOptionOperation for MultiSelectTypeOption {
     }
 }
 
-impl CellDataOperation<String> for MultiSelectTypeOption {
+impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -220,6 +224,10 @@ impl CellDataOperation<String> for MultiSelectTypeOption {
         DecodedCellData::try_from_bytes(cell_data)
     }
 
+    fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
+        todo!()
+    }
+
     fn apply_changeset<T>(&self, changeset: T, cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
     where
         T: Into<CellContentChangeset>,

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

@@ -4,7 +4,7 @@ use crate::services::row::{try_decode_cell_data, CellContentChangeset, CellDataO
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::FieldType;
+use flowy_grid_data_model::entities::{FieldType, GridTextFilter};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
 use serde::{Deserialize, Serialize};
 
@@ -30,7 +30,7 @@ pub struct RichTextTypeOption {
 }
 impl_type_option!(RichTextTypeOption, FieldType::RichText);
 
-impl CellDataOperation<String> for RichTextTypeOption {
+impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -45,13 +45,17 @@ impl CellDataOperation<String> for RichTextTypeOption {
             || decoded_field_type.is_multi_select()
             || decoded_field_type.is_number()
         {
-            try_decode_cell_data(encoded_data, field_rev, decoded_field_type, decoded_field_type)
+            try_decode_cell_data(encoded_data.into(), field_rev, decoded_field_type, decoded_field_type)
         } else {
             let cell_data = encoded_data.into();
             Ok(DecodedCellData::new(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>,

+ 6 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs

@@ -5,7 +5,7 @@ use bytes::Bytes;
 use fancy_regex::Regex;
 use flowy_derive::ProtoBuf;
 use flowy_error::{internal_error, FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::FieldType;
+use flowy_grid_data_model::entities::{FieldType, GridTextFilter};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
 use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
@@ -33,7 +33,7 @@ pub struct URLTypeOption {
 }
 impl_type_option!(URLTypeOption, FieldType::URL);
 
-impl CellDataOperation<EncodedCellData<URLCellData>> for URLTypeOption {
+impl CellDataOperation<EncodedCellData<URLCellData>, GridTextFilter> for URLTypeOption {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -50,6 +50,10 @@ impl CellDataOperation<EncodedCellData<URLCellData>> for URLTypeOption {
         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>,

+ 217 - 28
frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs

@@ -1,10 +1,15 @@
-use crate::manager::GridTaskSchedulerRwLock;
 use crate::services::block_manager::GridBlockManager;
-use crate::services::tasks::Task;
-use flowy_error::FlowyResult;
-
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
+use crate::services::row::GridBlockSnapshot;
+use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::entities::{
+    FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter,
+    GridSettingChangesetParams, GridTextFilter,
+};
+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;
 
@@ -12,47 +17,231 @@ pub(crate) struct GridFilterService {
     scheduler: Arc<dyn GridServiceTaskScheduler>,
     grid_pad: Arc<RwLock<GridRevisionPad>>,
     block_manager: Arc<GridBlockManager>,
+    filter_cache: Arc<RwLock<FilterCache>>,
+    filter_result: Arc<RwLock<GridFilterResult>>,
 }
 impl GridFilterService {
-    pub fn new<S: GridServiceTaskScheduler>(
+    pub async fn new<S: GridServiceTaskScheduler>(
         grid_pad: Arc<RwLock<GridRevisionPad>>,
         block_manager: Arc<GridBlockManager>,
         scheduler: S,
     ) -> Self {
+        let filter_cache = Arc::new(RwLock::new(FilterCache::from_grid_pad(&grid_pad).await));
+        let filter_result = Arc::new(RwLock::new(GridFilterResult::default()));
         Self {
             grid_pad,
             block_manager,
             scheduler: Arc::new(scheduler),
+            filter_cache,
+            filter_result,
         }
     }
 
-    pub async fn process_task(&self, _task: Task) -> FlowyResult<()> {
+    pub async fn process(&self, task_context: FilterTaskContext) -> FlowyResult<()> {
+        let mut filter_result = self.filter_result.write().await;
+        for block in task_context.blocks {
+            for row_rev in block.row_revs {
+                let row_filter_result = RowFilterResult::new(&row_rev);
+
+                filter_result.insert(&row_rev.id, row_filter_result);
+            }
+        }
         Ok(())
     }
 
-    pub async fn notify_changed(&self) {
+    pub async fn apply_changeset(&self, changeset: GridFilterChangeset) {
+        if !changeset.is_changed() {
+            return;
+        }
+
+        if let Some(filter_id) = &changeset.insert_filter {
+            let mut cache = self.filter_cache.write().await;
+            let field_ids = Some(vec![filter_id.field_id.clone()]);
+            reload_filter_cache(&mut cache, field_ids, &self.grid_pad).await;
+        }
+
+        if let Some(filter_id) = &changeset.delete_filter {
+            self.filter_cache.write().await.remove(filter_id);
+        }
+
+        match self.block_manager.get_block_snapshots(None).await {
+            Ok(blocks) => {
+                let task = self.gen_task(blocks).await;
+                let _ = self.scheduler.register_task(task).await;
+            }
+            Err(_) => {}
+        }
+    }
+
+    async fn gen_task(&self, blocks: Vec<GridBlockSnapshot>) -> Task {
         let task_id = self.scheduler.gen_task_id().await;
+        let handler_id = self.grid_pad.read().await.grid_id();
+
+        let context = FilterTaskContext { blocks };
+        let task = Task {
+            handler_id,
+            id: task_id,
+            content: TaskContent::Filter(context),
+        };
+
+        task
+    }
+}
+pub struct GridFilterChangeset {
+    insert_filter: Option<FilterId>,
+    delete_filter: Option<FilterId>,
+}
+
+impl GridFilterChangeset {
+    fn is_changed(&self) -> bool {
+        self.insert_filter.is_some() || self.delete_filter.is_some()
+    }
+}
+
+impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset {
+    fn from(params: &GridSettingChangesetParams) -> Self {
+        let insert_filter = params.insert_filter.as_ref().map(|insert_filter_params| FilterId {
+            field_id: insert_filter_params.field_id.clone(),
+            field_type: insert_filter_params.field_type.clone(),
+        });
+
+        let delete_filter = params.delete_filter.as_ref().map(|delete_filter_params| FilterId {
+            field_id: delete_filter_params.filter_id.clone(),
+            field_type: delete_filter_params.field_type.clone(),
+        });
+        GridFilterChangeset {
+            insert_filter,
+            delete_filter,
+        }
+    }
+}
+
+#[derive(Default)]
+struct GridFilterResult {
+    rows: HashMap<String, RowFilterResult>,
+}
+
+impl GridFilterResult {
+    fn insert(&mut self, row_id: &str, result: RowFilterResult) {
+        self.rows.insert(row_id.to_owned(), result);
+    }
+}
+
+#[derive(Default)]
+struct RowFilterResult {
+    cell_by_field_id: HashMap<String, bool>,
+}
+
+impl RowFilterResult {
+    fn new(row_rev: &RowRevision) -> Self {
+        Self {
+            cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
+        }
+    }
+
+    fn update_cell(&mut self, cell_id: &str, exist: bool) {
+        self.cell_by_field_id.insert(cell_id.to_owned(), exist);
+    }
+}
+
+#[derive(Default)]
+struct FilterCache {
+    text_filter: HashMap<FilterId, GridTextFilter>,
+    url_filter: HashMap<FilterId, GridTextFilter>,
+    number_filter: HashMap<FilterId, GridNumberFilter>,
+    date_filter: HashMap<FilterId, GridDateFilter>,
+    select_option_filter: HashMap<FilterId, GridSelectOptionFilter>,
+    checkbox_filter: HashMap<FilterId, GridCheckboxFilter>,
+}
+
+impl FilterCache {
+    async fn from_grid_pad(grid_pad: &Arc<RwLock<GridRevisionPad>>) -> Self {
+        let mut this = Self::default();
+        reload_filter_cache(&mut this, None, grid_pad);
+        this
+    }
+
+    fn remove(&mut self, filter_id: &FilterId) {
+        let _ = match filter_id.field_type {
+            FieldType::RichText => {
+                let _ = self.text_filter.remove(filter_id);
+            }
+            FieldType::Number => {
+                let _ = self.number_filter.remove(filter_id);
+            }
+            FieldType::DateTime => {
+                let _ = self.date_filter.remove(filter_id);
+            }
+            FieldType::SingleSelect => {
+                let _ = self.select_option_filter.remove(filter_id);
+            }
+            FieldType::MultiSelect => {
+                let _ = self.select_option_filter.remove(filter_id);
+            }
+            FieldType::Checkbox => {
+                let _ = self.checkbox_filter.remove(filter_id);
+            }
+            FieldType::URL => {
+                let _ = self.url_filter.remove(filter_id);
+            }
+        };
+    }
+}
+
+async fn reload_filter_cache(
+    cache: &mut FilterCache,
+    field_ids: Option<Vec<String>>,
+    grid_pad: &Arc<RwLock<GridRevisionPad>>,
+) {
+    let grid_pad = grid_pad.read().await;
+    let filters_revs = grid_pad.get_filters(None, field_ids).unwrap_or_default();
 
-        //
-        // let grid_pad = self.grid_pad.read().await;
-        // match grid_pad.get_filters(None) {
-        //     None => {}
-        //     Some(filter_revs) => {
-        //         filter_revs
-        //             .iter()
-        //             .for_each(|filter_rev| match grid_pad.get_field_rev(&filter_rev.field_id) {
-        //                 None => {}
-        //                 Some((_, _field_rev)) => match field_rev.field_type {
-        //                     FieldType::RichText => {}
-        //                     FieldType::Number => {}
-        //                     FieldType::DateTime => {}
-        //                     FieldType::SingleSelect => {}
-        //                     FieldType::MultiSelect => {}
-        //                     FieldType::Checkbox => {}
-        //                     FieldType::URL => {}
-        //                 },
-        //             });
-        //     }
-        // }
+    for filter_rev in filters_revs {
+        match grid_pad.get_field_rev(&filter_rev.field_id) {
+            None => {}
+            Some((_, field_rev)) => {
+                let filter_id = FilterId::from(field_rev);
+                match &field_rev.field_type {
+                    FieldType::RichText => {
+                        let _ = cache.text_filter.insert(filter_id, GridTextFilter::from(filter_rev));
+                    }
+                    FieldType::Number => {
+                        let _ = cache
+                            .number_filter
+                            .insert(filter_id, GridNumberFilter::from(filter_rev));
+                    }
+                    FieldType::DateTime => {
+                        let _ = cache.date_filter.insert(filter_id, GridDateFilter::from(filter_rev));
+                    }
+                    FieldType::SingleSelect | FieldType::MultiSelect => {
+                        let _ = cache
+                            .select_option_filter
+                            .insert(filter_id, GridSelectOptionFilter::from(filter_rev));
+                    }
+                    FieldType::Checkbox => {
+                        let _ = cache
+                            .checkbox_filter
+                            .insert(filter_id, GridCheckboxFilter::from(filter_rev));
+                    }
+                    FieldType::URL => {
+                        let _ = cache.url_filter.insert(filter_id, GridTextFilter::from(filter_rev));
+                    }
+                }
+            }
+        }
+    }
+}
+#[derive(Hash, Eq, PartialEq)]
+struct FilterId {
+    field_id: String,
+    field_type: FieldType,
+}
+
+impl std::convert::From<&FieldRevision> for FilterId {
+    fn from(rev: &FieldRevision) -> Self {
+        Self {
+            field_id: rev.id.clone(),
+            field_type: rev.field_type.clone(),
+        }
     }
 }

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

@@ -3,7 +3,7 @@ use crate::entities::CellIdentifier;
 use crate::manager::{GridTaskSchedulerRwLock, GridUser};
 use crate::services::block_manager::GridBlockManager;
 use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
-use crate::services::filter::GridFilterService;
+use crate::services::filter::{GridFilterChangeset, GridFilterService};
 use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::row::*;
 
@@ -53,11 +53,8 @@ impl GridRevisionEditor {
         let grid_pad = Arc::new(RwLock::new(grid_pad));
         let block_meta_revs = grid_pad.read().await.get_block_meta_revs();
         let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?);
-        let filter_service = Arc::new(GridFilterService::new(
-            grid_pad.clone(),
-            block_manager.clone(),
-            task_scheduler.clone(),
-        ));
+        let filter_service =
+            Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
         let editor = Arc::new(Self {
             grid_id: grid_id.to_owned(),
             user,
@@ -454,32 +451,31 @@ impl GridRevisionEditor {
     }
 
     pub async fn get_grid_setting(&self) -> FlowyResult<GridSetting> {
-        let read_guard = self.grid_pad.read().await;
-        let grid_setting_rev = read_guard.get_grid_setting_rev();
-        Ok(grid_setting_rev.into())
+        // let read_guard = self.grid_pad.read().await;
+        // let grid_setting_rev = read_guard.get_grid_setting_rev();
+        // Ok(grid_setting_rev.into())
+        todo!()
     }
 
     pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult<Vec<GridFilter>> {
         let read_guard = self.grid_pad.read().await;
         let layout_rev = layout_type.clone().into();
-        match read_guard.get_filters(Some(&layout_rev)) {
+        match read_guard.get_filters(Some(&layout_rev), None) {
             Some(filter_revs) => Ok(filter_revs.iter().map(GridFilter::from).collect::<Vec<GridFilter>>()),
             None => Ok(vec![]),
         }
     }
 
     pub async fn update_grid_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> {
-        let is_filter_changed = params.is_filter_changed();
+        let filter_changeset = GridFilterChangeset::from(&params);
         let _ = self
             .modify(|grid_pad| Ok(grid_pad.update_grid_setting_rev(params)?))
             .await?;
 
-        if is_filter_changed {
-            let filter_service = self.filter_service.clone();
-            tokio::spawn(async move {
-                filter_service.notify_changed().await;
-            });
-        }
+        let filter_service = self.filter_service.clone();
+        tokio::spawn(async move {
+            filter_service.apply_changeset(filter_changeset).await;
+        });
         Ok(())
     }
 
@@ -495,7 +491,7 @@ impl GridRevisionEditor {
                 .collect::<Vec<String>>(),
             Some(block_ids) => block_ids,
         };
-        let snapshots = self.block_manager.make_block_snapshots(block_ids).await?;
+        let snapshots = self.block_manager.get_block_snapshots(Some(block_ids)).await?;
         Ok(snapshots)
     }
 

+ 4 - 4
frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs

@@ -5,7 +5,7 @@ use flowy_error::FlowyError;
 use futures::future::BoxFuture;
 use lib_infra::future::BoxResultFuture;
 
-pub trait GridServiceTaskScheduler: Send + Sync + 'static {
+pub(crate) trait GridServiceTaskScheduler: Send + Sync + 'static {
     fn gen_task_id(&self) -> BoxFuture<TaskId>;
     fn register_task(&self, task: Task) -> BoxFuture<()>;
 }
@@ -17,9 +17,9 @@ impl GridTaskHandler for GridRevisionEditor {
 
     fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError> {
         Box::pin(async move {
-            match &task.content {
-                TaskContent::Snapshot { .. } => {}
-                TaskContent::Filter { .. } => self.filter_service.process_task(task).await?,
+            match task.content {
+                TaskContent::Snapshot => {}
+                TaskContent::Filter(context) => self.filter_service.process(context).await?,
             }
             Ok(())
         })

+ 16 - 7
frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs

@@ -2,12 +2,13 @@ use crate::services::field::*;
 use bytes::Bytes;
 use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::FieldType;
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, GridFilterRevision};
 use serde::{Deserialize, Serialize};
 use std::fmt::Formatter;
 use std::str::FromStr;
+use std::sync::Arc;
 
-pub trait CellDataOperation<ED> {
+pub trait CellDataOperation<D, F> {
     fn decode_cell_data<T>(
         &self,
         encoded_data: T,
@@ -15,9 +16,10 @@ pub trait CellDataOperation<ED> {
         field_rev: &FieldRevision,
     ) -> FlowyResult<DecodedCellData>
     where
-        T: Into<ED>;
+        T: Into<D>;
+
+    fn apply_filter(&self, filter: F) -> bool;
 
-    //
     fn apply_changeset<C: Into<CellContentChangeset>>(
         &self,
         changeset: C,
@@ -113,6 +115,14 @@ impl TypeOptionCellData {
     }
 }
 
+pub fn apply_cell_filter(
+    _filter_rev: Arc<GridFilterRevision>,
+    _field_rev: &FieldRevision,
+    _cell_rev: Option<CellRevision>,
+) -> bool {
+    todo!()
+}
+
 /// The changeset will be deserialized into specific data base on the FieldType.
 /// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect
 pub fn apply_cell_data_changeset<T: Into<CellContentChangeset>>(
@@ -150,13 +160,12 @@ pub fn decode_cell_data<T: TryInto<TypeOptionCellData>>(data: T, field_rev: &Fie
     }
 }
 
-pub fn try_decode_cell_data<T: Into<String>>(
-    encoded_data: T,
+pub fn try_decode_cell_data(
+    encoded_data: String,
     field_rev: &FieldRevision,
     s_field_type: &FieldType,
     t_field_type: &FieldType,
 ) -> FlowyResult<DecodedCellData> {
-    let encoded_data = encoded_data.into();
     let get_cell_data = || {
         let data = match t_field_type {
             FieldType::RichText => field_rev

+ 5 - 3
frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs

@@ -1,4 +1,6 @@
-use flowy_grid_data_model::entities::{CreateGridFilterParams, GridLayoutType, GridSettingChangesetParams};
+use flowy_grid_data_model::entities::{
+    CreateGridFilterParams, DeleteFilterParams, GridLayoutType, GridSettingChangesetParams,
+};
 
 pub struct GridSettingChangesetBuilder {
     params: GridSettingChangesetParams,
@@ -24,8 +26,8 @@ impl GridSettingChangesetBuilder {
         self
     }
 
-    pub fn delete_filter(mut self, filter_id: &str) -> Self {
-        self.params.delete_filter = Some(filter_id.to_string());
+    pub fn delete_filter(mut self, params: DeleteFilterParams) -> Self {
+        self.params.delete_filter = Some(params);
         self
     }
 

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

@@ -21,7 +21,7 @@ impl GridTaskQueue {
 
     pub(crate) fn push(&mut self, task: &Task) {
         let task_type = match task.content {
-            TaskContent::Snapshot { .. } => TaskType::Snapshot,
+            TaskContent::Snapshot => TaskType::Snapshot,
             TaskContent::Filter { .. } => TaskType::Filter,
         };
         let pending_task = PendingTask {

+ 9 - 9
frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs

@@ -11,7 +11,7 @@ use std::sync::Arc;
 use std::time::Duration;
 use tokio::sync::{watch, RwLock};
 
-pub trait GridTaskHandler: Send + Sync + 'static {
+pub(crate) trait GridTaskHandler: Send + Sync + 'static {
     fn handler_id(&self) -> &TaskHandlerId;
 
     fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError>;
@@ -25,7 +25,7 @@ pub struct GridTaskScheduler {
 }
 
 impl GridTaskScheduler {
-    pub fn new() -> Arc<RwLock<Self>> {
+    pub(crate) fn new() -> Arc<RwLock<Self>> {
         let (notifier, rx) = watch::channel(());
 
         let scheduler = Self {
@@ -45,7 +45,7 @@ impl GridTaskScheduler {
         scheduler
     }
 
-    pub fn register_handler<T>(&mut self, handler: Arc<T>)
+    pub(crate) fn register_handler<T>(&mut self, handler: Arc<T>)
     where
         T: GridTaskHandler,
     {
@@ -53,11 +53,11 @@ impl GridTaskScheduler {
         self.handlers.insert(handler_id, handler);
     }
 
-    pub fn unregister_handler<T: AsRef<str>>(&mut self, handler_id: T) {
+    pub(crate) fn unregister_handler<T: AsRef<str>>(&mut self, handler_id: T) {
         let _ = self.handlers.remove(handler_id.as_ref());
     }
 
-    pub async fn process_next_task(&mut self) -> FlowyResult<()> {
+    pub(crate) async fn process_next_task(&mut self) -> FlowyResult<()> {
         let mut get_next_task = || {
             let pending_task = self.queue.mut_head(|list| list.pop())?;
             let task = self.store.remove_task(&pending_task.id)?;
@@ -65,7 +65,7 @@ impl GridTaskScheduler {
         };
 
         if let Some(task) = get_next_task() {
-            match self.handlers.get(&task.hid) {
+            match self.handlers.get(&task.handler_id) {
                 None => {}
                 Some(handler) => {
                     let _ = handler.process_task(task).await;
@@ -75,18 +75,18 @@ impl GridTaskScheduler {
         Ok(())
     }
 
-    pub fn register_task(&mut self, task: Task) {
+    pub(crate) fn register_task(&mut self, task: Task) {
         assert!(!task.is_finished());
         self.queue.push(&task);
         self.store.insert_task(task);
         self.notify();
     }
 
-    pub fn next_task_id(&self) -> TaskId {
+    pub(crate) fn next_task_id(&self) -> TaskId {
         self.store.next_task_id()
     }
 
-    pub fn notify(&self) {
+    pub(crate) fn notify(&self) {
         let _ = self.notifier.send(());
     }
 }

+ 4 - 4
frontend/rust-lib/flowy-grid/src/services/tasks/store.rs

@@ -4,7 +4,7 @@ use std::collections::HashMap;
 use std::sync::atomic::AtomicU32;
 use std::sync::atomic::Ordering::SeqCst;
 
-pub struct GridTaskStore {
+pub(crate) struct GridTaskStore {
     tasks: HashMap<TaskId, Task>,
     task_id_counter: AtomicU32,
 }
@@ -17,15 +17,15 @@ impl GridTaskStore {
         }
     }
 
-    pub fn insert_task(&mut self, task: Task) {
+    pub(crate) fn insert_task(&mut self, task: Task) {
         self.tasks.insert(task.id, task);
     }
 
-    pub fn remove_task(&mut self, task_id: &TaskId) -> Option<Task> {
+    pub(crate) fn remove_task(&mut self, task_id: &TaskId) -> Option<Task> {
         self.tasks.remove(task_id)
     }
 
-    pub fn next_task_id(&self) -> TaskId {
+    pub(crate) fn next_task_id(&self) -> TaskId {
         let _ = self.task_id_counter.fetch_add(1, SeqCst);
         self.task_id_counter.load(SeqCst)
     }

+ 9 - 8
frontend/rust-lib/flowy-grid/src/services/tasks/task.rs

@@ -1,3 +1,4 @@
+use crate::services::row::GridBlockSnapshot;
 use crate::services::tasks::queue::TaskHandlerId;
 use std::cmp::Ordering;
 
@@ -49,17 +50,17 @@ impl Ord for PendingTask {
     }
 }
 
-pub struct SnapshotTaskContext {}
-
-pub struct FilterTaskContext {}
+pub(crate) struct FilterTaskContext {
+    pub blocks: Vec<GridBlockSnapshot>,
+}
 
-pub enum TaskContent {
-    Snapshot { context: SnapshotTaskContext },
-    Filter { context: FilterTaskContext },
+pub(crate) enum TaskContent {
+    Snapshot,
+    Filter(FilterTaskContext),
 }
 
-pub struct Task {
-    pub hid: TaskHandlerId,
+pub(crate) struct Task {
+    pub handler_id: TaskHandlerId,
     pub id: TaskId,
     pub content: TaskContent,
 }

+ 6 - 3
frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs

@@ -26,14 +26,17 @@ async fn grid_filter_invalid_condition_panic_test() {
 #[tokio::test]
 async fn grid_filter_delete_test() {
     let mut test = GridEditorTest::new().await;
-    let field_rev = test.text_field();
-    let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
+    let field_rev = test.text_field().clone();
+    let payload = CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
     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 },
+        DeleteGridTableFilter {
+            filter_id: filter.id,
+            field_type: field_rev.field_type.clone(),
+        },
         AssertTableFilterCount { count: 0 },
     ])
     .await;

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

@@ -77,6 +77,7 @@ pub enum EditorScript {
     },
     DeleteGridTableFilter {
         filter_id: String,
+        field_type: FieldType,
     },
     #[allow(dead_code)]
     AssertGridSetting {
@@ -265,10 +266,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 } => {
+            EditorScript::DeleteGridTableFilter { filter_id ,field_type} => {
                 let layout_type = GridLayoutType::Table;
                 let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type)
-                    .delete_filter(&filter_id)
+                    .delete_filter(DeleteFilterParams { filter_id, field_type })
                     .build();
                 let _ = self.editor.update_grid_setting(params).await.unwrap();
             }

+ 2 - 2
shared-lib/flowy-grid-data-model/src/entities/field.rs

@@ -438,6 +438,7 @@ impl TryInto<FieldChangesetParams> for FieldChangesetPayload {
     Debug,
     Clone,
     PartialEq,
+    Hash,
     Eq,
     ProtoBuf_Enum,
     EnumCountMacro,
@@ -478,8 +479,7 @@ impl From<&FieldType> for FieldType {
 
 impl FieldType {
     pub fn type_id(&self) -> String {
-        let ty = self.clone() as u8;
-        ty.to_string()
+        (self.clone() as u8).to_string()
     }
 
     pub fn default_cell_width(&self) -> i32 {

+ 96 - 20
shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs

@@ -1,10 +1,10 @@
+use crate::entities::FieldType;
 use crate::parser::NotEmptyStr;
+use crate::revision::{FieldRevision, GridFilterRevision};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error_code::ErrorCode;
-
-use crate::entities::FieldType;
-use crate::revision::{FieldRevision, GridFilterRevision};
 use std::convert::TryInto;
+use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 pub struct GridFilter {
@@ -18,14 +18,14 @@ pub struct RepeatedGridFilter {
     pub items: Vec<GridFilter>,
 }
 
-impl std::convert::From<&GridFilterRevision> for GridFilter {
-    fn from(rev: &GridFilterRevision) -> Self {
+impl std::convert::From<&Arc<GridFilterRevision>> for GridFilter {
+    fn from(rev: &Arc<GridFilterRevision>) -> Self {
         Self { id: rev.id.clone() }
     }
 }
 
-impl std::convert::From<&Vec<GridFilterRevision>> for RepeatedGridFilter {
-    fn from(revs: &Vec<GridFilterRevision>) -> Self {
+impl std::convert::From<&Vec<Arc<GridFilterRevision>>> for RepeatedGridFilter {
+    fn from(revs: &Vec<Arc<GridFilterRevision>>) -> Self {
         RepeatedGridFilter {
             items: revs.iter().map(|rev| rev.into()).collect(),
         }
@@ -38,6 +38,34 @@ impl std::convert::From<Vec<GridFilter>> for RepeatedGridFilter {
     }
 }
 
+#[derive(ProtoBuf, Debug, Default, Clone)]
+pub struct DeleteFilterPayload {
+    #[pb(index = 1)]
+    pub filter_id: String,
+
+    #[pb(index = 2)]
+    pub field_type: FieldType,
+}
+
+pub struct DeleteFilterParams {
+    pub filter_id: String,
+    pub field_type: FieldType,
+}
+
+impl TryInto<DeleteFilterParams> for DeleteFilterPayload {
+    type Error = ErrorCode;
+
+    fn try_into(self) -> Result<DeleteFilterParams, Self::Error> {
+        let filter_id = NotEmptyStr::parse(self.filter_id)
+            .map_err(|_| ErrorCode::UnexpectedEmptyString)?
+            .0;
+        Ok(DeleteFilterParams {
+            filter_id,
+            field_type: self.field_type,
+        })
+    }
+}
+
 #[derive(ProtoBuf, Debug, Default, Clone)]
 pub struct CreateGridFilterPayload {
     #[pb(index = 1)]
@@ -81,9 +109,12 @@ impl TryInto<CreateGridFilterParams> for CreateGridFilterPayload {
             .0;
         let condition = self.condition as u8;
         match self.field_type {
-            FieldType::RichText | FieldType::Checkbox | FieldType::URL => {
+            FieldType::RichText | FieldType::URL => {
                 let _ = TextFilterCondition::try_from(condition)?;
             }
+            FieldType::Checkbox => {
+                let _ = CheckboxCondition::try_from(condition)?;
+            }
             FieldType::Number => {
                 let _ = NumberFilterCondition::try_from(condition)?;
             }
@@ -154,11 +185,11 @@ impl std::convert::TryFrom<u8> for TextFilterCondition {
     }
 }
 
-impl std::convert::From<GridFilterRevision> for GridTextFilter {
-    fn from(rev: GridFilterRevision) -> Self {
+impl std::convert::From<Arc<GridFilterRevision>> for GridTextFilter {
+    fn from(rev: Arc<GridFilterRevision>) -> Self {
         GridTextFilter {
             condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is),
-            content: rev.content,
+            content: rev.content.clone(),
         }
     }
 }
@@ -213,11 +244,11 @@ impl std::convert::TryFrom<u8> for NumberFilterCondition {
     }
 }
 
-impl std::convert::From<GridFilterRevision> for GridNumberFilter {
-    fn from(rev: GridFilterRevision) -> Self {
+impl std::convert::From<Arc<GridFilterRevision>> for GridNumberFilter {
+    fn from(rev: Arc<GridFilterRevision>) -> Self {
         GridNumberFilter {
             condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal),
-            content: rev.content,
+            content: rev.content.clone(),
         }
     }
 }
@@ -266,11 +297,11 @@ impl std::convert::TryFrom<u8> for SelectOptionCondition {
     }
 }
 
-impl std::convert::From<GridFilterRevision> for GridSelectOptionFilter {
-    fn from(rev: GridFilterRevision) -> Self {
+impl std::convert::From<Arc<GridFilterRevision>> for GridSelectOptionFilter {
+    fn from(rev: Arc<GridFilterRevision>) -> Self {
         GridSelectOptionFilter {
             condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs),
-            content: rev.content,
+            content: rev.content.clone(),
         }
     }
 }
@@ -318,11 +349,56 @@ impl std::convert::TryFrom<u8> for DateFilterCondition {
         }
     }
 }
-impl std::convert::From<GridFilterRevision> for GridDateFilter {
-    fn from(rev: GridFilterRevision) -> Self {
+impl std::convert::From<Arc<GridFilterRevision>> for GridDateFilter {
+    fn from(rev: Arc<GridFilterRevision>) -> Self {
         GridDateFilter {
             condition: DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs),
-            content: rev.content,
+            content: rev.content.clone(),
+        }
+    }
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct GridCheckboxFilter {
+    #[pb(index = 1)]
+    pub condition: CheckboxCondition,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
+#[repr(u8)]
+pub enum CheckboxCondition {
+    IsChecked = 0,
+    IsUnChecked = 1,
+}
+
+impl std::convert::From<CheckboxCondition> for i32 {
+    fn from(value: CheckboxCondition) -> Self {
+        value as i32
+    }
+}
+
+impl std::default::Default for CheckboxCondition {
+    fn default() -> Self {
+        CheckboxCondition::IsChecked
+    }
+}
+
+impl std::convert::TryFrom<u8> for CheckboxCondition {
+    type Error = ErrorCode;
+
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        match value {
+            0 => Ok(CheckboxCondition::IsChecked),
+            1 => Ok(CheckboxCondition::IsUnChecked),
+            _ => Err(ErrorCode::InvalidData),
+        }
+    }
+}
+
+impl std::convert::From<Arc<GridFilterRevision>> for GridCheckboxFilter {
+    fn from(rev: Arc<GridFilterRevision>) -> Self {
+        GridCheckboxFilter {
+            condition: CheckboxCondition::try_from(rev.condition).unwrap_or(CheckboxCondition::IsChecked),
         }
     }
 }

+ 35 - 33
shared-lib/flowy-grid-data-model/src/entities/grid_setting.rs

@@ -1,9 +1,10 @@
 use crate::entities::{
     CreateGridFilterParams, CreateGridFilterPayload, CreateGridGroupParams, CreateGridGroupPayload,
-    CreateGridSortParams, CreateGridSortPayload, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort,
+    CreateGridSortParams, CreateGridSortPayload, DeleteFilterParams, DeleteFilterPayload, RepeatedGridFilter,
+    RepeatedGridGroup, RepeatedGridSort,
 };
 use crate::parser::NotEmptyStr;
-use crate::revision::{GridLayoutRevision, GridSettingRevision};
+use crate::revision::GridLayoutRevision;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error_code::ErrorCode;
 use std::collections::HashMap;
@@ -21,34 +22,35 @@ pub struct GridSetting {
     pub sorts_by_layout_ty: HashMap<String, RepeatedGridSort>,
 }
 
-impl std::convert::From<&GridSettingRevision> for GridSetting {
-    fn from(rev: &GridSettingRevision) -> Self {
-        let filters_by_layout_ty: HashMap<String, RepeatedGridFilter> = rev
-            .filters
-            .iter()
-            .map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into()))
-            .collect();
-
-        let groups_by_layout_ty: HashMap<String, RepeatedGridGroup> = rev
-            .groups
-            .iter()
-            .map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into()))
-            .collect();
-
-        let sorts_by_layout_ty: HashMap<String, RepeatedGridSort> = 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,
-        }
-    }
-}
-
+//
+// impl std::convert::From<&GridSettingRevision> for GridSetting {
+//     fn from(rev: &GridSettingRevision) -> Self {
+//         let filters_by_layout_ty: HashMap<String, RepeatedGridFilter> = rev
+//             .filters
+//             .iter()
+//             .map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into()))
+//             .collect();
+//
+//         let groups_by_layout_ty: HashMap<String, RepeatedGridGroup> = rev
+//             .groups
+//             .iter()
+//             .map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into()))
+//             .collect();
+//
+//         let sorts_by_layout_ty: HashMap<String, RepeatedGridSort> = 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)]
 #[repr(u8)]
 pub enum GridLayoutType {
@@ -92,7 +94,7 @@ pub struct GridSettingChangesetPayload {
     pub insert_filter: Option<CreateGridFilterPayload>,
 
     #[pb(index = 4, one_of)]
-    pub delete_filter: Option<String>,
+    pub delete_filter: Option<DeleteFilterPayload>,
 
     #[pb(index = 5, one_of)]
     pub insert_group: Option<CreateGridGroupPayload>,
@@ -111,7 +113,7 @@ pub struct GridSettingChangesetParams {
     pub grid_id: String,
     pub layout_type: GridLayoutType,
     pub insert_filter: Option<CreateGridFilterParams>,
-    pub delete_filter: Option<String>,
+    pub delete_filter: Option<DeleteFilterParams>,
     pub insert_group: Option<CreateGridGroupParams>,
     pub delete_group: Option<String>,
     pub insert_sort: Option<CreateGridSortParams>,
@@ -139,7 +141,7 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayload {
 
         let delete_filter = match self.delete_filter {
             None => None,
-            Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
+            Some(payload) => Some(payload.try_into()?),
         };
 
         let insert_group = match self.insert_group {

+ 85 - 3
shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs

@@ -1,7 +1,9 @@
+use crate::entities::FieldType;
 use indexmap::IndexMap;
 use nanoid::nanoid;
 use serde::{Deserialize, Serialize};
 use serde_repr::*;
+use std::sync::Arc;
 
 pub fn gen_grid_filter_id() -> String {
     nanoid!(6)
@@ -18,9 +20,17 @@ pub fn gen_grid_sort_id() -> String {
 #[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<GridLayoutRevision, Vec<GridFilterRevision>>,
+    pub filters: IndexMap<GridLayoutRevision, IndexMap<String, GridFilterRevisionMap>>,
 
     #[serde(skip, with = "indexmap::serde_seq")]
     pub groups: IndexMap<GridLayoutRevision, Vec<GridGroupRevision>>,
@@ -29,6 +39,78 @@ pub struct GridSettingRevision {
     pub sorts: IndexMap<GridLayoutRevision, Vec<GridSortRevision>>,
 }
 
+impl GridSettingRevision {
+    pub fn get_mut_filters(
+        &mut self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type: &FieldType,
+    ) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
+        self.filters
+            .get_mut(layout)
+            .and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get_mut(field_id))
+            .and_then(|filter_rev_map| filter_rev_map.get_mut(field_type))
+    }
+
+    pub fn get_filters(
+        &self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type: &FieldType,
+    ) -> Option<Vec<Arc<GridFilterRevision>>> {
+        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))
+            .cloned()
+    }
+
+    pub fn insert_filter(
+        &mut self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type: &FieldType,
+        filter_rev: GridFilterRevision,
+    ) {
+        let filter_rev_map_by_field_id = self.filters.entry(layout.clone()).or_insert_with(IndexMap::new);
+        let filter_rev_map = filter_rev_map_by_field_id
+            .entry(field_id.to_string())
+            .or_insert_with(GridFilterRevisionMap::new);
+
+        filter_rev_map
+            .entry(field_type.clone())
+            .or_insert_with(Vec::new)
+            .push(Arc::new(filter_rev))
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
+#[serde(transparent)]
+pub struct GridFilterRevisionMap {
+    #[serde(with = "indexmap::serde_seq")]
+    pub filter_by_field_type: IndexMap<FieldType, Vec<Arc<GridFilterRevision>>>,
+}
+
+impl GridFilterRevisionMap {
+    pub fn new() -> Self {
+        GridFilterRevisionMap::default()
+    }
+}
+
+impl std::ops::Deref for GridFilterRevisionMap {
+    type Target = IndexMap<FieldType, Vec<Arc<GridFilterRevision>>>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.filter_by_field_type
+    }
+}
+
+impl std::ops::DerefMut for GridFilterRevisionMap {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.filter_by_field_type
+    }
+}
+
 #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
 #[repr(u8)]
 pub enum GridLayoutRevision {
@@ -49,7 +131,7 @@ impl std::default::Default for GridLayoutRevision {
     }
 }
 
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
+#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
 pub struct GridFilterRevision {
     pub id: String,
     pub field_id: String,

+ 42 - 11
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -27,6 +27,9 @@ pub trait JsonDeserializer {
 }
 
 impl GridRevisionPad {
+    pub fn grid_id(&self) -> String {
+        self.grid_rev.grid_id.clone()
+    }
     pub async fn duplicate_grid_block_meta(&self) -> (Vec<FieldRevision>, Vec<GridBlockMetaRevision>) {
         let fields = self.grid_rev.fields.to_vec();
 
@@ -334,9 +337,35 @@ impl GridRevisionPad {
         &self.grid_rev.setting
     }
 
-    pub fn get_filters(&self, layout: Option<&GridLayoutRevision>) -> Option<&Vec<GridFilterRevision>> {
+    /// If layout is None, then the default layout will be the read from GridSettingRevision
+    pub fn get_filters(
+        &self,
+        layout: Option<&GridLayoutRevision>,
+        field_ids: Option<Vec<String>>,
+    ) -> Option<Vec<Arc<GridFilterRevision>>> {
+        let mut filter_revs = vec![];
         let layout_ty = layout.unwrap_or(&self.grid_rev.setting.layout);
-        self.grid_rev.setting.filters.get(layout_ty)
+        let field_revs = self.get_field_revs(None).ok()?;
+
+        field_revs.iter().for_each(|field_rev| {
+            let mut is_contain = true;
+            if let Some(field_ids) = &field_ids {
+                is_contain = field_ids.contains(&field_rev.id);
+            }
+
+            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)
+                {
+                    filter_revs.append(&mut t_filter_revs);
+                }
+            }
+        });
+
+        Some(filter_revs)
     }
 
     pub fn update_grid_setting_rev(
@@ -348,25 +377,27 @@ impl GridRevisionPad {
             let layout_rev: GridLayoutRevision = changeset.layout_type.into();
 
             if let Some(params) = changeset.insert_filter {
-                let rev = GridFilterRevision {
+                let filter_rev = GridFilterRevision {
                     id: gen_grid_filter_id(),
-                    field_id: params.field_id,
+                    field_id: params.field_id.clone(),
                     condition: params.condition,
                     content: params.content,
                 };
 
                 grid_rev
                     .setting
-                    .filters
-                    .entry(layout_rev.clone())
-                    .or_insert_with(std::vec::Vec::new)
-                    .push(rev);
+                    .insert_filter(&layout_rev, &params.field_id, &params.field_type, filter_rev);
 
                 is_changed = Some(())
             }
-            if let Some(delete_filter_id) = changeset.delete_filter {
-                match grid_rev.setting.filters.get_mut(&layout_rev) {
-                    Some(filters) => filters.retain(|filter| filter.id != delete_filter_id),
+            if let Some(params) = changeset.delete_filter {
+                match grid_rev
+                    .setting
+                    .get_mut_filters(&layout_rev, &params.filter_id, &params.field_type)
+                {
+                    Some(filters) => {
+                        filters.retain(|filter| filter.id != params.filter_id);
+                    }
                     None => {
                         tracing::warn!("Can't find the filter with {:?}", layout_rev);
                     }