database_editor.rs 10 KB

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