diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs index 29fecf8f29..1efc19c81f 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs @@ -1,3 +1,4 @@ +use crate::grid::field_util::make_date_cell_string; use crate::grid::script::EditorScript::*; use crate::grid::script::*; use flowy_grid::services::field::{MultiSelectTypeOption, SelectOptionCellContentChangeset, SingleSelectTypeOption}; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs index 5fe5d599d6..cc2ee2ca87 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs @@ -1,3 +1,4 @@ +use crate::grid::field_util::*; use crate::grid::script::EditorScript::*; use crate::grid::script::*; use flowy_grid::services::field::{SelectOption, SingleSelectTypeOption}; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs new file mode 100644 index 0000000000..138e069b61 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs @@ -0,0 +1,84 @@ +use flowy_grid::services::field::*; +use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; +use flowy_grid::services::row::CreateRowRevisionPayload; +use flowy_grid::services::setting::GridSettingChangesetBuilder; +use flowy_grid_data_model::entities::*; +use flowy_grid_data_model::revision::*; +use flowy_sync::client_grid::GridBuilder; + +pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { + let field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .build(); + + let cloned_field_rev = field_rev.clone(); + + let type_option_data = field_rev + .get_type_option_entry::(&field_rev.field_type) + .unwrap() + .protobuf_bytes() + .to_vec(); + + let field = Field { + id: field_rev.id, + name: field_rev.name, + desc: field_rev.desc, + field_type: field_rev.field_type, + frozen: field_rev.frozen, + visibility: field_rev.visibility, + width: field_rev.width, + is_primary: false, + }; + + let params = InsertFieldParams { + grid_id: grid_id.to_owned(), + field, + type_option_data, + start_field_id: None, + }; + (params, cloned_field_rev) +} + +pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { + let single_select = SingleSelectTypeOptionBuilder::default() + .option(SelectOption::new("Done")) + .option(SelectOption::new("Progress")); + + let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build(); + let cloned_field_rev = field_rev.clone(); + let type_option_data = field_rev + .get_type_option_entry::(&field_rev.field_type) + .unwrap() + .protobuf_bytes() + .to_vec(); + + let field = Field { + id: field_rev.id, + name: field_rev.name, + desc: field_rev.desc, + field_type: field_rev.field_type, + frozen: field_rev.frozen, + visibility: field_rev.visibility, + width: field_rev.width, + is_primary: false, + }; + + let params = InsertFieldParams { + grid_id: grid_id.to_owned(), + field, + type_option_data, + start_field_id: None, + }; + (params, cloned_field_rev) +} + +// The grid will contains all existing field types and there are three empty rows in this grid. + +pub fn make_date_cell_string(s: &str) -> String { + serde_json::to_string(&DateCellContentChangeset { + date: Some(s.to_string()), + time: None, + }) + .unwrap() +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs new file mode 100644 index 0000000000..e2520e0419 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs @@ -0,0 +1,46 @@ +use crate::grid::script::EditorScript::*; +use crate::grid::script::*; + +use flowy_grid_data_model::entities::{ + CreateGridFilterParams, CreateGridFilterPayload, GridLayoutType, GridSettingChangesetParams, TextFilterCondition, +}; + +#[tokio::test] +async fn grid_setting_create_text_filter_test() { + let test = GridEditorTest::new().await; + let field_rev = test.text_field(); + let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); + let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; + GridEditorTest::new().await.run_scripts(scripts).await; +} + +#[tokio::test] +#[should_panic] +async fn grid_setting_create_text_filter_panic_test() { + let test = GridEditorTest::new().await; + let field_rev = test.text_field(); + + // 100 is not a valid condition, so this test should be panic. + let payload = CreateGridFilterPayload::new(field_rev, 100, Some("abc".to_owned())); + let scripts = vec![InsertGridTableFilter { payload }]; + GridEditorTest::new().await.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_setting_delete_text_filter_test() { + let mut test = GridEditorTest::new().await; + let field_rev = test.text_field(); + let payload = CreateGridFilterPayload::new(field_rev, 100, 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 }, + AssertTableFilterCount { count: 0 }, + ]) + .await; +} + +#[tokio::test] +async fn grid_setting_sort_test() {} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs index 1ca8ad3983..4d746661eb 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs @@ -1,6 +1,8 @@ mod block_test; mod cell_test; mod field_test; +mod field_util; +mod filter_test; mod row_test; +mod row_util; mod script; -mod setting_test; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs index 735ed91202..e8f7b9020b 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs @@ -1,23 +1,26 @@ +use crate::grid::field_util::*; +use crate::grid::row_util::GridRowTestBuilder; use crate::grid::script::EditorScript::*; use crate::grid::script::*; use chrono::NaiveDateTime; use flowy_grid::services::field::{ DateCellData, MultiSelectTypeOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, }; -use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowRevisionBuilder}; +use flowy_grid::services::row::{ + decode_cell_data_from_type_option_cell_data, CreateRowRevisionBuilder, CreateRowRevisionPayload, +}; use flowy_grid_data_model::entities::FieldType; -use flowy_grid_data_model::revision::RowMetaChangeset; +use flowy_grid_data_model::revision::{FieldRevision, RowMetaChangeset}; #[tokio::test] async fn grid_create_row_count_test() { let test = GridEditorTest::new().await; - let create_row_context = CreateRowRevisionBuilder::new(&test.field_revs).build(); let scripts = vec![ AssertRowCount(3), CreateEmptyRow, CreateEmptyRow, CreateRow { - context: create_row_context, + payload: GridRowTestBuilder::new(&test).build(), }, AssertRowCount(6), ]; @@ -27,15 +30,15 @@ async fn grid_create_row_count_test() { #[tokio::test] async fn grid_update_row() { let mut test = GridEditorTest::new().await; - let context = CreateRowRevisionBuilder::new(&test.field_revs).build(); + let payload = GridRowTestBuilder::new(&test).build(); let changeset = RowMetaChangeset { - row_id: context.row_id.clone(), + row_id: payload.row_id.clone(), height: None, visibility: None, cell_by_field_id: Default::default(), }; - let scripts = vec![AssertRowCount(3), CreateRow { context }, UpdateRow { changeset }]; + let scripts = vec![AssertRowCount(3), CreateRow { payload }, UpdateRow { changeset }]; test.run_scripts(scripts).await; let expected_row = (&*test.row_revs.last().cloned().unwrap()).clone(); @@ -46,13 +49,13 @@ async fn grid_update_row() { #[tokio::test] async fn grid_delete_row() { let mut test = GridEditorTest::new().await; - let context_1 = CreateRowRevisionBuilder::new(&test.field_revs).build(); - let context_2 = CreateRowRevisionBuilder::new(&test.field_revs).build(); - let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()]; + let payload1 = GridRowTestBuilder::new(&test).build(); + let payload2 = GridRowTestBuilder::new(&test).build(); + let row_ids = vec![payload1.row_id.clone(), payload2.row_id.clone()]; let scripts = vec![ AssertRowCount(3), - CreateRow { context: context_1 }, - CreateRow { context: context_2 }, + CreateRow { payload: payload1 }, + CreateRow { payload: payload2 }, AssertBlockCount(1), AssertBlock { block_index: 0, @@ -110,7 +113,7 @@ async fn grid_row_add_cells_test() { } } let context = builder.build(); - let scripts = vec![CreateRow { context }, AssertGridRevisionPad]; + let scripts = vec![CreateRow { payload: context }, AssertGridRevisionPad]; test.run_scripts(scripts).await; } @@ -142,6 +145,6 @@ async fn grid_row_add_date_cell_test() { .date, "2022/03/16", ); - let scripts = vec![CreateRow { context }]; + let scripts = vec![CreateRow { payload: context }]; test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs new file mode 100644 index 0000000000..8320a463da --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs @@ -0,0 +1,32 @@ +use crate::grid::script::GridEditorTest; +use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; +use flowy_grid_data_model::entities::FieldType; +use flowy_grid_data_model::revision::FieldRevision; +use strum::EnumCount; + +pub struct GridRowTestBuilder<'a> { + test: &'a GridEditorTest, + inner_builder: CreateRowRevisionBuilder<'a>, +} + +impl<'a> GridRowTestBuilder<'a> { + pub fn new(test: &'a GridEditorTest) -> Self { + assert_eq!(test.field_revs.len(), FieldType::COUNT); + + let inner_builder = CreateRowRevisionBuilder::new(&test.field_revs); + Self { test, inner_builder } + } + + pub fn update_text_cell(&mut self) -> Self { + let text_field = self + .test + .field_revs + .iter() + .find(|field_rev| field_rev.field_type == FieldType::RichText); + // self.inner_builder + } + + pub fn build(self) -> CreateRowRevisionPayload { + self.inner_builder.build() + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs index edc297c91e..db663627f0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -48,7 +48,7 @@ pub enum EditorScript { }, CreateEmptyRow, CreateRow { - context: CreateRowRevisionPayload, + payload: CreateRowRevisionPayload, }, UpdateRow { changeset: RowMetaChangeset, @@ -98,7 +98,7 @@ impl GridEditorTest { pub async fn new() -> Self { let sdk = FlowySDKTest::default(); let _ = sdk.init_user().await; - let build_context = make_test_grid(); + let build_context = make_all_field_test_grid(); let view_data: Bytes = build_context.into(); let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); @@ -199,7 +199,7 @@ impl GridEditorTest { self.row_revs = self.get_row_revs().await; self.grid_block_revs = self.editor.get_block_metas().await.unwrap(); } - EditorScript::CreateRow { context } => { + EditorScript::CreateRow { payload: context } => { let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); for row_order in row_orders { self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order); @@ -307,74 +307,7 @@ impl GridEditorTest { } } -pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { - let field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default()) - .name("Name") - .visibility(true) - .build(); - - let cloned_field_rev = field_rev.clone(); - - let type_option_data = field_rev - .get_type_option_entry::(&field_rev.field_type) - .unwrap() - .protobuf_bytes() - .to_vec(); - - let field = Field { - id: field_rev.id, - name: field_rev.name, - desc: field_rev.desc, - field_type: field_rev.field_type, - frozen: field_rev.frozen, - visibility: field_rev.visibility, - width: field_rev.width, - is_primary: false, - }; - - let params = InsertFieldParams { - grid_id: grid_id.to_owned(), - field, - type_option_data, - start_field_id: None, - }; - (params, cloned_field_rev) -} - -pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { - let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Done")) - .option(SelectOption::new("Progress")); - - let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build(); - let cloned_field_rev = field_rev.clone(); - let type_option_data = field_rev - .get_type_option_entry::(&field_rev.field_type) - .unwrap() - .protobuf_bytes() - .to_vec(); - - let field = Field { - id: field_rev.id, - name: field_rev.name, - desc: field_rev.desc, - field_type: field_rev.field_type, - frozen: field_rev.frozen, - visibility: field_rev.visibility, - width: field_rev.width, - is_primary: false, - }; - - let params = InsertFieldParams { - grid_id: grid_id.to_owned(), - field, - type_option_data, - start_field_id: None, - }; - (params, cloned_field_rev) -} - -fn make_test_grid() -> BuildGridContext { +fn make_all_field_test_grid() -> BuildGridContext { let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) .name("Name") .visibility(true) @@ -429,11 +362,3 @@ fn make_test_grid() -> BuildGridContext { .add_empty_row() .build() } - -pub fn make_date_cell_string(s: &str) -> String { - serde_json::to_string(&DateCellContentChangeset { - date: Some(s.to_string()), - time: None, - }) - .unwrap() -} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/setting_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/setting_test.rs deleted file mode 100644 index ab32594db1..0000000000 --- a/frontend/rust-lib/flowy-grid/tests/grid/setting_test.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; - -use flowy_grid_data_model::entities::{ - CreateGridFilterParams, CreateGridFilterPayload, GridLayoutType, GridSettingChangesetParams, TextFilterCondition, -}; - -#[tokio::test] -async fn grid_setting_create_text_filter_test() { - let test = GridEditorTest::new().await; - let field_rev = test.text_field(); - let condition = TextFilterCondition::TextIsEmpty as i32; - - let scripts = vec![ - InsertGridTableFilter { - payload: CreateGridFilterPayload { - field_id: field_rev.id.clone(), - field_type: field_rev.field_type.clone(), - condition, - content: Some("abc".to_owned()), - }, - }, - AssertTableFilterCount { count: 1 }, - ]; - GridEditorTest::new().await.run_scripts(scripts).await; -} - -#[tokio::test] -#[should_panic] -async fn grid_setting_create_text_filter_panic_test() { - let test = GridEditorTest::new().await; - let field_rev = test.text_field(); - let scripts = vec![InsertGridTableFilter { - payload: CreateGridFilterPayload { - field_id: field_rev.id.clone(), - field_type: field_rev.field_type.clone(), - condition: 20, // Invalid condition type - content: Some("abc".to_owned()), - }, - }]; - GridEditorTest::new().await.run_scripts(scripts).await; -} - -#[tokio::test] -async fn grid_setting_delete_text_filter_test() { - let mut test = GridEditorTest::new().await; - let field_rev = test.text_field(); - let condition = TextFilterCondition::TextIsEmpty as i32; - - let scripts = vec![ - InsertGridTableFilter { - payload: CreateGridFilterPayload { - field_id: field_rev.id.clone(), - field_type: field_rev.field_type.clone(), - condition, - content: Some("abc".to_owned()), - }, - }, - 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 }, - AssertTableFilterCount { count: 0 }, - ]) - .await; -} -#[tokio::test] -async fn grid_setting_sort_test() {} diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs b/shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs index 948003e8fa..5558515385 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs @@ -3,7 +3,7 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error_code::ErrorCode; use crate::entities::FieldType; -use crate::revision::GridFilterRevision; +use crate::revision::{FieldRevision, GridFilterRevision}; use std::convert::TryInto; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] @@ -53,6 +53,18 @@ pub struct CreateGridFilterPayload { pub content: Option, } +impl CreateGridFilterPayload { + #[allow(dead_code)] + pub fn new>(field_rev: &FieldRevision, condition: T, content: Option) -> Self { + Self { + field_id: field_rev.id.clone(), + field_type: field_rev.field_type.clone(), + condition: condition.into(), + content, + } + } +} + pub struct CreateGridFilterParams { pub field_id: String, pub field_type: FieldType, @@ -113,6 +125,11 @@ pub enum TextFilterCondition { TextIsEmpty = 6, TextIsNotEmpty = 7, } +impl std::convert::Into for TextFilterCondition { + fn into(self) -> i32 { + self as i32 + } +} impl std::default::Default for TextFilterCondition { fn default() -> Self { @@ -173,6 +190,11 @@ impl std::default::Default for NumberFilterCondition { } } +impl std::convert::Into for NumberFilterCondition { + fn into(self) -> i32 { + self as i32 + } +} impl std::convert::TryFrom for NumberFilterCondition { type Error = ErrorCode; @@ -218,6 +240,12 @@ pub enum SelectOptionCondition { OptionIsNotEmpty = 3, } +impl std::convert::Into for SelectOptionCondition { + fn into(self) -> i32 { + self as i32 + } +} + impl std::default::Default for SelectOptionCondition { fn default() -> Self { SelectOptionCondition::OptionIs diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 4d657547c7..ca78c78496 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -359,7 +359,12 @@ impl GridRevisionPad { is_changed = Some(()) } - + if let Some(delete_filter_id) = changeset.delete_filter { + match grid_rev.setting.filter.get_mut(&layout_rev) { + Some(filters) => filters.retain(|filter| filter.id != delete_filter_id), + None => {} + } + } if let Some(params) = changeset.insert_group { let rev = GridGroupRevision { id: gen_grid_group_id(), @@ -376,7 +381,12 @@ impl GridRevisionPad { is_changed = Some(()) } - + if let Some(delete_group_id) = changeset.delete_group { + match grid_rev.setting.group.get_mut(&layout_rev) { + Some(groups) => groups.retain(|group| group.id != delete_group_id), + None => {} + } + } if let Some(sort) = changeset.insert_sort { let rev = GridSortRevision { id: gen_grid_sort_id(), @@ -386,12 +396,18 @@ impl GridRevisionPad { grid_rev .setting .sort - .entry(layout_rev) + .entry(layout_rev.clone()) .or_insert_with(std::vec::Vec::new) .push(rev); is_changed = Some(()) } + if let Some(delete_sort_id) = changeset.delete_sort { + match grid_rev.setting.sort.get_mut(&layout_rev) { + Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id), + None => {} + } + } Ok(is_changed) }) }