database_editor.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. use collab_database::database::gen_database_view_id;
  2. use std::collections::HashMap;
  3. use std::sync::Arc;
  4. use collab_database::fields::Field;
  5. use collab_database::rows::{CreateRowParams, Row, RowId};
  6. use strum::EnumCount;
  7. use flowy_database2::entities::{DatabaseLayoutPB, FieldType, FilterPB, RowPB, SelectOptionPB};
  8. use flowy_database2::services::cell::{CellBuilder, ToCellChangeset};
  9. use flowy_database2::services::database::DatabaseEditor;
  10. use flowy_database2::services::field::checklist_type_option::{
  11. ChecklistCellChangeset, ChecklistTypeOption,
  12. };
  13. use flowy_database2::services::field::{
  14. CheckboxTypeOption, DateCellChangeset, MultiSelectTypeOption, SelectOption,
  15. SelectOptionCellChangeset, SingleSelectTypeOption,
  16. };
  17. use flowy_database2::services::share::csv::{CSVFormat, ImportResult};
  18. use flowy_error::FlowyResult;
  19. use flowy_test::folder_event::ViewTest;
  20. use flowy_test::FlowyCoreTest;
  21. use crate::database::mock_data::{make_test_board, make_test_calendar, make_test_grid};
  22. pub struct DatabaseEditorTest {
  23. pub sdk: FlowyCoreTest,
  24. pub app_id: String,
  25. pub view_id: String,
  26. pub editor: Arc<DatabaseEditor>,
  27. pub fields: Vec<Arc<Field>>,
  28. pub rows: Vec<Arc<Row>>,
  29. pub field_count: usize,
  30. pub row_by_row_id: HashMap<String, RowPB>,
  31. }
  32. impl DatabaseEditorTest {
  33. pub async fn new_grid() -> Self {
  34. Self::new(DatabaseLayoutPB::Grid).await
  35. }
  36. pub async fn new_board() -> Self {
  37. Self::new(DatabaseLayoutPB::Board).await
  38. }
  39. pub async fn new_calendar() -> Self {
  40. Self::new(DatabaseLayoutPB::Calendar).await
  41. }
  42. pub async fn new(layout: DatabaseLayoutPB) -> Self {
  43. let sdk = FlowyCoreTest::new();
  44. let _ = sdk.init_user().await;
  45. let test = match layout {
  46. DatabaseLayoutPB::Grid => {
  47. let params = make_test_grid();
  48. ViewTest::new_grid_view(&sdk, params.to_json_bytes().unwrap()).await
  49. },
  50. DatabaseLayoutPB::Board => {
  51. let data = make_test_board();
  52. ViewTest::new_board_view(&sdk, data.to_json_bytes().unwrap()).await
  53. },
  54. DatabaseLayoutPB::Calendar => {
  55. let data = make_test_calendar();
  56. ViewTest::new_calendar_view(&sdk, data.to_json_bytes().unwrap()).await
  57. },
  58. };
  59. let editor = sdk
  60. .database_manager
  61. .get_database_with_view_id(&test.child_view.id)
  62. .await
  63. .unwrap();
  64. let fields = editor
  65. .get_fields(&test.child_view.id, None)
  66. .into_iter()
  67. .map(Arc::new)
  68. .collect();
  69. let rows = editor
  70. .get_rows(&test.child_view.id)
  71. .await
  72. .unwrap()
  73. .into_iter()
  74. .collect();
  75. let view_id = test.child_view.id;
  76. let app_id = test.parent_view.id;
  77. Self {
  78. sdk,
  79. app_id,
  80. view_id,
  81. editor,
  82. fields,
  83. rows,
  84. field_count: FieldType::COUNT,
  85. row_by_row_id: HashMap::default(),
  86. }
  87. }
  88. pub async fn database_filters(&self) -> Vec<FilterPB> {
  89. self.editor.get_all_filters(&self.view_id).await.items
  90. }
  91. pub async fn get_rows(&self) -> Vec<Arc<Row>> {
  92. self.editor.get_rows(&self.view_id).await.unwrap()
  93. }
  94. pub fn get_field(&self, field_id: &str, field_type: FieldType) -> Field {
  95. self
  96. .editor
  97. .get_fields(&self.view_id, None)
  98. .into_iter()
  99. .filter(|field| {
  100. let t_field_type = FieldType::from(field.field_type);
  101. field.id == field_id && t_field_type == field_type
  102. })
  103. .collect::<Vec<_>>()
  104. .pop()
  105. .unwrap()
  106. }
  107. /// returns the first `Field` in the build-in test grid.
  108. /// Not support duplicate `FieldType` in test grid yet.
  109. pub fn get_first_field(&self, field_type: FieldType) -> Field {
  110. self
  111. .editor
  112. .get_fields(&self.view_id, None)
  113. .into_iter()
  114. .filter(|field| {
  115. let t_field_type = FieldType::from(field.field_type);
  116. t_field_type == field_type
  117. })
  118. .collect::<Vec<_>>()
  119. .pop()
  120. .unwrap()
  121. }
  122. pub fn get_fields(&self) -> Vec<Field> {
  123. self.editor.get_fields(&self.view_id, None)
  124. }
  125. pub fn get_multi_select_type_option(&self, field_id: &str) -> Vec<SelectOption> {
  126. let field_type = FieldType::MultiSelect;
  127. let field = self.get_field(field_id, field_type.clone());
  128. let type_option = field
  129. .get_type_option::<MultiSelectTypeOption>(field_type)
  130. .unwrap();
  131. type_option.options
  132. }
  133. pub fn get_single_select_type_option(&self, field_id: &str) -> SingleSelectTypeOption {
  134. let field_type = FieldType::SingleSelect;
  135. let field = self.get_field(field_id, field_type.clone());
  136. field
  137. .get_type_option::<SingleSelectTypeOption>(field_type)
  138. .unwrap()
  139. }
  140. #[allow(dead_code)]
  141. pub fn get_checklist_type_option(&self, field_id: &str) -> ChecklistTypeOption {
  142. let field_type = FieldType::Checklist;
  143. let field = self.get_field(field_id, field_type.clone());
  144. field
  145. .get_type_option::<ChecklistTypeOption>(field_type)
  146. .unwrap()
  147. }
  148. #[allow(dead_code)]
  149. pub fn get_checkbox_type_option(&self, field_id: &str) -> CheckboxTypeOption {
  150. let field_type = FieldType::Checkbox;
  151. let field = self.get_field(field_id, field_type.clone());
  152. field
  153. .get_type_option::<CheckboxTypeOption>(field_type)
  154. .unwrap()
  155. }
  156. pub async fn update_cell<T: ToCellChangeset>(
  157. &mut self,
  158. field_id: &str,
  159. row_id: RowId,
  160. cell_changeset: T,
  161. ) -> FlowyResult<()> {
  162. let field = self
  163. .editor
  164. .get_fields(&self.view_id, None)
  165. .into_iter()
  166. .find(|field| field.id == field_id)
  167. .unwrap();
  168. self
  169. .editor
  170. .update_cell_with_changeset(&self.view_id, row_id, &field.id, cell_changeset)
  171. .await
  172. }
  173. pub(crate) async fn update_text_cell(&mut self, row_id: RowId, content: &str) -> FlowyResult<()> {
  174. let field = self
  175. .editor
  176. .get_fields(&self.view_id, None)
  177. .iter()
  178. .find(|field| {
  179. let field_type = FieldType::from(field.field_type);
  180. field_type == FieldType::RichText
  181. })
  182. .unwrap()
  183. .clone();
  184. self
  185. .update_cell(&field.id, row_id, content.to_string())
  186. .await
  187. }
  188. pub(crate) async fn set_checklist_cell(
  189. &mut self,
  190. row_id: RowId,
  191. f: Box<dyn FnOnce(Vec<SelectOptionPB>) -> Vec<String>>,
  192. ) -> FlowyResult<()> {
  193. let field = self
  194. .editor
  195. .get_fields(&self.view_id, None)
  196. .iter()
  197. .find(|field| {
  198. let field_type = FieldType::from(field.field_type);
  199. field_type == FieldType::Checklist
  200. })
  201. .unwrap()
  202. .clone();
  203. let options = self
  204. .editor
  205. .get_checklist_option(row_id.clone(), &field.id)
  206. .await
  207. .options;
  208. let cell_changeset = ChecklistCellChangeset {
  209. selected_option_ids: f(options),
  210. ..Default::default()
  211. };
  212. self
  213. .editor
  214. .set_checklist_options(&self.view_id, row_id, &field.id, cell_changeset)
  215. .await
  216. }
  217. pub(crate) async fn update_single_select_cell(
  218. &mut self,
  219. row_id: RowId,
  220. option_id: &str,
  221. ) -> FlowyResult<()> {
  222. let field = self
  223. .editor
  224. .get_fields(&self.view_id, None)
  225. .iter()
  226. .find(|field| {
  227. let field_type = FieldType::from(field.field_type);
  228. field_type == FieldType::SingleSelect
  229. })
  230. .unwrap()
  231. .clone();
  232. let cell_changeset = SelectOptionCellChangeset::from_insert_option_id(option_id);
  233. self.update_cell(&field.id, row_id, cell_changeset).await
  234. }
  235. pub async fn import(&self, s: String, format: CSVFormat) -> ImportResult {
  236. self
  237. .sdk
  238. .database_manager
  239. .import_csv(gen_database_view_id(), s, format)
  240. .await
  241. .unwrap()
  242. }
  243. pub async fn get_database(&self, database_id: &str) -> Option<Arc<DatabaseEditor>> {
  244. self
  245. .sdk
  246. .database_manager
  247. .get_database(database_id)
  248. .await
  249. .ok()
  250. }
  251. }
  252. pub struct TestRowBuilder<'a> {
  253. row_id: RowId,
  254. fields: &'a [Field],
  255. cell_build: CellBuilder<'a>,
  256. }
  257. impl<'a> TestRowBuilder<'a> {
  258. pub fn new(row_id: RowId, fields: &'a [Field]) -> Self {
  259. let cell_build = CellBuilder::with_cells(Default::default(), fields);
  260. Self {
  261. row_id,
  262. fields,
  263. cell_build,
  264. }
  265. }
  266. pub fn insert_text_cell(&mut self, data: &str) -> String {
  267. let text_field = self.field_with_type(&FieldType::RichText);
  268. self
  269. .cell_build
  270. .insert_text_cell(&text_field.id, data.to_string());
  271. text_field.id.clone()
  272. }
  273. pub fn insert_number_cell(&mut self, data: &str) -> String {
  274. let number_field = self.field_with_type(&FieldType::Number);
  275. self
  276. .cell_build
  277. .insert_text_cell(&number_field.id, data.to_string());
  278. number_field.id.clone()
  279. }
  280. pub fn insert_date_cell(
  281. &mut self,
  282. data: &str,
  283. time: Option<String>,
  284. include_time: Option<bool>,
  285. field_type: &FieldType,
  286. ) -> String {
  287. let value = serde_json::to_string(&DateCellChangeset {
  288. date: Some(data.to_string()),
  289. time,
  290. include_time,
  291. })
  292. .unwrap();
  293. let date_field = self.field_with_type(field_type);
  294. self.cell_build.insert_text_cell(&date_field.id, value);
  295. date_field.id.clone()
  296. }
  297. pub fn insert_checkbox_cell(&mut self, data: &str) -> String {
  298. let checkbox_field = self.field_with_type(&FieldType::Checkbox);
  299. self
  300. .cell_build
  301. .insert_text_cell(&checkbox_field.id, data.to_string());
  302. checkbox_field.id.clone()
  303. }
  304. pub fn insert_url_cell(&mut self, content: &str) -> String {
  305. let url_field = self.field_with_type(&FieldType::URL);
  306. self
  307. .cell_build
  308. .insert_url_cell(&url_field.id, content.to_string());
  309. url_field.id.clone()
  310. }
  311. pub fn insert_single_select_cell<F>(&mut self, f: F) -> String
  312. where
  313. F: Fn(Vec<SelectOption>) -> SelectOption,
  314. {
  315. let single_select_field = self.field_with_type(&FieldType::SingleSelect);
  316. let type_option = single_select_field
  317. .get_type_option::<SingleSelectTypeOption>(FieldType::SingleSelect)
  318. .unwrap();
  319. let option = f(type_option.options);
  320. self
  321. .cell_build
  322. .insert_select_option_cell(&single_select_field.id, vec![option.id]);
  323. single_select_field.id.clone()
  324. }
  325. pub fn insert_multi_select_cell<F>(&mut self, f: F) -> String
  326. where
  327. F: Fn(Vec<SelectOption>) -> Vec<SelectOption>,
  328. {
  329. let multi_select_field = self.field_with_type(&FieldType::MultiSelect);
  330. let type_option = multi_select_field
  331. .get_type_option::<MultiSelectTypeOption>(FieldType::MultiSelect)
  332. .unwrap();
  333. let options = f(type_option.options);
  334. let ops_ids = options
  335. .iter()
  336. .map(|option| option.id.clone())
  337. .collect::<Vec<_>>();
  338. self
  339. .cell_build
  340. .insert_select_option_cell(&multi_select_field.id, ops_ids);
  341. multi_select_field.id.clone()
  342. }
  343. pub fn insert_checklist_cell(&mut self, option_names: Vec<String>) -> String {
  344. let checklist_field = self.field_with_type(&FieldType::Checklist);
  345. self
  346. .cell_build
  347. .insert_checklist_cell(&checklist_field.id, option_names);
  348. checklist_field.id.clone()
  349. }
  350. pub fn field_with_type(&self, field_type: &FieldType) -> Field {
  351. self
  352. .fields
  353. .iter()
  354. .find(|field| {
  355. let t_field_type = FieldType::from(field.field_type);
  356. &t_field_type == field_type
  357. })
  358. .unwrap()
  359. .clone()
  360. }
  361. pub fn build(self) -> CreateRowParams {
  362. CreateRowParams {
  363. id: self.row_id,
  364. cells: self.cell_build.build(),
  365. height: 60,
  366. visibility: true,
  367. prev_row_id: None,
  368. timestamp: 0,
  369. }
  370. }
  371. }