import.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. use crate::entities::FieldType;
  2. use crate::services::field::{default_type_option_data_from_type, CELL_DATA};
  3. use crate::services::share::csv::CSVFormat;
  4. use collab_database::database::{gen_database_id, gen_field_id, gen_row_id};
  5. use collab_database::fields::Field;
  6. use collab_database::rows::{new_cell_builder, Cell, CreateRowParams};
  7. use collab_database::views::{CreateDatabaseParams, DatabaseLayout};
  8. use flowy_error::{FlowyError, FlowyResult};
  9. use std::{fs::File, io::prelude::*};
  10. #[derive(Default)]
  11. pub struct CSVImporter;
  12. impl CSVImporter {
  13. pub fn import_csv_from_file(
  14. &self,
  15. view_id: &str,
  16. path: &str,
  17. style: CSVFormat,
  18. ) -> FlowyResult<CreateDatabaseParams> {
  19. let mut file = File::open(path)?;
  20. let mut content = String::new();
  21. file.read_to_string(&mut content)?;
  22. let fields_with_rows = self.get_fields_and_rows(content)?;
  23. let database_data = database_from_fields_and_rows(view_id, fields_with_rows, &style);
  24. Ok(database_data)
  25. }
  26. pub fn import_csv_from_string(
  27. &self,
  28. view_id: String,
  29. content: String,
  30. format: CSVFormat,
  31. ) -> FlowyResult<CreateDatabaseParams> {
  32. let fields_with_rows = self.get_fields_and_rows(content)?;
  33. let database_data = database_from_fields_and_rows(&view_id, fields_with_rows, &format);
  34. Ok(database_data)
  35. }
  36. fn get_fields_and_rows(&self, content: String) -> Result<FieldsRows, FlowyError> {
  37. let mut fields: Vec<String> = vec![];
  38. if content.is_empty() {
  39. return Err(FlowyError::invalid_data().context("Import content is empty"));
  40. }
  41. let mut reader = csv::Reader::from_reader(content.as_bytes());
  42. if let Ok(headers) = reader.headers() {
  43. for header in headers {
  44. fields.push(header.to_string());
  45. }
  46. } else {
  47. return Err(FlowyError::invalid_data().context("Header not found"));
  48. }
  49. let rows = reader
  50. .records()
  51. .into_iter()
  52. .flat_map(|r| r.ok())
  53. .map(|record| {
  54. record
  55. .into_iter()
  56. .map(|s| s.to_string())
  57. .collect::<Vec<String>>()
  58. })
  59. .collect();
  60. Ok(FieldsRows { fields, rows })
  61. }
  62. }
  63. fn database_from_fields_and_rows(
  64. view_id: &str,
  65. fields_and_rows: FieldsRows,
  66. format: &CSVFormat,
  67. ) -> CreateDatabaseParams {
  68. let (fields, rows) = fields_and_rows.split();
  69. let database_id = gen_database_id();
  70. let fields = fields
  71. .into_iter()
  72. .enumerate()
  73. .map(|(index, field_meta)| match format {
  74. CSVFormat::Original => default_field(field_meta, index == 0),
  75. CSVFormat::META => {
  76. //
  77. match serde_json::from_str(&field_meta) {
  78. Ok(field) => field,
  79. Err(e) => {
  80. dbg!(e);
  81. default_field(field_meta, index == 0)
  82. },
  83. }
  84. },
  85. })
  86. .collect::<Vec<Field>>();
  87. let created_rows = rows
  88. .iter()
  89. .map(|cells| {
  90. let mut params = CreateRowParams::new(gen_row_id());
  91. for (index, cell_content) in cells.iter().enumerate() {
  92. if let Some(field) = fields.get(index) {
  93. let field_type = FieldType::from(field.field_type);
  94. // Make the cell based on the style.
  95. let cell = match format {
  96. CSVFormat::Original => new_cell_builder(field_type)
  97. .insert_str_value(CELL_DATA, cell_content.to_string())
  98. .build(),
  99. CSVFormat::META => match serde_json::from_str::<Cell>(cell_content) {
  100. Ok(cell) => cell,
  101. Err(_) => new_cell_builder(field_type)
  102. .insert_str_value(CELL_DATA, "".to_string())
  103. .build(),
  104. },
  105. };
  106. params.cells.insert(field.id.clone(), cell);
  107. }
  108. }
  109. params
  110. })
  111. .collect::<Vec<CreateRowParams>>();
  112. CreateDatabaseParams {
  113. database_id,
  114. view_id: view_id.to_string(),
  115. name: "".to_string(),
  116. layout: DatabaseLayout::Grid,
  117. layout_settings: Default::default(),
  118. filters: vec![],
  119. groups: vec![],
  120. sorts: vec![],
  121. created_rows,
  122. fields,
  123. }
  124. }
  125. fn default_field(field_str: String, is_primary: bool) -> Field {
  126. let field_type = FieldType::RichText;
  127. let type_option_data = default_type_option_data_from_type(&field_type);
  128. Field::new(
  129. gen_field_id(),
  130. field_str,
  131. field_type.clone().into(),
  132. is_primary,
  133. )
  134. .with_type_option_data(field_type, type_option_data)
  135. }
  136. struct FieldsRows {
  137. fields: Vec<String>,
  138. rows: Vec<Vec<String>>,
  139. }
  140. impl FieldsRows {
  141. fn split(self) -> (Vec<String>, Vec<Vec<String>>) {
  142. (self.fields, self.rows)
  143. }
  144. }
  145. pub struct ImportResult {
  146. pub database_id: String,
  147. pub view_id: String,
  148. }
  149. #[cfg(test)]
  150. mod tests {
  151. use crate::services::share::csv::{CSVFormat, CSVImporter};
  152. use collab_database::database::gen_database_view_id;
  153. #[test]
  154. fn test_import_csv_from_str() {
  155. let s = r#"Name,Tags,Number,Date,Checkbox,URL
  156. 1,tag 1,1,"May 26, 2023",Yes,appflowy.io
  157. 2,tag 2,2,"May 22, 2023",No,
  158. ,,,,Yes,"#;
  159. let importer = CSVImporter;
  160. let result = importer
  161. .import_csv_from_string(gen_database_view_id(), s.to_string(), CSVFormat::Original)
  162. .unwrap();
  163. assert_eq!(result.created_rows.len(), 3);
  164. assert_eq!(result.fields.len(), 6);
  165. assert_eq!(result.fields[0].name, "Name");
  166. assert_eq!(result.fields[1].name, "Tags");
  167. assert_eq!(result.fields[2].name, "Number");
  168. assert_eq!(result.fields[3].name, "Date");
  169. assert_eq!(result.fields[4].name, "Checkbox");
  170. assert_eq!(result.fields[5].name, "URL");
  171. assert_eq!(result.created_rows[0].cells.len(), 6);
  172. assert_eq!(result.created_rows[1].cells.len(), 6);
  173. assert_eq!(result.created_rows[2].cells.len(), 6);
  174. println!("{:?}", result);
  175. }
  176. #[test]
  177. fn import_empty_csv_data_test() {
  178. let s = r#""#;
  179. let importer = CSVImporter;
  180. let result =
  181. importer.import_csv_from_string(gen_database_view_id(), s.to_string(), CSVFormat::Original);
  182. assert!(result.is_err());
  183. }
  184. }