grid_block_meta_pad.rs 13 KB

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