grid_block_meta_pad.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. use crate::entities::revision::{md5, RepeatedRevision, Revision};
  2. use crate::errors::{CollaborateError, CollaborateResult};
  3. use crate::util::{cal_diff, make_delta_from_revisions};
  4. use flowy_grid_data_model::entities::{CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset};
  5. use lib_infra::uuid;
  6. use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
  7. use serde::{Deserialize, Serialize};
  8. use std::borrow::Cow;
  9. use std::collections::HashMap;
  10. use std::sync::Arc;
  11. pub type GridBlockMetaDelta = PlainTextDelta;
  12. pub type GridBlockMetaDeltaBuilder = PlainTextDeltaBuilder;
  13. #[derive(Debug, Deserialize, Serialize, Clone)]
  14. pub struct GridBlockMetaPad {
  15. block_id: String,
  16. row_metas: Vec<Arc<RowMeta>>,
  17. #[serde(skip)]
  18. pub(crate) delta: GridBlockMetaDelta,
  19. }
  20. impl GridBlockMetaPad {
  21. pub fn from_delta(delta: GridBlockMetaDelta) -> CollaborateResult<Self> {
  22. let s = delta.to_str()?;
  23. let meta_data: GridBlockMetaData = serde_json::from_str(&s).map_err(|e| {
  24. let msg = format!("Deserialize delta to block meta failed: {}", e);
  25. tracing::error!("{}", s);
  26. CollaborateError::internal().context(msg)
  27. })?;
  28. let block_id = meta_data.block_id;
  29. let rows = meta_data.rows.into_iter().map(Arc::new).collect::<Vec<Arc<RowMeta>>>();
  30. Ok(Self {
  31. block_id,
  32. row_metas: rows,
  33. delta,
  34. })
  35. }
  36. pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
  37. let block_delta: GridBlockMetaDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
  38. Self::from_delta(block_delta)
  39. }
  40. #[tracing::instrument(level = "trace", skip(self, row), err)]
  41. pub fn add_row_meta(
  42. &mut self,
  43. row: RowMeta,
  44. start_row_id: Option<String>,
  45. ) -> CollaborateResult<Option<GridBlockMetaChange>> {
  46. self.modify(|rows| {
  47. if let Some(start_row_id) = start_row_id {
  48. if start_row_id.is_empty() {
  49. rows.insert(0, Arc::new(row));
  50. return Ok(Some(()));
  51. }
  52. if let Some(index) = rows.iter().position(|row| row.id == start_row_id) {
  53. rows.insert(index + 1, Arc::new(row));
  54. return Ok(Some(()));
  55. }
  56. }
  57. rows.push(Arc::new(row));
  58. Ok(Some(()))
  59. })
  60. }
  61. pub fn delete_rows(&mut self, row_ids: Vec<Cow<'_, String>>) -> CollaborateResult<Option<GridBlockMetaChange>> {
  62. self.modify(|rows| {
  63. rows.retain(|row| !row_ids.contains(&Cow::Borrowed(&row.id)));
  64. Ok(Some(()))
  65. })
  66. }
  67. pub fn get_row_metas<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> CollaborateResult<Vec<Arc<RowMeta>>>
  68. where
  69. T: AsRef<str> + ToOwned + ?Sized,
  70. {
  71. match row_ids {
  72. None => Ok(self.row_metas.to_vec()),
  73. Some(row_ids) => {
  74. let row_map = self
  75. .row_metas
  76. .iter()
  77. .map(|row| (row.id.as_str(), row.clone()))
  78. .collect::<HashMap<&str, Arc<RowMeta>>>();
  79. Ok(row_ids
  80. .iter()
  81. .flat_map(|row_id| {
  82. let row_id = row_id.as_ref().as_ref();
  83. match row_map.get(row_id) {
  84. None => {
  85. tracing::error!("Can't find the row with id: {}", row_id);
  86. None
  87. }
  88. Some(row) => Some(row.clone()),
  89. }
  90. })
  91. .collect::<Vec<_>>())
  92. }
  93. }
  94. }
  95. pub fn get_cell_metas(
  96. &self,
  97. field_id: &str,
  98. row_ids: Option<Vec<Cow<'_, String>>>,
  99. ) -> CollaborateResult<Vec<CellMeta>> {
  100. let rows = self.get_row_metas(row_ids)?;
  101. let cell_metas = rows
  102. .iter()
  103. .flat_map(|row| {
  104. let cell_meta = row.cells.get(field_id)?;
  105. Some(cell_meta.clone())
  106. })
  107. .collect::<Vec<CellMeta>>();
  108. Ok(cell_metas)
  109. }
  110. pub fn number_of_rows(&self) -> i32 {
  111. self.row_metas.len() as i32
  112. }
  113. pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
  114. let row_id = changeset.row_id.clone();
  115. self.modify_row(&row_id, |row| {
  116. let mut is_changed = None;
  117. if let Some(height) = changeset.height {
  118. row.height = height;
  119. is_changed = Some(());
  120. }
  121. if let Some(visibility) = changeset.visibility {
  122. row.visibility = visibility;
  123. is_changed = Some(());
  124. }
  125. if !changeset.cell_by_field_id.is_empty() {
  126. is_changed = Some(());
  127. changeset.cell_by_field_id.into_iter().for_each(|(field_id, cell)| {
  128. row.cells.insert(field_id, cell);
  129. })
  130. }
  131. Ok(is_changed)
  132. })
  133. }
  134. pub fn modify<F>(&mut self, f: F) -> CollaborateResult<Option<GridBlockMetaChange>>
  135. where
  136. F: for<'a> FnOnce(&'a mut Vec<Arc<RowMeta>>) -> CollaborateResult<Option<()>>,
  137. {
  138. let cloned_self = self.clone();
  139. match f(&mut self.row_metas)? {
  140. None => Ok(None),
  141. Some(_) => {
  142. let old = cloned_self.to_json()?;
  143. let new = self.to_json()?;
  144. match cal_diff::<PlainTextAttributes>(old, new) {
  145. None => Ok(None),
  146. Some(delta) => {
  147. tracing::debug!("[GridBlockMeta] Composing change {}", delta.to_delta_str());
  148. self.delta = self.delta.compose(&delta)?;
  149. Ok(Some(GridBlockMetaChange { delta, md5: self.md5() }))
  150. }
  151. }
  152. }
  153. }
  154. }
  155. fn modify_row<F>(&mut self, row_id: &str, f: F) -> CollaborateResult<Option<GridBlockMetaChange>>
  156. where
  157. F: FnOnce(&mut RowMeta) -> CollaborateResult<Option<()>>,
  158. {
  159. self.modify(|rows| {
  160. if let Some(row_meta) = rows.iter_mut().find(|row_meta| row_id == row_meta.id) {
  161. f(Arc::make_mut(row_meta))
  162. } else {
  163. tracing::warn!("[BlockMetaPad]: Can't find any row with id: {}", row_id);
  164. Ok(None)
  165. }
  166. })
  167. }
  168. pub fn to_json(&self) -> CollaborateResult<String> {
  169. serde_json::to_string(self)
  170. .map_err(|e| CollaborateError::internal().context(format!("serial trash to json failed: {}", e)))
  171. }
  172. pub fn md5(&self) -> String {
  173. md5(&self.delta.to_delta_bytes())
  174. }
  175. pub fn delta_str(&self) -> String {
  176. self.delta.to_delta_str()
  177. }
  178. }
  179. pub struct GridBlockMetaChange {
  180. pub delta: GridBlockMetaDelta,
  181. /// md5: the md5 of the grid after applying the change.
  182. pub md5: String,
  183. }
  184. pub fn make_block_meta_delta(grid_block_meta_data: &GridBlockMetaData) -> GridBlockMetaDelta {
  185. let json = serde_json::to_string(&grid_block_meta_data).unwrap();
  186. PlainTextDeltaBuilder::new().insert(&json).build()
  187. }
  188. pub fn make_block_meta_revisions(user_id: &str, grid_block_meta_data: &GridBlockMetaData) -> RepeatedRevision {
  189. let delta = make_block_meta_delta(grid_block_meta_data);
  190. let bytes = delta.to_delta_bytes();
  191. let revision = Revision::initial_revision(user_id, &grid_block_meta_data.block_id, bytes);
  192. revision.into()
  193. }
  194. impl std::default::Default for GridBlockMetaPad {
  195. fn default() -> Self {
  196. let block_meta_data = GridBlockMetaData {
  197. block_id: uuid(),
  198. rows: vec![],
  199. };
  200. let delta = make_block_meta_delta(&block_meta_data);
  201. GridBlockMetaPad {
  202. block_id: block_meta_data.block_id,
  203. row_metas: block_meta_data.rows.into_iter().map(Arc::new).collect::<Vec<_>>(),
  204. delta,
  205. }
  206. }
  207. }
  208. #[cfg(test)]
  209. mod tests {
  210. use crate::client_grid::{GridBlockMetaDelta, GridBlockMetaPad};
  211. use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset};
  212. use std::borrow::Cow;
  213. #[test]
  214. fn block_meta_add_row() {
  215. let mut pad = test_pad();
  216. let row = RowMeta {
  217. id: "1".to_string(),
  218. block_id: pad.block_id.clone(),
  219. cells: Default::default(),
  220. height: 0,
  221. visibility: false,
  222. };
  223. let change = pad.add_row_meta(row, None).unwrap().unwrap();
  224. assert_eq!(
  225. change.delta.to_delta_str(),
  226. r#"[{"retain":29},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
  227. );
  228. }
  229. #[test]
  230. fn block_meta_insert_row() {
  231. let mut pad = test_pad();
  232. let row_1 = test_row_meta("1", &pad);
  233. let row_2 = test_row_meta("2", &pad);
  234. let row_3 = test_row_meta("3", &pad);
  235. let change = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap();
  236. assert_eq!(
  237. change.delta.to_delta_str(),
  238. r#"[{"retain":29},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
  239. );
  240. let change = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap();
  241. assert_eq!(
  242. change.delta.to_delta_str(),
  243. r#"[{"retain":106},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
  244. );
  245. let change = pad.add_row_meta(row_3.clone(), Some("2".to_string())).unwrap().unwrap();
  246. assert_eq!(
  247. change.delta.to_delta_str(),
  248. r#"[{"retain":114},{"insert":"3\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false},{\"id\":\""},{"retain":72}]"#
  249. );
  250. assert_eq!(*pad.row_metas[0], row_1);
  251. assert_eq!(*pad.row_metas[1], row_3);
  252. assert_eq!(*pad.row_metas[2], row_2);
  253. }
  254. fn test_row_meta(id: &str, pad: &GridBlockMetaPad) -> RowMeta {
  255. RowMeta {
  256. id: id.to_string(),
  257. block_id: pad.block_id.clone(),
  258. cells: Default::default(),
  259. height: 0,
  260. visibility: false,
  261. }
  262. }
  263. #[test]
  264. fn block_meta_insert_row2() {
  265. let mut pad = test_pad();
  266. let row_1 = test_row_meta("1", &pad);
  267. let row_2 = test_row_meta("2", &pad);
  268. let row_3 = test_row_meta("3", &pad);
  269. let _ = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap();
  270. let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap();
  271. let _ = pad.add_row_meta(row_3.clone(), Some("1".to_string())).unwrap().unwrap();
  272. assert_eq!(*pad.row_metas[0], row_3);
  273. assert_eq!(*pad.row_metas[1], row_1);
  274. assert_eq!(*pad.row_metas[2], row_2);
  275. }
  276. #[test]
  277. fn block_meta_insert_row3() {
  278. let mut pad = test_pad();
  279. let row_1 = test_row_meta("1", &pad);
  280. let row_2 = test_row_meta("2", &pad);
  281. let row_3 = test_row_meta("3", &pad);
  282. let _ = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap();
  283. let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap();
  284. let _ = pad.add_row_meta(row_3.clone(), Some("".to_string())).unwrap().unwrap();
  285. assert_eq!(*pad.row_metas[0], row_3);
  286. assert_eq!(*pad.row_metas[1], row_1);
  287. assert_eq!(*pad.row_metas[2], row_2);
  288. }
  289. #[test]
  290. fn block_meta_delete_row() {
  291. let mut pad = test_pad();
  292. let pre_delta_str = pad.delta_str();
  293. let row = RowMeta {
  294. id: "1".to_string(),
  295. block_id: pad.block_id.clone(),
  296. cells: Default::default(),
  297. height: 0,
  298. visibility: false,
  299. };
  300. let _ = pad.add_row_meta(row.clone(), None).unwrap().unwrap();
  301. let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap();
  302. assert_eq!(
  303. change.delta.to_delta_str(),
  304. r#"[{"retain":29},{"delete":77},{"retain":2}]"#
  305. );
  306. assert_eq!(pad.delta_str(), pre_delta_str);
  307. }
  308. #[test]
  309. fn block_meta_update_row() {
  310. let mut pad = test_pad();
  311. let row = RowMeta {
  312. id: "1".to_string(),
  313. block_id: pad.block_id.clone(),
  314. cells: Default::default(),
  315. height: 0,
  316. visibility: false,
  317. };
  318. let changeset = RowMetaChangeset {
  319. row_id: row.id.clone(),
  320. height: Some(100),
  321. visibility: Some(true),
  322. cell_by_field_id: Default::default(),
  323. };
  324. let _ = pad.add_row_meta(row, None).unwrap().unwrap();
  325. let change = pad.update_row(changeset).unwrap().unwrap();
  326. assert_eq!(
  327. change.delta.to_delta_str(),
  328. r#"[{"retain":85},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"#
  329. );
  330. assert_eq!(
  331. pad.to_json().unwrap(),
  332. r#"{"block_id":"1","row_metas":[{"id":"1","block_id":"1","cell_by_field_id":{},"height":100,"visibility":true}]}"#
  333. );
  334. }
  335. fn test_pad() -> GridBlockMetaPad {
  336. let delta =
  337. GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"row_metas\":[]}"}]"#).unwrap();
  338. GridBlockMetaPad::from_delta(delta).unwrap()
  339. }
  340. }