浏览代码

chore: seperate FolderRevision from FolderPad

appflowy 2 年之前
父节点
当前提交
b695ceb832

+ 3 - 3
frontend/rust-lib/flowy-folder/src/services/folder_editor.rs

@@ -6,7 +6,7 @@ use flowy_revision::{
 };
 use flowy_sync::util::make_delta_from_revisions;
 use flowy_sync::{
-    client_folder::{FolderChange, FolderPad},
+    client_folder::{FolderChangeset, FolderPad},
     entities::{revision::Revision, ws_data::ServerRevisionWSData},
 };
 use lib_infra::future::FutureResult;
@@ -77,8 +77,8 @@ impl FolderEditor {
         Ok(())
     }
 
-    pub(crate) fn apply_change(&self, change: FolderChange) -> FlowyResult<()> {
-        let FolderChange { delta, md5 } = change;
+    pub(crate) fn apply_change(&self, change: FolderChangeset) -> FlowyResult<()> {
+        let FolderChangeset { delta, md5 } = change;
         let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
         let delta_data = delta.json_bytes();
         let revision = Revision::new(

+ 1 - 1
shared-lib/flowy-folder-data-model/Cargo.toml

@@ -17,7 +17,7 @@ log = "0.4.14"
 nanoid = "0.4.0"
 chrono = { version = "0.4" }
 flowy-error-code = { path = "../flowy-error-code"}
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0", features = ["derive", "rc"] }
 serde_json = "1.0"
 serde_repr = "0.1"
 

+ 9 - 0
shared-lib/flowy-folder-data-model/src/revision/folder_rev.rs

@@ -0,0 +1,9 @@
+use crate::revision::{TrashRevision, WorkspaceRevision};
+use serde::{Deserialize, Serialize};
+use std::sync::Arc;
+
+#[derive(Debug, Default, Deserialize, Serialize, Clone, Eq, PartialEq)]
+pub struct FolderRevision {
+    pub workspaces: Vec<Arc<WorkspaceRevision>>,
+    pub trash: Vec<Arc<TrashRevision>>,
+}

+ 2 - 0
shared-lib/flowy-folder-data-model/src/revision/mod.rs

@@ -1,9 +1,11 @@
 mod app_rev;
+mod folder_rev;
 mod trash_rev;
 mod view_rev;
 mod workspace_rev;
 
 pub use app_rev::*;
+pub use folder_rev::*;
 pub use trash_rev::*;
 pub use view_rev::*;
 pub use workspace_rev::*;

+ 15 - 31
shared-lib/flowy-sync/src/client_folder/builder.rs

@@ -3,18 +3,17 @@ use crate::util::make_delta_from_revisions;
 use crate::{
     client_folder::{default_folder_delta, FolderPad},
     entities::revision::Revision,
-    errors::{CollaborateError, CollaborateResult},
+    errors::CollaborateResult,
 };
 
 use flowy_folder_data_model::revision::{TrashRevision, WorkspaceRevision};
-use lib_ot::core::{PhantomAttributes, TextDelta, TextDeltaBuilder};
+use lib_ot::core::PhantomAttributes;
 use serde::{Deserialize, Serialize};
-use std::sync::Arc;
 
 #[derive(Serialize, Deserialize)]
 pub(crate) struct FolderPadBuilder {
-    workspaces: Vec<Arc<WorkspaceRevision>>,
-    trash: Vec<Arc<TrashRevision>>,
+    workspaces: Vec<WorkspaceRevision>,
+    trash: Vec<TrashRevision>,
 }
 
 impl FolderPadBuilder {
@@ -25,43 +24,28 @@ impl FolderPadBuilder {
         }
     }
 
+    #[allow(dead_code)]
     pub(crate) fn with_workspace(mut self, workspaces: Vec<WorkspaceRevision>) -> Self {
-        self.workspaces = workspaces.into_iter().map(Arc::new).collect();
+        self.workspaces = workspaces;
         self
     }
 
+    #[allow(dead_code)]
     pub(crate) fn with_trash(mut self, trash: Vec<TrashRevision>) -> Self {
-        self.trash = trash.into_iter().map(Arc::new).collect::<Vec<_>>();
+        self.trash = trash;
         self
     }
 
-    pub(crate) fn build_with_delta(self, mut delta: TextDelta) -> CollaborateResult<FolderPad> {
-        if delta.is_empty() {
-            delta = default_folder_delta();
-        }
-
-        // TODO: Reconvert from history if delta.to_str() failed.
-        let content = delta.content()?;
-        let mut folder: FolderPad = serde_json::from_str(&content).map_err(|e| {
-            tracing::error!("Deserialize folder from {} failed", content);
-            return CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e));
-        })?;
-        folder.delta = delta;
-        Ok(folder)
-    }
-
     pub(crate) fn build_with_revisions(self, revisions: Vec<Revision>) -> CollaborateResult<FolderPad> {
-        let folder_delta: FolderDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
-        self.build_with_delta(folder_delta)
+        let mut folder_delta: FolderDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
+        if folder_delta.is_empty() {
+            folder_delta = default_folder_delta();
+        }
+        FolderPad::from_delta(folder_delta)
     }
 
+    #[allow(dead_code)]
     pub(crate) fn build(self) -> CollaborateResult<FolderPad> {
-        let json = serde_json::to_string(&self)
-            .map_err(|e| CollaborateError::internal().context(format!("Serialize to folder json str failed: {}", e)))?;
-        Ok(FolderPad {
-            workspaces: self.workspaces,
-            trash: self.trash,
-            delta: TextDeltaBuilder::new().insert(&json).build(),
-        })
+        FolderPad::new(self.workspaces, self.trash)
     }
 }

