2024-05-05 22:04:34 +08:00
|
|
|
use collab_database::database::gen_database_view_id;
|
2024-09-25 11:44:19 +08:00
|
|
|
use collab_database::fields::checkbox_type_option::CheckboxTypeOption;
|
2024-12-03 17:05:40 +08:00
|
|
|
use collab_database::fields::checklist_type_option::ChecklistTypeOption;
|
2024-09-25 11:44:19 +08:00
|
|
|
use collab_database::fields::select_type_option::{
|
|
|
|
MultiSelectTypeOption, SelectOption, SingleSelectTypeOption,
|
|
|
|
};
|
2023-04-28 14:08:53 +08:00
|
|
|
use collab_database::fields::Field;
|
2024-08-26 09:46:16 +08:00
|
|
|
use collab_database::rows::{Row, RowId};
|
2024-04-26 18:00:56 +08:00
|
|
|
use event_integration_test::folder_event::ViewTest;
|
|
|
|
use event_integration_test::EventIntegrationTest;
|
2024-12-25 16:50:38 +08:00
|
|
|
use flowy_database2::entities::{
|
|
|
|
DatabasePB, DatabaseViewSettingPB, FieldType, FilterPB, FilterType, RowMetaPB,
|
|
|
|
TextFilterConditionPB, TextFilterPB, UpdateCalculationChangesetPB,
|
|
|
|
};
|
|
|
|
use lib_infra::box_any::BoxAny;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::sync::Arc;
|
|
|
|
use std::time::Duration;
|
|
|
|
use strum::EnumCount;
|
|
|
|
use tokio::sync::broadcast::Receiver;
|
2024-05-05 22:04:34 +08:00
|
|
|
|
2023-07-14 13:37:13 +08:00
|
|
|
use flowy_database2::services::database::DatabaseEditor;
|
2024-12-25 16:50:38 +08:00
|
|
|
use flowy_database2::services::database_view::DatabaseViewChanged;
|
2024-12-05 14:12:25 +08:00
|
|
|
use flowy_database2::services::field::checklist_filter::ChecklistCellChangeset;
|
2024-09-25 11:44:19 +08:00
|
|
|
use flowy_database2::services::field::SelectOptionCellChangeset;
|
2024-12-25 16:50:38 +08:00
|
|
|
use flowy_database2::services::filter::{FilterChangeset, FilterInner};
|
2023-05-27 21:29:18 +08:00
|
|
|
use flowy_database2::services::share::csv::{CSVFormat, ImportResult};
|
2023-05-10 19:43:32 +08:00
|
|
|
use flowy_error::FlowyResult;
|
2023-04-28 14:08:53 +08:00
|
|
|
|
2023-06-01 20:23:27 +08:00
|
|
|
use crate::database::mock_data::{
|
|
|
|
make_no_date_test_grid, make_test_board, make_test_calendar, make_test_grid,
|
|
|
|
};
|
2023-04-28 14:08:53 +08:00
|
|
|
|
|
|
|
pub struct DatabaseEditorTest {
|
2023-10-24 20:11:06 +08:00
|
|
|
pub sdk: EventIntegrationTest,
|
2023-04-28 14:08:53 +08:00
|
|
|
pub view_id: String,
|
|
|
|
pub editor: Arc<DatabaseEditor>,
|
|
|
|
pub fields: Vec<Arc<Field>>,
|
2024-08-26 09:46:16 +08:00
|
|
|
pub rows: Vec<Arc<Row>>,
|
2023-04-28 14:08:53 +08:00
|
|
|
pub field_count: usize,
|
2023-06-14 22:16:33 +08:00
|
|
|
pub row_by_row_id: HashMap<String, RowMetaPB>,
|
2024-12-25 16:50:38 +08:00
|
|
|
view_change_recv: Option<Receiver<DatabaseViewChanged>>,
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DatabaseEditorTest {
|
|
|
|
pub async fn new_grid() -> Self {
|
2023-10-30 12:35:06 +08:00
|
|
|
let sdk = EventIntegrationTest::new().await;
|
2023-10-24 23:13:51 +08:00
|
|
|
let _ = sdk.init_anon_user().await;
|
2023-06-01 20:23:27 +08:00
|
|
|
|
|
|
|
let params = make_test_grid();
|
|
|
|
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;
|
|
|
|
Self::new(sdk, view_test).await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2023-06-01 20:23:27 +08:00
|
|
|
pub async fn new_no_date_grid() -> Self {
|
2023-10-30 12:35:06 +08:00
|
|
|
let sdk = EventIntegrationTest::new().await;
|
2023-10-24 23:13:51 +08:00
|
|
|
let _ = sdk.init_anon_user().await;
|
2023-06-01 20:23:27 +08:00
|
|
|
|
|
|
|
let params = make_no_date_test_grid();
|
|
|
|
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;
|
|
|
|
Self::new(sdk, view_test).await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2023-06-01 20:23:27 +08:00
|
|
|
pub async fn new_board() -> Self {
|
2023-10-30 12:35:06 +08:00
|
|
|
let sdk = EventIntegrationTest::new().await;
|
2023-10-24 23:13:51 +08:00
|
|
|
let _ = sdk.init_anon_user().await;
|
2023-06-01 20:23:27 +08:00
|
|
|
|
|
|
|
let params = make_test_board();
|
2023-10-26 11:48:58 +08:00
|
|
|
let view_test = ViewTest::new_board_view(&sdk, params.to_json_bytes().unwrap()).await;
|
2023-06-01 20:23:27 +08:00
|
|
|
Self::new(sdk, view_test).await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2023-06-01 20:23:27 +08:00
|
|
|
pub async fn new_calendar() -> Self {
|
2023-10-30 12:35:06 +08:00
|
|
|
let sdk = EventIntegrationTest::new().await;
|
2023-10-24 23:13:51 +08:00
|
|
|
let _ = sdk.init_anon_user().await;
|
2023-04-28 14:08:53 +08:00
|
|
|
|
2023-06-01 20:23:27 +08:00
|
|
|
let params = make_test_calendar();
|
|
|
|
let view_test = ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await;
|
|
|
|
Self::new(sdk, view_test).await
|
|
|
|
}
|
|
|
|
|
2023-10-24 20:11:06 +08:00
|
|
|
pub async fn new(sdk: EventIntegrationTest, test: ViewTest) -> Self {
|
2023-04-28 14:08:53 +08:00
|
|
|
let editor = sdk
|
|
|
|
.database_manager
|
2024-08-18 05:16:42 +02:00
|
|
|
.get_database_editor_with_view_id(&test.child_view.id)
|
2023-04-28 14:08:53 +08:00
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let fields = editor
|
|
|
|
.get_fields(&test.child_view.id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
.into_iter()
|
|
|
|
.map(Arc::new)
|
|
|
|
.collect();
|
|
|
|
let rows = editor
|
2024-08-26 09:46:16 +08:00
|
|
|
.get_all_rows(&test.child_view.id)
|
2023-04-28 14:08:53 +08:00
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.into_iter()
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let view_id = test.child_view.id;
|
2024-09-12 08:47:49 +08:00
|
|
|
let this = Self {
|
2023-04-28 14:08:53 +08:00
|
|
|
sdk,
|
2024-09-12 08:47:49 +08:00
|
|
|
view_id: view_id.clone(),
|
2023-04-28 14:08:53 +08:00
|
|
|
editor,
|
|
|
|
fields,
|
2024-08-26 09:46:16 +08:00
|
|
|
rows,
|
2023-04-28 14:08:53 +08:00
|
|
|
field_count: FieldType::COUNT,
|
|
|
|
row_by_row_id: HashMap::default(),
|
2024-12-25 16:50:38 +08:00
|
|
|
view_change_recv: None,
|
2024-09-12 08:47:49 +08:00
|
|
|
};
|
|
|
|
this.get_database_data(&view_id).await;
|
|
|
|
this
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_database_data(&self, view_id: &str) -> DatabasePB {
|
|
|
|
self.editor.open_database_view(view_id, None).await.unwrap()
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2024-10-15 09:32:06 +08:00
|
|
|
#[allow(dead_code)]
|
2023-04-28 14:08:53 +08:00
|
|
|
pub async fn database_filters(&self) -> Vec<FilterPB> {
|
|
|
|
self.editor.get_all_filters(&self.view_id).await.items
|
|
|
|
}
|
|
|
|
|
2024-08-26 09:46:16 +08:00
|
|
|
pub async fn get_rows(&self) -> Vec<Arc<Row>> {
|
|
|
|
self.editor.get_all_rows(&self.view_id).await.unwrap()
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_field(&self, field_id: &str, field_type: FieldType) -> Field {
|
2023-04-28 14:08:53 +08:00
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.get_fields(&self.view_id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
.into_iter()
|
|
|
|
.filter(|field| {
|
|
|
|
let t_field_type = FieldType::from(field.field_type);
|
|
|
|
field.id == field_id && t_field_type == field_type
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.pop()
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// returns the first `Field` in the build-in test grid.
|
|
|
|
/// Not support duplicate `FieldType` in test grid yet.
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_first_field(&self, field_type: FieldType) -> Field {
|
2023-04-28 14:08:53 +08:00
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.get_fields(&self.view_id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
.into_iter()
|
|
|
|
.filter(|field| {
|
|
|
|
let t_field_type = FieldType::from(field.field_type);
|
|
|
|
t_field_type == field_type
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.pop()
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_fields(&self) -> Vec<Field> {
|
|
|
|
self.editor.get_fields(&self.view_id, None).await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_multi_select_type_option(&self, field_id: &str) -> Vec<SelectOption> {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field_type = FieldType::MultiSelect;
|
2024-08-18 05:16:42 +02:00
|
|
|
let field = self.get_field(field_id, field_type).await;
|
2023-04-28 14:08:53 +08:00
|
|
|
let type_option = field
|
|
|
|
.get_type_option::<MultiSelectTypeOption>(field_type)
|
2024-09-25 11:44:19 +08:00
|
|
|
.unwrap()
|
|
|
|
.0;
|
2023-04-28 14:08:53 +08:00
|
|
|
type_option.options
|
|
|
|
}
|
|
|
|
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_single_select_type_option(&self, field_id: &str) -> Vec<SelectOption> {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field_type = FieldType::SingleSelect;
|
2024-08-18 05:16:42 +02:00
|
|
|
let field = self.get_field(field_id, field_type).await;
|
2024-03-16 17:18:30 +08:00
|
|
|
let type_option = field
|
2023-04-28 14:08:53 +08:00
|
|
|
.get_type_option::<SingleSelectTypeOption>(field_type)
|
2024-09-25 11:44:19 +08:00
|
|
|
.unwrap()
|
|
|
|
.0;
|
2024-03-16 17:18:30 +08:00
|
|
|
type_option.options
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_checklist_type_option(&self, field_id: &str) -> ChecklistTypeOption {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field_type = FieldType::Checklist;
|
2024-08-18 05:16:42 +02:00
|
|
|
let field = self.get_field(field_id, field_type).await;
|
2023-04-28 14:08:53 +08:00
|
|
|
field
|
|
|
|
.get_type_option::<ChecklistTypeOption>(field_type)
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_checkbox_type_option(&self, field_id: &str) -> CheckboxTypeOption {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field_type = FieldType::Checkbox;
|
2024-08-18 05:16:42 +02:00
|
|
|
let field = self.get_field(field_id, field_type).await;
|
2023-04-28 14:08:53 +08:00
|
|
|
field
|
|
|
|
.get_type_option::<CheckboxTypeOption>(field_type)
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
2024-02-22 07:12:52 +08:00
|
|
|
pub async fn update_cell(
|
2024-10-15 17:20:53 +08:00
|
|
|
&self,
|
2023-04-28 14:08:53 +08:00
|
|
|
field_id: &str,
|
|
|
|
row_id: RowId,
|
2024-02-22 07:12:52 +08:00
|
|
|
cell_changeset: BoxAny,
|
2023-05-10 19:43:32 +08:00
|
|
|
) -> FlowyResult<()> {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field = self
|
|
|
|
.editor
|
|
|
|
.get_fields(&self.view_id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
.into_iter()
|
|
|
|
.find(|field| field.id == field_id)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
self
|
|
|
|
.editor
|
2024-05-05 22:04:34 +08:00
|
|
|
.update_cell_with_changeset(&self.view_id, &row_id, &field.id, cell_changeset)
|
2023-05-10 19:43:32 +08:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2023-05-10 19:43:32 +08:00
|
|
|
pub(crate) async fn update_text_cell(&mut self, row_id: RowId, content: &str) -> FlowyResult<()> {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field = self
|
|
|
|
.editor
|
|
|
|
.get_fields(&self.view_id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
.iter()
|
|
|
|
.find(|field| {
|
|
|
|
let field_type = FieldType::from(field.field_type);
|
|
|
|
field_type == FieldType::RichText
|
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
|
|
|
self
|
2024-02-22 07:12:52 +08:00
|
|
|
.update_cell(&field.id, row_id, BoxAny::new(content.to_string()))
|
2023-05-10 19:43:32 +08:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
|
|
|
|
2023-05-30 09:41:33 +08:00
|
|
|
pub(crate) async fn set_checklist_cell(
|
|
|
|
&mut self,
|
|
|
|
row_id: RowId,
|
2023-10-24 10:15:28 +08:00
|
|
|
selected_options: Vec<String>,
|
2023-05-30 09:41:33 +08:00
|
|
|
) -> FlowyResult<()> {
|
|
|
|
let field = self
|
|
|
|
.editor
|
|
|
|
.get_fields(&self.view_id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-05-30 09:41:33 +08:00
|
|
|
.iter()
|
|
|
|
.find(|field| {
|
|
|
|
let field_type = FieldType::from(field.field_type);
|
|
|
|
field_type == FieldType::Checklist
|
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
let cell_changeset = ChecklistCellChangeset {
|
2024-10-10 11:38:17 +08:00
|
|
|
completed_task_ids: selected_options,
|
2023-05-30 09:41:33 +08:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.set_checklist_options(&self.view_id, row_id, &field.id, cell_changeset)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2023-05-10 19:43:32 +08:00
|
|
|
pub(crate) async fn update_single_select_cell(
|
|
|
|
&mut self,
|
|
|
|
row_id: RowId,
|
|
|
|
option_id: &str,
|
|
|
|
) -> FlowyResult<()> {
|
2023-04-28 14:08:53 +08:00
|
|
|
let field = self
|
|
|
|
.editor
|
|
|
|
.get_fields(&self.view_id, None)
|
2024-08-18 05:16:42 +02:00
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
.iter()
|
|
|
|
.find(|field| {
|
|
|
|
let field_type = FieldType::from(field.field_type);
|
|
|
|
field_type == FieldType::SingleSelect
|
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
|
|
|
let cell_changeset = SelectOptionCellChangeset::from_insert_option_id(option_id);
|
2024-02-22 07:12:52 +08:00
|
|
|
self
|
|
|
|
.update_cell(&field.id, row_id, BoxAny::new(cell_changeset))
|
|
|
|
.await
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|
2023-05-25 23:22:23 +08:00
|
|
|
|
2023-05-27 21:29:18 +08:00
|
|
|
pub async fn import(&self, s: String, format: CSVFormat) -> ImportResult {
|
|
|
|
self
|
|
|
|
.sdk
|
|
|
|
.database_manager
|
2023-05-31 14:08:54 +08:00
|
|
|
.import_csv(gen_database_view_id(), s, format)
|
2023-05-27 21:29:18 +08:00
|
|
|
.await
|
|
|
|
.unwrap()
|
2023-05-25 23:22:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_database(&self, database_id: &str) -> Option<Arc<DatabaseEditor>> {
|
|
|
|
self
|
|
|
|
.sdk
|
|
|
|
.database_manager
|
2024-09-15 00:02:17 +08:00
|
|
|
.get_or_init_database_editor(database_id)
|
2023-05-25 23:22:23 +08:00
|
|
|
.await
|
|
|
|
.ok()
|
|
|
|
}
|
2024-12-25 16:50:38 +08:00
|
|
|
|
|
|
|
pub async fn insert_calculation(&mut self, payload: UpdateCalculationChangesetPB) {
|
|
|
|
self.view_change_recv = Some(
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.subscribe_view_changed(&self.view_id())
|
|
|
|
.await
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
self.editor.update_calculation(payload).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assert_calculation_float_value(&mut self, expected: f64) {
|
|
|
|
let calculations = self.editor.get_all_calculations(&self.view_id()).await;
|
|
|
|
let calculation = calculations.items.first().unwrap();
|
|
|
|
assert_eq!(calculation.value, format!("{:.2}", expected));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assert_calculation_value(&mut self, expected: &str) {
|
|
|
|
let calculations = self.editor.get_all_calculations(&self.view_id()).await;
|
|
|
|
let calculation = calculations.items.first().unwrap();
|
|
|
|
assert_eq!(calculation.value, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn duplicate_row(&self, row_id: &RowId) {
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.duplicate_row(&self.view_id, row_id)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
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 get_filter(
|
|
|
|
&self,
|
|
|
|
filter_type: FilterType,
|
|
|
|
field_type: Option<FieldType>,
|
|
|
|
) -> Option<FilterPB> {
|
|
|
|
let filters = self.editor.get_all_filters(&self.view_id).await;
|
|
|
|
|
|
|
|
for filter in filters.items.iter() {
|
|
|
|
let result = Self::find_filter(filter, filter_type, field_type);
|
|
|
|
if result.is_some() {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_filter(
|
|
|
|
filter: &FilterPB,
|
|
|
|
filter_type: FilterType,
|
|
|
|
field_type: Option<FieldType>,
|
|
|
|
) -> Option<FilterPB> {
|
|
|
|
match &filter.filter_type {
|
|
|
|
FilterType::And | FilterType::Or if filter.filter_type == filter_type => Some(filter.clone()),
|
|
|
|
FilterType::And | FilterType::Or => {
|
|
|
|
for child_filter in filter.children.iter() {
|
|
|
|
if let Some(result) = Self::find_filter(child_filter, filter_type, field_type) {
|
|
|
|
return Some(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
},
|
|
|
|
FilterType::Data
|
|
|
|
if filter.filter_type == filter_type
|
|
|
|
&& field_type.map_or(false, |field_type| {
|
|
|
|
field_type == filter.data.clone().unwrap().field_type
|
|
|
|
}) =>
|
|
|
|
{
|
|
|
|
Some(filter.clone())
|
|
|
|
},
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_text_cell_with_change(
|
|
|
|
&mut self,
|
|
|
|
row_id: RowId,
|
|
|
|
text: String,
|
|
|
|
changed: Option<FilterRowChanged>,
|
|
|
|
) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
self.update_text_cell(row_id, &text).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_checklist_cell(&mut self, row_id: RowId, selected_option_ids: Vec<String>) {
|
|
|
|
self
|
|
|
|
.set_checklist_cell(row_id, selected_option_ids)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_single_select_cell_with_change(
|
|
|
|
&mut self,
|
|
|
|
row_id: RowId,
|
|
|
|
option_id: String,
|
|
|
|
changed: Option<FilterRowChanged>,
|
|
|
|
) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
self
|
|
|
|
.update_single_select_cell(row_id, &option_id)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_data_filter(
|
|
|
|
&mut self,
|
|
|
|
parent_filter_id: Option<String>,
|
|
|
|
field_type: FieldType,
|
|
|
|
data: BoxAny,
|
|
|
|
changed: Option<FilterRowChanged>,
|
|
|
|
) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
let field = self.get_first_field(field_type).await;
|
|
|
|
let params = FilterChangeset::Insert {
|
|
|
|
parent_filter_id,
|
|
|
|
data: FilterInner::Data {
|
|
|
|
field_id: field.id,
|
|
|
|
field_type,
|
|
|
|
condition_and_content: data,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.modify_view_filters(&self.view_id, params)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_text_filter(
|
|
|
|
&mut self,
|
|
|
|
filter: FilterPB,
|
|
|
|
condition: TextFilterConditionPB,
|
|
|
|
content: String,
|
|
|
|
changed: Option<FilterRowChanged>,
|
|
|
|
) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
let current_filter = filter.data.unwrap();
|
|
|
|
let params = FilterChangeset::UpdateData {
|
|
|
|
filter_id: filter.id,
|
|
|
|
data: FilterInner::Data {
|
|
|
|
field_id: current_filter.field_id,
|
|
|
|
field_type: current_filter.field_type,
|
|
|
|
condition_and_content: BoxAny::new(TextFilterPB { condition, content }),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.modify_view_filters(&self.view_id, params)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_and_filter(
|
|
|
|
&mut self,
|
|
|
|
parent_filter_id: Option<String>,
|
|
|
|
changed: Option<FilterRowChanged>,
|
|
|
|
) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
let params = FilterChangeset::Insert {
|
|
|
|
parent_filter_id,
|
|
|
|
data: FilterInner::And { children: vec![] },
|
|
|
|
};
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.modify_view_filters(&self.view_id, params)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_or_filter(
|
|
|
|
&mut self,
|
|
|
|
parent_filter_id: Option<String>,
|
|
|
|
changed: Option<FilterRowChanged>,
|
|
|
|
) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
let params = FilterChangeset::Insert {
|
|
|
|
parent_filter_id,
|
|
|
|
data: FilterInner::Or { children: vec![] },
|
|
|
|
};
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.modify_view_filters(&self.view_id, params)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn delete_filter(&mut self, filter_id: String, changed: Option<FilterRowChanged>) {
|
|
|
|
self.subscribe_view_changed().await;
|
|
|
|
self.assert_future_changed(changed).await;
|
|
|
|
let params = FilterChangeset::Delete { filter_id };
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.modify_view_filters(&self.view_id, params)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assert_filter_count(&self, count: usize) {
|
|
|
|
let filters = self.editor.get_all_filters(&self.view_id).await.items;
|
|
|
|
assert_eq!(count, filters.len());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assert_grid_setting(&self, expected_setting: DatabaseViewSettingPB) {
|
|
|
|
let setting = self
|
|
|
|
.editor
|
|
|
|
.get_database_view_setting(&self.view_id)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
assert_eq!(expected_setting, setting);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assert_filters(&self, expected: Vec<FilterPB>) {
|
|
|
|
let actual = self.get_all_filters().await;
|
|
|
|
for (actual_filter, expected_filter) in actual.iter().zip(expected.iter()) {
|
|
|
|
Self::assert_filter(actual_filter, expected_filter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn assert_number_of_visible_rows(&self, expected: usize) {
|
|
|
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
|
|
|
let _ = self
|
|
|
|
.editor
|
|
|
|
.open_database_view(&self.view_id, Some(tx))
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
rx.await.unwrap();
|
|
|
|
|
|
|
|
let rows = self.editor.get_all_rows(&self.view_id).await.unwrap();
|
|
|
|
assert_eq!(rows.len(), expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn wait(&self, millisecond: u64) {
|
|
|
|
tokio::time::sleep(Duration::from_millis(millisecond)).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn subscribe_view_changed(&mut self) {
|
|
|
|
self.view_change_recv = Some(
|
|
|
|
self
|
|
|
|
.editor
|
|
|
|
.subscribe_view_changed(&self.view_id)
|
|
|
|
.await
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn assert_future_changed(&mut self, change: Option<FilterRowChanged>) {
|
|
|
|
if change.is_none() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let change = change.unwrap();
|
|
|
|
let mut receiver = self.view_change_recv.take().unwrap();
|
|
|
|
tokio::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);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assert_filter(actual: &FilterPB, expected: &FilterPB) {
|
|
|
|
assert_eq!(actual.filter_type, expected.filter_type);
|
|
|
|
assert_eq!(actual.children.is_empty(), expected.children.is_empty());
|
|
|
|
assert_eq!(actual.data.is_some(), expected.data.is_some());
|
|
|
|
|
|
|
|
match actual.filter_type {
|
|
|
|
FilterType::Data => {
|
|
|
|
let actual_data = actual.data.clone().unwrap();
|
|
|
|
let expected_data = expected.data.clone().unwrap();
|
|
|
|
assert_eq!(actual_data.field_type, expected_data.field_type);
|
|
|
|
assert_eq!(actual_data.data, expected_data.data);
|
|
|
|
},
|
|
|
|
FilterType::And | FilterType::Or => {
|
|
|
|
for (actual_child, expected_child) in actual.children.iter().zip(expected.children.iter()) {
|
|
|
|
Self::assert_filter(actual_child, expected_child);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct FilterRowChanged {
|
|
|
|
pub(crate) showing_num_of_rows: usize,
|
|
|
|
pub(crate) hiding_num_of_rows: usize,
|
2023-04-28 14:08:53 +08:00
|
|
|
}
|