|
@@ -1,8 +1,8 @@
|
|
use crate::entities::filter_entities::*;
|
|
use crate::entities::filter_entities::*;
|
|
use crate::entities::{FieldType, InsertedRowPB, RowPB};
|
|
use crate::entities::{FieldType, InsertedRowPB, RowPB};
|
|
-use crate::services::cell::{CellFilterable, TypeCellData};
|
|
|
|
|
|
+use crate::services::cell::{AnyTypeCache, AtomicCellDataCache, AtomicCellFilterCache, TypeCellData};
|
|
use crate::services::field::*;
|
|
use crate::services::field::*;
|
|
-use crate::services::filter::{FilterChangeset, FilterMap, FilterResult, FilterResultNotification, FilterType};
|
|
|
|
|
|
+use crate::services::filter::{FilterChangeset, FilterResult, FilterResultNotification, FilterType};
|
|
use crate::services::row::GridBlockRowRevision;
|
|
use crate::services::row::GridBlockRowRevision;
|
|
use crate::services::view_editor::{GridViewChanged, GridViewChangedNotifier};
|
|
use crate::services::view_editor::{GridViewChanged, GridViewChangedNotifier};
|
|
use flowy_error::FlowyResult;
|
|
use flowy_error::FlowyResult;
|
|
@@ -24,12 +24,19 @@ pub trait FilterDelegate: Send + Sync + 'static {
|
|
fn get_row_rev(&self, rows_id: &str) -> Fut<Option<(usize, Arc<RowRevision>)>>;
|
|
fn get_row_rev(&self, rows_id: &str) -> Fut<Option<(usize, Arc<RowRevision>)>>;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+pub trait FromFilterString {
|
|
|
|
+ fn from_filter_rev(filter_rev: &FilterRevision) -> Self
|
|
|
|
+ where
|
|
|
|
+ Self: Sized;
|
|
|
|
+}
|
|
|
|
+
|
|
pub struct FilterController {
|
|
pub struct FilterController {
|
|
view_id: String,
|
|
view_id: String,
|
|
handler_id: String,
|
|
handler_id: String,
|
|
delegate: Box<dyn FilterDelegate>,
|
|
delegate: Box<dyn FilterDelegate>,
|
|
- filter_map: FilterMap,
|
|
|
|
result_by_row_id: HashMap<RowId, FilterResult>,
|
|
result_by_row_id: HashMap<RowId, FilterResult>,
|
|
|
|
+ cell_data_cache: AtomicCellDataCache,
|
|
|
|
+ cell_filter_cache: AtomicCellFilterCache,
|
|
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
|
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
|
notifier: GridViewChangedNotifier,
|
|
notifier: GridViewChangedNotifier,
|
|
}
|
|
}
|
|
@@ -41,6 +48,7 @@ impl FilterController {
|
|
delegate: T,
|
|
delegate: T,
|
|
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
|
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
|
filter_revs: Vec<Arc<FilterRevision>>,
|
|
filter_revs: Vec<Arc<FilterRevision>>,
|
|
|
|
+ cell_data_cache: AtomicCellDataCache,
|
|
notifier: GridViewChangedNotifier,
|
|
notifier: GridViewChangedNotifier,
|
|
) -> Self
|
|
) -> Self
|
|
where
|
|
where
|
|
@@ -50,8 +58,9 @@ impl FilterController {
|
|
view_id: view_id.to_string(),
|
|
view_id: view_id.to_string(),
|
|
handler_id: handler_id.to_string(),
|
|
handler_id: handler_id.to_string(),
|
|
delegate: Box::new(delegate),
|
|
delegate: Box::new(delegate),
|
|
- filter_map: FilterMap::new(),
|
|
|
|
result_by_row_id: HashMap::default(),
|
|
result_by_row_id: HashMap::default(),
|
|
|
|
+ cell_data_cache,
|
|
|
|
+ cell_filter_cache: AnyTypeCache::<FilterType>::new(),
|
|
task_scheduler,
|
|
task_scheduler,
|
|
notifier,
|
|
notifier,
|
|
};
|
|
};
|
|
@@ -75,16 +84,17 @@ impl FilterController {
|
|
}
|
|
}
|
|
|
|
|
|
pub async fn filter_row_revs(&mut self, row_revs: &mut Vec<Arc<RowRevision>>) {
|
|
pub async fn filter_row_revs(&mut self, row_revs: &mut Vec<Arc<RowRevision>>) {
|
|
- if self.filter_map.is_empty() {
|
|
|
|
|
|
+ if self.cell_filter_cache.read().is_empty() {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
let field_rev_by_field_id = self.get_filter_revs_map().await;
|
|
let field_rev_by_field_id = self.get_filter_revs_map().await;
|
|
row_revs.iter().for_each(|row_rev| {
|
|
row_revs.iter().for_each(|row_rev| {
|
|
let _ = filter_row(
|
|
let _ = filter_row(
|
|
row_rev,
|
|
row_rev,
|
|
- &self.filter_map,
|
|
|
|
&mut self.result_by_row_id,
|
|
&mut self.result_by_row_id,
|
|
&field_rev_by_field_id,
|
|
&field_rev_by_field_id,
|
|
|
|
+ &self.cell_data_cache,
|
|
|
|
+ &self.cell_filter_cache,
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -121,9 +131,10 @@ impl FilterController {
|
|
let mut notification = FilterResultNotification::new(self.view_id.clone(), row_rev.block_id.clone());
|
|
let mut notification = FilterResultNotification::new(self.view_id.clone(), row_rev.block_id.clone());
|
|
if let Some((row_id, is_visible)) = filter_row(
|
|
if let Some((row_id, is_visible)) = filter_row(
|
|
&row_rev,
|
|
&row_rev,
|
|
- &self.filter_map,
|
|
|
|
&mut self.result_by_row_id,
|
|
&mut self.result_by_row_id,
|
|
&field_rev_by_field_id,
|
|
&field_rev_by_field_id,
|
|
|
|
+ &self.cell_data_cache,
|
|
|
|
+ &self.cell_filter_cache,
|
|
) {
|
|
) {
|
|
if is_visible {
|
|
if is_visible {
|
|
if let Some((index, row_rev)) = self.delegate.get_row_rev(&row_id).await {
|
|
if let Some((index, row_rev)) = self.delegate.get_row_rev(&row_id).await {
|
|
@@ -154,9 +165,10 @@ impl FilterController {
|
|
for (index, row_rev) in block.row_revs.iter().enumerate() {
|
|
for (index, row_rev) in block.row_revs.iter().enumerate() {
|
|
if let Some((row_id, is_visible)) = filter_row(
|
|
if let Some((row_id, is_visible)) = filter_row(
|
|
row_rev,
|
|
row_rev,
|
|
- &self.filter_map,
|
|
|
|
&mut self.result_by_row_id,
|
|
&mut self.result_by_row_id,
|
|
&field_rev_by_field_id,
|
|
&field_rev_by_field_id,
|
|
|
|
+ &self.cell_data_cache,
|
|
|
|
+ &self.cell_filter_cache,
|
|
) {
|
|
) {
|
|
if is_visible {
|
|
if is_visible {
|
|
let row_pb = RowPB::from(row_rev.as_ref());
|
|
let row_pb = RowPB::from(row_rev.as_ref());
|
|
@@ -233,7 +245,7 @@ impl FilterController {
|
|
if let Some(filter) = self.filter_from_filter_type(filter_type).await {
|
|
if let Some(filter) = self.filter_from_filter_type(filter_type).await {
|
|
notification = Some(FilterChangesetNotificationPB::from_delete(&self.view_id, vec![filter]));
|
|
notification = Some(FilterChangesetNotificationPB::from_delete(&self.view_id, vec![filter]));
|
|
}
|
|
}
|
|
- self.filter_map.remove(filter_type);
|
|
|
|
|
|
+ self.cell_filter_cache.write().remove(filter_type);
|
|
}
|
|
}
|
|
|
|
|
|
let _ = self
|
|
let _ = self
|
|
@@ -258,46 +270,39 @@ impl FilterController {
|
|
tracing::trace!("Create filter with type: {:?}", filter_type);
|
|
tracing::trace!("Create filter with type: {:?}", filter_type);
|
|
match &filter_type.field_type {
|
|
match &filter_type.field_type {
|
|
FieldType::RichText => {
|
|
FieldType::RichText => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .text_filter
|
|
|
|
- .insert(filter_type, TextFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, TextFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
FieldType::Number => {
|
|
FieldType::Number => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .number_filter
|
|
|
|
- .insert(filter_type, NumberFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, NumberFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
FieldType::DateTime => {
|
|
FieldType::DateTime => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .date_filter
|
|
|
|
- .insert(filter_type, DateFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, DateFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
FieldType::SingleSelect | FieldType::MultiSelect => {
|
|
FieldType::SingleSelect | FieldType::MultiSelect => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .select_option_filter
|
|
|
|
- .insert(filter_type, SelectOptionFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, SelectOptionFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
FieldType::Checkbox => {
|
|
FieldType::Checkbox => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .checkbox_filter
|
|
|
|
- .insert(filter_type, CheckboxFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, CheckboxFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
FieldType::URL => {
|
|
FieldType::URL => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .url_filter
|
|
|
|
- .insert(filter_type, TextFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, TextFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
FieldType::Checklist => {
|
|
FieldType::Checklist => {
|
|
- let _ = self
|
|
|
|
- .filter_map
|
|
|
|
- .checklist_filter
|
|
|
|
- .insert(filter_type, ChecklistFilterPB::from(filter_rev.as_ref()));
|
|
|
|
|
|
+ self.cell_filter_cache
|
|
|
|
+ .write()
|
|
|
|
+ .insert(&filter_type, ChecklistFilterPB::from_filter_rev(filter_rev.as_ref()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -309,9 +314,10 @@ impl FilterController {
|
|
#[tracing::instrument(level = "trace", skip_all)]
|
|
#[tracing::instrument(level = "trace", skip_all)]
|
|
fn filter_row(
|
|
fn filter_row(
|
|
row_rev: &Arc<RowRevision>,
|
|
row_rev: &Arc<RowRevision>,
|
|
- filter_map: &FilterMap,
|
|
|
|
result_by_row_id: &mut HashMap<RowId, FilterResult>,
|
|
result_by_row_id: &mut HashMap<RowId, FilterResult>,
|
|
field_rev_by_field_id: &HashMap<FieldId, Arc<FieldRevision>>,
|
|
field_rev_by_field_id: &HashMap<FieldId, Arc<FieldRevision>>,
|
|
|
|
+ cell_data_cache: &AtomicCellDataCache,
|
|
|
|
+ cell_filter_cache: &AtomicCellFilterCache,
|
|
) -> Option<(String, bool)> {
|
|
) -> Option<(String, bool)> {
|
|
// Create a filter result cache if it's not exist
|
|
// Create a filter result cache if it's not exist
|
|
let filter_result = result_by_row_id
|
|
let filter_result = result_by_row_id
|
|
@@ -322,7 +328,7 @@ fn filter_row(
|
|
// Iterate each cell of the row to check its visibility
|
|
// Iterate each cell of the row to check its visibility
|
|
for (field_id, field_rev) in field_rev_by_field_id {
|
|
for (field_id, field_rev) in field_rev_by_field_id {
|
|
let filter_type = FilterType::from(field_rev);
|
|
let filter_type = FilterType::from(field_rev);
|
|
- if !filter_map.has_filter(&filter_type) {
|
|
|
|
|
|
+ if !cell_filter_cache.read().contains(&filter_type) {
|
|
filter_result.visible_by_filter_id.remove(&filter_type);
|
|
filter_result.visible_by_filter_id.remove(&filter_type);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
@@ -330,7 +336,7 @@ fn filter_row(
|
|
let cell_rev = row_rev.cells.get(field_id);
|
|
let cell_rev = row_rev.cells.get(field_id);
|
|
// if the visibility of the cell_rew is changed, which means the visibility of the
|
|
// if the visibility of the cell_rew is changed, which means the visibility of the
|
|
// row is changed too.
|
|
// row is changed too.
|
|
- if let Some(is_visible) = filter_cell(&filter_type, field_rev, filter_map, cell_rev) {
|
|
|
|
|
|
+ if let Some(is_visible) = filter_cell(&filter_type, field_rev, cell_rev, cell_data_cache, cell_filter_cache) {
|
|
filter_result.visible_by_filter_id.insert(filter_type, is_visible);
|
|
filter_result.visible_by_filter_id.insert(filter_type, is_visible);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -348,93 +354,32 @@ fn filter_row(
|
|
|
|
|
|
#[tracing::instrument(level = "trace", skip_all, fields(cell_content))]
|
|
#[tracing::instrument(level = "trace", skip_all, fields(cell_content))]
|
|
fn filter_cell(
|
|
fn filter_cell(
|
|
- filter_id: &FilterType,
|
|
|
|
|
|
+ filter_type: &FilterType,
|
|
field_rev: &Arc<FieldRevision>,
|
|
field_rev: &Arc<FieldRevision>,
|
|
- filter_map: &FilterMap,
|
|
|
|
cell_rev: Option<&CellRevision>,
|
|
cell_rev: Option<&CellRevision>,
|
|
|
|
+ cell_data_cache: &AtomicCellDataCache,
|
|
|
|
+ cell_filter_cache: &AtomicCellFilterCache,
|
|
) -> Option<bool> {
|
|
) -> Option<bool> {
|
|
let type_cell_data = match cell_rev {
|
|
let type_cell_data = match cell_rev {
|
|
- None => TypeCellData::from_field_type(&filter_id.field_type),
|
|
|
|
|
|
+ None => TypeCellData::from_field_type(&filter_type.field_type),
|
|
Some(cell_rev) => match TypeCellData::try_from(cell_rev) {
|
|
Some(cell_rev) => match TypeCellData::try_from(cell_rev) {
|
|
Ok(cell_data) => cell_data,
|
|
Ok(cell_data) => cell_data,
|
|
Err(err) => {
|
|
Err(err) => {
|
|
tracing::error!("Deserialize TypeCellData failed: {}", err);
|
|
tracing::error!("Deserialize TypeCellData failed: {}", err);
|
|
- TypeCellData::from_field_type(&filter_id.field_type)
|
|
|
|
|
|
+ TypeCellData::from_field_type(&filter_type.field_type)
|
|
}
|
|
}
|
|
},
|
|
},
|
|
};
|
|
};
|
|
- let cloned_type_cell_data = type_cell_data.cell_str.clone();
|
|
|
|
- let is_visible = match &filter_id.field_type {
|
|
|
|
- FieldType::RichText => filter_map.text_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<RichTextTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::Number => filter_map.number_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<NumberTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::DateTime => filter_map.date_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<DateTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::SingleSelect => filter_map.select_option_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<SingleSelectTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::MultiSelect => filter_map.select_option_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<MultiSelectTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::Checkbox => filter_map.checkbox_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<CheckboxTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::URL => filter_map.url_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<URLTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- FieldType::Checklist => filter_map.checklist_filter.get(filter_id).and_then(|filter| {
|
|
|
|
- Some(
|
|
|
|
- field_rev
|
|
|
|
- .get_type_option::<ChecklistTypeOptionPB>(field_rev.ty)?
|
|
|
|
- .apply_filter(type_cell_data, filter)
|
|
|
|
- .ok(),
|
|
|
|
- )
|
|
|
|
- }),
|
|
|
|
- }?;
|
|
|
|
- tracing::Span::current().record(
|
|
|
|
- "cell_content",
|
|
|
|
- &format!("{} => {:?}", cloned_type_cell_data, is_visible.unwrap()).as_str(),
|
|
|
|
- );
|
|
|
|
- is_visible
|
|
|
|
|
|
+
|
|
|
|
+ let handler = TypeOptionCellExt::new(
|
|
|
|
+ field_rev.as_ref(),
|
|
|
|
+ Some(cell_data_cache.clone()),
|
|
|
|
+ Some(cell_filter_cache.clone()),
|
|
|
|
+ )
|
|
|
|
+ .get_type_option_cell_data_handler(&filter_type.field_type)?;
|
|
|
|
+
|
|
|
|
+ let is_visible = handler.handle_cell_filter(filter_type, field_rev.as_ref(), type_cell_data);
|
|
|
|
+ Some(is_visible)
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|