chore: clean up sort and filter code (#4585)

* refactor: port away from extra SortType struct

* refactor: add validator to flowy_database and clean up unused structs

* refactor: port away from extra FilterType struct

* chore: analysis options

* fix: clippy and dart/ts compile

* fix: tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Richard Shiue
2024-02-04 05:49:28 +08:00
committed by GitHub
parent d117cd6b5b
commit 250f29f325
18 changed files with 541 additions and 667 deletions

View File

@ -81,10 +81,8 @@ class SortBackendService {
required FieldType fieldType, required FieldType fieldType,
}) { }) {
final deleteSortPayload = DeleteSortPayloadPB.create() final deleteSortPayload = DeleteSortPayloadPB.create()
..fieldId = fieldId
..sortId = sortId ..sortId = sortId
..viewId = viewId ..viewId = viewId;
..fieldType = fieldType;
final payload = DatabaseSettingChangesetPB.create() final payload = DatabaseSettingChangesetPB.create()
..viewId = viewId ..viewId = viewId

View File

@ -57,8 +57,6 @@ export async function deleteSort(viewId: string, sort: Sort): Promise<void> {
delete_sort: { delete_sort: {
view_id: viewId, view_id: viewId,
sort_id: sort.id, sort_id: sort.id,
field_id: sort.fieldId,
field_type: sort.fieldType,
}, },
}); });

View File

@ -1102,7 +1102,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa", "itoa",
"phf 0.11.2", "phf 0.8.0",
"smallvec", "smallvec",
] ]
@ -3588,7 +3588,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [ dependencies = [
"phf_macros 0.8.0", "phf_macros",
"phf_shared 0.8.0", "phf_shared 0.8.0",
"proc-macro-hack", "proc-macro-hack",
] ]
@ -3608,7 +3608,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [ dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2", "phf_shared 0.11.2",
] ]
@ -3676,19 +3675,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.47",
]
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.8.0" version = "0.8.0"

View File

@ -6,6 +6,7 @@ use collab_database::fields::Field;
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use validator::Validate;
use crate::entities::parser::NotEmptyStr; use crate::entities::parser::NotEmptyStr;
use crate::entities::{ use crate::entities::{
@ -13,7 +14,7 @@ use crate::entities::{
NumberFilterPB, SelectOptionFilterPB, TextFilterPB, NumberFilterPB, SelectOptionFilterPB, TextFilterPB,
}; };
use crate::services::field::SelectOptionIds; use crate::services::field::SelectOptionIds;
use crate::services::filter::{Filter, FilterType}; use crate::services::filter::Filter;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct FilterPB { pub struct FilterPB {
@ -73,60 +74,28 @@ impl std::convert::From<Vec<FilterPB>> for RepeatedFilterPB {
} }
} }
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone, Validate)]
pub struct DeleteFilterPayloadPB { pub struct DeleteFilterPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub field_id: String, pub field_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub field_type: FieldType, pub field_type: FieldType,
#[pb(index = 3)] #[pb(index = 3)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub filter_id: String, pub filter_id: String,
#[pb(index = 4)] #[pb(index = 4)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub view_id: String, pub view_id: String,
} }
impl TryInto<DeleteFilterParams> for DeleteFilterPayloadPB { #[derive(ProtoBuf, Debug, Default, Clone, Validate)]
type Error = ErrorCode;
fn try_into(self) -> Result<DeleteFilterParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)?
.0;
let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let filter_id = NotEmptyStr::parse(self.filter_id)
.map_err(|_| ErrorCode::UnexpectedEmpty)?
.0;
let filter_type = FilterType {
filter_id: filter_id.clone(),
field_id,
field_type: self.field_type,
};
Ok(DeleteFilterParams {
view_id,
filter_id,
filter_type,
})
}
}
#[derive(Debug)]
pub struct DeleteFilterParams {
pub view_id: String,
pub filter_id: String,
pub filter_type: FilterType,
}
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct UpdateFilterPayloadPB { pub struct UpdateFilterPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub field_id: String, pub field_id: String,
#[pb(index = 2)] #[pb(index = 2)]
@ -134,12 +103,14 @@ pub struct UpdateFilterPayloadPB {
/// Create a new filter if the filter_id is None /// Create a new filter if the filter_id is None
#[pb(index = 3, one_of)] #[pb(index = 3, one_of)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub filter_id: Option<String>, pub filter_id: Option<String>,
#[pb(index = 4)] #[pb(index = 4)]
pub data: Vec<u8>, pub data: Vec<u8>,
#[pb(index = 5)] #[pb(index = 5)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub view_id: String, pub view_id: String,
} }

View File

