Explorar el Código

chore: filter with cell data

appflowy hace 2 años
padre
commit
35491b22ac
Se han modificado 19 ficheros con 343 adiciones y 257 borrados
  1. 2 2
      frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart
  2. 10 4
      frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart
  3. 20 18
      frontend/rust-lib/flowy-grid/src/entities/block_entities.rs
  4. 6 17
      frontend/rust-lib/flowy-grid/src/services/block_manager.rs
  5. 5 5
      frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs
  6. 4 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs
  7. 4 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs
  8. 4 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
  9. 8 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs
  10. 4 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs
  11. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs
  12. 163 0
      frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
  13. 88 188
      frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
  14. 1 0
      frontend/rust-lib/flowy-grid/src/services/filter/mod.rs
  15. 5 5
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  16. 10 1
      frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs
  17. 4 4
      frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs
  18. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/row_test.rs
  19. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/script.rs

+ 2 - 2
frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart

@@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
 
-typedef GridBlockUpdateNotifierValue = Either<List<GridRowsChangeset>, FlowyError>;
+typedef GridBlockUpdateNotifierValue = Either<List<GridBlockChangeset>, FlowyError>;
 
 class GridBlockListener {
   final String blockId;
@@ -33,7 +33,7 @@ class GridBlockListener {
     switch (ty) {
       case GridNotification.DidUpdateGridBlock:
         result.fold(
-          (payload) => _rowsUpdateNotifier?.value = left([GridRowsChangeset.fromBuffer(payload)]),
+          (payload) => _rowsUpdateNotifier?.value = left([GridBlockChangeset.fromBuffer(payload)]),
           (error) => _rowsUpdateNotifier?.value = right(error),
         );
         break;

+ 10 - 4
frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart

@@ -57,17 +57,19 @@ class GridRowCacheService {
       _deleteRows(changeset.deletedRows);
       _insertRows(changeset.insertedRows);
       _updateRows(changeset.updatedRows);
+      _hideRows(changeset.hideRows);
+      _showRows(changeset.visibleRows);
     }
   }
 
-  void _deleteRows(List<GridRowId> deletedRows) {
+  void _deleteRows(List<String> deletedRows) {
     if (deletedRows.isEmpty) {
       return;
     }
 
     final List<GridRow> newRows = [];
     final DeletedIndexs deletedIndex = [];
-    final Map<String, GridRowId> deletedRowByRowId = {for (var e in deletedRows) e.rowId: e};
+    final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId};
 
     _rows.asMap().forEach((index, row) {
       if (deletedRowByRowId[row.rowId] == null) {
@@ -80,7 +82,7 @@ class GridRowCacheService {
     _notifier.receive(GridRowChangeReason.delete(deletedIndex));
   }
 
-  void _insertRows(List<IndexRow> insertRows) {
+  void _insertRows(List<InsertedRow> insertRows) {
     if (insertRows.isEmpty) {
       return;
     }
@@ -93,7 +95,7 @@ class GridRowCacheService {
         rowId: insertRow.rowId,
       );
       insertIndexs.add(insertIndex);
-      newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertIndex.row.height)));
+      newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
     }
 
     _notifier.receive(GridRowChangeReason.insert(insertIndexs));
@@ -121,6 +123,10 @@ class GridRowCacheService {
     _notifier.receive(GridRowChangeReason.update(updatedIndexs));
   }
 
+  void _hideRows(List<String> hideRows) {}
+
+  void _showRows(List<String> visibleRows) {}
+
   void onRowsChanged(
     void Function(GridRowChangeReason) onRowChanged,
   ) {

+ 20 - 18
frontend/rust-lib/flowy-grid/src/entities/block_entities.rs

@@ -1,4 +1,3 @@
-use crate::entities::GridRowId;
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
@@ -11,11 +10,11 @@ pub struct GridBlock {
     pub id: String,
 
     #[pb(index = 2)]
-    pub row_infos: Vec<BlockRowInfo>,
+    pub row_infos: Vec<RowInfo>,
 }
 
 impl GridBlock {
-    pub fn new(block_id: &str, row_orders: Vec<BlockRowInfo>) -> Self {
+    pub fn new(block_id: &str, row_orders: Vec<RowInfo>) -> Self {
         Self {
             id: block_id.to_owned(),
             row_infos: row_orders,
@@ -24,7 +23,7 @@ impl GridBlock {
 }
 
 #[derive(Debug, Default, Clone, ProtoBuf)]
-pub struct BlockRowInfo {
+pub struct RowInfo {
     #[pb(index = 1)]
     pub block_id: String,
 
@@ -35,7 +34,7 @@ pub struct BlockRowInfo {
     pub height: i32,
 }
 
-impl BlockRowInfo {
+impl RowInfo {
     pub fn row_id(&self) -> &str {
         &self.row_id
     }
@@ -45,7 +44,7 @@ impl BlockRowInfo {
     }
 }
 
-impl std::convert::From<&RowRevision> for BlockRowInfo {
+impl std::convert::From<&RowRevision> for RowInfo {
     fn from(rev: &RowRevision) -> Self {
         Self {
             block_id: rev.block_id.clone(),
@@ -55,7 +54,7 @@ impl std::convert::From<&RowRevision> for BlockRowInfo {
     }
 }
 
-impl std::convert::From<&Arc<RowRevision>> for BlockRowInfo {
+impl std::convert::From<&Arc<RowRevision>> for RowInfo {
     fn from(rev: &Arc<RowRevision>) -> Self {
         Self {
             block_id: rev.block_id.clone(),
@@ -140,8 +139,8 @@ impl UpdatedRow {
     }
 }
 
-impl std::convert::From<BlockRowInfo> for InsertedRow {
-    fn from(row_info: BlockRowInfo) -> Self {
+impl std::convert::From<RowInfo> for InsertedRow {
+    fn from(row_info: RowInfo) -> Self {
         Self {
             row_id: row_info.row_id,
             block_id: row_info.block_id,
@@ -153,7 +152,7 @@ impl std::convert::From<BlockRowInfo> for InsertedRow {
 
 impl std::convert::From<&RowRevision> for InsertedRow {
     fn from(row: &RowRevision) -> Self {
-        let row_order = BlockRowInfo::from(row);
+        let row_order = RowInfo::from(row);
         Self::from(row_order)
     }
 }
@@ -167,36 +166,39 @@ pub struct GridBlockChangeset {
     pub inserted_rows: Vec<InsertedRow>,
 
     #[pb(index = 3)]
-    pub deleted_rows: Vec<GridRowId>,
+    pub deleted_rows: Vec<String>,
 
     #[pb(index = 4)]
     pub updated_rows: Vec<UpdatedRow>,
+
+    #[pb(index = 5)]
+    pub visible_rows: Vec<String>,
+
+    #[pb(index = 6)]
+    pub hide_rows: Vec<String>,
 }
 impl GridBlockChangeset {
     pub fn insert(block_id: &str, inserted_rows: Vec<InsertedRow>) -> Self {
         Self {
             block_id: block_id.to_owned(),
             inserted_rows,
-            deleted_rows: vec![],
-            updated_rows: vec![],
+            ..Default::default()
         }
     }
 
-    pub fn delete(block_id: &str, deleted_rows: Vec<GridRowId>) -> Self {
+    pub fn delete(block_id: &str, deleted_rows: Vec<String>) -> Self {
         Self {
             block_id: block_id.to_owned(),
-            inserted_rows: vec![],
             deleted_rows,
-            updated_rows: vec![],
+            ..Default::default()
         }
     }
 
     pub fn update(block_id: &str, updated_rows: Vec<UpdatedRow>) -> Self {
         Self {
             block_id: block_id.to_owned(),
-            inserted_rows: vec![],
-            deleted_rows: vec![],
             updated_rows,
+            ..Default::default()
         }
     }
 }

+ 6 - 17
frontend/rust-lib/flowy-grid/src/services/block_manager.rs

@@ -1,5 +1,5 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
-use crate::entities::{BlockRowInfo, CellChangeset, GridBlockChangeset, GridRowId, InsertedRow, Row, UpdatedRow};
+use crate::entities::{CellChangeset, GridBlockChangeset, InsertedRow, Row, RowInfo, UpdatedRow};
 use crate::manager::GridUser;
 use crate::services::block_revision_editor::GridBlockRevisionEditor;
 use crate::services::persistence::block_index::BlockIndexCache;
@@ -137,14 +137,8 @@ impl GridBlockManager {
             None => {}
             Some(row_info) => {
                 let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
-
-                let row_identifier = GridRowId {
-                    grid_id: self.grid_id.clone(),
-                    block_id: row_info.block_id,
-                    row_id: row_info.row_id,
-                };
                 let _ = self
-                    .notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_identifier]))
+                    .notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_info.row_id]))
                     .await?;
             }
         }
@@ -154,7 +148,7 @@ impl GridBlockManager {
 
     pub(crate) async fn delete_rows(
         &self,
-        row_orders: Vec<BlockRowInfo>,
+        row_orders: Vec<RowInfo>,
     ) -> FlowyResult<Vec<GridBlockMetaRevisionChangeset>> {
         let mut changesets = vec![];
         for grid_block in block_from_row_orders(row_orders) {
@@ -186,16 +180,11 @@ impl GridBlockManager {
                     height: row_rev.height,
                 };
 
-                let deleted_row = GridRowId {
-                    grid_id: self.grid_id.clone(),
-                    block_id: row_rev.block_id.clone(),
-                    row_id: row_rev.id.clone(),
-                };
                 let notified_changeset = GridBlockChangeset {
                     block_id: editor.block_id.clone(),
                     inserted_rows: vec![insert_row],
-                    deleted_rows: vec![deleted_row],
-                    updated_rows: vec![],
+                    deleted_rows: vec![row_rev.id.clone()],
+                    ..Default::default()
                 };
 
                 let _ = self
@@ -228,7 +217,7 @@ impl GridBlockManager {
         }
     }
 
-    pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<BlockRowInfo>> {
+    pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowInfo>> {
         let editor = self.get_editor(block_id).await?;
         editor.get_row_infos::<&str>(None).await
     }

+ 5 - 5
frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs

@@ -1,4 +1,4 @@
-use crate::entities::BlockRowInfo;
+use crate::entities::RowInfo;
 use bytes::Bytes;
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision};
@@ -123,12 +123,12 @@ impl GridBlockRevisionEditor {
         Ok(cell_revs)
     }
 
-    pub async fn get_row_info(&self, row_id: &str) -> FlowyResult<Option<BlockRowInfo>> {
+    pub async fn get_row_info(&self, row_id: &str) -> FlowyResult<Option<RowInfo>> {
         let row_ids = Some(vec![Cow::Borrowed(row_id)]);
         Ok(self.get_row_infos(row_ids).await?.pop())
     }
 
-    pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<BlockRowInfo>>
+    pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowInfo>>
     where
         T: AsRef<str> + ToOwned + ?Sized,
     {
@@ -138,8 +138,8 @@ impl GridBlockRevisionEditor {
             .await
             .get_row_revs(row_ids)?
             .iter()
-            .map(BlockRowInfo::from)
-            .collect::<Vec<BlockRowInfo>>();
+            .map(RowInfo::from)
+            .collect::<Vec<RowInfo>>();
         Ok(row_infos)
     }
 

+ 4 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs

@@ -62,7 +62,10 @@ impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
         Ok(DecodedCellData::default())
     }
 
-    fn apply_filter(&self, _filter: GridCheckboxFilter) -> bool {
+    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridCheckboxFilter) -> bool
+    where
+        T: Into<String>,
+    {
         todo!()
     }
 

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

@@ -137,8 +137,10 @@ impl CellDataOperation<String, GridDateFilter> for DateTypeOption {
         let date = self.today_desc_from_timestamp(timestamp);
         DecodedCellData::try_from_bytes(date)
     }
-
-    fn apply_filter(&self, _filter: GridDateFilter) -> bool {
+    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridDateFilter) -> bool
+    where
+        T: Into<String>,
+    {
         todo!()
     }
 

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

@@ -178,8 +178,10 @@ impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
             }
         }
     }
-
-    fn apply_filter(&self, _filter: GridNumberFilter) -> bool {
+    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridNumberFilter) -> bool
+    where
+        T: Into<String>,
+    {
         todo!()
     }
 

+ 8 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs

@@ -123,7 +123,10 @@ impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOptio
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
+    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridSelectOptionFilter) -> bool
+    where
+        T: Into<String>,
+    {
         todo!()
     }
 
@@ -225,7 +228,10 @@ impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
+    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridSelectOptionFilter) -> bool
+    where
+        T: Into<String>,
+    {
         todo!()
     }
 

+ 4 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs

@@ -52,7 +52,10 @@ impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
         }
     }
 
-    fn apply_filter(&self, _filter: GridTextFilter) -> bool {
+    fn apply_filter<T>(&self, encoded_data: T, _filter: &GridTextFilter) -> bool
+    where
+        T: Into<String>,
+    {
         todo!()
     }
 

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

@@ -50,7 +50,7 @@ impl CellDataOperation<EncodedCellData<URLCellData>, GridTextFilter> for URLType
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_filter(&self, _filter: GridTextFilter) -> bool {
+    fn apply_filter(&self, _filter: &GridTextFilter) -> bool {
         todo!()
     }
 

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

@@ -0,0 +1,163 @@
+use crate::entities::{
+    FieldType, GridBlockChangeset, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridRowId,
+    GridSelectOptionFilter, GridTextFilter, InsertedRow,
+};
+
+use dashmap::DashMap;
+
+use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
+use flowy_sync::client_grid::GridRevisionPad;
+
+use std::collections::HashMap;
+use std::sync::Arc;
+use tokio::sync::RwLock;
+
+#[derive(Default)]
+pub(crate) struct FilterResultCache {
+    // key: row id
+    inner: DashMap<String, FilterResult>,
+}
+
+impl FilterResultCache {
+    pub fn new() -> Arc<Self> {
+        let this = Self::default();
+        Arc::new(this)
+    }
+}
+
+impl std::ops::Deref for FilterResultCache {
+    type Target = DashMap<String, FilterResult>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+#[derive(Default)]
+pub(crate) struct FilterResult {
+    pub(crate) row_id: String,
+    pub(crate) row_index: i32,
+    pub(crate) cell_by_field_id: HashMap<String, bool>,
+}
+
+impl FilterResult {
+    pub(crate) fn new(index: i32, row_rev: &RowRevision) -> Self {
+        Self {
+            row_index: index,
+            row_id: row_rev.id.clone(),
+            cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
+        }
+    }
+
+    #[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!()
+    }
+}
+
+#[derive(Default)]
+pub(crate) struct FilterCache {
+    pub(crate) text_filter: DashMap<FilterId, GridTextFilter>,
+    pub(crate) url_filter: DashMap<FilterId, GridTextFilter>,
+    pub(crate) number_filter: DashMap<FilterId, GridNumberFilter>,
+    pub(crate) date_filter: DashMap<FilterId, GridDateFilter>,
+    pub(crate) select_option_filter: DashMap<FilterId, GridSelectOptionFilter>,
+    pub(crate) checkbox_filter: DashMap<FilterId, GridCheckboxFilter>,
+}
+
+impl FilterCache {
+    pub(crate) async fn from_grid_pad(grid_pad: &Arc<RwLock<GridRevisionPad>>) -> Arc<Self> {
+        let this = Arc::new(Self::default());
+        let _ = reload_filter_cache(this.clone(), None, grid_pad).await;
+        this
+    }
+
+    pub(crate) fn remove(&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);
+            }
+        };
+    }
+}
+
+pub(crate) async fn reload_filter_cache(
+    cache: Arc<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();
+
+    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);
+                let field_type: FieldType = field_rev.field_type_rev.into();
+                match &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)]
+pub(crate) struct FilterId {
+    pub(crate) field_id: String,
+    pub(crate) field_type: FieldType,
+}
+
+impl std::convert::From<&Arc<FieldRevision>> for FilterId {
+    fn from(rev: &Arc<FieldRevision>) -> Self {
+        Self {
+            field_id: rev.id.clone(),
+            field_type: rev.field_type_rev.into(),
+        }
+    }
+}

+ 88 - 188
frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs

@@ -1,16 +1,20 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
-use crate::entities::{
-    FieldType, GridBlockChangeset, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridRowId,
-    GridSelectOptionFilter, GridTextFilter, InsertedRow,
-};
+use crate::entities::{FieldType, GridBlockChangeset, GridTextFilter};
 use crate::services::block_manager::GridBlockManager;
+use crate::services::field::RichTextTypeOption;
+use crate::services::filter::filter_cache::{
+    reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
+};
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::row::GridBlockSnapshot;
+use crate::services::row::{CellDataOperation, GridBlockSnapshot};
 use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
+use dashmap::mapref::one::{Ref, RefMut};
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
 use flowy_sync::client_grid::GridRevisionPad;
 use flowy_sync::entities::grid::GridSettingChangesetParams;
+use rayon::prelude::*;
+use std::borrow::Cow;
 use std::collections::HashMap;
 use std::sync::Arc;
 use tokio::sync::RwLock;
@@ -21,8 +25,8 @@ pub(crate) struct GridFilterService {
     scheduler: Arc<dyn GridServiceTaskScheduler>,
     grid_pad: Arc<RwLock<GridRevisionPad>>,
     block_manager: Arc<GridBlockManager>,
-    filter_cache: Arc<RwLock<FilterCache>>,
-    filter_result_cache: Arc<RwLock<FilterResultCache>>,
+    filter_cache: Arc<FilterCache>,
+    filter_result_cache: Arc<FilterResultCache>,
 }
 impl GridFilterService {
     pub async fn new<S: GridServiceTaskScheduler>(
@@ -31,13 +35,14 @@ impl GridFilterService {
         scheduler: S,
     ) -> Self {
         let grid_id = grid_pad.read().await.grid_id();
-        let filter_cache = Arc::new(RwLock::new(FilterCache::from_grid_pad(&grid_pad).await));
-        let filter_result_cache = Arc::new(RwLock::new(FilterResultCache::default()));
+        let scheduler = Arc::new(scheduler);
+        let filter_cache = FilterCache::from_grid_pad(&grid_pad).await;
+        let filter_result_cache = FilterResultCache::new();
         Self {
             grid_id,
             grid_pad,
             block_manager,
-            scheduler: Arc::new(scheduler),
+            scheduler,
             filter_cache,
             filter_result_cache,
         }
@@ -55,37 +60,31 @@ impl GridFilterService {
 
         let mut changesets = vec![];
         for (index, block) in task_context.blocks.into_iter().enumerate() {
-            let mut inserted_rows = vec![];
-            let mut deleted_rows = vec![];
-            block.row_revs.iter().for_each(|row_rev| {
-                let result = filter_row(
-                    index,
-                    row_rev,
-                    &self.filter_cache,
-                    &self.filter_result_cache,
-                    &field_revs,
-                );
+            let results = block
+                .row_revs
+                .par_iter()
+                .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>>();
+
+            let mut visible_rows = vec![];
+            let mut hide_rows = vec![];
+            for result in results {
                 if result.is_visible() {
-                    inserted_rows.push(InsertedRow {
-                        row_id: Default::default(),
-                        block_id: Default::default(),
-                        height: 1,
-                        index: Some(result.row_index),
-                    });
+                    visible_rows.push(result.row_id);
                 } else {
-                    deleted_rows.push(GridRowId {
-                        grid_id: self.grid_id.clone(),
-                        block_id: block.block_id.clone(),
-                        row_id: result.row_id,
-                    });
+                    hide_rows.push(result.row_id);
                 }
-            });
+            }
 
             let changeset = GridBlockChangeset {
                 block_id: block.block_id,
-                inserted_rows,
-                deleted_rows,
-                updated_rows: vec![],
+                hide_rows,
+                visible_rows,
+                ..Default::default()
             };
             changesets.push(changeset);
         }
@@ -99,13 +98,13 @@ impl GridFilterService {
         }
 
         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;
+            reload_filter_cache(self.filter_cache.clone(), field_ids, &self.grid_pad).await;
+            todo!()
         }
 
         if let Some(filter_id) = &changeset.delete_filter {
-            self.filter_cache.write().await.remove(filter_id);
+            self.filter_cache.remove(filter_id);
         }
 
         if let Ok(blocks) = self.block_manager.get_block_snapshots(None).await {
@@ -138,15 +137,58 @@ impl GridFilterService {
 fn filter_row(
     index: usize,
     row_rev: &Arc<RowRevision>,
-    _filter_cache: &Arc<RwLock<FilterCache>>,
-    _filter_result_cache: &Arc<RwLock<FilterResultCache>>,
-    _field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
+    filter_cache: Arc<FilterCache>,
+    filter_result_cache: Arc<FilterResultCache>,
+    field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
 ) -> FilterResult {
-    let filter_result = FilterResult::new(index as i32, row_rev);
-    row_rev.cells.iter().for_each(|(_k, cell_rev)| {
-        let _cell_rev: &CellRevision = cell_rev;
-    });
-    filter_result
+    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);
+            }
+        }
+    }
+
+    todo!()
+}
+
+fn update_filter_result(
+    field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
+    filter_result: &mut FilterResult,
+    filter_cache: &Arc<FilterCache>,
+    field_id: &str,
+    cell_rev: &CellRevision,
+) -> Option<()> {
+    let field_rev = field_revs.get(field_id)?;
+    let field_type = FieldType::from(field_rev.field_type_rev);
+    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);
+            }
+        },
+        FieldType::Number => {}
+        FieldType::DateTime => {}
+        FieldType::SingleSelect => {}
+        FieldType::MultiSelect => {}
+        FieldType::Checkbox => {}
+        FieldType::URL => {}
+    }
+    None
 }
 
 pub struct GridFilterChangeset {
@@ -177,145 +219,3 @@ impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset {
         }
     }
 }
-
-#[derive(Default)]
-struct FilterResultCache {
-    #[allow(dead_code)]
-    rows: HashMap<String, FilterResult>,
-}
-
-impl FilterResultCache {
-    #[allow(dead_code)]
-    fn insert(&mut self, row_id: &str, result: FilterResult) {
-        self.rows.insert(row_id.to_owned(), result);
-    }
-}
-
-#[derive(Default)]
-struct FilterResult {
-    row_id: String,
-    row_index: i32,
-    cell_by_field_id: HashMap<String, bool>,
-}
-
-impl FilterResult {
-    fn new(index: i32, row_rev: &RowRevision) -> Self {
-        Self {
-            row_index: index,
-            row_id: row_rev.id.clone(),
-            cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
-        }
-    }
-
-    #[allow(dead_code)]
-    fn update_cell(&mut self, cell_id: &str, exist: bool) {
-        self.cell_by_field_id.insert(cell_id.to_owned(), exist);
-    }
-
-    fn is_visible(&self) -> bool {
-        todo!()
-    }
-}
-
-#[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();
-        let _ = reload_filter_cache(&mut this, None, grid_pad).await;
-        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();
-
-    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);
-                let field_type: FieldType = field_rev.field_type_rev.into();
-                match &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<&Arc<FieldRevision>> for FilterId {
-    fn from(rev: &Arc<FieldRevision>) -> Self {
-        Self {
-            field_id: rev.id.clone(),
-            field_type: rev.field_type_rev.into(),
-        }
-    }
-}

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/filter/mod.rs

@@ -1,3 +1,4 @@
+mod filter_cache;
 mod filter_service;
 
 pub(crate) use filter_service::*;

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

@@ -265,14 +265,14 @@ impl GridRevisionEditor {
         Ok(())
     }
 
-    pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<BlockRowInfo> {
+    pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowInfo> {
         let field_revs = self.grid_pad.read().await.get_field_revs(None)?;
         let block_id = self.block_id().await?;
 
         // insert empty row below the row whose id is upper_row_id
         let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build();
         let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx);
-        let row_order = BlockRowInfo::from(&row_rev);
+        let row_order = RowInfo::from(&row_rev);
 
         // insert the row
         let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?;
@@ -283,13 +283,13 @@ impl GridRevisionEditor {
         Ok(row_order)
     }
 
-    pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<BlockRowInfo>> {
+    pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<RowInfo>> {
         let block_id = self.block_id().await?;
         let mut rows_by_block_id: HashMap<String, Vec<RowRevision>> = HashMap::new();
         let mut row_orders = vec![];
         for ctx in contexts {
             let row_rev = make_row_rev_from_context(&block_id, ctx);
-            row_orders.push(BlockRowInfo::from(&row_rev));
+            row_orders.push(RowInfo::from(&row_rev));
             rows_by_block_id
                 .entry(block_id.clone())
                 .or_insert_with(Vec::new)
@@ -421,7 +421,7 @@ impl GridRevisionEditor {
         Ok(block_meta_revs)
     }
 
-    pub async fn delete_rows(&self, row_orders: Vec<BlockRowInfo>) -> FlowyResult<()> {
+    pub async fn delete_rows(&self, row_orders: Vec<RowInfo>) -> FlowyResult<()> {
         let changesets = self.block_manager.delete_rows(row_orders).await?;
         for changeset in changesets {
             let _ = self.update_block(changeset).await?;

+ 10 - 1
frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs

@@ -17,7 +17,9 @@ pub trait CellDataOperation<D, F> {
     where
         T: Into<D>;
 
-    fn apply_filter(&self, filter: F) -> bool;
+    fn apply_filter<T>(&self, encoded_data: T, filter: &F) -> bool
+    where
+        T: Into<D>;
 
     fn apply_changeset<C: Into<CellContentChangeset>>(
         &self,
@@ -73,6 +75,13 @@ impl std::convert::TryInto<TypeOptionCellData> for String {
     }
 }
 
+impl std::convert::TryFrom<&CellRevision> for TypeOptionCellData {
+    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 {

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

@@ -1,4 +1,4 @@
-use crate::entities::{BlockRowInfo, GridBlock, RepeatedGridBlock, Row};
+use crate::entities::{GridBlock, RepeatedGridBlock, Row, RowInfo};
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
 use std::collections::HashMap;
@@ -9,7 +9,7 @@ pub struct GridBlockSnapshot {
     pub row_revs: Vec<Arc<RowRevision>>,
 }
 
-pub(crate) fn block_from_row_orders(row_orders: Vec<BlockRowInfo>) -> Vec<GridBlock> {
+pub(crate) fn block_from_row_orders(row_orders: Vec<RowInfo>) -> Vec<GridBlock> {
     let mut map: HashMap<String, GridBlock> = HashMap::new();
     row_orders.into_iter().for_each(|row_info| {
         // Memory Optimization: escape clone block_id
@@ -35,8 +35,8 @@ pub(crate) fn block_from_row_orders(row_orders: Vec<BlockRowInfo>) -> Vec<GridBl
 //     Some((field_id, cell))
 // }
 
-pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<BlockRowInfo> {
-    row_revs.iter().map(BlockRowInfo::from).collect::<Vec<_>>()
+pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<RowInfo> {
+    row_revs.iter().map(RowInfo::from).collect::<Vec<_>>()
 }
 
 pub(crate) fn make_row_from_row_rev(fields: &[Arc<FieldRevision>], row_rev: Arc<RowRevision>) -> Option<Row> {

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

@@ -137,9 +137,9 @@ async fn grid_row_add_date_cell_test() {
     }
     let context = builder.build();
     let date_field = date_field.unwrap();
-    let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
+    let cell_rev = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
     assert_eq!(
-        decode_cell_data(cell_data.data.clone(), &date_field)
+        decode_cell_data(cell_rev, &date_field)
             .parse::<DateCellData>()
             .unwrap()
             .date,

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

@@ -99,7 +99,7 @@ pub struct GridEditorTest {
     pub row_revs: Vec<Arc<RowRevision>>,
     pub field_count: usize,
 
-    pub row_order_by_row_id: HashMap<String, BlockRowInfo>,
+    pub row_order_by_row_id: HashMap<String, RowInfo>,
 }
 
 impl GridEditorTest {
@@ -220,7 +220,7 @@ impl GridEditorTest {
                 let row_orders = row_ids
                     .into_iter()
                     .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
-                    .collect::<Vec<BlockRowInfo>>();
+                    .collect::<Vec<RowInfo>>();
 
                 self.editor.delete_rows(row_orders).await.unwrap();
                 self.row_revs = self.get_row_revs().await;