mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: cache filter result
This commit is contained in:
parent
4d8f101a42
commit
50d0eff039
@ -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()?;
|
||||
|
@ -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>,
|
||||
|
@ -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,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>,
|
||||
|
@ -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>,
|
||||
|
@ -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>,
|
||||
|
@ -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>,
|
||||
|
@ -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) {
|
||||
let task_id = self.scheduler.gen_task_id().await;
|
||||
pub async fn apply_changeset(&self, changeset: GridFilterChangeset) {
|
||||
if !changeset.is_changed() {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 => {}
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
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();
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(¶ms);
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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(())
|
||||
})
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,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)
|
||||
}
|
||||
|
@ -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 enum TaskContent {
|
||||
Snapshot { context: SnapshotTaskContext },
|
||||
Filter { context: FilterTaskContext },
|
||||
pub(crate) struct FilterTaskContext {
|
||||
pub blocks: Vec<GridBlockSnapshot>,
|
||||
}
|
||||
|
||||
pub struct Task {
|
||||
pub hid: TaskHandlerId,
|
||||
pub(crate) enum TaskContent {
|
||||
Snapshot,
|
||||
Filter(FilterTaskContext),
|
||||
}
|
||||
|
||||
pub(crate) struct Task {
|
||||
pub handler_id: TaskHandlerId,
|
||||
pub id: TaskId,
|
||||
pub content: TaskContent,
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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, ¶ms.field_id, ¶ms.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, ¶ms.filter_id, ¶ms.field_type)
|
||||
{
|
||||
Some(filters) => {
|
||||
filters.retain(|filter| filter.id != params.filter_id);
|
||||
}
|
||||
None => {
|
||||
tracing::warn!("Can't find the filter with {:?}", layout_rev);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user