@ -2,6 +2,7 @@ use std::convert::TryInto;
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use validator::Validate;
use crate::entities::parser::NotEmptyStr; use crate::entities::parser::NotEmptyStr;
use crate::entities::RowMetaPB; use crate::entities::RowMetaPB;
@ -130,15 +131,18 @@ pub struct GroupByFieldParams {
pub view_id: String, pub view_id: String,
} }
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone, Validate)]
pub struct UpdateGroupPB { pub struct UpdateGroupPB {
#[pb(index = 1)] #[pb(index = 1)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub view_id: String, pub view_id: String,
#[pb(index = 2)] #[pb(index = 2)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub group_id: String, pub group_id: String,
#[pb(index = 3)] #[pb(index = 3)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub field_id: String, pub field_id: String,
#[pb(index = 4, one_of)] #[pb(index = 4, one_of)]

View File

@ -5,12 +5,12 @@ use strum_macros::EnumIter;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use validator::Validate;
use crate::entities::parser::NotEmptyStr; use crate::entities::parser::NotEmptyStr;
use crate::entities::{ use crate::entities::{
CalendarLayoutSettingPB, DeleteFilterParams, DeleteFilterPayloadPB, DeleteSortParams, CalendarLayoutSettingPB, DeleteFilterPayloadPB, DeleteSortPayloadPB, RepeatedFieldSettingsPB,
DeleteSortPayloadPB, RepeatedFieldSettingsPB, RepeatedFilterPB, RepeatedGroupSettingPB, RepeatedFilterPB, RepeatedGroupSettingPB, RepeatedSortPB, UpdateFilterPayloadPB, UpdateGroupPB,
RepeatedSortPB, UpdateFilterParams, UpdateFilterPayloadPB, UpdateGroupPB, UpdateSortParams,
UpdateSortPayloadPB, UpdateSortPayloadPB,
}; };
use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting}; use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting};
@ -69,84 +69,36 @@ impl std::convert::From<DatabaseLayoutPB> for DatabaseLayout {
} }
} }
#[derive(Default, ProtoBuf)] #[derive(Default, Validate, ProtoBuf)]
pub struct DatabaseSettingChangesetPB { pub struct DatabaseSettingChangesetPB {
#[pb(index = 1)] #[pb(index = 1)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub view_id: String, pub view_id: String,
#[pb(index = 2, one_of)] #[pb(index = 2, one_of)]
pub layout_type: Option<DatabaseLayoutPB>, pub layout_type: Option<DatabaseLayoutPB>,
#[pb(index = 3, one_of)] #[pb(index = 3, one_of)]
#[validate]
pub update_filter: Option<UpdateFilterPayloadPB>, pub update_filter: Option<UpdateFilterPayloadPB>,
#[pb(index = 4, one_of)] #[pb(index = 4, one_of)]
#[validate]
pub delete_filter: Option<DeleteFilterPayloadPB>, pub delete_filter: Option<DeleteFilterPayloadPB>,
#[pb(index = 5, one_of)] #[pb(index = 5, one_of)]
#[validate]
pub update_group: Option<UpdateGroupPB>, pub update_group: Option<UpdateGroupPB>,
#[pb(index = 6, one_of)] #[pb(index = 6, one_of)]
#[validate]
pub update_sort: Option<UpdateSortPayloadPB>, pub update_sort: Option<UpdateSortPayloadPB>,
#[pb(index = 7, one_of)] #[pb(index = 7, one_of)]
#[validate]
pub delete_sort: Option<DeleteSortPayloadPB>, pub delete_sort: Option<DeleteSortPayloadPB>,
} }
impl TryInto<DatabaseSettingChangesetParams> for DatabaseSettingChangesetPB {
type Error = ErrorCode;
fn try_into(self) -> Result<DatabaseSettingChangesetParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::ViewIdIsInvalid)?
.0;
let insert_filter = match self.update_filter {
None => None,
Some(payload) => Some(payload.try_into()?),
};
let delete_filter = match self.delete_filter {
None => None,
Some(payload) => Some(payload.try_into()?),
};
let alert_sort = match self.update_sort {
None => None,
Some(payload) => Some(payload.try_into()?),
};
let delete_sort = match self.delete_sort {
None => None,
Some(payload) => Some(payload.try_into()?),
};
Ok(DatabaseSettingChangesetParams {
view_id,
layout_type: self.layout_type.map(|ty| ty.into()),
insert_filter,
delete_filter,
alert_sort,
delete_sort,
})
}
}
pub struct DatabaseSettingChangesetParams {
pub view_id: String,
pub layout_type: Option<DatabaseLayout>,
pub insert_filter: Option<UpdateFilterParams>,
pub delete_filter: Option<DeleteFilterParams>,
pub alert_sort: Option<UpdateSortParams>,
pub delete_sort: Option<DeleteSortParams>,
}
impl DatabaseSettingChangesetParams {
pub fn is_filter_changed(&self) -> bool {
self.insert_filter.is_some() || self.delete_filter.is_some()
}
}
#[derive(Debug, Eq, PartialEq, Default, ProtoBuf, Clone)] #[derive(Debug, Eq, PartialEq, Default, ProtoBuf, Clone)]
pub struct DatabaseLayoutSettingPB { pub struct DatabaseLayoutSettingPB {
#[pb(index = 1)] #[pb(index = 1)]

View File

@ -1,9 +1,8 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode; use validator::Validate;
use crate::entities::parser::NotEmptyStr;
use crate::entities::FieldType; use crate::entities::FieldType;
use crate::services::sort::{Sort, SortCondition, SortType}; use crate::services::sort::{Sort, SortCondition};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct SortPB { pub struct SortPB {
@ -91,12 +90,14 @@ impl std::convert::From<SortConditionPB> for SortCondition {
} }
} }
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone, Validate)]
pub struct UpdateSortPayloadPB { pub struct UpdateSortPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub view_id: String, pub view_id: String,
#[pb(index = 2)] #[pb(index = 2)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub field_id: String, pub field_id: String,
#[pb(index = 3)] #[pb(index = 3)]
@ -110,95 +111,14 @@ pub struct UpdateSortPayloadPB {
pub condition: SortConditionPB, pub condition: SortConditionPB,
} }
impl TryInto<UpdateSortParams> for UpdateSortPayloadPB { #[derive(ProtoBuf, Debug, Default, Clone, Validate)]
type Error = ErrorCode;
fn try_into(self) -> Result<UpdateSortParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)?
.0;
let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let sort_id = match self.sort_id {
None => None,
Some(sort_id) => Some(
NotEmptyStr::parse(sort_id)
.map_err(|_| ErrorCode::SortIdIsEmpty)?
.0,
),
};
Ok(UpdateSortParams {
view_id,
field_id,
sort_id,
field_type: self.field_type,
condition: self.condition.into(),
})
}
}
#[derive(Debug)]
pub struct UpdateSortParams {
pub view_id: String,
pub field_id: String,
/// Create a new sort if the sort is None
pub sort_id: Option<String>,
pub field_type: FieldType,
pub condition: SortCondition,
}
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct DeleteSortPayloadPB { pub struct DeleteSortPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
pub view_id: String, pub view_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub field_id: String, #[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
#[pb(index = 3)]
pub field_type: FieldType,
#[pb(index = 4)]
pub sort_id: String,
}
impl TryInto<DeleteSortParams> for DeleteSortPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<DeleteSortParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)?
.0;
let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let sort_id = NotEmptyStr::parse(self.sort_id)
.map_err(|_| ErrorCode::UnexpectedEmpty)?
.0;
let sort_type = SortType {
sort_id: sort_id.clone(),
field_id,
field_type: self.field_type,
};
Ok(DeleteSortParams {
view_id,
sort_type,
sort_id,
})
}
}
#[derive(Debug, Clone)]
pub struct DeleteSortParams {
pub view_id: String,
pub sort_type: SortType,
pub sort_id: String, pub sort_id: String,
} }

View File

