chore: cache filter result

This commit is contained in:
appflowy 2022-06-30 23:00:03 +08:00
parent 4d8f101a42
commit 50d0eff039
23 changed files with 622 additions and 204 deletions

View File

@ -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()?;

View File

@ -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>,

View File

@ -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>,

View File

@ -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>,

View File

@ -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>,

View File

@ -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>,

View File

@ -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>,

View File

@ -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(),
}
}
}

View File

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

View File

@ -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(())
})

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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(());
}
}

View File

@ -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)
}

View File

@ -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,
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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 {

View File

@ -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),
}
}
}

View File

@ -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 {

View File

@ -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,

View File

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