block_revision_pad.rs 15 KB

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