@ -87,27 +87,30 @@ pub(crate) async fn update_database_setting_handler(
manager: AFPluginState<Weak<DatabaseManager>>, manager: AFPluginState<Weak<DatabaseManager>>,
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
let manager = upgrade_manager(manager)?; let manager = upgrade_manager(manager)?;
let params: DatabaseSettingChangesetParams = data.into_inner().try_into()?; let params = data.try_into_inner()?;
let editor = manager.get_database_with_view_id(&params.view_id).await?; let editor = manager.get_database_with_view_id(&params.view_id).await?;
if let Some(update_filter) = params.insert_filter { if let Some(update_filter) = params.update_filter {
editor.create_or_update_filter(update_filter).await?; editor
.create_or_update_filter(update_filter.try_into()?)
.await?;
} }
if let Some(delete_filter) = params.delete_filter { if let Some(delete_filter) = params.delete_filter {
editor.delete_filter(delete_filter).await?; editor.delete_filter(delete_filter).await?;
} }
if let Some(update_sort) = params.alert_sort { if let Some(update_sort) = params.update_sort {
let _ = editor.create_or_update_sort(update_sort).await?; let _ = editor.create_or_update_sort(update_sort).await?;
} }
if let Some(delete_sort) = params.delete_sort { if let Some(delete_sort) = params.delete_sort {
editor.delete_sort(delete_sort).await?; editor.delete_sort(delete_sort).await?;
} }
if let Some(layout_type) = params.layout_type { if let Some(layout_type) = params.layout_type {
editor editor
.update_view_layout(&params.view_id, layout_type) .update_view_layout(&params.view_id, layout_type.into())
.await?; .await?;
} }
Ok(()) Ok(())

View File

@ -208,19 +208,19 @@ impl DatabaseEditor {
Ok(()) Ok(())
} }
pub async fn delete_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> { pub async fn delete_filter(&self, params: DeleteFilterPayloadPB) -> FlowyResult<()> {
let view_editor = self.database_views.get_view_editor(&params.view_id).await?; let view_editor = self.database_views.get_view_editor(&params.view_id).await?;
view_editor.v_delete_filter(params).await?; view_editor.v_delete_filter(params).await?;
Ok(()) Ok(())
} }
pub async fn create_or_update_sort(&self, params: UpdateSortParams) -> FlowyResult<Sort> { pub async fn create_or_update_sort(&self, params: UpdateSortPayloadPB) -> FlowyResult<Sort> {
let view_editor = self.database_views.get_view_editor(&params.view_id).await?; let view_editor = self.database_views.get_view_editor(&params.view_id).await?;
let sort = view_editor.v_insert_sort(params).await?; let sort = view_editor.insert_or_update_sort(params).await?;
Ok(sort) Ok(sort)
} }
pub async fn delete_sort(&self, params: DeleteSortParams) -> FlowyResult<()> { pub async fn delete_sort(&self, params: DeleteSortPayloadPB) -> FlowyResult<()> {
let view_editor = self.database_views.get_view_editor(&params.view_id).await?; let view_editor = self.database_views.get_view_editor(&params.view_id).await?;
view_editor.v_delete_sort(params).await?; view_editor.v_delete_sort(params).await?;
Ok(()) Ok(())

View File

@ -15,11 +15,11 @@ use flowy_error::{FlowyError, FlowyResult};
use lib_dispatch::prelude::af_spawn; use lib_dispatch::prelude::af_spawn;
use crate::entities::{ use crate::entities::{
CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterParams, CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterPayloadPB,
DeleteSortParams, FieldType, FieldVisibility, GroupChangesPB, GroupPB, InsertedRowPB, DeleteSortPayloadPB, FieldType, FieldVisibility, GroupChangesPB, GroupPB, InsertedRowPB,
LayoutSettingChangeset, LayoutSettingParams, RemoveCalculationChangesetPB, RowMetaPB, LayoutSettingChangeset, LayoutSettingParams, RemoveCalculationChangesetPB, RowMetaPB,
RowsChangePB, SortChangesetNotificationPB, SortPB, UpdateCalculationChangesetPB, RowsChangePB, SortChangesetNotificationPB, SortPB, UpdateCalculationChangesetPB,
UpdateFilterParams, UpdateSortParams, UpdateFilterParams, UpdateSortPayloadPB,
}; };
use crate::notification::{send_notification, DatabaseNotification}; use crate::notification::{send_notification, DatabaseNotification};
use crate::services::calculations::{Calculation, CalculationChangeset, CalculationsController}; use crate::services::calculations::{Calculation, CalculationChangeset, CalculationsController};
@ -38,11 +38,11 @@ use crate::services::database_view::{
}; };
use crate::services::field_settings::FieldSettings; use crate::services::field_settings::FieldSettings;
use crate::services::filter::{ use crate::services::filter::{
Filter, FilterChangeset, FilterController, FilterType, UpdatedFilterType, Filter, FilterChangeset, FilterContext, FilterController, UpdatedFilter,
}; };
use crate::services::group::{GroupChangesets, GroupController, MoveGroupRowContext, RowChangeset}; use crate::services::group::{GroupChangesets, GroupController, MoveGroupRowContext, RowChangeset};
use crate::services::setting::CalendarLayoutSetting; use crate::services::setting::CalendarLayoutSetting;
use crate::services::sort::{DeletedSortType, Sort, SortChangeset, SortController, SortType}; use crate::services::sort::{Sort, SortChangeset, SortController};
use super::notify_did_update_calculation; use super::notify_did_update_calculation;
use super::view_calculations::make_calculations_controller; use super::view_calculations::make_calculations_controller;
@ -499,7 +499,7 @@ impl DatabaseViewEditor {
} }
#[tracing::instrument(level = "trace", skip(self), err)] #[tracing::instrument(level = "trace", skip(self), err)]
pub async fn v_insert_sort(&self, params: UpdateSortParams) -> FlowyResult<Sort> { pub async fn insert_or_update_sort(&self, params: UpdateSortPayloadPB) -> FlowyResult<Sort> {
let is_exist = params.sort_id.is_some(); let is_exist = params.sort_id.is_some();
let sort_id = match params.sort_id { let sort_id = match params.sort_id {
None => gen_database_sort_id(), None => gen_database_sort_id(),
@ -510,18 +510,18 @@ impl DatabaseViewEditor {
id: sort_id, id: sort_id,
field_id: params.field_id.clone(), field_id: params.field_id.clone(),
field_type: params.field_type, field_type: params.field_type,
condition: params.condition, condition: params.condition.into(),
}; };
let sort_type = SortType::from(&sort);
let mut sort_controller = self.sort_controller.write().await; let mut sort_controller = self.sort_controller.write().await;
self.delegate.insert_sort(&self.view_id, sort.clone()); self.delegate.insert_sort(&self.view_id, sort.clone());
let changeset = if is_exist { let changeset = if is_exist {
sort_controller sort_controller
.did_receive_changes(SortChangeset::from_update(sort_type)) .apply_changeset(SortChangeset::from_update(sort.clone()))
.await .await
} else { } else {
sort_controller sort_controller
.did_receive_changes(SortChangeset::from_insert(sort_type)) .apply_changeset(SortChangeset::from_insert(sort.clone()))
.await .await
}; };
drop(sort_controller); drop(sort_controller);
@ -529,18 +529,17 @@ impl DatabaseViewEditor {
Ok(sort) Ok(sort)
} }
pub async fn v_delete_sort(&self, params: DeleteSortParams) -> FlowyResult<()> { pub async fn v_delete_sort(&self, params: DeleteSortPayloadPB) -> FlowyResult<()> {
let notification = self let notification = self
.sort_controller .sort_controller
.write() .write()
.await .await
.did_receive_changes(SortChangeset::from_delete(DeletedSortType::from( .apply_changeset(SortChangeset::from_delete(params.sort_id.clone()))
params.clone(),
)))
.await; .await;
self.delegate.remove_sort(&self.view_id, &params.sort_id); self.delegate.remove_sort(&self.view_id, &params.sort_id);
notify_did_update_sort(notification).await; notify_did_update_sort(notification).await;
Ok(()) Ok(())
} }
@ -635,25 +634,20 @@ impl DatabaseViewEditor {
condition: params.condition, condition: params.condition,
content: params.content, content: params.content,
}; };
let filter_type = FilterType::from(&filter);
let filter_controller = self.filter_controller.clone(); let filter_controller = self.filter_controller.clone();
let changeset = if is_exist { let changeset = if is_exist {
let old_filter_type = self let old_filter = self.delegate.get_filter(&self.view_id, &filter.id);
.delegate
.get_filter(&self.view_id, &filter.id)
.map(|field| FilterType::from(&field));
self.delegate.insert_filter(&self.view_id, filter); self.delegate.insert_filter(&self.view_id, filter.clone());
filter_controller filter_controller
.did_receive_changes(FilterChangeset::from_update(UpdatedFilterType::new( .did_receive_changes(FilterChangeset::from_update(UpdatedFilter::new(
old_filter_type, old_filter, filter,
filter_type,
))) )))
.await .await
} else { } else {
self.delegate.insert_filter(&self.view_id, filter); self.delegate.insert_filter(&self.view_id, filter.clone());
filter_controller filter_controller
.did_receive_changes(FilterChangeset::from_insert(filter_type)) .did_receive_changes(FilterChangeset::from_insert(filter))
.await .await
}; };
drop(filter_controller); drop(filter_controller);
@ -665,16 +659,20 @@ impl DatabaseViewEditor {
} }
#[tracing::instrument(level = "trace", skip(self), err)] #[tracing::instrument(level = "trace", skip(self), err)]
pub async fn v_delete_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> { pub async fn v_delete_filter(&self, params: DeleteFilterPayloadPB) -> FlowyResult<()> {
let filter_type = params.filter_type; let filter_context = FilterContext {
filter_id: params.filter_id.clone(),
field_id: params.field_id.clone(),
field_type: params.field_type,
};
let changeset = self let changeset = self
.filter_controller .filter_controller
.did_receive_changes(FilterChangeset::from_delete(filter_type.clone())) .did_receive_changes(FilterChangeset::from_delete(filter_context.clone()))
.await; .await;
self self
.delegate .delegate
.delete_filter(&self.view_id, &filter_type.filter_id); .delete_filter(&self.view_id, &params.filter_id);
if changeset.is_some() { if changeset.is_some() {
notify_did_update_filter(changeset.unwrap()).await; notify_did_update_filter(changeset.unwrap()).await;
} }
@ -799,11 +797,12 @@ impl DatabaseViewEditor {
.delegate .delegate
.get_filter_by_field_id(&self.view_id, field_id) .get_filter_by_field_id(&self.view_id, field_id)
{ {
let mut old = FilterType::from(&filter); let old = Filter {
old.field_type = FieldType::from(old_field.field_type); field_type: FieldType::from(old_field.field_type),
let new = FilterType::from(&filter); ..filter.clone()
let filter_type = UpdatedFilterType::new(Some(old), new); };
let filter_changeset = FilterChangeset::from_update(filter_type); let updated_filter = UpdatedFilter::new(Some(old), filter);
let filter_changeset = FilterChangeset::from_update(updated_filter);
let filter_controller = self.filter_controller.clone(); let filter_controller = self.filter_controller.clone();
af_spawn(async move { af_spawn(async move {
if let Some(notification) = filter_controller if let Some(notification) = filter_controller

View File

@ -237,7 +237,7 @@ impl FilterController {
let mut notification: Option<FilterChangesetNotificationPB> = None; let mut notification: Option<FilterChangesetNotificationPB> = None;
if let Some(filter_type) = &changeset.insert_filter { if let Some(filter_type) = &changeset.insert_filter {
if let Some(filter) = self.filter_from_filter_id(&filter_type.filter_id).await { if let Some(filter) = self.filter_from_filter_id(&filter_type.id).await {
notification = Some(FilterChangesetNotificationPB::from_insert( notification = Some(FilterChangesetNotificationPB::from_insert(
&self.view_id, &self.view_id,
vec![filter], vec![filter],
@ -245,7 +245,7 @@ impl FilterController {
} }
if let Some(filter) = self if let Some(filter) = self
.delegate .delegate
.get_filter(&self.view_id, &filter_type.filter_id) .get_filter(&self.view_id, &filter_type.id)
.await .await
{ {
self.refresh_filters(vec![filter]).await; self.refresh_filters(vec![filter]).await;
@ -255,9 +255,9 @@ impl FilterController {
if let Some(updated_filter_type) = changeset.update_filter { if let Some(updated_filter_type) = changeset.update_filter {
if let Some(old_filter_type) = updated_filter_type.old { if let Some(old_filter_type) = updated_filter_type.old {
let new_filter = self let new_filter = self
.filter_from_filter_id(&updated_filter_type.new.filter_id) .filter_from_filter_id(&updated_filter_type.new.id)
.await; .await;
let old_filter = self.filter_from_filter_id(&old_filter_type.filter_id).await; let old_filter = self.filter_from_filter_id(&old_filter_type.id).await;
// Get the filter id // Get the filter id
let mut filter_id = old_filter.map(|filter| filter.id); let mut filter_id = old_filter.map(|filter| filter.id);
@ -282,14 +282,17 @@ impl FilterController {
} }
} }
if let Some(filter_type) = &changeset.delete_filter { if let Some(filter_context) = &changeset.delete_filter {
if let Some(filter) = self.filter_from_filter_id(&filter_type.filter_id).await { if let Some(filter) = self.filter_from_filter_id(&filter_context.filter_id).await {
notification = Some(FilterChangesetNotificationPB::from_delete( notification = Some(FilterChangesetNotificationPB::from_delete(
&self.view_id, &self.view_id,
vec![filter], vec![filter],
)); ));
} }
self.cell_filter_cache.write().remove(&filter_type.field_id); self
.cell_filter_cache
.write()
.remove(&filter_context.field_id);
} }
self self

View File

@ -3,7 +3,7 @@ use collab::core::any_map::AnyMapExtension;
use collab_database::rows::RowId; use collab_database::rows::RowId;
use collab_database::views::{FilterMap, FilterMapBuilder}; use collab_database::views::{FilterMap, FilterMapBuilder};
use crate::entities::{DeleteFilterParams, FieldType, FilterPB, InsertedRowPB}; use crate::entities::{FieldType, FilterPB, InsertedRowPB};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Filter { pub struct Filter {
@ -63,66 +63,56 @@ impl TryFrom<FilterMap> for Filter {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct FilterChangeset { pub struct FilterChangeset {
pub(crate) insert_filter: Option<FilterType>, pub(crate) insert_filter: Option<Filter>,
pub(crate) update_filter: Option<UpdatedFilterType>, pub(crate) update_filter: Option<UpdatedFilter>,
pub(crate) delete_filter: Option<FilterType>, pub(crate) delete_filter: Option<FilterContext>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct UpdatedFilterType { pub struct UpdatedFilter {
pub old: Option<FilterType>, pub old: Option<Filter>,
pub new: FilterType, pub new: Filter,
} }
impl UpdatedFilterType { impl UpdatedFilter {
pub fn new(old: Option<FilterType>, new: FilterType) -> UpdatedFilterType { pub fn new(old: Option<Filter>, new: Filter) -> UpdatedFilter {
Self { old, new } Self { old, new }
} }
} }
impl FilterChangeset { impl FilterChangeset {
pub fn from_insert(filter_type: FilterType) -> Self { pub fn from_insert(filter: Filter) -> Self {
Self { Self {
insert_filter: Some(filter_type), insert_filter: Some(filter),
update_filter: None, update_filter: None,
delete_filter: None, delete_filter: None,
} }
} }
pub fn from_update(filter_type: UpdatedFilterType) -> Self { pub fn from_update(filter: UpdatedFilter) -> Self {
Self { Self {
insert_filter: None, insert_filter: None,
update_filter: Some(filter_type), update_filter: Some(filter),
delete_filter: None, delete_filter: None,
} }
} }
pub fn from_delete(filter_type: FilterType) -> Self { pub fn from_delete(filter_context: FilterContext) -> Self {
Self { Self {
insert_filter: None, insert_filter: None,
update_filter: None, update_filter: None,
delete_filter: Some(filter_type), delete_filter: Some(filter_context),
} }
} }
} }
#[derive(Hash, Eq, PartialEq, Debug, Clone)] #[derive(Debug, Clone)]
pub struct FilterType { pub struct FilterContext {
pub filter_id: String, pub filter_id: String,
pub field_id: String, pub field_id: String,
pub field_type: FieldType, pub field_type: FieldType,
} }
impl std::convert::From<&Filter> for FilterType { impl From<&FilterPB> for FilterContext {
fn from(filter: &Filter) -> Self {
Self {
filter_id: filter.id.clone(),
field_id: filter.field_id.clone(),
field_type: filter.field_type,
}
}
}
impl std::convert::From<&FilterPB> for FilterType {
fn from(filter: &FilterPB) -> Self { fn from(filter: &FilterPB) -> Self {
Self { Self {
filter_id: filter.id.clone(), filter_id: filter.id.clone(),
@ -132,29 +122,6 @@ impl std::convert::From<&FilterPB> for FilterType {
} }
} }
// #[derive(Hash, Eq, PartialEq, Debug, Clone)]
// pub struct InsertedFilterType {
// pub field_id: String,
// pub filter_id: Option<String>,
// pub field_type: FieldType,
// }
//
// impl std::convert::From<&Filter> for InsertedFilterType {
// fn from(params: &Filter) -> Self {
// Self {
// field_id: params.field_id.clone(),
// filter_id: Some(params.id.clone()),
// field_type: params.field_type.clone(),
// }
// }
// }
impl std::convert::From<&DeleteFilterParams> for FilterType {
fn from(params: &DeleteFilterParams) -> Self {
params.filter_type.clone()
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FilterResultNotification { pub struct FilterResultNotification {
pub view_id: String, pub view_id: String,

View File

@ -179,39 +179,25 @@ impl SortController {
} }
#[tracing::instrument(level = "trace", skip(self))] #[tracing::instrument(level = "trace", skip(self))]
pub async fn did_receive_changes( pub async fn apply_changeset(&mut self, changeset: SortChangeset) -> SortChangesetNotificationPB {
&mut self,
changeset: SortChangeset,
) -> SortChangesetNotificationPB {
let mut notification = SortChangesetNotificationPB::new(self.view_id.clone()); let mut notification = SortChangesetNotificationPB::new(self.view_id.clone());
if let Some(insert_sort) = changeset.insert_sort { if let Some(insert_sort) = changeset.insert_sort {
if let Some(sort) = self if let Some(sort) = self.delegate.get_sort(&self.view_id, &insert_sort.id).await {
.delegate
.get_sort(&self.view_id, &insert_sort.sort_id)
.await
{
notification.insert_sorts.push(sort.as_ref().into()); notification.insert_sorts.push(sort.as_ref().into());
self.sorts.push(sort); self.sorts.push(sort);
} }
} }
if let Some(delete_sort_type) = changeset.delete_sort { if let Some(sort_id) = changeset.delete_sort {
if let Some(index) = self if let Some(index) = self.sorts.iter().position(|sort| sort.id == sort_id) {
.sorts
.iter()
.position(|sort| sort.id == delete_sort_type.sort_id)
{
let sort = self.sorts.remove(index); let sort = self.sorts.remove(index);
notification.delete_sorts.push(sort.as_ref().into()); notification.delete_sorts.push(sort.as_ref().into());
} }
} }
if let Some(update_sort) = changeset.update_sort { if let Some(update_sort) = changeset.update_sort {
if let Some(updated_sort) = self if let Some(updated_sort) = self.delegate.get_sort(&self.view_id, &update_sort.id).await {
.delegate
.get_sort(&self.view_id, &update_sort.sort_id)
.await
{
notification.update_sorts.push(updated_sort.as_ref().into()); notification.update_sorts.push(updated_sort.as_ref().into());
if let Some(index) = self if let Some(index) = self
.sorts .sorts

View File

@ -5,7 +5,7 @@ use collab::core::any_map::AnyMapExtension;
use collab_database::rows::RowId; use collab_database::rows::RowId;
use collab_database::views::{SortMap, SortMapBuilder}; use collab_database::views::{SortMap, SortMapBuilder};
use crate::entities::{DeleteSortParams, FieldType}; use crate::entities::FieldType;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Sort { pub struct Sort {
@ -98,23 +98,6 @@ impl From<i64> for SortCondition {
} }
} }
#[derive(Hash, Eq, PartialEq, Debug, Clone)]
pub struct SortType {
pub sort_id: String,
pub field_id: String,
pub field_type: FieldType,
}
impl From<&Sort> for SortType {
fn from(data: &Sort) -> Self {
Self {
sort_id: data.id.clone(),
field_id: data.field_id.clone(),
field_type: data.field_type,
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct ReorderAllRowsResult { pub struct ReorderAllRowsResult {
pub view_id: String, pub view_id: String,
@ -140,13 +123,13 @@ pub struct ReorderSingleRowResult {
#[derive(Debug)] #[derive(Debug)]
pub struct SortChangeset { pub struct SortChangeset {
pub(crate) insert_sort: Option<SortType>, pub(crate) insert_sort: Option<Sort>,
pub(crate) update_sort: Option<SortType>, pub(crate) update_sort: Option<Sort>,
pub(crate) delete_sort: Option<DeletedSortType>, pub(crate) delete_sort: Option<String>,
} }
impl SortChangeset { impl SortChangeset {
pub fn from_insert(sort: SortType) -> Self { pub fn from_insert(sort: Sort) -> Self {
Self { Self {
insert_sort: Some(sort), insert_sort: Some(sort),
update_sort: None, update_sort: None,
@ -154,7 +137,7 @@ impl SortChangeset {
} }
} }
pub fn from_update(sort: SortType) -> Self { pub fn from_update(sort: Sort) -> Self {
Self { Self {
insert_sort: None, insert_sort: None,
update_sort: Some(sort), update_sort: Some(sort),
@ -162,26 +145,11 @@ impl SortChangeset {
} }
} }
pub fn from_delete(deleted_sort: DeletedSortType) -> Self { pub fn from_delete(sort_id: String) -> Self {
Self { Self {
insert_sort: None, insert_sort: None,
update_sort: None, update_sort: None,
delete_sort: Some(deleted_sort), delete_sort: Some(sort_id),
}
}
}
#[derive(Debug)]
pub struct DeletedSortType {
pub sort_type: SortType,
pub sort_id: String,
}
impl std::convert::From<DeleteSortParams> for DeletedSortType {
fn from(params: DeleteSortParams) -> Self {
Self {
sort_type: params.sort_type,
sort_id: params.sort_id,
} }
} }
} }

View File

@ -1,321 +1,445 @@
#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(clippy::all)]
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_imports)]
use std::time::Duration; use std::time::Duration;
use bytes::Bytes; use collab_database::rows::RowId;
use collab_database::rows::{Row, RowId}; use flowy_database2::services::filter::FilterContext;
use futures::TryFutureExt;
use tokio::sync::broadcast::Receiver; use tokio::sync::broadcast::Receiver;
use flowy_database2::entities::{CheckboxFilterConditionPB, CheckboxFilterPB, ChecklistFilterConditionPB, ChecklistFilterPB, DatabaseViewSettingPB, DateFilterConditionPB, DateFilterPB, DeleteFilterParams, FieldType, FilterPB, NumberFilterConditionPB, NumberFilterPB, SelectOptionConditionPB, SelectOptionFilterPB, SelectOptionPB, TextFilterConditionPB, TextFilterPB, UpdateFilterParams, UpdateFilterPayloadPB}; use flowy_database2::entities::{
CheckboxFilterConditionPB, CheckboxFilterPB, ChecklistFilterConditionPB, ChecklistFilterPB,
DatabaseViewSettingPB, DateFilterConditionPB, DateFilterPB, DeleteFilterPayloadPB, FieldType,
FilterPB, NumberFilterConditionPB, NumberFilterPB, SelectOptionConditionPB, SelectOptionFilterPB,
TextFilterConditionPB, TextFilterPB, UpdateFilterParams, UpdateFilterPayloadPB,
};
use flowy_database2::services::database_view::DatabaseViewChanged; use flowy_database2::services::database_view::DatabaseViewChanged;
use flowy_database2::services::field::SelectOption;
use flowy_database2::services::filter::FilterType;
use lib_dispatch::prelude::af_spawn; use lib_dispatch::prelude::af_spawn;
use crate::database::database_editor::DatabaseEditorTest; use crate::database::database_editor::DatabaseEditorTest;
pub struct FilterRowChanged { pub struct FilterRowChanged {
pub(crate) showing_num_of_rows: usize, pub(crate) showing_num_of_rows: usize,
pub(crate) hiding_num_of_rows: usize, pub(crate) hiding_num_of_rows: usize,
} }
pub enum FilterScript { pub enum FilterScript {
UpdateTextCell { UpdateTextCell {
row_id: RowId, row_id: RowId,
text: String, text: String,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
UpdateChecklistCell{ UpdateChecklistCell {
row_id: RowId, row_id: RowId,
selected_option_ids: Vec<String>, selected_option_ids: Vec<String>,
}, },
UpdateSingleSelectCell { UpdateSingleSelectCell {
row_id: RowId, row_id: RowId,
option_id: String, option_id: String,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
InsertFilter { InsertFilter {
payload: UpdateFilterPayloadPB, payload: UpdateFilterPayloadPB,
}, },
CreateTextFilter { CreateTextFilter {
condition: TextFilterConditionPB, condition: TextFilterConditionPB,
content: String, content: String,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
UpdateTextFilter { UpdateTextFilter {
filter: FilterPB, filter: FilterPB,
condition: TextFilterConditionPB, condition: TextFilterConditionPB,
content: String, content: String,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
CreateNumberFilter { CreateNumberFilter {
condition: NumberFilterConditionPB, condition: NumberFilterConditionPB,
content: String, content: String,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
CreateCheckboxFilter { CreateCheckboxFilter {
condition: CheckboxFilterConditionPB, condition: CheckboxFilterConditionPB,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
CreateDateFilter{ CreateDateFilter {
condition: DateFilterConditionPB, condition: DateFilterConditionPB,
start: Option<i64>, start: Option<i64>,
end: Option<i64>, end: Option<i64>,
timestamp: Option<i64>, timestamp: Option<i64>,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
CreateMultiSelectFilter { CreateMultiSelectFilter {
condition: SelectOptionConditionPB, condition: SelectOptionConditionPB,
option_ids: Vec<String>, option_ids: Vec<String>,
}, },
CreateSingleSelectFilter { CreateSingleSelectFilter {
condition: SelectOptionConditionPB, condition: SelectOptionConditionPB,
option_ids: Vec<String>, option_ids: Vec<String>,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
CreateChecklistFilter { CreateChecklistFilter {
condition: ChecklistFilterConditionPB, condition: ChecklistFilterConditionPB,
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
AssertFilterCount { AssertFilterCount {
count: i32, count: i32,
}, },
DeleteFilter { DeleteFilter {
filter_id: String, filter_context: FilterContext,
filter_type: FilterType, changed: Option<FilterRowChanged>,
changed: Option<FilterRowChanged>, },
}, AssertFilterContent {
AssertFilterContent { filter_id: String,
filter_id: String, condition: i64,
condition: i64, content: String,
content: String },
}, AssertNumberOfVisibleRows {
AssertNumberOfVisibleRows { expected: usize,
expected: usize, },
}, #[allow(dead_code)]
#[allow(dead_code)] AssertGridSetting {
AssertGridSetting { expected_setting: DatabaseViewSettingPB,
expected_setting: DatabaseViewSettingPB, },
}, Wait {
Wait { millisecond: u64 } millisecond: u64,
},
} }
pub struct DatabaseFilterTest { pub struct DatabaseFilterTest {
inner: DatabaseEditorTest, inner: DatabaseEditorTest,
recv: Option<Receiver<DatabaseViewChanged>>, recv: Option<Receiver<DatabaseViewChanged>>,
} }
impl DatabaseFilterTest { impl DatabaseFilterTest {
pub async fn new() -> Self { pub async fn new() -> Self {
let editor_test = DatabaseEditorTest::new_grid().await; let editor_test = DatabaseEditorTest::new_grid().await;
Self { Self {
inner: editor_test, inner: editor_test,
recv: None, recv: None,
}
} }
}
pub fn view_id(&self) -> String {
self.view_id.clone() pub fn view_id(&self) -> String {
self.view_id.clone()
}
pub async fn get_all_filters(&self) -> Vec<FilterPB> {
self.editor.get_all_filters(&self.view_id).await.items
}
pub async fn run_scripts(&mut self, scripts: Vec<FilterScript>) {
for script in scripts {
self.run_script(script).await;
} }
}
pub async fn get_all_filters(&self) -> Vec<FilterPB> { pub async fn run_script(&mut self, script: FilterScript) {
self.editor.get_all_filters(&self.view_id).await.items match script {
FilterScript::UpdateTextCell {
row_id,
text,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
self.update_text_cell(row_id, &text).await.unwrap();
},
FilterScript::UpdateChecklistCell {
row_id,
selected_option_ids,
} => {
self
.set_checklist_cell(row_id, selected_option_ids)
.await
.unwrap();
},
FilterScript::UpdateSingleSelectCell {
row_id,
option_id,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
self
.update_single_select_cell(row_id, &option_id)
.await
.unwrap();
},
FilterScript::InsertFilter { payload } => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.insert_filter(payload).await;
},
FilterScript::CreateTextFilter {
condition,
content,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::RichText);
let text_filter = TextFilterPB { condition, content };
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, text_filter);
self.insert_filter(payload).await;
},
FilterScript::UpdateTextFilter {
filter,
condition,
content,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let params = UpdateFilterParams {
view_id: self.view_id(),
field_id: filter.field_id,
filter_id: Some(filter.id),
field_type: filter.field_type,
condition: condition as i64,
content,
};
self.editor.create_or_update_filter(params).await.unwrap();
},
FilterScript::CreateNumberFilter {
condition,
content,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::Number);
let number_filter = NumberFilterPB { condition, content };
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, number_filter);
self.insert_filter(payload).await;
},
FilterScript::CreateCheckboxFilter { condition, changed } => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::Checkbox);
let checkbox_filter = CheckboxFilterPB { condition };
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, checkbox_filter);
self.insert_filter(payload).await;
},
FilterScript::CreateDateFilter {
condition,
start,
end,
timestamp,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::DateTime);
let date_filter = DateFilterPB {
condition,
start,
end,
timestamp,
};
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, date_filter);
self.insert_filter(payload).await;
},
FilterScript::CreateMultiSelectFilter {
condition,
option_ids,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
let field = self.get_first_field(FieldType::MultiSelect);
let filter = SelectOptionFilterPB {
condition,
option_ids,
};
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, filter);
self.insert_filter(payload).await;
},
FilterScript::CreateSingleSelectFilter {
condition,
option_ids,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::SingleSelect);
let filter = SelectOptionFilterPB {
condition,
option_ids,
};
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, filter);
self.insert_filter(payload).await;
},
FilterScript::CreateChecklistFilter { condition, changed } => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::Checklist);
let filter = ChecklistFilterPB { condition };
let payload = UpdateFilterPayloadPB::new(&self.view_id(), &field, filter);
self.insert_filter(payload).await;
},
FilterScript::AssertFilterCount { count } => {
let filters = self.editor.get_all_filters(&self.view_id).await.items;
assert_eq!(count as usize, filters.len());
},
FilterScript::AssertFilterContent {
filter_id,
condition,
content,
} => {
let filter = self
.editor
.get_filter(&self.view_id, &filter_id)
.await
.unwrap();
assert_eq!(&filter.content, &content);
assert_eq!(filter.condition, condition);
},
FilterScript::DeleteFilter {
filter_context,
changed,
} => {
self.recv = Some(
self
.editor
.subscribe_view_changed(&self.view_id())
.await
.unwrap(),
);
self.assert_future_changed(changed).await;
let params = DeleteFilterPayloadPB {
filter_id: filter_context.filter_id,
view_id: self.view_id(),
field_id: filter_context.field_id,
field_type: filter_context.field_type,
};
self.editor.delete_filter(params).await.unwrap();
},
FilterScript::AssertGridSetting { expected_setting } => {
let setting = self
.editor
.get_database_view_setting(&self.view_id)
.await
.unwrap();
assert_eq!(expected_setting, setting);
},
FilterScript::AssertNumberOfVisibleRows { expected } => {
let grid = self.editor.get_database_data(&self.view_id).await.unwrap();
assert_eq!(grid.rows.len(), expected);
},
FilterScript::Wait { millisecond } => {
tokio::time::sleep(Duration::from_millis(millisecond)).await;
},
} }
}
pub async fn run_scripts(&mut self, scripts: Vec<FilterScript>) { async fn assert_future_changed(&mut self, change: Option<FilterRowChanged>) {
for script in scripts { if change.is_none() {
self.run_script(script).await; return;
}
}
pub async fn run_script(&mut self, script: FilterScript) {
match script {
FilterScript::UpdateTextCell { row_id, text, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
self.update_text_cell(row_id, &text).await.unwrap();
}
FilterScript::UpdateChecklistCell { row_id, selected_option_ids } => {
self.set_checklist_cell( row_id, selected_option_ids).await.unwrap();
}
FilterScript::UpdateSingleSelectCell { row_id, option_id, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
self.update_single_select_cell(row_id, &option_id).await.unwrap();
}
FilterScript::InsertFilter { payload } => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.insert_filter(payload).await;
}
FilterScript::CreateTextFilter { condition, content, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::RichText);
let text_filter= TextFilterPB {
condition,
content
};
let payload =
UpdateFilterPayloadPB::new(
& self.view_id(),
&field, text_filter);
self.insert_filter(payload).await;
}
FilterScript::UpdateTextFilter { filter, condition, content, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let params = UpdateFilterParams {
view_id: self.view_id(),
field_id: filter.field_id,
filter_id: Some(filter.id),
field_type: filter.field_type.into(),
condition: condition as i64,
content
};
self.editor.create_or_update_filter(params).await.unwrap();
}
FilterScript::CreateNumberFilter {condition, content, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::Number);
let number_filter = NumberFilterPB {
condition,
content
};
let payload =
UpdateFilterPayloadPB::new(
&self.view_id(),
&field, number_filter);
self.insert_filter(payload).await;
}
FilterScript::CreateCheckboxFilter {condition, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::Checkbox);
let checkbox_filter = CheckboxFilterPB {
condition
};
let payload =
UpdateFilterPayloadPB::new(& self.view_id(), &field, checkbox_filter);
self.insert_filter(payload).await;
}
FilterScript::CreateDateFilter { condition, start, end, timestamp, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::DateTime);
let date_filter = DateFilterPB {
condition,
start,
end,
timestamp
};
let payload =
UpdateFilterPayloadPB::new(&self.view_id(), &field, date_filter);
self.insert_filter(payload).await;
}
FilterScript::CreateMultiSelectFilter { condition, option_ids} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
let field = self.get_first_field(FieldType::MultiSelect);
let filter = SelectOptionFilterPB { condition, option_ids };
let payload =
UpdateFilterPayloadPB::new(&self.view_id(), &field, filter);
self.insert_filter(payload).await;
}
FilterScript::CreateSingleSelectFilter { condition, option_ids, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::SingleSelect);
let filter = SelectOptionFilterPB { condition, option_ids };
let payload =
UpdateFilterPayloadPB::new(& self.view_id(), &field, filter);
self.insert_filter(payload).await;
}
FilterScript::CreateChecklistFilter { condition,changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let field = self.get_first_field(FieldType::Checklist);
// let type_option = self.get_checklist_type_option(&field_rev.id);
let filter = ChecklistFilterPB { condition };
let payload =
UpdateFilterPayloadPB::new(& self.view_id(), &field, filter);
self.insert_filter(payload).await;
}
FilterScript::AssertFilterCount { count } => {
let filters = self.editor.get_all_filters(&self.view_id).await.items;
assert_eq!(count as usize, filters.len());
}
FilterScript::AssertFilterContent { filter_id, condition, content} => {
let filter = self.editor.get_filter(&self.view_id, &filter_id).await.unwrap();
assert_eq!(&filter.content, &content);
assert_eq!(filter.condition, condition);
}
FilterScript::DeleteFilter { filter_id, filter_type ,changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await;
let params = DeleteFilterParams { filter_id, view_id: self.view_id(),filter_type };
let _ = self.editor.delete_filter(params).await.unwrap();
}
FilterScript::AssertGridSetting { expected_setting } => {
let setting = self.editor.get_database_view_setting(&self.view_id).await.unwrap();
assert_eq!(expected_setting, setting);
}
FilterScript::AssertNumberOfVisibleRows { expected } => {
let grid = self.editor.get_database_data(&self.view_id).await.unwrap();
assert_eq!(grid.rows.len(), expected);
}
FilterScript::Wait { millisecond } => {
tokio::time::sleep(Duration::from_millis(millisecond)).await;
}
}
}
async fn assert_future_changed(&mut self, change: Option<FilterRowChanged>) {
if change.is_none() {return;}
let change = change.unwrap();
let mut receiver = self.recv.take().unwrap();
af_spawn(async move {
match tokio::time::timeout(Duration::from_secs(2), receiver.recv()).await {
Ok(changed) => {
match changed.unwrap() { DatabaseViewChanged::FilterNotification(notification) => {
assert_eq!(notification.visible_rows.len(), change.showing_num_of_rows, "visible rows not match");
assert_eq!(notification.invisible_rows.len(), change.hiding_num_of_rows, "invisible rows not match");
}
_ => {}
}
},
Err(e) => {
panic!("Process filter task timeout: {:?}", e);
}
}
});
}
async fn insert_filter(&self, payload: UpdateFilterPayloadPB) {
let params: UpdateFilterParams = payload.try_into().unwrap();
let _ = self.editor.create_or_update_filter(params).await.unwrap();
} }
let change = change.unwrap();
let mut receiver = self.recv.take().unwrap();
af_spawn(async move {
match tokio::time::timeout(Duration::from_secs(2), receiver.recv()).await {
Ok(changed) => {
if let DatabaseViewChanged::FilterNotification(notification) = changed.unwrap() {
assert_eq!(
notification.visible_rows.len(),
change.showing_num_of_rows,
"visible rows not match"
);
assert_eq!(
notification.invisible_rows.len(),
change.hiding_num_of_rows,
"invisible rows not match"
);
}
},
Err(e) => {
panic!("Process filter task timeout: {:?}", e);
},
}
});
}
async fn insert_filter(&self, payload: UpdateFilterPayloadPB) {
let params: UpdateFilterParams = payload.try_into().unwrap();
self.editor.create_or_update_filter(params).await.unwrap();
}
} }
impl std::ops::Deref for DatabaseFilterTest { impl std::ops::Deref for DatabaseFilterTest {
type Target = DatabaseEditorTest; type Target = DatabaseEditorTest;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.inner &self.inner
} }
} }
impl std::ops::DerefMut for DatabaseFilterTest { impl std::ops::DerefMut for DatabaseFilterTest {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner &mut self.inner
} }
} }

View File

@ -1,7 +1,7 @@
use flowy_database2::entities::{ use flowy_database2::entities::{
FieldType, TextFilterConditionPB, TextFilterPB, UpdateFilterPayloadPB, FieldType, TextFilterConditionPB, TextFilterPB, UpdateFilterPayloadPB,
}; };
use flowy_database2::services::filter::FilterType; use flowy_database2::services::filter::FilterContext;
use crate::database::filter_test::script::FilterScript::*; use crate::database::filter_test::script::FilterScript::*;
use crate::database::filter_test::script::*; use crate::database::filter_test::script::*;
@ -44,8 +44,7 @@ async fn grid_filter_text_is_not_empty_test() {
test test
.run_scripts(vec![ .run_scripts(vec![
DeleteFilter { DeleteFilter {
filter_id: filter.id.clone(), filter_context: FilterContext::from(&filter),
filter_type: FilterType::from(&filter),
changed: Some(FilterRowChanged { changed: Some(FilterRowChanged {
showing_num_of_rows: 1, showing_num_of_rows: 1,
hiding_num_of_rows: 0, hiding_num_of_rows: 0,
@ -208,8 +207,7 @@ async fn grid_filter_delete_test() {
test test
.run_scripts(vec![ .run_scripts(vec![
DeleteFilter { DeleteFilter {
filter_id: filter.id.clone(), filter_context: FilterContext::from(&filter),
filter_type: FilterType::from(&filter),
changed: None, changed: None,
}, },
AssertFilterCount { count: 0 }, AssertFilterCount { count: 0 },

View File

@ -7,10 +7,10 @@ use collab_database::rows::RowId;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use tokio::sync::broadcast::Receiver; use tokio::sync::broadcast::Receiver;
use flowy_database2::entities::{DeleteSortParams, FieldType, UpdateSortParams}; use flowy_database2::entities::{DeleteSortPayloadPB, FieldType, UpdateSortPayloadPB};
use flowy_database2::services::cell::stringify_cell_data; use flowy_database2::services::cell::stringify_cell_data;
use flowy_database2::services::database_view::DatabaseViewChanged; use flowy_database2::services::database_view::DatabaseViewChanged;
use flowy_database2::services::sort::{Sort, SortCondition, SortType}; use flowy_database2::services::sort::{Sort, SortCondition};
use crate::database::database_editor::DatabaseEditorTest; use crate::database::database_editor::DatabaseEditorTest;
@ -20,7 +20,6 @@ pub enum SortScript {
condition: SortCondition, condition: SortCondition,
}, },
DeleteSort { DeleteSort {
sort: Sort,
sort_id: String, sort_id: String,
}, },
AssertCellContentOrder { AssertCellContentOrder {
@ -71,17 +70,17 @@ impl DatabaseSortTest {
.await .await
.unwrap(), .unwrap(),
); );
let params = UpdateSortParams { let params = UpdateSortPayloadPB {
view_id: self.view_id.clone(), view_id: self.view_id.clone(),
field_id: field.id.clone(), field_id: field.id.clone(),
sort_id: None, sort_id: None,
field_type: FieldType::from(field.field_type), field_type: FieldType::from(field.field_type),
condition, condition: condition.into(),
}; };
let sort_rev = self.editor.create_or_update_sort(params).await.unwrap(); let sort_rev = self.editor.create_or_update_sort(params).await.unwrap();
self.current_sort_rev = Some(sort_rev); self.current_sort_rev = Some(sort_rev);
}, },
SortScript::DeleteSort { sort, sort_id } => { SortScript::DeleteSort { sort_id } => {
self.recv = Some( self.recv = Some(
self self
.editor .editor
@ -89,9 +88,8 @@ impl DatabaseSortTest {
.await .await
.unwrap(), .unwrap(),
); );
let params = DeleteSortParams { let params = DeleteSortPayloadPB {
view_id: self.view_id.clone(), view_id: self.view_id.clone(),
sort_type: SortType::from(&sort),
sort_id, sort_id,
}; };
self.editor.delete_sort(params).await.unwrap(); self.editor.delete_sort(params).await.unwrap();

View File

@ -93,7 +93,6 @@ async fn sort_text_by_ascending_and_delete_sort_test() {
let sort = test.current_sort_rev.as_ref().unwrap(); let sort = test.current_sort_rev.as_ref().unwrap();
let scripts = vec![ let scripts = vec![
DeleteSort { DeleteSort {
sort: sort.clone(),
sort_id: sort.id.clone(), sort_id: sort.id.clone(),
}, },
AssertCellContentOrder { AssertCellContentOrder {