+ 81 - 58
shared-lib/flowy-sync/src/client_folder/folder_pad.rs

@@ -8,26 +8,33 @@ use crate::{
     },
     errors::{CollaborateError, CollaborateResult},
 };
-use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
+use flowy_folder_data_model::revision::{AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision};
 use lib_infra::util::move_vec_element;
 use lib_ot::core::*;
-use serde::{Deserialize, Serialize};
+
 use std::sync::Arc;
 
-#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
+#[derive(Debug, Clone, Eq, PartialEq)]
 pub struct FolderPad {
-    pub(crate) workspaces: Vec<Arc<WorkspaceRevision>>,
-    pub(crate) trash: Vec<Arc<TrashRevision>>,
-    #[serde(skip)]
-    pub(crate) delta: FolderDelta,
+    folder_rev: FolderRevision,
+    delta: FolderDelta,
 }
 
 impl FolderPad {
     pub fn new(workspaces: Vec<WorkspaceRevision>, trash: Vec<TrashRevision>) -> CollaborateResult<Self> {
-        FolderPadBuilder::new()
-            .with_workspace(workspaces)
-            .with_trash(trash)
-            .build()
+        let folder_rev = FolderRevision {
+            workspaces: workspaces.into_iter().map(Arc::new).collect(),
+            trash: trash.into_iter().map(Arc::new).collect(),
+        };
+        Self::from_folder_rev(folder_rev)
+    }
+
+    pub fn from_folder_rev(folder_rev: FolderRevision) -> CollaborateResult<Self> {
+        let json = serde_json::to_string(&folder_rev)
+            .map_err(|e| CollaborateError::internal().context(format!("Serialize to folder json str failed: {}", e)))?;
+        let delta = TextDeltaBuilder::new().insert(&json).build();
+
+        Ok(Self { folder_rev, delta })
     }
 
     pub fn from_revisions(revisions: Vec<Revision>) -> CollaborateResult<Self> {
@@ -35,7 +42,14 @@ impl FolderPad {
     }
 
     pub fn from_delta(delta: FolderDelta) -> CollaborateResult<Self> {
-        FolderPadBuilder::new().build_with_delta(delta)
+        // TODO: Reconvert from history if delta.to_str() failed.
+        let content = delta.content()?;
+        let folder_rev: FolderRevision = serde_json::from_str(&content).map_err(|e| {
+            tracing::error!("Deserialize folder from {} failed", content);
+            return CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e));
+        })?;
+
+        Ok(Self { folder_rev, delta })
     }
 
     pub fn delta(&self) -> &FolderDelta {
@@ -44,8 +58,7 @@ impl FolderPad {
 
     pub fn reset_folder(&mut self, delta: FolderDelta) -> CollaborateResult<String> {
         let folder = FolderPad::from_delta(delta)?;
-        self.workspaces = folder.workspaces;
-        self.trash = folder.trash;
+        self.folder_rev = folder.folder_rev;
         self.delta = folder.delta;
 
         Ok(self.md5())
@@ -57,13 +70,13 @@ impl FolderPad {
     }
 
     pub fn is_empty(&self) -> bool {
-        self.workspaces.is_empty() && self.trash.is_empty()
+        self.folder_rev.workspaces.is_empty() && self.folder_rev.trash.is_empty()
     }
 
     #[tracing::instrument(level = "trace", skip(self, workspace_rev), fields(workspace_name=%workspace_rev.name), err)]
-    pub fn create_workspace(&mut self, workspace_rev: WorkspaceRevision) -> CollaborateResult<Option<FolderChange>> {
+    pub fn create_workspace(&mut self, workspace_rev: WorkspaceRevision) -> CollaborateResult<Option<FolderChangeset>> {
         let workspace = Arc::new(workspace_rev);
-        if self.workspaces.contains(&workspace) {
+        if self.folder_rev.workspaces.contains(&workspace) {
             tracing::warn!("[RootFolder]: Duplicate workspace");
             return Ok(None);
         }
@@ -79,7 +92,7 @@ impl FolderPad {
         workspace_id: &str,
         name: Option<String>,
         desc: Option<String>,
-    ) -> CollaborateResult<Option<FolderChange>> {
+    ) -> CollaborateResult<Option<FolderChangeset>> {
         self.with_workspace(workspace_id, |workspace| {
             if let Some(name) = name {
                 workspace.name = name;
@@ -96,6 +109,7 @@ impl FolderPad {
         match workspace_id {
             None => {
                 let workspaces = self
+                    .folder_rev
                     .workspaces
                     .iter()
                     .map(|workspace| workspace.as_ref().clone())
@@ -103,7 +117,12 @@ impl FolderPad {
                 Ok(workspaces)
             }
             Some(workspace_id) => {
-                if let Some(workspace) = self.workspaces.iter().find(|workspace| workspace.id == workspace_id) {
+                if let Some(workspace) = self
+                    .folder_rev
+                    .workspaces
+                    .iter()
+                    .find(|workspace| workspace.id == workspace_id)
+                {
                     Ok(vec![workspace.as_ref().clone()])
                 } else {
                     Err(CollaborateError::record_not_found()
@@ -114,7 +133,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn delete_workspace(&mut self, workspace_id: &str) -> CollaborateResult<Option<FolderChange>> {
+    pub fn delete_workspace(&mut self, workspace_id: &str) -> CollaborateResult<Option<FolderChangeset>> {
         self.modify_workspaces(|workspaces| {
             workspaces.retain(|w| w.id != workspace_id);
             Ok(Some(()))
@@ -122,7 +141,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), fields(app_name=%app_rev.name), err)]
-    pub fn create_app(&mut self, app_rev: AppRevision) -> CollaborateResult<Option<FolderChange>> {
+    pub fn create_app(&mut self, app_rev: AppRevision) -> CollaborateResult<Option<FolderChangeset>> {
         let workspace_id = app_rev.workspace_id.clone();
         self.with_workspace(&workspace_id, move |workspace| {
             if workspace.apps.contains(&app_rev) {
@@ -135,7 +154,7 @@ impl FolderPad {
     }
 
     pub fn read_app(&self, app_id: &str) -> CollaborateResult<AppRevision> {
-        for workspace in &self.workspaces {
+        for workspace in &self.folder_rev.workspaces {
             if let Some(app) = workspace.apps.iter().find(|app| app.id == app_id) {
                 return Ok(app.clone());
             }
@@ -148,7 +167,7 @@ impl FolderPad {
         app_id: &str,
         name: Option<String>,
         desc: Option<String>,
-    ) -> CollaborateResult<Option<FolderChange>> {
+    ) -> CollaborateResult<Option<FolderChangeset>> {
         self.with_app(app_id, move |app| {
             if let Some(name) = name {
                 app.name = name;
@@ -162,7 +181,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn delete_app(&mut self, app_id: &str) -> CollaborateResult<Option<FolderChange>> {
+    pub fn delete_app(&mut self, app_id: &str) -> CollaborateResult<Option<FolderChangeset>> {
         let app = self.read_app(app_id)?;
         self.with_workspace(&app.workspace_id, |workspace| {
             workspace.apps.retain(|app| app.id != app_id);
@@ -171,7 +190,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn move_app(&mut self, app_id: &str, from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
+    pub fn move_app(&mut self, app_id: &str, from: usize, to: usize) -> CollaborateResult<Option<FolderChangeset>> {
         let app = self.read_app(app_id)?;
         self.with_workspace(&app.workspace_id, |workspace| {
             match move_vec_element(&mut workspace.apps, |app| app.id == app_id, from, to).map_err(internal_error)? {
@@ -182,7 +201,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), fields(view_name=%view_rev.name), err)]
-    pub fn create_view(&mut self, view_rev: ViewRevision) -> CollaborateResult<Option<FolderChange>> {
+    pub fn create_view(&mut self, view_rev: ViewRevision) -> CollaborateResult<Option<FolderChangeset>> {
         let app_id = view_rev.belong_to_id.clone();
         self.with_app(&app_id, move |app| {
             if app.belongings.contains(&view_rev) {
@@ -195,7 +214,7 @@ impl FolderPad {
     }
 
     pub fn read_view(&self, view_id: &str) -> CollaborateResult<ViewRevision> {
-        for workspace in &self.workspaces {
+        for workspace in &self.folder_rev.workspaces {
             for app in &(*workspace.apps) {
                 if let Some(view) = app.belongings.iter().find(|b| b.id == view_id) {
                     return Ok(view.clone());
@@ -206,7 +225,7 @@ impl FolderPad {
     }
 
     pub fn read_views(&self, belong_to_id: &str) -> CollaborateResult<Vec<ViewRevision>> {
-        for workspace in &self.workspaces {
+        for workspace in &self.folder_rev.workspaces {
             for app in &(*workspace.apps) {
                 if app.id == belong_to_id {
                     return Ok(app.belongings.to_vec());
@@ -222,7 +241,7 @@ impl FolderPad {
         name: Option<String>,
         desc: Option<String>,
         modified_time: i64,
-    ) -> CollaborateResult<Option<FolderChange>> {
+    ) -> CollaborateResult<Option<FolderChangeset>> {
         let view = self.read_view(view_id)?;
         self.with_view(&view.belong_to_id, view_id, |view| {
             if let Some(name) = name {
@@ -239,7 +258,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn delete_view(&mut self, view_id: &str) -> CollaborateResult<Option<FolderChange>> {
+    pub fn delete_view(&mut self, view_id: &str) -> CollaborateResult<Option<FolderChangeset>> {
         let view = self.read_view(view_id)?;
         self.with_app(&view.belong_to_id, |app| {
             app.belongings.retain(|view| view.id != view_id);
@@ -248,7 +267,7 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn move_view(&mut self, view_id: &str, from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
+    pub fn move_view(&mut self, view_id: &str, from: usize, to: usize) -> CollaborateResult<Option<FolderChangeset>> {
         let view = self.read_view(view_id)?;
         self.with_app(&view.belong_to_id, |app| {
             match move_vec_element(&mut app.belongings, |view| view.id == view_id, from, to).map_err(internal_error)? {
@@ -258,7 +277,7 @@ impl FolderPad {
         })
     }
 
-    pub fn create_trash(&mut self, trash: Vec<TrashRevision>) -> CollaborateResult<Option<FolderChange>> {
+    pub fn create_trash(&mut self, trash: Vec<TrashRevision>) -> CollaborateResult<Option<FolderChangeset>> {
         self.with_trash(|t| {
             let mut new_trash = trash.into_iter().map(Arc::new).collect::<Vec<Arc<TrashRevision>>>();
             t.append(&mut new_trash);
@@ -270,18 +289,19 @@ impl FolderPad {
     pub fn read_trash(&self, trash_id: Option<String>) -> CollaborateResult<Vec<TrashRevision>> {
         match trash_id {
             None => Ok(self
+                .folder_rev
                 .trash
                 .iter()
                 .map(|t| t.as_ref().clone())
                 .collect::<Vec<TrashRevision>>()),
-            Some(trash_id) => match self.trash.iter().find(|t| t.id == trash_id) {
+            Some(trash_id) => match self.folder_rev.trash.iter().find(|t| t.id == trash_id) {
                 Some(trash) => Ok(vec![trash.as_ref().clone()]),
                 None => Ok(vec![]),
             },
         }
     }
 
-    pub fn delete_trash(&mut self, trash_ids: Option<Vec<String>>) -> CollaborateResult<Option<FolderChange>> {
+    pub fn delete_trash(&mut self, trash_ids: Option<Vec<String>>) -> CollaborateResult<Option<FolderChangeset>> {
         match trash_ids {
             None => self.with_trash(|trash| {
                 trash.clear();
@@ -299,18 +319,18 @@ impl FolderPad {
     }
 
     pub fn to_json(&self) -> CollaborateResult<String> {
-        serde_json::to_string(self)
+        serde_json::to_string(&self.folder_rev)
             .map_err(|e| CollaborateError::internal().context(format!("serial trash to json failed: {}", e)))
     }
 }
 
 impl FolderPad {
-    fn modify_workspaces<F>(&mut self, f: F) -> CollaborateResult<Option<FolderChange>>
+    fn modify_workspaces<F>(&mut self, f: F) -> CollaborateResult<Option<FolderChangeset>>
     where
         F: FnOnce(&mut Vec<Arc<WorkspaceRevision>>) -> CollaborateResult<Option<()>>,
     {
         let cloned_self = self.clone();
-        match f(&mut self.workspaces)? {
+        match f(&mut self.folder_rev.workspaces)? {
             None => Ok(None),
             Some(_) => {
                 let old = cloned_self.to_json()?;
@@ -319,14 +339,14 @@ impl FolderPad {
                     None => Ok(None),
                     Some(delta) => {
                         self.delta = self.delta.compose(&delta)?;
-                        Ok(Some(FolderChange { delta, md5: self.md5() }))
+                        Ok(Some(FolderChangeset { delta, md5: self.md5() }))
                     }
                 }
             }
         }
     }
 
-    fn with_workspace<F>(&mut self, workspace_id: &str, f: F) -> CollaborateResult<Option<FolderChange>>
+    fn with_workspace<F>(&mut self, workspace_id: &str, f: F) -> CollaborateResult<Option<FolderChangeset>>
     where
         F: FnOnce(&mut WorkspaceRevision) -> CollaborateResult<Option<()>>,
     {
@@ -340,12 +360,12 @@ impl FolderPad {
         })
     }
 
-    fn with_trash<F>(&mut self, f: F) -> CollaborateResult<Option<FolderChange>>
+    fn with_trash<F>(&mut self, f: F) -> CollaborateResult<Option<FolderChangeset>>
     where
         F: FnOnce(&mut Vec<Arc<TrashRevision>>) -> CollaborateResult<Option<()>>,
     {
         let cloned_self = self.clone();
-        match f(&mut self.trash)? {
+        match f(&mut self.folder_rev.trash)? {
             None => Ok(None),
             Some(_) => {
                 let old = cloned_self.to_json()?;
@@ -354,18 +374,19 @@ impl FolderPad {
                     None => Ok(None),
                     Some(delta) => {
                         self.delta = self.delta.compose(&delta)?;
-                        Ok(Some(FolderChange { delta, md5: self.md5() }))
+                        Ok(Some(FolderChangeset { delta, md5: self.md5() }))
                     }
                 }
             }
         }
     }
 
-    fn with_app<F>(&mut self, app_id: &str, f: F) -> CollaborateResult<Option<FolderChange>>
+    fn with_app<F>(&mut self, app_id: &str, f: F) -> CollaborateResult<Option<FolderChangeset>>
     where
         F: FnOnce(&mut AppRevision) -> CollaborateResult<Option<()>>,
     {
         let workspace_id = match self
+            .folder_rev
             .workspaces
             .iter()
             .find(|workspace| workspace.apps.iter().any(|app| app.id == app_id))
@@ -383,7 +404,7 @@ impl FolderPad {
         })
     }
 
-    fn with_view<F>(&mut self, belong_to_id: &str, view_id: &str, f: F) -> CollaborateResult<Option<FolderChange>>
+    fn with_view<F>(&mut self, belong_to_id: &str, view_id: &str, f: F) -> CollaborateResult<Option<FolderChangeset>>
     where
         F: FnOnce(&mut ViewRevision) -> CollaborateResult<Option<()>>,
     {
@@ -414,14 +435,13 @@ pub fn initial_folder_delta(folder_pad: &FolderPad) -> CollaborateResult<FolderD
 impl std::default::Default for FolderPad {
     fn default() -> Self {
         FolderPad {
-            workspaces: vec![],
-            trash: vec![],
+            folder_rev: FolderRevision::default(),
             delta: default_folder_delta(),
         }
     }
 }
 
-pub struct FolderChange {
+pub struct FolderChangeset {
     pub delta: FolderDelta,
     /// md5: the md5 of the FolderPad's delta after applying the change.
     pub md5: String,
@@ -433,7 +453,9 @@ mod tests {
     use crate::{client_folder::folder_pad::FolderPad, entities::folder::FolderDelta};
     use chrono::Utc;
 
-    use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
+    use flowy_folder_data_model::revision::{
+        AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
+    };
     use lib_ot::core::{OperationTransform, TextDelta, TextDeltaBuilder};
 
     #[test]
@@ -747,14 +769,16 @@ mod tests {
     }
 
     fn test_folder() -> (FolderPad, FolderDelta, WorkspaceRevision) {
-        let mut folder = FolderPad::default();
-        let folder_json = serde_json::to_string(&folder).unwrap();
+        let folder_rev = FolderRevision::default();
+        let folder_json = serde_json::to_string(&folder_rev).unwrap();
         let mut delta = TextDeltaBuilder::new().insert(&folder_json).build();
 
         let mut workspace_rev = WorkspaceRevision::default();
         workspace_rev.name = "😁 my first workspace".to_owned();
         workspace_rev.id = "1".to_owned();
 
+        let mut folder = FolderPad::from_folder_rev(folder_rev).unwrap();
+
         delta = delta
             .compose(&folder.create_workspace(workspace_rev.clone()).unwrap().unwrap().delta)
             .unwrap();
@@ -763,16 +787,16 @@ mod tests {
     }
 
     fn test_app_folder() -> (FolderPad, FolderDelta, AppRevision) {
-        let (mut folder, mut initial_delta, workspace) = test_folder();
+        let (mut folder_rev, mut initial_delta, workspace) = test_folder();
         let mut app_rev = AppRevision::default();
         app_rev.workspace_id = workspace.id;
         app_rev.name = "😁 my first app".to_owned();
 
         initial_delta = initial_delta
-            .compose(&folder.create_app(app_rev.clone()).unwrap().unwrap().delta)
+            .compose(&folder_rev.create_app(app_rev.clone()).unwrap().unwrap().delta)
             .unwrap();
 
-        (folder, initial_delta, app_rev)
+        (folder_rev, initial_delta, app_rev)
     }
 
     fn test_view_folder() -> (FolderPad, FolderDelta, ViewRevision) {
@@ -789,14 +813,14 @@ mod tests {
     }
 
     fn test_trash() -> (FolderPad, FolderDelta, TrashRevision) {
-        let mut folder = FolderPad::default();
-        let folder_json = serde_json::to_string(&folder).unwrap();
+        let folder_rev = FolderRevision::default();
+        let folder_json = serde_json::to_string(&folder_rev).unwrap();
         let mut delta = TextDeltaBuilder::new().insert(&folder_json).build();
 
         let mut trash_rev = TrashRevision::default();
         trash_rev.name = "🚽 my first trash".to_owned();
         trash_rev.id = "1".to_owned();
-
+        let mut folder = FolderPad::from_folder_rev(folder_rev).unwrap();
         delta = delta
             .compose(
                 &folder
@@ -823,8 +847,7 @@ mod tests {
         let json1 = old.to_json().unwrap();
         let json2 = new.to_json().unwrap();
 
-        let expect_folder: FolderPad = serde_json::from_str(expected).unwrap();
-        assert_eq!(json1, expect_folder.to_json().unwrap());
+        assert_eq!(json1, expected);
         assert_eq!(json1, json2);
     }
 }

+ 0 - 432
shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs

@@ -1,432 +0,0 @@
-use crate::entities::revision::{md5, RepeatedRevision, Revision};
-use crate::errors::{internal_error, CollaborateError, CollaborateResult};
-use crate::util::{cal_diff, make_delta_from_revisions};
-use bytes::Bytes;
-use flowy_grid_data_model::entities::{
-    gen_block_id, gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockInfoChangeset,
-    GridBlockMetaSnapshot, GridMeta,
-};
-use lib_infra::util::move_vec_element;
-use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
-use std::collections::HashMap;
-use std::sync::Arc;
-
-pub type GridMetaDelta = PlainTextDelta;
-pub type GridDeltaBuilder = PlainTextDeltaBuilder;
-
-pub struct GridMetaPad {
-    pub(crate) grid_meta: Arc<GridMeta>,
-    pub(crate) delta: GridMetaDelta,
-}
-
-pub trait JsonDeserializer {
-    fn deserialize(&self, type_option_data: Vec<u8>) -> CollaborateResult<String>;
-}
-
-impl GridMetaPad {
-    pub async fn duplicate_grid_meta(&self) -> (Vec<FieldMeta>, Vec<GridBlockMetaSnapshot>) {
-        let fields = self.grid_meta.fields.to_vec();
-
-        let blocks = self
-            .grid_meta
-            .blocks
-            .iter()
-            .map(|block| {
-                let mut duplicated_block = block.clone();
-                duplicated_block.block_id = gen_block_id();
-                duplicated_block
-            })
-            .collect::<Vec<GridBlockMetaSnapshot>>();
-
-        (fields, blocks)
-    }
-
-    pub fn from_delta(delta: GridMetaDelta) -> CollaborateResult<Self> {
-        let s = delta.to_str()?;
-        let grid: GridMeta = serde_json::from_str(&s)
-            .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?;
-
-        Ok(Self {
-            grid_meta: Arc::new(grid),
-            delta,
-        })
-    }
-
-    pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
-        let grid_delta: GridMetaDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
-        Self::from_delta(grid_delta)
-    }
-
-    #[tracing::instrument(level = "debug", skip_all, err)]
-    pub fn create_field_meta(
-        &mut self,
-        new_field_meta: FieldMeta,
-        start_field_id: Option<String>,
-    ) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(|grid_meta| {
-            // Check if the field exists or not
-            if grid_meta
-                .fields
-                .iter()
-                .any(|field_meta| field_meta.id == new_field_meta.id)
-            {
-                tracing::error!("Duplicate grid field");
-                return Ok(None);
-            }
-
-            let insert_index = match start_field_id {
-                None => None,
-                Some(start_field_id) => grid_meta.fields.iter().position(|field| field.id == start_field_id),
-            };
-
-            match insert_index {
-                None => grid_meta.fields.push(new_field_meta),
-                Some(index) => grid_meta.fields.insert(index, new_field_meta),
-            }
-            Ok(Some(()))
-        })
-    }
-
-    pub fn delete_field_meta(&mut self, field_id: &str) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(
-            |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
-                None => Ok(None),
-                Some(index) => {
-                    grid_meta.fields.remove(index);
-                    Ok(Some(()))
-                }
-            },
-        )
-    }
-
-    pub fn duplicate_field_meta(
-        &mut self,
-        field_id: &str,
-        duplicated_field_id: &str,
-    ) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(
-            |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
-                None => Ok(None),
-                Some(index) => {
-                    let mut duplicate_field_meta = grid_meta.fields[index].clone();
-                    duplicate_field_meta.id = duplicated_field_id.to_string();
-                    duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name);
-                    grid_meta.fields.insert(index + 1, duplicate_field_meta);
-                    Ok(Some(()))
-                }
-            },
-        )
-    }
-
-    pub fn switch_to_field<B>(
-        &mut self,
-        field_id: &str,
-        field_type: FieldType,
-        type_option_json_builder: B,
-    ) -> CollaborateResult<Option<GridChangeset>>
-    where
-        B: FnOnce(&FieldType) -> String,
-    {
-        self.modify_grid(|grid_meta| {
-            //
-            match grid_meta.fields.iter_mut().find(|field_meta| field_meta.id == field_id) {
-                None => {
-                    tracing::warn!("Can not find the field with id: {}", field_id);
-                    Ok(None)
-                }
-                Some(field_meta) => {
-                    if field_meta.get_type_option_str(&field_type).is_none() {
-                        let type_option_json = type_option_json_builder(&field_type);
-                        field_meta.insert_type_option_str(&field_type, type_option_json);
-                    }
-
-                    field_meta.field_type = field_type;
-                    Ok(Some(()))
-                }
-            }
-        })
-    }
-
-    pub fn update_field_meta<T: JsonDeserializer>(
-        &mut self,
-        changeset: FieldChangesetParams,
-        deserializer: T,
-    ) -> CollaborateResult<Option<GridChangeset>> {
-        let field_id = changeset.field_id.clone();
-        self.modify_field(&field_id, |field| {
-            let mut is_changed = None;
-            if let Some(name) = changeset.name {
-                field.name = name;
-                is_changed = Some(())
-            }
-
-            if let Some(desc) = changeset.desc {
-                field.desc = desc;
-                is_changed = Some(())
-            }
-
-            if let Some(field_type) = changeset.field_type {
-                field.field_type = field_type;
-                is_changed = Some(())
-            }
-
-            if let Some(frozen) = changeset.frozen {
-                field.frozen = frozen;
-                is_changed = Some(())
-            }
-
-            if let Some(visibility) = changeset.visibility {
-                field.visibility = visibility;
-                is_changed = Some(())
-            }
-
-            if let Some(width) = changeset.width {
-                field.width = width;
-                is_changed = Some(())
-            }
-
-            if let Some(type_option_data) = changeset.type_option_data {
-                match deserializer.deserialize(type_option_data) {
-                    Ok(json_str) => {
-                        let field_type = field.field_type.clone();
-                        field.insert_type_option_str(&field_type, json_str);
-                        is_changed = Some(())
-                    }
-                    Err(err) => {
-                        tracing::error!("Deserialize data to type option json failed: {}", err);
-                    }
-                }
-            }
-
-            Ok(is_changed)
-        })
-    }
-
-    pub fn get_field_meta(&self, field_id: &str) -> Option<(usize, &FieldMeta)> {
-        self.grid_meta
-            .fields
-            .iter()
-            .enumerate()
-            .find(|(_, field)| field.id == field_id)
-    }
-
-    pub fn replace_field_meta(&mut self, field_meta: FieldMeta) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(
-            |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_meta.id) {
-                None => Ok(None),
-                Some(index) => {
-                    grid_meta.fields.remove(index);
-                    grid_meta.fields.insert(index, field_meta);
-                    Ok(Some(()))
-                }
-            },
-        )
-    }
-
-    pub fn move_field(
-        &mut self,
-        field_id: &str,
-        from_index: usize,
-        to_index: usize,
-    ) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(|grid_meta| {
-            match move_vec_element(
-                &mut grid_meta.fields,
-                |field| field.id == field_id,
-                from_index,
-                to_index,
-            )
-            .map_err(internal_error)?
-            {
-                true => Ok(Some(())),
-                false => Ok(None),
-            }
-        })
-    }
-
-    pub fn contain_field(&self, field_id: &str) -> bool {
-        self.grid_meta.fields.iter().any(|field| field.id == field_id)
-    }
-
-    pub fn get_field_orders(&self) -> Vec<FieldOrder> {
-        self.grid_meta.fields.iter().map(FieldOrder::from).collect()
-    }
-
-    pub fn get_field_metas(&self, field_orders: Option<Vec<FieldOrder>>) -> CollaborateResult<Vec<FieldMeta>> {
-        match field_orders {
-            None => Ok(self.grid_meta.fields.clone()),
-            Some(field_orders) => {
-                let field_by_field_id = self
-                    .grid_meta
-                    .fields
-                    .iter()
-                    .map(|field| (&field.id, field))
-                    .collect::<HashMap<&String, &FieldMeta>>();
-
-                let fields = field_orders
-                    .iter()
-                    .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) {
-                        None => {
-                            tracing::error!("Can't find the field with id: {}", field_order.field_id);
-                            None
-                        }
-                        Some(field) => Some((*field).clone()),
-                    })
-                    .collect::<Vec<FieldMeta>>();
-                Ok(fields)
-            }
-        }
-    }
-
-    pub fn create_block_meta(&mut self, block: GridBlockMetaSnapshot) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(|grid_meta| {
-            if grid_meta.blocks.iter().any(|b| b.block_id == block.block_id) {
-                tracing::warn!("Duplicate grid block");
-                Ok(None)
-            } else {
-                match grid_meta.blocks.last() {
-                    None => grid_meta.blocks.push(block),
-                    Some(last_block) => {
-                        if last_block.start_row_index > block.start_row_index
-                            && last_block.len() > block.start_row_index
-                        {
-                            let msg = "GridBlock's start_row_index should be greater than the last_block's start_row_index and its len".to_string();
-                            return Err(CollaborateError::internal().context(msg))
-                        }
-                        grid_meta.blocks.push(block);
-                    }
-                }
-                Ok(Some(()))
-            }
-        })
-    }
-
-    pub fn get_block_metas(&self) -> Vec<GridBlockMetaSnapshot> {
-        self.grid_meta.blocks.clone()
-    }
-
-    pub fn update_block_meta(&mut self, changeset: GridBlockInfoChangeset) -> CollaborateResult<Option<GridChangeset>> {
-        let block_id = changeset.block_id.clone();
-        self.modify_block(&block_id, |block| {
-            let mut is_changed = None;
-
-            if let Some(row_count) = changeset.row_count {
-                block.row_count = row_count;
-                is_changed = Some(());
-            }
-
-            if let Some(start_row_index) = changeset.start_row_index {
-                block.start_row_index = start_row_index;
-                is_changed = Some(());
-            }
-
-            Ok(is_changed)
-        })
-    }
-
-    pub fn md5(&self) -> String {
-        md5(&self.delta.to_delta_bytes())
-    }
-
-    pub fn delta_str(&self) -> String {
-        self.delta.to_delta_str()
-    }
-
-    pub fn delta_bytes(&self) -> Bytes {
-        self.delta.to_delta_bytes()
-    }
-
-    pub fn fields(&self) -> &[FieldMeta] {
-        &self.grid_meta.fields
-    }
-
-    fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChangeset>>
-    where
-        F: FnOnce(&mut GridMeta) -> CollaborateResult<Option<()>>,
-    {
-        let cloned_grid = self.grid_meta.clone();
-        match f(Arc::make_mut(&mut self.grid_meta))? {
-            None => Ok(None),
-            Some(_) => {
-                let old = json_from_grid(&cloned_grid)?;
-                let new = json_from_grid(&self.grid_meta)?;
-                match cal_diff::<PlainTextAttributes>(old, new) {
-                    None => Ok(None),
-                    Some(delta) => {
-                        self.delta = self.delta.compose(&delta)?;
-                        Ok(Some(GridChangeset { delta, md5: self.md5() }))
-                    }
-                }
-            }
-        }
-    }
-
-    pub fn modify_block<F>(&mut self, block_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
-    where
-        F: FnOnce(&mut GridBlockMetaSnapshot) -> CollaborateResult<Option<()>>,
-    {
-        self.modify_grid(
-            |grid_meta| match grid_meta.blocks.iter().position(|block| block.block_id == block_id) {
-                None => {
-                    tracing::warn!("[GridMetaPad]: Can't find any block with id: {}", block_id);
-                    Ok(None)
-                }
-                Some(index) => f(&mut grid_meta.blocks[index]),
-            },
-        )
-    }
-
-    pub fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
-    where
-        F: FnOnce(&mut FieldMeta) -> CollaborateResult<Option<()>>,
-    {
-        self.modify_grid(
-            |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
-                None => {
-                    tracing::warn!("[GridMetaPad]: Can't find any field with id: {}", field_id);
-                    Ok(None)
-                }
-                Some(index) => f(&mut grid_meta.fields[index]),
-            },
-        )
-    }
-}
-
-fn json_from_grid(grid: &Arc<GridMeta>) -> CollaborateResult<String> {
-    let json = serde_json::to_string(grid)
-        .map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?;
-    Ok(json)
-}
-
-pub struct GridChangeset {
-    pub delta: GridMetaDelta,
-    /// md5: the md5 of the grid after applying the change.
-    pub md5: String,
-}
-
-pub fn make_grid_delta(grid_meta: &GridMeta) -> GridMetaDelta {
-    let json = serde_json::to_string(&grid_meta).unwrap();
-    PlainTextDeltaBuilder::new().insert(&json).build()
-}
-
-pub fn make_grid_revisions(user_id: &str, grid_meta: &GridMeta) -> RepeatedRevision {
-    let delta = make_grid_delta(grid_meta);
-    let bytes = delta.to_delta_bytes();
-    let revision = Revision::initial_revision(user_id, &grid_meta.grid_id, bytes);
-    revision.into()
-}
-
-impl std::default::Default for GridMetaPad {
-    fn default() -> Self {
-        let grid = GridMeta {
-            grid_id: gen_grid_id(),
-            fields: vec![],
-            blocks: vec![],
-        };
-        let delta = make_grid_delta(&grid);
-        GridMetaPad {
-            grid_meta: Arc::new(grid),
-            delta,
-        }
-    }
-}

+ 5 - 2
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -53,8 +53,11 @@ impl GridRevisionPad {
 
     pub fn from_delta(delta: GridRevisionDelta) -> CollaborateResult<Self> {
         let content = delta.content()?;
-        let grid: GridRevision = serde_json::from_str(&content)
-            .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?;
+        let grid: GridRevision = serde_json::from_str(&content).map_err(|e| {
+            let msg = format!("Deserialize delta to grid failed: {}", e);
+            tracing::error!("{}", msg);
+            CollaborateError::internal().context(msg)
+        })?;
 
         Ok(Self {
             grid_rev: Arc::new(grid),

+ 6 - 5
shared-lib/lib-ot/src/core/operation/builder.rs

@@ -4,6 +4,7 @@ use crate::rich_text::RichTextAttributes;
 pub type RichTextOpBuilder = OperationsBuilder<RichTextAttributes>;
 pub type PlainTextOpBuilder = OperationsBuilder<PhantomAttributes>;
 
+#[derive(Default)]
 pub struct OperationsBuilder<T: Attributes> {
     operations: Vec<Operation<T>>,
 }
@@ -13,17 +14,17 @@ where
     T: Attributes,
 {
     pub fn new() -> OperationsBuilder<T> {
-        OperationsBuilder { operations: vec![] }
+        OperationsBuilder::default()
     }
 
     pub fn retain_with_attributes(mut self, n: usize, attributes: T) -> OperationsBuilder<T> {
-        let retain = Operation::retain_with_attributes(n.into(), attributes);
+        let retain = Operation::retain_with_attributes(n, attributes);
         self.operations.push(retain);
         self
     }
 
     pub fn retain(mut self, n: usize) -> OperationsBuilder<T> {
-        let retain = Operation::retain(n.into());
+        let retain = Operation::retain(n);
         self.operations.push(retain);
         self
     }
@@ -34,13 +35,13 @@ where
     }
 
     pub fn insert_with_attributes(mut self, s: &str, attributes: T) -> OperationsBuilder<T> {
-        let insert = Operation::insert_with_attributes(s.into(), attributes);
+        let insert = Operation::insert_with_attributes(s, attributes);
         self.operations.push(insert);
         self
     }
 
     pub fn insert(mut self, s: &str) -> OperationsBuilder<T> {
-        let insert = Operation::insert(s.into());
+        let insert = Operation::insert(s);
         self.operations.push(insert);
         self
     }