database_editor.rs 11 KB

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