grid_block_revsion_pad.rs 15 KB

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