cell_operation.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. use crate::entities::FieldType;
  2. use crate::services::cell::{AnyCellData, CellBytes};
  3. use crate::services::field::*;
  4. use std::fmt::Debug;
  5. use flowy_error::{ErrorCode, FlowyError, FlowyResult};
  6. use grid_rev_model::{CellRevision, FieldRevision, FieldTypeRevision};
  7. /// This trait is used when doing filter/search on the grid.
  8. pub trait CellFilterOperation<T> {
  9. /// Return true if any_cell_data match the filter condition.
  10. fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>;
  11. }
  12. pub trait CellGroupOperation {
  13. fn apply_group(&self, any_cell_data: AnyCellData, group_content: &str) -> FlowyResult<bool>;
  14. }
  15. /// Return object that describes the cell.
  16. pub trait CellDisplayable<CD> {
  17. /// Serialize the cell data into `CellBytes` that will be posted to the `Dart` side. Using the
  18. /// corresponding protobuf struct implement in `Dart` to deserialize the data.
  19. ///
  20. /// Using `utf8` to encode the cell data if the cell data use `String` as its data container.
  21. /// Using `protobuf` to encode the cell data if the cell data use `Protobuf struct` as its data container.
  22. ///
  23. /// When switching the field type of the `FieldRevision` to another field type. The `field_type`
  24. /// of the `FieldRevision` is not equal to the `decoded_field_type`. The cell data is need to do
  25. /// some custom transformation.
  26. ///
  27. /// For example, the current field type of the `FieldRevision` is a checkbox. When switching the field
  28. /// type from the checkbox to single select, the `TypeOptionBuilder`'s transform method gets called.
  29. /// It will create two new options,`Yes` and `No`, if they don't exist. But the cell data didn't change,
  30. /// because we can't iterate all the rows to transform the cell data that can be parsed by the current
  31. /// field type. One approach is to transform the cell data when it get read. For the moment,
  32. /// the cell data is a string, `Yes` or `No`. It needs to compare with the option's name, if match
  33. /// return the id of the option. Otherwise, return a default value of `CellBytes`.
  34. ///
  35. /// # Arguments
  36. ///
  37. /// * `cell_data`: the generic annotation `CD` represents as the deserialize data type of the cell.
  38. /// * `decoded_field_type`: the field type of the cell_data when doing serialization
  39. ///
  40. /// returns: Result<CellBytes, FlowyError>
  41. ///
  42. fn displayed_cell_bytes(
  43. &self,
  44. cell_data: CellData<CD>,
  45. decoded_field_type: &FieldType,
  46. field_rev: &FieldRevision,
  47. ) -> FlowyResult<CellBytes>;
  48. /// Serialize the cell data into `String` that is readable
  49. ///
  50. /// The cell data is not readable which means it can't display the cell data directly to user.
  51. /// For example,
  52. /// 1. the cell data is timestamp if its field type is FieldType::Date that is not readable.
  53. /// It needs to be parsed as the date string.
  54. ///
  55. /// 2. the cell data is a commas separated id if its field type if FieldType::MultiSelect that is not readable.
  56. /// It needs to be parsed as a commas separated option name.
  57. ///
  58. fn displayed_cell_string(
  59. &self,
  60. cell_data: CellData<CD>,
  61. decoded_field_type: &FieldType,
  62. field_rev: &FieldRevision,
  63. ) -> FlowyResult<String>;
  64. }
  65. pub trait CellDataOperation<CD, CS> {
  66. /// The generic annotation `CD` represents as the deserialize data type of the cell data.
  67. /// The Serialize/Deserialize struct of the cell is base on the field type of the cell.
  68. ///
  69. /// For example:
  70. /// FieldType::URL => URLCellData
  71. /// FieldType::Date=> DateCellData
  72. ///
  73. /// Each cell data is a opaque data, it needs to deserialized to a concrete data struct
  74. ///
  75. /// `cell_data`: the opaque data of the cell.
  76. /// `decoded_field_type`: the field type of the cell data when doing serialization
  77. /// `field_rev`: the field of the cell data
  78. ///
  79. /// Returns the error if the cell data can't be parsed into `CD`.
  80. ///
  81. fn decode_cell_data(
  82. &self,
  83. cell_data: CellData<CD>,
  84. decoded_field_type: &FieldType,
  85. field_rev: &FieldRevision,
  86. ) -> FlowyResult<CellBytes>;
  87. /// The changeset is able to parse into the concrete data struct if CS implements
  88. /// the `FromCellChangeset` trait.
  89. ///
  90. /// For example:
  91. /// SelectOptionCellChangeset,DateCellChangeset. etc.
  92. ///
  93. fn apply_changeset(&self, changeset: CellDataChangeset<CS>, cell_rev: Option<CellRevision>) -> FlowyResult<String>;
  94. }
  95. /// changeset: It will be deserialized into specific data base on the FieldType.
  96. /// For example,
  97. /// FieldType::RichText => String
  98. /// FieldType::SingleSelect => SelectOptionChangeset
  99. ///
  100. /// cell_rev: It will be None if the cell does not contain any data.
  101. pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
  102. changeset: C,
  103. cell_rev: Option<CellRevision>,
  104. field_rev: T,
  105. ) -> Result<String, FlowyError> {
  106. let field_rev = field_rev.as_ref();
  107. let changeset = changeset.to_string();
  108. let field_type = field_rev.ty.into();
  109. let s = match field_type {
  110. FieldType::RichText => RichTextTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
  111. FieldType::Number => NumberTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
  112. FieldType::DateTime => DateTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
  113. FieldType::SingleSelect => {
  114. SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
  115. }
  116. FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
  117. FieldType::Checkbox => CheckboxTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
  118. FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
  119. }?;
  120. Ok(AnyCellData::new(s, field_type).json())
  121. }
  122. pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>(
  123. data: T,
  124. field_rev: &FieldRevision,
  125. ) -> (FieldType, CellBytes) {
  126. let to_field_type = field_rev.ty.into();
  127. match data.try_into() {
  128. Ok(any_cell_data) => {
  129. let AnyCellData { data, field_type } = any_cell_data;
  130. match try_decode_cell_data(data.into(), &field_type, &to_field_type, field_rev) {
  131. Ok(cell_bytes) => (field_type, cell_bytes),
  132. Err(e) => {
  133. tracing::error!("Decode cell data failed, {:?}", e);
  134. (field_type, CellBytes::default())
  135. }
  136. }
  137. }
  138. Err(_err) => {
  139. // It's okay to ignore this error, because it's okay that the current cell can't
  140. // display the existing cell data. For example, the UI of the text cell will be blank if
  141. // the type of the data of cell is Number.
  142. (to_field_type, CellBytes::default())
  143. }
  144. }
  145. }
  146. pub fn decode_cell_data_to_string(
  147. cell_data: CellData<String>,
  148. from_field_type: &FieldType,
  149. to_field_type: &FieldType,
  150. field_rev: &FieldRevision,
  151. ) -> FlowyResult<String> {
  152. let cell_data = cell_data.try_into_inner()?;
  153. let get_cell_display_str = || {
  154. let field_type: FieldTypeRevision = to_field_type.into();
  155. let result = match to_field_type {
  156. FieldType::RichText => field_rev
  157. .get_type_option::<RichTextTypeOptionPB>(field_type)?
  158. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  159. FieldType::Number => field_rev
  160. .get_type_option::<NumberTypeOptionPB>(field_type)?
  161. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  162. FieldType::DateTime => field_rev
  163. .get_type_option::<DateTypeOptionPB>(field_type)?
  164. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  165. FieldType::SingleSelect => field_rev
  166. .get_type_option::<SingleSelectTypeOptionPB>(field_type)?
  167. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  168. FieldType::MultiSelect => field_rev
  169. .get_type_option::<MultiSelectTypeOptionPB>(field_type)?
  170. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  171. FieldType::Checkbox => field_rev
  172. .get_type_option::<CheckboxTypeOptionPB>(field_type)?
  173. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  174. FieldType::URL => field_rev
  175. .get_type_option::<URLTypeOptionPB>(field_type)?
  176. .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
  177. };
  178. Some(result)
  179. };
  180. match get_cell_display_str() {
  181. Some(Ok(s)) => Ok(s),
  182. Some(Err(err)) => {
  183. tracing::error!("{:?}", err);
  184. Ok("".to_owned())
  185. }
  186. None => Ok("".to_owned()),
  187. }
  188. }
  189. /// Use the `to_field_type`'s TypeOption to parse the cell data into `from_field_type` type's data.
  190. ///
  191. /// Each `FieldType` has its corresponding `TypeOption` that implements the `CellDisplayable`
  192. /// and `CellDataOperation` traits.
  193. ///
  194. pub fn try_decode_cell_data(
  195. cell_data: CellData<String>,
  196. from_field_type: &FieldType,
  197. to_field_type: &FieldType,
  198. field_rev: &FieldRevision,
  199. ) -> FlowyResult<CellBytes> {
  200. let cell_data = cell_data.try_into_inner()?;
  201. let get_cell_data = || {
  202. let field_type: FieldTypeRevision = to_field_type.into();
  203. let data = match to_field_type {
  204. FieldType::RichText => field_rev
  205. .get_type_option::<RichTextTypeOptionPB>(field_type)?
  206. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  207. FieldType::Number => field_rev
  208. .get_type_option::<NumberTypeOptionPB>(field_type)?
  209. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  210. FieldType::DateTime => field_rev
  211. .get_type_option::<DateTypeOptionPB>(field_type)?
  212. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  213. FieldType::SingleSelect => field_rev
  214. .get_type_option::<SingleSelectTypeOptionPB>(field_type)?
  215. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  216. FieldType::MultiSelect => field_rev
  217. .get_type_option::<MultiSelectTypeOptionPB>(field_type)?
  218. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  219. FieldType::Checkbox => field_rev
  220. .get_type_option::<CheckboxTypeOptionPB>(field_type)?
  221. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  222. FieldType::URL => field_rev
  223. .get_type_option::<URLTypeOptionPB>(field_type)?
  224. .decode_cell_data(cell_data.into(), from_field_type, field_rev),
  225. };
  226. Some(data)
  227. };
  228. match get_cell_data() {
  229. Some(Ok(data)) => Ok(data),
  230. Some(Err(err)) => {
  231. tracing::error!("{:?}", err);
  232. Ok(CellBytes::default())
  233. }
  234. None => Ok(CellBytes::default()),
  235. }
  236. }
  237. pub fn insert_text_cell(s: String, field_rev: &FieldRevision) -> CellRevision {
  238. let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
  239. CellRevision::new(data)
  240. }
  241. pub fn insert_number_cell(num: i64, field_rev: &FieldRevision) -> CellRevision {
  242. let data = apply_cell_data_changeset(num, None, field_rev).unwrap();
  243. CellRevision::new(data)
  244. }
  245. pub fn insert_url_cell(url: String, field_rev: &FieldRevision) -> CellRevision {
  246. let data = apply_cell_data_changeset(url, None, field_rev).unwrap();
  247. CellRevision::new(data)
  248. }
  249. pub fn insert_checkbox_cell(is_check: bool, field_rev: &FieldRevision) -> CellRevision {
  250. let s = if is_check {
  251. CHECK.to_string()
  252. } else {
  253. UNCHECK.to_string()
  254. };
  255. let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
  256. CellRevision::new(data)
  257. }
  258. pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevision {
  259. let cell_data = serde_json::to_string(&DateCellChangesetPB {
  260. date: Some(timestamp.to_string()),
  261. time: None,
  262. })
  263. .unwrap();
  264. let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
  265. CellRevision::new(data)
  266. }
  267. pub fn insert_select_option_cell(option_ids: Vec<String>, field_rev: &FieldRevision) -> CellRevision {
  268. let cell_data = SelectOptionCellChangeset::from_insert_options(option_ids).to_str();
  269. let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
  270. CellRevision::new(data)
  271. }
  272. pub fn delete_select_option_cell(option_ids: Vec<String>, field_rev: &FieldRevision) -> CellRevision {
  273. let cell_data = SelectOptionCellChangeset::from_delete_options(option_ids).to_str();
  274. let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
  275. CellRevision::new(data)
  276. }
  277. /// Deserialize the String into cell specific data type.
  278. pub trait FromCellString {
  279. fn from_cell_str(s: &str) -> FlowyResult<Self>
  280. where
  281. Self: Sized;
  282. }
  283. /// CellData is a helper struct. String will be parser into Option<T> only if the T impl the FromCellString trait.
  284. pub struct CellData<T>(pub Option<T>);
  285. impl<T> CellData<T> {
  286. pub fn try_into_inner(self) -> FlowyResult<T> {
  287. match self.0 {
  288. None => Err(ErrorCode::InvalidData.into()),
  289. Some(data) => Ok(data),
  290. }
  291. }
  292. }
  293. impl<T> std::convert::From<String> for CellData<T>
  294. where
  295. T: FromCellString,
  296. {
  297. fn from(s: String) -> Self {
  298. match T::from_cell_str(&s) {
  299. Ok(inner) => CellData(Some(inner)),
  300. Err(e) => {
  301. tracing::error!("Deserialize Cell Data failed: {}", e);
  302. CellData(None)
  303. }
  304. }
  305. }
  306. }
  307. impl std::convert::From<usize> for CellData<String> {
  308. fn from(n: usize) -> Self {
  309. CellData(Some(n.to_string()))
  310. }
  311. }
  312. impl<T> std::convert::From<T> for CellData<T> {
  313. fn from(val: T) -> Self {
  314. CellData(Some(val))
  315. }
  316. }
  317. impl std::convert::From<CellData<String>> for String {
  318. fn from(p: CellData<String>) -> Self {
  319. p.try_into_inner().unwrap_or_else(|_| String::new())
  320. }
  321. }
  322. /// If the changeset applying to the cell is not String type, it should impl this trait.
  323. /// Deserialize the string into cell specific changeset.
  324. pub trait FromCellChangeset {
  325. fn from_changeset(changeset: String) -> FlowyResult<Self>
  326. where
  327. Self: Sized;
  328. }
  329. pub struct CellDataChangeset<T>(pub Option<T>);
  330. impl<T> CellDataChangeset<T> {
  331. pub fn try_into_inner(self) -> FlowyResult<T> {
  332. match self.0 {
  333. None => Err(ErrorCode::InvalidData.into()),
  334. Some(data) => Ok(data),
  335. }
  336. }
  337. }
  338. impl<T, C: ToString> std::convert::From<C> for CellDataChangeset<T>
  339. where
  340. T: FromCellChangeset,
  341. {
  342. fn from(changeset: C) -> Self {
  343. match T::from_changeset(changeset.to_string()) {
  344. Ok(data) => CellDataChangeset(Some(data)),
  345. Err(e) => {
  346. tracing::error!("Deserialize CellDataChangeset failed: {}", e);
  347. CellDataChangeset(None)
  348. }
  349. }
  350. }
  351. }
  352. impl std::convert::From<String> for CellDataChangeset<String> {
  353. fn from(s: String) -> Self {
  354. CellDataChangeset(Some(s))
  355. }
  356. }