Procházet zdrojové kódy

[backend]: refactor document persistence

appflowy před 3 roky
rodič
revize
64ea2d4f31
43 změnil soubory, kde provedl 740 přidání a 760 odebrání
  1. 3 3
      backend/src/application.rs
  2. 1 1
      backend/src/context.rs
  3. 8 4
      backend/src/services/core/trash/router.rs
  4. 17 9
      backend/src/services/core/trash/trash.rs
  5. 26 20
      backend/src/services/core/view/controller.rs
  6. 9 3
      backend/src/services/core/view/router.rs
  7. 31 33
      backend/src/services/document/controller.rs
  8. 0 48
      backend/src/services/document/persistence/kv.rs
  9. 91 0
      backend/src/services/document/persistence/kv_store.rs
  10. 2 2
      backend/src/services/document/persistence/mod.rs
  11. 41 114
      backend/src/services/document/persistence/postgres.rs
  12. 10 9
      backend/src/services/document/router.rs
  13. 32 24
      backend/src/services/document/ws_actor.rs
  14. 103 12
      backend/src/services/kv/kv.rs
  15. 4 0
      backend/src/services/kv/mod.rs
  16. 1 1
      backend/src/services/mod.rs
  17. 1 1
      backend/tests/api_test/kv_test.rs
  18. 2 2
      backend/tests/document_test/edit_script.rs
  19. 40 52
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/doc.pb.dart
  20. 10 11
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/doc.pbjson.dart
  21. 0 14
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-core-data-model/view_create.pb.dart
  22. 1 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-core-data-model/view_create.pbjson.dart
  23. 1 2
      frontend/rust-lib/flowy-core/src/services/view/controller.rs
  24. 3 2
      frontend/rust-lib/flowy-document/src/services/doc/revision/manager.rs
  25. 2 2
      frontend/rust-lib/flowy-document/src/services/server/mod.rs
  26. 3 3
      frontend/rust-lib/flowy-document/src/services/server/server_api.rs
  27. 4 4
      frontend/rust-lib/flowy-document/src/services/server/server_api_mock.rs
  28. 4 9
      frontend/rust-lib/flowy-net/src/services/mock/ws_mock.rs
  29. 1 1
      shared-lib/flowy-collaboration/src/core/document/default/mod.rs
  30. 1 1
      shared-lib/flowy-collaboration/src/core/document/document.rs
  31. 3 2
      shared-lib/flowy-collaboration/src/core/sync/server_editor.rs
  32. 9 20
      shared-lib/flowy-collaboration/src/core/sync/synchronizer.rs
  33. 6 9
      shared-lib/flowy-collaboration/src/entities/doc.rs
  34. 22 17
      shared-lib/flowy-collaboration/src/entities/revision.rs
  35. 1 1
      shared-lib/flowy-collaboration/src/errors.rs
  36. 161 184
      shared-lib/flowy-collaboration/src/protobuf/model/doc.rs
  37. 4 5
      shared-lib/flowy-collaboration/src/protobuf/proto/doc.proto
  38. 1 5
      shared-lib/flowy-core-data-model/src/entities/view/view_create.rs
  39. 78 124
      shared-lib/flowy-core-data-model/src/protobuf/model/view_create.rs
  40. 0 1
      shared-lib/flowy-core-data-model/src/protobuf/proto/view_create.proto
  41. 1 1
      shared-lib/flowy-derive/src/derive_cache/derive_cache.rs
  42. 1 1
      shared-lib/lib-ot/src/errors.rs
  43. 1 1
      shared-lib/lib-ws/src/errors.rs

+ 3 - 3
backend/src/application.rs

@@ -111,9 +111,9 @@ fn user_scope() -> Scope {
             .route(web::patch().to(view::update_handler))
         )
         .service(web::resource("/document")
-            .route(web::post().to(doc::create_handler))
-            .route(web::get().to(doc::read_handler))
-            .route(web::patch().to(doc::update_handler))
+            .route(web::post().to(doc::create_document_handler))
+            .route(web::get().to(doc::read_document_handler))
+            .route(web::patch().to(doc::reset_document_handler))
         )
         .service(web::resource("/trash")
             .route(web::post().to(trash::create_handler))

+ 1 - 1
backend/src/context.rs

@@ -1,5 +1,5 @@
 use crate::services::{
-    kv_store::{KVStore, PostgresKV},
+    kv::{KVStore, PostgresKV},
     web_socket::{WSServer, WebSocketReceivers},
 };
 use actix::Addr;

+ 8 - 4
backend/src/services/core/trash/router.rs

@@ -1,4 +1,5 @@
 use crate::{
+    context::FlowyPersistence,
     entities::logged_user::LoggedUser,
     services::core::trash::{create_trash, delete_all_trash, delete_trash, read_trash},
     util::serde_ext::parse_from_payload,
@@ -15,6 +16,7 @@ use backend_service::{
 };
 use flowy_core_data_model::{parser::trash::TrashId, protobuf::TrashIdentifiers};
 use sqlx::PgPool;
+use std::sync::Arc;
 use uuid::Uuid;
 
 #[tracing::instrument(skip(payload, pool, logged_user), err)]
@@ -39,12 +41,14 @@ pub async fn create_handler(
     Ok(FlowyResponse::success().into())
 }
 
-#[tracing::instrument(skip(payload, pool, logged_user), fields(delete_trash), err)]
+#[tracing::instrument(skip(payload, persistence, logged_user), fields(delete_trash), err)]
 pub async fn delete_handler(
     payload: Payload,
-    pool: Data<PgPool>,
+    persistence: Data<Arc<FlowyPersistence>>,
     logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
+    let pool = persistence.pg_pool();
+    let kv_store = persistence.kv_store();
     let params: TrashIdentifiers = parse_from_payload(payload).await?;
     let mut transaction = pool
         .begin()
@@ -53,10 +57,10 @@ pub async fn delete_handler(
 
     if params.delete_all {
         tracing::Span::current().record("delete_trash", &"all");
-        let _ = delete_all_trash(&mut transaction, &logged_user).await?;
+        let _ = delete_all_trash(&mut transaction, &kv_store, &logged_user).await?;
     } else {
         let records = make_records(params)?;
-        let _ = delete_trash(&mut transaction, records).await?;
+        let _ = delete_trash(&mut transaction, &kv_store, records).await?;
     }
 
     transaction

+ 17 - 9
backend/src/services/core/trash/trash.rs

@@ -1,9 +1,12 @@
 use crate::{
     entities::logged_user::LoggedUser,
-    services::core::{
-        app::controller::{delete_app, read_app_table},
-        trash::persistence::{TrashTable, TRASH_TABLE},
-        view::{delete_view, read_view_table},
+    services::{
+        core::{
+            app::controller::{delete_app, read_app_table},
+            trash::persistence::{TrashTable, TRASH_TABLE},
+            view::{delete_view, read_view_table},
+        },
+        document::persistence::DocumentKVPersistence,
     },
     util::sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
 };
@@ -11,6 +14,7 @@ use ::protobuf::ProtobufEnum;
 use backend_service::errors::ServerError;
 use flowy_core_data_model::protobuf::{RepeatedTrash, Trash, TrashType};
 use sqlx::{postgres::PgArguments, Postgres, Row};
+use std::sync::Arc;
 use uuid::Uuid;
 
 #[tracing::instrument(skip(transaction, user), err)]
@@ -35,9 +39,10 @@ pub(crate) async fn create_trash(
     Ok(())
 }
 
-#[tracing::instrument(skip(transaction, user), fields(delete_rows), err)]
+#[tracing::instrument(skip(transaction, kv_store, user), fields(delete_rows), err)]
 pub(crate) async fn delete_all_trash(
     transaction: &mut DBTransaction<'_>,
+    kv_store: &Arc<DocumentKVPersistence>,
     user: &LoggedUser,
 ) -> Result<(), ServerError> {
     let (sql, args) = SqlBuilder::select(TRASH_TABLE)
@@ -52,7 +57,7 @@ pub(crate) async fn delete_all_trash(
         .collect::<Vec<(Uuid, i32)>>();
     tracing::Span::current().record("delete_rows", &format!("{:?}", rows).as_str());
     let affected_row_count = rows.len();
-    let _ = delete_trash_associate_targets(transaction as &mut DBTransaction<'_>, rows).await?;
+    let _ = delete_trash_associate_targets(transaction as &mut DBTransaction<'_>, kv_store, rows).await?;
 
     let (sql, args) = SqlBuilder::delete(TRASH_TABLE)
         .and_where_eq("user_id", &user.user_id)
@@ -67,9 +72,10 @@ pub(crate) async fn delete_all_trash(
     Ok(())
 }
 
-#[tracing::instrument(skip(transaction), err)]
+#[tracing::instrument(skip(transaction, kv_store), err)]
 pub(crate) async fn delete_trash(
     transaction: &mut DBTransaction<'_>,
+    kv_store: &Arc<DocumentKVPersistence>,
     records: Vec<(Uuid, i32)>,
 ) -> Result<(), ServerError> {
     for (trash_id, _) in records {
@@ -86,6 +92,7 @@ pub(crate) async fn delete_trash(
 
         let _ = delete_trash_associate_targets(
             transaction as &mut DBTransaction<'_>,
+            kv_store,
             vec![(trash_table.id, trash_table.ty)],
         )
         .await?;
@@ -100,9 +107,10 @@ pub(crate) async fn delete_trash(
     Ok(())
 }
 
-#[tracing::instrument(skip(transaction, targets), err)]
+#[tracing::instrument(skip(transaction, kv_store, targets), err)]
 async fn delete_trash_associate_targets(
     transaction: &mut DBTransaction<'_>,
+    kv_store: &Arc<DocumentKVPersistence>,
     targets: Vec<(Uuid, i32)>,
 ) -> Result<(), ServerError> {
     for (id, ty) in targets {
@@ -111,7 +119,7 @@ async fn delete_trash_associate_targets(
             Some(ty) => match ty {
                 TrashType::Unknown => {},
                 TrashType::View => {
-                    let _ = delete_view(transaction as &mut DBTransaction<'_>, vec![id]).await;
+                    let _ = delete_view(transaction as &mut DBTransaction<'_>, kv_store, vec![id]).await;
                 },
                 TrashType::App => {
                     let _ = delete_app(transaction as &mut DBTransaction<'_>, id).await;

+ 26 - 20
backend/src/services/core/view/controller.rs

@@ -2,13 +2,16 @@ use crate::{
     entities::logged_user::LoggedUser,
     services::{
         core::{trash::read_trash_ids, view::persistence::*},
-        document::persistence::{create_doc_with_transaction, delete_doc, DocumentKVPersistence},
+        document::persistence::{create_doc, delete_doc, DocumentKVPersistence},
     },
     util::sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
 };
 use backend_service::errors::{invalid_params, ServerError};
 use chrono::Utc;
-use flowy_collaboration::protobuf::CreateDocParams;
+use flowy_collaboration::{
+    entities::revision::{RevType, Revision},
+    protobuf::{CreateDocParams, RepeatedRevision},
+};
 use flowy_core_data_model::{
     parser::{
         app::AppId,
@@ -17,7 +20,7 @@ use flowy_core_data_model::{
     protobuf::{CreateViewParams, RepeatedView, View},
 };
 use sqlx::{postgres::PgArguments, Postgres};
-use std::sync::Arc;
+use std::{convert::TryInto, sync::Arc};
 use uuid::Uuid;
 
 pub(crate) async fn update_view(
@@ -43,8 +46,12 @@ pub(crate) async fn update_view(
     Ok(())
 }
 
-#[tracing::instrument(skip(transaction), err)]
-pub(crate) async fn delete_view(transaction: &mut DBTransaction<'_>, view_ids: Vec<Uuid>) -> Result<(), ServerError> {
+#[tracing::instrument(skip(transaction, kv_store), err)]
+pub(crate) async fn delete_view(
+    transaction: &mut DBTransaction<'_>,
+    kv_store: &Arc<DocumentKVPersistence>,
+    view_ids: Vec<Uuid>,
+) -> Result<(), ServerError> {
     for view_id in view_ids {
         let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;
         let _ = sqlx::query_with(&sql, args)
@@ -52,7 +59,7 @@ pub(crate) async fn delete_view(transaction: &mut DBTransaction<'_>, view_ids: V
             .await
             .map_err(map_sqlx_error)?;
 
-        let _ = delete_doc(transaction, view_id).await?;
+        let _ = delete_doc(kv_store, view_id).await?;
     }
     Ok(())
 }
@@ -62,6 +69,7 @@ pub(crate) async fn create_view(
     transaction: &mut DBTransaction<'_>,
     kv_store: Arc<DocumentKVPersistence>,
     params: CreateViewParams,
+    user_id: &str,
 ) -> Result<View, ServerError> {
     let name = ViewName::parse(params.name).map_err(invalid_params)?;
     let belong_to_id = AppId::parse(params.belong_to_id).map_err(invalid_params)?;
@@ -75,27 +83,25 @@ pub(crate) async fn create_view(
         .view_type(params.view_type)
         .build()?;
 
-    let view = create_view_with_args(transaction, kv_store, sql, args, view, params.data).await?;
-    Ok(view)
-}
-
-async fn create_view_with_args(
-    transaction: &mut DBTransaction<'_>,
-    kv_store: Arc<DocumentKVPersistence>,
-    sql: String,
-    args: PgArguments,
-    view: View,
-    view_data: String,
-) -> Result<View, ServerError> {
     let _ = sqlx::query_with(&sql, args)
         .execute(transaction as &mut DBTransaction<'_>)
         .await
         .map_err(map_sqlx_error)?;
 
+    let doc_id = view.id.clone();
+    let revision: flowy_collaboration::protobuf::Revision =
+        Revision::initial_revision(user_id, &doc_id, RevType::Remote)
+            .try_into()
+            .unwrap();
+    let mut repeated_revision = RepeatedRevision::new();
+    repeated_revision.set_items(vec![revision].into());
+
     let mut create_doc_params = CreateDocParams::new();
-    create_doc_params.set_data(view_data);
+    create_doc_params.set_revisions(repeated_revision);
     create_doc_params.set_id(view.id.clone());
-    let _ = create_doc_with_transaction(transaction, kv_store, create_doc_params).await?;
+
+    let _ = create_doc(&kv_store, create_doc_params).await?;
+
     Ok(view)
 }
 

+ 9 - 3
backend/src/services/core/view/router.rs

@@ -23,6 +23,7 @@ use std::sync::Arc;
 pub async fn create_handler(
     payload: Payload,
     persistence: Data<Arc<FlowyPersistence>>,
+    user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
     let params: CreateViewParams = parse_from_payload(payload).await?;
     let kv_store = persistence.kv_store();
@@ -32,7 +33,7 @@ pub async fn create_handler(
         .await
         .context("Failed to acquire a Postgres connection to create view")?;
 
-    let view = create_view(&mut transaction, kv_store, params).await?;
+    let view = create_view(&mut transaction, kv_store, params, &user.user_id).await?;
     transaction
         .commit()
         .await
@@ -96,15 +97,20 @@ pub async fn update_handler(payload: Payload, pool: Data<PgPool>) -> Result<Http
     Ok(FlowyResponse::success().into())
 }
 
-pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
+pub async fn delete_handler(
+    payload: Payload,
+    persistence: Data<Arc<FlowyPersistence>>,
+) -> Result<HttpResponse, ServerError> {
     let params: QueryViewRequest = parse_from_payload(payload).await?;
+    let pool = persistence.pg_pool();
+    let kv_store = persistence.kv_store();
     let view_ids = check_view_ids(params.view_ids.to_vec())?;
     let mut transaction = pool
         .begin()
         .await
         .context("Failed to acquire a Postgres connection to delete view")?;
 
-    let _ = delete_view(&mut transaction, view_ids).await?;
+    let _ = delete_view(&mut transaction, &kv_store, view_ids).await?;
 
     transaction
         .commit()

+ 31 - 33
backend/src/services/document/controller.rs

@@ -1,6 +1,6 @@
 use crate::services::{
     document::{
-        persistence::{create_doc, read_doc, update_doc},
+        persistence::{create_doc, read_doc},
         ws_actor::{DocumentWebSocketActor, WSActorMessage},
     },
     web_socket::{WSClientData, WebSocketReceiver},
@@ -10,12 +10,15 @@ use crate::context::FlowyPersistence;
 use backend_service::errors::ServerError;
 use flowy_collaboration::{
     core::sync::{DocumentPersistence, ServerDocumentManager},
-    entities::{doc::Doc, revision::Revision},
+    entities::{
+        doc::{CreateDocParams, Doc},
+        revision::{RepeatedRevision, Revision},
+    },
     errors::CollaborateError,
-    protobuf::{CreateDocParams, DocIdentifier, UpdateDocParams},
+    protobuf::DocIdentifier,
 };
 use lib_infra::future::FutureResultSend;
-use lib_ot::rich_text::RichTextDelta;
+
 use std::{convert::TryInto, sync::Arc};
 use tokio::sync::{mpsc, oneshot};
 
@@ -45,13 +48,13 @@ impl WebSocketReceiver for DocumentWebSocketReceiver {
     fn receive(&self, data: WSClientData) {
         let (ret, rx) = oneshot::channel();
         let sender = self.ws_sender.clone();
-        let pool = self.persistence.pg_pool();
+        let persistence = self.persistence.clone();
 
         actix_rt::spawn(async move {
             let msg = WSActorMessage::ClientData {
                 client_data: data,
                 ret,
-                pool,
+                persistence,
             };
             match sender.send(msg).await {
                 Ok(_) => {},
@@ -67,21 +70,21 @@ impl WebSocketReceiver for DocumentWebSocketReceiver {
 
 struct DocumentPersistenceImpl(Arc<FlowyPersistence>);
 impl DocumentPersistence for DocumentPersistenceImpl {
-    fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError> {
-        let pg_pool = self.0.pg_pool();
-        let mut params = UpdateDocParams::new();
-        let doc_json = delta.to_json();
-        params.set_doc_id(doc_id.to_string());
-        params.set_data(doc_json);
-        params.set_rev_id(rev_id);
-
-        FutureResultSend::new(async move {
-            let _ = update_doc(&pg_pool, params)
-                .await
-                .map_err(server_error_to_collaborate_error)?;
-            Ok(())
-        })
-    }
+    // fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) ->
+    // FutureResultSend<(), CollaborateError> {     let pg_pool =
+    // self.0.pg_pool();     let mut params = ResetDocumentParams::new();
+    //     let doc_json = delta.to_json();
+    //     params.set_doc_id(doc_id.to_string());
+    //     params.set_data(doc_json);
+    //     params.set_rev_id(rev_id);
+    //
+    //     FutureResultSend::new(async move {
+    //         let _ = update_doc(&pg_pool, params)
+    //             .await
+    //             .map_err(server_error_to_collaborate_error)?;
+    //         Ok(())
+    //     })
+    // }
 
     fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError> {
         let params = DocIdentifier {
@@ -101,22 +104,17 @@ impl DocumentPersistence for DocumentPersistenceImpl {
     }
 
     fn create_doc(&self, revision: Revision) -> FutureResultSend<Doc, CollaborateError> {
-        let persistence = self.0.clone();
+        let kv_store = self.0.kv_store();
         FutureResultSend::new(async move {
-            let delta = RichTextDelta::from_bytes(&revision.delta_data)?;
-            let doc_json = delta.to_json();
-
-            let params = CreateDocParams {
-                id: revision.doc_id.clone(),
-                data: doc_json.clone(),
-                unknown_fields: Default::default(),
-                cached_size: Default::default(),
-            };
+            let doc: Doc = revision.clone().try_into()?;
+            let doc_id = revision.doc_id.clone();
+            let revisions = RepeatedRevision { items: vec![revision] };
 
-            let _ = create_doc(&persistence, params)
+            let params = CreateDocParams { id: doc_id, revisions };
+            let pb_params: flowy_collaboration::protobuf::CreateDocParams = params.try_into().unwrap();
+            let _ = create_doc(&kv_store, pb_params)
                 .await
                 .map_err(server_error_to_collaborate_error)?;
-            let doc: Doc = revision.try_into()?;
             Ok(doc)
         })
     }

+ 0 - 48
backend/src/services/document/persistence/kv.rs

@@ -1,48 +0,0 @@
-use crate::{services::kv_store::KVStore, util::serde_ext::parse_from_bytes};
-use backend_service::errors::ServerError;
-use bytes::Bytes;
-use flowy_collaboration::protobuf::{RepeatedRevision, Revision};
-use protobuf::Message;
-use std::sync::Arc;
-
-pub struct DocumentKVPersistence {
-    inner: Arc<dyn KVStore>,
-}
-
-impl std::ops::Deref for DocumentKVPersistence {
-    type Target = Arc<dyn KVStore>;
-
-    fn deref(&self) -> &Self::Target { &self.inner }
-}
-
-impl std::ops::DerefMut for DocumentKVPersistence {
-    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
-}
-
-impl DocumentKVPersistence {
-    pub(crate) fn new(kv_store: Arc<dyn KVStore>) -> Self { DocumentKVPersistence { inner: kv_store } }
-
-    pub(crate) async fn set_revision(&self, revision: Revision) -> Result<(), ServerError> {
-        let key = revision.rev_id.to_string();
-        let bytes = revision.write_to_bytes()?;
-        let _ = self.inner.set(&key, Bytes::from(bytes)).await?;
-        Ok(())
-    }
-
-    pub(crate) async fn batch_get_revisions(&self, rev_ids: Vec<i64>) -> Result<RepeatedRevision, ServerError> {
-        let keys = rev_ids
-            .into_iter()
-            .map(|rev_id| rev_id.to_string())
-            .collect::<Vec<String>>();
-
-        let items = self.inner.batch_get(keys).await?;
-        let revisions = items
-            .into_iter()
-            .filter_map(|kv| parse_from_bytes::<Revision>(&kv.value).ok())
-            .collect::<Vec<Revision>>();
-
-        let mut repeated_revision = RepeatedRevision::new();
-        repeated_revision.set_items(revisions.into());
-        Ok(repeated_revision)
-    }
-}

+ 91 - 0
backend/src/services/document/persistence/kv_store.rs

@@ -0,0 +1,91 @@
+use crate::{services::kv::KVStore, util::serde_ext::parse_from_bytes};
+use backend_service::errors::ServerError;
+use bytes::Bytes;
+use flowy_collaboration::protobuf::{RepeatedRevision, Revision};
+use futures::stream::{self, StreamExt};
+use protobuf::Message;
+use std::sync::Arc;
+
+pub struct DocumentKVPersistence {
+    inner: Arc<dyn KVStore>,
+}
+
+impl std::ops::Deref for DocumentKVPersistence {
+    type Target = Arc<dyn KVStore>;
+
+    fn deref(&self) -> &Self::Target { &self.inner }
+}
+
+impl std::ops::DerefMut for DocumentKVPersistence {
+    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
+}
+
+impl DocumentKVPersistence {
+    pub(crate) fn new(kv_store: Arc<dyn KVStore>) -> Self { DocumentKVPersistence { inner: kv_store } }
+
+    pub(crate) async fn batch_set_revision(&self, revisions: Vec<Revision>) -> Result<(), ServerError> {
+        let kv_store = self.inner.clone();
+
+        let f = |revision: Revision, kv_store: Arc<dyn KVStore>| async move {
+            let key = make_revision_key(&revision.doc_id, revision.rev_id);
+            let bytes = revision.write_to_bytes().unwrap();
+            let _ = kv_store.set(&key, Bytes::from(bytes)).await;
+        };
+
+        stream::iter(revisions)
+            .for_each_concurrent(None, |revision| f(revision, kv_store.clone()))
+            .await;
+        Ok(())
+    }
+
+    pub(crate) async fn batch_get_revisions<T: Into<Option<Vec<i64>>>>(
+        &self,
+        doc_id: &str,
+        rev_ids: T,
+    ) -> Result<RepeatedRevision, ServerError> {
+        let rev_ids = rev_ids.into();
+        let items = match rev_ids {
+            None => self.inner.batch_get_key_start_with(doc_id).await?,
+            Some(rev_ids) => {
+                let keys = rev_ids
+                    .into_iter()
+                    .map(|rev_id| make_revision_key(doc_id, rev_id))
+                    .collect::<Vec<String>>();
+                self.inner.batch_get(keys).await?
+            },
+        };
+
+        let revisions = items
+            .into_iter()
+            .filter_map(|kv| parse_from_bytes::<Revision>(&kv.value).ok())
+            .collect::<Vec<Revision>>();
+
+        let mut repeated_revision = RepeatedRevision::new();
+        repeated_revision.set_items(revisions.into());
+        Ok(repeated_revision)
+    }
+
+    pub(crate) async fn batch_delete_revisions<T: Into<Option<Vec<i64>>>>(
+        &self,
+        doc_id: &str,
+        rev_ids: T,
+    ) -> Result<(), ServerError> {
+        match rev_ids.into() {
+            None => {
+                let _ = self.inner.batch_delete_key_start_with(doc_id).await?;
+                Ok(())
+            },
+            Some(rev_ids) => {
+                let keys = rev_ids
+                    .into_iter()
+                    .map(|rev_id| make_revision_key(doc_id, rev_id))
+                    .collect::<Vec<String>>();
+                let _ = self.inner.batch_delete(keys).await?;
+                Ok(())
+            },
+        }
+    }
+}
+
+#[inline]
+fn make_revision_key(doc_id: &str, rev_id: i64) -> String { format!("{}:{}", doc_id, rev_id) }

+ 2 - 2
backend/src/services/document/persistence/mod.rs

@@ -1,5 +1,5 @@
-mod kv;
+mod kv_store;
 mod postgres;
 
-pub use kv::*;
+pub use kv_store::*;
 pub use postgres::*;

+ 41 - 114
backend/src/services/document/persistence/postgres.rs

@@ -1,127 +1,42 @@
-use crate::{
-    context::FlowyPersistence,
-    services::{document::persistence::DocumentKVPersistence, kv_store::KVStore},
-    util::sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
-};
-use anyhow::Context;
-use backend_service::errors::ServerError;
-use flowy_collaboration::protobuf::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
+use crate::{context::FlowyPersistence, services::document::persistence::DocumentKVPersistence};
+
+use backend_service::errors::{internal_error, ServerError};
+use flowy_collaboration::protobuf::{CreateDocParams, Doc, DocIdentifier, RepeatedRevision, ResetDocumentParams};
+use lib_ot::{core::OperationTransformable, rich_text::RichTextDelta};
 use protobuf::Message;
-use sqlx::{postgres::PgArguments, PgPool, Postgres};
+use sqlx::PgPool;
 use std::sync::Arc;
 use uuid::Uuid;
 
 const DOC_TABLE: &str = "doc_table";
 
-#[tracing::instrument(level = "debug", skip(transaction, kv_store), err)]
-pub(crate) async fn create_doc_with_transaction(
-    transaction: &mut DBTransaction<'_>,
-    kv_store: Arc<DocumentKVPersistence>,
-    params: CreateDocParams,
-) -> Result<(), ServerError> {
-    let uuid = Uuid::parse_str(&params.id)?;
-    let (sql, args) = SqlBuilder::create(DOC_TABLE)
-        .add_field_with_arg("id", uuid)
-        .add_field_with_arg("rev_id", 0)
-        .build()?;
-
-    // TODO kv
-    // kv_store.set_revision()
-    let _ = sqlx::query_with(&sql, args)
-        .execute(transaction)
-        .await
-        .map_err(map_sqlx_error)?;
-
-    Ok(())
-}
-
+#[tracing::instrument(level = "debug", skip(kv_store), err)]
 pub(crate) async fn create_doc(
-    persistence: &Arc<FlowyPersistence>,
-    params: CreateDocParams,
+    kv_store: &Arc<DocumentKVPersistence>,
+    mut params: CreateDocParams,
 ) -> Result<(), ServerError> {
-    let pool = persistence.pg_pool();
-    let kv_store = persistence.kv_store();
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to create document")?;
-
-    let _ = create_doc_with_transaction(&mut transaction, kv_store, params).await?;
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to create document.")?;
-
+    let revisions = params.take_revisions().take_items();
+    let _ = kv_store.batch_set_revision(revisions.into()).await?;
     Ok(())
 }
 
 #[tracing::instrument(level = "debug", skip(persistence), err)]
 pub(crate) async fn read_doc(persistence: &Arc<FlowyPersistence>, params: DocIdentifier) -> Result<Doc, ServerError> {
-    let doc_id = Uuid::parse_str(&params.doc_id)?;
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to read document")?;
-
-    let builder = SqlBuilder::select(DOC_TABLE).add_field("*").and_where_eq("id", &doc_id);
+    let _ = Uuid::parse_str(&params.doc_id)?;
 
-    let (sql, args) = builder.build()?;
-    // TODO: benchmark the speed of different documents with different size
-    let _table = sqlx::query_as_with::<Postgres, DocTable, PgArguments>(&sql, args)
-        .fetch_one(&mut transaction)
-        .await
-        .map_err(map_sqlx_error)?;
-
-    // TODO: kv
-    panic!("")
-
-    // transaction
-    //     .commit()
-    //     .await
-    //     .context("Failed to commit SQL transaction to read document.")?;
-    //
-    // Ok(doc)
+    let kv_store = persistence.kv_store();
+    let revisions = kv_store.batch_get_revisions(&params.doc_id, None).await?;
+    make_doc_from_revisions(&params.doc_id, revisions)
 }
 
-#[tracing::instrument(level = "debug", skip(pool, params), fields(delta), err)]
-pub async fn update_doc(pool: &PgPool, mut params: UpdateDocParams) -> Result<(), ServerError> {
-    let doc_id = Uuid::parse_str(&params.doc_id)?;
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to update document")?;
-
-    let data = Some(params.take_data());
-
-    tracing::Span::current().record("delta", &data.as_ref().unwrap_or(&"".to_owned()).as_str());
-
-    let (sql, args) = SqlBuilder::update(DOC_TABLE)
-        .add_some_arg("data", data)
-        .add_field_with_arg("rev_id", params.rev_id)
-        .and_where_eq("id", doc_id)
-        .build()?;
-
-    sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
-        .await
-        .map_err(map_sqlx_error)?;
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to update document.")?;
-
-    Ok(())
+#[tracing::instrument(level = "debug", skip(_pool, _params), fields(delta), err)]
+pub async fn reset_document(_pool: &PgPool, _params: ResetDocumentParams) -> Result<(), ServerError> {
+    unimplemented!()
 }
 
-#[tracing::instrument(level = "debug", skip(transaction), err)]
-pub(crate) async fn delete_doc(transaction: &mut DBTransaction<'_>, doc_id: Uuid) -> Result<(), ServerError> {
-    let (sql, args) = SqlBuilder::delete(DOC_TABLE).and_where_eq("id", doc_id).build()?;
-    let _ = sqlx::query_with(&sql, args)
-        .execute(transaction)
-        .await
-        .map_err(map_sqlx_error)?;
+#[tracing::instrument(level = "debug", skip(kv_store), err)]
+pub(crate) async fn delete_doc(kv_store: &Arc<DocumentKVPersistence>, doc_id: Uuid) -> Result<(), ServerError> {
+    let _ = kv_store.batch_delete_revisions(&doc_id.to_string(), None).await?;
 
     Ok(())
 }
@@ -132,11 +47,23 @@ struct DocTable {
     rev_id: i64,
 }
 
-// impl std::convert::From<DocTable> for Doc {
-//     fn from(table: DocTable) -> Self {
-//         let mut doc = Doc::new();
-//         doc.set_id(table.id.to_string());
-//         doc.set_rev_id(table.rev_id);
-//         doc
-//     }
-// }
+fn make_doc_from_revisions(doc_id: &str, mut revisions: RepeatedRevision) -> Result<Doc, ServerError> {
+    let revisions = revisions.take_items();
+    let mut document_delta = RichTextDelta::new();
+    let mut base_rev_id = 0;
+    let mut rev_id = 0;
+    // TODO: generate delta from revision should be wrapped into function.
+    for revision in revisions {
+        base_rev_id = revision.base_rev_id;
+        rev_id = revision.rev_id;
+        let delta = RichTextDelta::from_bytes(revision.delta_data).map_err(internal_error)?;
+        document_delta = document_delta.compose(&delta).map_err(internal_error)?;
+    }
+    let text = document_delta.to_json();
+    let mut doc = Doc::new();
+    doc.set_id(doc_id.to_owned());
+    doc.set_text(text);
+    doc.set_base_rev_id(base_rev_id);
+    doc.set_rev_id(rev_id);
+    Ok(doc)
+}

+ 10 - 9
backend/src/services/document/router.rs

@@ -1,6 +1,6 @@
 use crate::{
     context::FlowyPersistence,
-    services::document::persistence::{create_doc, read_doc, update_doc},
+    services::document::persistence::{create_doc, read_doc},
     util::serde_ext::parse_from_payload,
 };
 use actix_web::{
@@ -8,21 +8,22 @@ use actix_web::{
     HttpResponse,
 };
 use backend_service::{errors::ServerError, response::FlowyResponse};
-use flowy_collaboration::protobuf::{CreateDocParams, DocIdentifier, UpdateDocParams};
+use flowy_collaboration::protobuf::{CreateDocParams, DocIdentifier, ResetDocumentParams};
 use sqlx::PgPool;
 use std::sync::Arc;
 
-pub async fn create_handler(
+pub async fn create_document_handler(
     payload: Payload,
     persistence: Data<Arc<FlowyPersistence>>,
 ) -> Result<HttpResponse, ServerError> {
     let params: CreateDocParams = parse_from_payload(payload).await?;
-    let _ = create_doc(persistence.get_ref(), params).await?;
+    let kv_store = persistence.kv_store();
+    let _ = create_doc(&kv_store, params).await?;
     Ok(FlowyResponse::success().into())
 }
 
 #[tracing::instrument(level = "debug", skip(payload, persistence), err)]
-pub async fn read_handler(
+pub async fn read_document_handler(
     payload: Payload,
     persistence: Data<Arc<FlowyPersistence>>,
 ) -> Result<HttpResponse, ServerError> {
@@ -32,8 +33,8 @@ pub async fn read_handler(
     Ok(response.into())
 }
 
-pub async fn update_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
-    let params: UpdateDocParams = parse_from_payload(payload).await?;
-    let _ = update_doc(pool.get_ref(), params).await?;
-    Ok(FlowyResponse::success().into())
+pub async fn reset_document_handler(payload: Payload, _pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
+    let _params: ResetDocumentParams = parse_from_payload(payload).await?;
+    // Ok(FlowyResponse::success().into())
+    unimplemented!()
 }

+ 32 - 24
backend/src/services/document/ws_actor.rs

@@ -1,27 +1,25 @@
 use crate::{
-    services::{
-        document::persistence::update_doc,
-        web_socket::{entities::Socket, WSClientData, WSMessageAdaptor, WSUser},
-    },
+    services::web_socket::{entities::Socket, WSClientData, WSMessageAdaptor, WSUser},
     util::serde_ext::{md5, parse_from_bytes},
 };
 use actix_rt::task::spawn_blocking;
 
+use crate::context::FlowyPersistence;
 use async_stream::stream;
 use backend_service::errors::{internal_error, Result, ServerError};
 use flowy_collaboration::{
     core::sync::{RevisionUser, ServerDocumentManager, SyncResponse},
-    protobuf::{DocumentWSData, DocumentWSDataType, NewDocumentUser, Revision, UpdateDocParams},
+    protobuf::{DocumentWSData, DocumentWSDataType, NewDocumentUser, Revision},
 };
 use futures::stream::StreamExt;
-use sqlx::PgPool;
+
 use std::{convert::TryInto, sync::Arc};
 use tokio::sync::{mpsc, oneshot};
 
 pub enum WSActorMessage {
     ClientData {
         client_data: WSClientData,
-        pool: PgPool,
+        persistence: Arc<FlowyPersistence>,
         ret: oneshot::Sender<Result<()>>,
     },
 }
@@ -59,13 +57,17 @@ impl DocumentWebSocketActor {
 
     async fn handle_message(&self, msg: WSActorMessage) {
         match msg {
-            WSActorMessage::ClientData { client_data, pool, ret } => {
-                let _ = ret.send(self.handle_client_data(client_data, pool).await);
+            WSActorMessage::ClientData {
+                client_data,
+                persistence,
+                ret,
+            } => {
+                let _ = ret.send(self.handle_client_data(client_data, persistence).await);
             },
         }
     }
 
-    async fn handle_client_data(&self, client_data: WSClientData, pg_pool: PgPool) -> Result<()> {
+    async fn handle_client_data(&self, client_data: WSClientData, persistence: Arc<FlowyPersistence>) -> Result<()> {
         let WSClientData { user, socket, data } = client_data;
         let document_data = spawn_blocking(move || {
             let document_data: DocumentWSData = parse_from_bytes(&data)?;
@@ -81,7 +83,11 @@ impl DocumentWebSocketActor {
             document_data.ty
         );
 
-        let user = Arc::new(ServerDocUser { user, socket, pg_pool });
+        let user = Arc::new(ServerDocUser {
+            user,
+            socket,
+            persistence,
+        });
         let result = match &document_data.ty {
             DocumentWSDataType::Ack => Ok(()),
             DocumentWSDataType::PushRev => self.handle_pushed_rev(user, document_data.data).await,
@@ -147,11 +153,20 @@ fn verify_md5(revision: &Revision) -> Result<()> {
     Ok(())
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct ServerDocUser {
     pub user: Arc<WSUser>,
     pub(crate) socket: Socket,
-    pub pg_pool: PgPool,
+    pub persistence: Arc<FlowyPersistence>,
+}
+
+impl std::fmt::Debug for ServerDocUser {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.debug_struct("ServerDocUser")
+            .field("user", &self.user)
+            .field("socket", &self.socket)
+            .finish()
+    }
 }
 
 impl RevisionUser for ServerDocUser {
@@ -171,18 +186,11 @@ impl RevisionUser for ServerDocUser {
                 let msg: WSMessageAdaptor = data.into();
                 self.socket.try_send(msg).map_err(internal_error)
             },
-            SyncResponse::NewRevision {
-                rev_id,
-                doc_id,
-                doc_json,
-            } => {
-                let pg_pool = self.pg_pool.clone();
+            SyncResponse::NewRevision(revision) => {
+                let kv_store = self.persistence.kv_store();
                 tokio::task::spawn(async move {
-                    let mut params = UpdateDocParams::new();
-                    params.set_doc_id(doc_id);
-                    params.set_data(doc_json);
-                    params.set_rev_id(rev_id);
-                    match update_doc(&pg_pool, params).await {
+                    let revision: flowy_collaboration::protobuf::Revision = revision.try_into().unwrap();
+                    match kv_store.batch_set_revision(vec![revision]).await {
                         Ok(_) => {},
                         Err(e) => log::error!("{}", e),
                     }

+ 103 - 12
backend/src/services/kv_store/kv.rs → backend/src/services/kv/kv.rs

@@ -1,5 +1,5 @@
 use crate::{
-    services::kv_store::{KVStore, KeyValue},
+    services::kv::{KVStore, KeyValue},
     util::sqlx_ext::{map_sqlx_error, SqlBuilder},
 };
 
@@ -8,7 +8,13 @@ use backend_service::errors::ServerError;
 use bytes::Bytes;
 use lib_infra::future::FutureResultSend;
 use sql_builder::{quote, SqlBuilder as RawSqlBuilder};
-use sqlx::{postgres::PgArguments, Error, PgPool, Postgres, Row};
+use sqlx::{
+    postgres::{PgArguments, PgRow},
+    Error,
+    PgPool,
+    Postgres,
+    Row,
+};
 
 const KV_TABLE: &str = "kv_table";
 
@@ -137,16 +143,7 @@ impl KVStore for PostgresKV {
                 .fetch_all(&mut transaction)
                 .await
                 .map_err(map_sqlx_error)?;
-            let kvs = rows
-                .into_iter()
-                .map(|row| {
-                    let bytes: Vec<u8> = row.get("blob");
-                    KeyValue {
-                        key: row.get("id"),
-                        value: Bytes::from(bytes),
-                    }
-                })
-                .collect::<Vec<KeyValue>>();
+            let kvs = rows_to_key_values(rows);
 
             transaction
                 .commit()
@@ -156,6 +153,100 @@ impl KVStore for PostgresKV {
             Ok::<Vec<KeyValue>, ServerError>(kvs)
         })
     }
+
+    fn batch_get_key_start_with(&self, prefix: &str) -> FutureResultSend<Vec<KeyValue>, ServerError> {
+        let pg_pool = self.pg_pool.clone();
+        let prefix = prefix.to_owned();
+        FutureResultSend::new(async move {
+            let mut transaction = pg_pool
+                .begin()
+                .await
+                .context("[KV]:Failed to acquire a Postgres connection")?;
+
+            let sql = RawSqlBuilder::select_from(KV_TABLE)
+                .field("id")
+                .field("blob")
+                .and_where_like_left("id", &prefix)
+                .sql()?;
+
+            let rows = sqlx::query(&sql)
+                .fetch_all(&mut transaction)
+                .await
+                .map_err(map_sqlx_error)?;
+
+            let kvs = rows_to_key_values(rows);
+
+            transaction
+                .commit()
+                .await
+                .context("[KV]:Failed to commit SQL transaction.")?;
+
+            Ok::<Vec<KeyValue>, ServerError>(kvs)
+        })
+    }
+
+    fn batch_delete(&self, keys: Vec<String>) -> FutureResultSend<(), ServerError> {
+        let pg_pool = self.pg_pool.clone();
+        FutureResultSend::new(async move {
+            let mut transaction = pg_pool
+                .begin()
+                .await
+                .context("[KV]:Failed to acquire a Postgres connection")?;
+
+            let sql = RawSqlBuilder::delete_from(KV_TABLE).and_where_in("id", &keys).sql()?;
+
+            let _ = sqlx::query(&sql)
+                .execute(&mut transaction)
+                .await
+                .map_err(map_sqlx_error)?;
+
+            transaction
+                .commit()
+                .await
+                .context("[KV]:Failed to commit SQL transaction.")?;
+
+            Ok::<(), ServerError>(())
+        })
+    }
+
+    fn batch_delete_key_start_with(&self, keyword: &str) -> FutureResultSend<(), ServerError> {
+        let pg_pool = self.pg_pool.clone();
+        let keyword = keyword.to_owned();
+        FutureResultSend::new(async move {
+            let mut transaction = pg_pool
+                .begin()
+                .await
+                .context("[KV]:Failed to acquire a Postgres connection")?;
+
+            let sql = RawSqlBuilder::delete_from(KV_TABLE)
+                .and_where_like_left("id", &keyword)
+                .sql()?;
+
+            let _ = sqlx::query(&sql)
+                .execute(&mut transaction)
+                .await
+                .map_err(map_sqlx_error)?;
+
+            transaction
+                .commit()
+                .await
+                .context("[KV]:Failed to commit SQL transaction.")?;
+
+            Ok::<(), ServerError>(())
+        })
+    }
+}
+
+fn rows_to_key_values(rows: Vec<PgRow>) -> Vec<KeyValue> {
+    rows.into_iter()
+        .map(|row| {
+            let bytes: Vec<u8> = row.get("blob");
+            KeyValue {
+                key: row.get("id"),
+                value: Bytes::from(bytes),
+            }
+        })
+        .collect::<Vec<KeyValue>>()
 }
 
 #[derive(Debug, Clone, sqlx::FromRow)]

+ 4 - 0
backend/src/services/kv_store/mod.rs → backend/src/services/kv/mod.rs

@@ -18,4 +18,8 @@ pub trait KVStore: Send + Sync {
     fn delete(&self, key: &str) -> FutureResultSend<(), ServerError>;
     fn batch_set(&self, kvs: Vec<KeyValue>) -> FutureResultSend<(), ServerError>;
     fn batch_get(&self, keys: Vec<String>) -> FutureResultSend<Vec<KeyValue>, ServerError>;
+    fn batch_get_key_start_with(&self, keyword: &str) -> FutureResultSend<Vec<KeyValue>, ServerError>;
+
+    fn batch_delete(&self, keys: Vec<String>) -> FutureResultSend<(), ServerError>;
+    fn batch_delete_key_start_with(&self, keyword: &str) -> FutureResultSend<(), ServerError>;
 }

+ 1 - 1
backend/src/services/mod.rs

@@ -1,5 +1,5 @@
 pub mod core;
 pub mod document;
-pub mod kv_store;
+pub mod kv;
 pub mod user;
 pub mod web_socket;

+ 1 - 1
backend/tests/api_test/kv_test.rs

@@ -1,5 +1,5 @@
 use crate::util::helper::spawn_server;
-use backend::services::kv_store::KeyValue;
+use backend::services::kv::KeyValue;
 use std::str;
 
 #[actix_rt::test]

+ 2 - 2
backend/tests/document_test/edit_script.rs

@@ -11,7 +11,7 @@ use std::sync::Arc;
 use tokio::time::{sleep, Duration};
 // use crate::helper::*;
 use crate::util::helper::{spawn_server, TestServer};
-use flowy_collaboration::{entities::doc::DocIdentifier, protobuf::UpdateDocParams};
+use flowy_collaboration::{entities::doc::DocIdentifier, protobuf::ResetDocumentParams};
 use lib_ot::rich_text::{RichTextAttribute, RichTextDelta};
 use parking_lot::RwLock;
 use lib_ot::core::Interval;
@@ -167,7 +167,7 @@ async fn create_doc(flowy_test: &FlowySDKTest) -> String {
 }
 
 async fn save_doc(doc_id: &str, json: String, rev_id: i64, pool: Data<PgPool>) {
-    let mut params = UpdateDocParams::new();
+    let mut params = ResetDocumentParams::new();
     params.set_doc_id(doc_id.to_owned());
     params.set_data(json);
     params.set_rev_id(rev_id);

+ 40 - 52
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/doc.pb.dart

@@ -15,21 +15,21 @@ import 'revision.pb.dart' as $0;
 class CreateDocParams extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateDocParams', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
-    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', subBuilder: $0.RepeatedRevision.create)
+    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
     ..hasRequiredFields = false
   ;
 
   CreateDocParams._() : super();
   factory CreateDocParams({
     $core.String? id,
-    $0.RepeatedRevision? data,
+    $0.RepeatedRevision? revisions,
   }) {
     final _result = create();
     if (id != null) {
       _result.id = id;
     }
-    if (data != null) {
-      _result.data = data;
+    if (revisions != null) {
+      _result.revisions = revisions;
     }
     return _result;
   }
@@ -64,21 +64,21 @@ class CreateDocParams extends $pb.GeneratedMessage {
   void clearId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $0.RepeatedRevision get data => $_getN(1);
+  $0.RepeatedRevision get revisions => $_getN(1);
   @$pb.TagNumber(2)
-  set data($0.RepeatedRevision v) { setField(2, v); }
+  set revisions($0.RepeatedRevision v) { setField(2, v); }
   @$pb.TagNumber(2)
-  $core.bool hasData() => $_has(1);
+  $core.bool hasRevisions() => $_has(1);
   @$pb.TagNumber(2)
-  void clearData() => clearField(2);
+  void clearRevisions() => clearField(2);
   @$pb.TagNumber(2)
-  $0.RepeatedRevision ensureData() => $_ensure(1);
+  $0.RepeatedRevision ensureRevisions() => $_ensure(1);
 }
 
 class Doc extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Doc', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'text')
     ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
     ..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'baseRevId')
     ..hasRequiredFields = false
@@ -87,7 +87,7 @@ class Doc extends $pb.GeneratedMessage {
   Doc._() : super();
   factory Doc({
     $core.String? id,
-    $core.String? data,
+    $core.String? text,
     $fixnum.Int64? revId,
     $fixnum.Int64? baseRevId,
   }) {
@@ -95,8 +95,8 @@ class Doc extends $pb.GeneratedMessage {
     if (id != null) {
       _result.id = id;
     }
-    if (data != null) {
-      _result.data = data;
+    if (text != null) {
+      _result.text = text;
     }
     if (revId != null) {
       _result.revId = revId;
@@ -137,13 +137,13 @@ class Doc extends $pb.GeneratedMessage {
   void clearId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get data => $_getSZ(1);
+  $core.String get text => $_getSZ(1);
   @$pb.TagNumber(2)
-  set data($core.String v) { $_setString(1, v); }
+  set text($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
-  $core.bool hasData() => $_has(1);
+  $core.bool hasText() => $_has(1);
   @$pb.TagNumber(2)
-  void clearData() => clearField(2);
+  void clearText() => clearField(2);
 
   @$pb.TagNumber(3)
   $fixnum.Int64 get revId => $_getI64(2);
@@ -164,52 +164,47 @@ class Doc extends $pb.GeneratedMessage {
   void clearBaseRevId() => clearField(4);
 }
 
-class UpdateDocParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateDocParams', createEmptyInstance: create)
+class ResetDocumentParams extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ResetDocumentParams', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
-    ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
+    ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
     ..hasRequiredFields = false
   ;
 
-  UpdateDocParams._() : super();
-  factory UpdateDocParams({
+  ResetDocumentParams._() : super();
+  factory ResetDocumentParams({
     $core.String? docId,
-    $core.String? data,
-    $fixnum.Int64? revId,
+    $0.RepeatedRevision? revisions,
   }) {
     final _result = create();
     if (docId != null) {
       _result.docId = docId;
     }
-    if (data != null) {
-      _result.data = data;
-    }
-    if (revId != null) {
-      _result.revId = revId;
+    if (revisions != null) {
+      _result.revisions = revisions;
     }
     return _result;
   }
-  factory UpdateDocParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory UpdateDocParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory ResetDocumentParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ResetDocumentParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
   'Will be removed in next major version')
-  UpdateDocParams clone() => UpdateDocParams()..mergeFromMessage(this);
+  ResetDocumentParams clone() => ResetDocumentParams()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  UpdateDocParams copyWith(void Function(UpdateDocParams) updates) => super.copyWith((message) => updates(message as UpdateDocParams)) as UpdateDocParams; // ignore: deprecated_member_use
+  ResetDocumentParams copyWith(void Function(ResetDocumentParams) updates) => super.copyWith((message) => updates(message as ResetDocumentParams)) as ResetDocumentParams; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static UpdateDocParams create() => UpdateDocParams._();
-  UpdateDocParams createEmptyInstance() => create();
-  static $pb.PbList<UpdateDocParams> createRepeated() => $pb.PbList<UpdateDocParams>();
+  static ResetDocumentParams create() => ResetDocumentParams._();
+  ResetDocumentParams createEmptyInstance() => create();
+  static $pb.PbList<ResetDocumentParams> createRepeated() => $pb.PbList<ResetDocumentParams>();
   @$core.pragma('dart2js:noInline')
-  static UpdateDocParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateDocParams>(create);
-  static UpdateDocParams? _defaultInstance;
+  static ResetDocumentParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ResetDocumentParams>(create);
+  static ResetDocumentParams? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get docId => $_getSZ(0);
@@ -221,22 +216,15 @@ class UpdateDocParams extends $pb.GeneratedMessage {
   void clearDocId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get data => $_getSZ(1);
+  $0.RepeatedRevision get revisions => $_getN(1);
   @$pb.TagNumber(2)
-  set data($core.String v) { $_setString(1, v); }
+  set revisions($0.RepeatedRevision v) { setField(2, v); }
   @$pb.TagNumber(2)
-  $core.bool hasData() => $_has(1);
+  $core.bool hasRevisions() => $_has(1);
   @$pb.TagNumber(2)
-  void clearData() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $fixnum.Int64 get revId => $_getI64(2);
-  @$pb.TagNumber(3)
-  set revId($fixnum.Int64 v) { $_setInt64(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasRevId() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearRevId() => clearField(3);
+  void clearRevisions() => clearField(2);
+  @$pb.TagNumber(2)
+  $0.RepeatedRevision ensureRevisions() => $_ensure(1);
 }
 
 class DocDelta extends $pb.GeneratedMessage {

+ 10 - 11
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/doc.pbjson.dart

@@ -13,37 +13,36 @@ const CreateDocParams$json = const {
   '1': 'CreateDocParams',
   '2': const [
     const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
-    const {'1': 'data', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'data'},
+    const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'},
   ],
 };
 
 /// Descriptor for `CreateDocParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List createDocParamsDescriptor = $convert.base64Decode('Cg9DcmVhdGVEb2NQYXJhbXMSDgoCaWQYASABKAlSAmlkEiUKBGRhdGEYAiABKAsyES5SZXBlYXRlZFJldmlzaW9uUgRkYXRh');
+final $typed_data.Uint8List createDocParamsDescriptor = $convert.base64Decode('Cg9DcmVhdGVEb2NQYXJhbXMSDgoCaWQYASABKAlSAmlkEi8KCXJldmlzaW9ucxgCIAEoCzIRLlJlcGVhdGVkUmV2aXNpb25SCXJldmlzaW9ucw==');
 @$core.Deprecated('Use docDescriptor instead')
 const Doc$json = const {
   '1': 'Doc',
   '2': const [
     const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
-    const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
+    const {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'},
     const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'},
     const {'1': 'base_rev_id', '3': 4, '4': 1, '5': 3, '10': 'baseRevId'},
   ],
 };
 
 /// Descriptor for `Doc`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List docDescriptor = $convert.base64Decode('CgNEb2MSDgoCaWQYASABKAlSAmlkEhIKBGRhdGEYAiABKAlSBGRhdGESFQoGcmV2X2lkGAMgASgDUgVyZXZJZBIeCgtiYXNlX3Jldl9pZBgEIAEoA1IJYmFzZVJldklk');
-@$core.Deprecated('Use updateDocParamsDescriptor instead')
-const UpdateDocParams$json = const {
-  '1': 'UpdateDocParams',
+final $typed_data.Uint8List docDescriptor = $convert.base64Decode('CgNEb2MSDgoCaWQYASABKAlSAmlkEhIKBHRleHQYAiABKAlSBHRleHQSFQoGcmV2X2lkGAMgASgDUgVyZXZJZBIeCgtiYXNlX3Jldl9pZBgEIAEoA1IJYmFzZVJldklk');
+@$core.Deprecated('Use resetDocumentParamsDescriptor instead')
+const ResetDocumentParams$json = const {
+  '1': 'ResetDocumentParams',
   '2': const [
     const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
-    const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
-    const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'},
+    const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'},
   ],
 };
 
-/// Descriptor for `UpdateDocParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List updateDocParamsDescriptor = $convert.base64Decode('Cg9VcGRhdGVEb2NQYXJhbXMSFQoGZG9jX2lkGAEgASgJUgVkb2NJZBISCgRkYXRhGAIgASgJUgRkYXRhEhUKBnJldl9pZBgDIAEoA1IFcmV2SWQ=');
+/// Descriptor for `ResetDocumentParams`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List resetDocumentParamsDescriptor = $convert.base64Decode('ChNSZXNldERvY3VtZW50UGFyYW1zEhUKBmRvY19pZBgBIAEoCVIFZG9jSWQSLwoJcmV2aXNpb25zGAIgASgLMhEuUmVwZWF0ZWRSZXZpc2lvblIJcmV2aXNpb25z');
 @$core.Deprecated('Use docDeltaDescriptor instead')
 const DocDelta$json = const {
   '1': 'DocDelta',

+ 0 - 14
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-core-data-model/view_create.pb.dart

@@ -137,7 +137,6 @@ class CreateViewParams extends $pb.GeneratedMessage {
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
     ..e<ViewType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewType.Blank, valueOf: ViewType.valueOf, enumValues: ViewType.values)
-    ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
     ..hasRequiredFields = false
   ;
 
@@ -148,7 +147,6 @@ class CreateViewParams extends $pb.GeneratedMessage {
     $core.String? desc,
     $core.String? thumbnail,
     ViewType? viewType,
-    $core.String? data,
   }) {
     final _result = create();
     if (belongToId != null) {
@@ -166,9 +164,6 @@ class CreateViewParams extends $pb.GeneratedMessage {
     if (viewType != null) {
       _result.viewType = viewType;
     }
-    if (data != null) {
-      _result.data = data;
-    }
     return _result;
   }
   factory CreateViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -236,15 +231,6 @@ class CreateViewParams extends $pb.GeneratedMessage {
   $core.bool hasViewType() => $_has(4);
   @$pb.TagNumber(5)
   void clearViewType() => clearField(5);
-
-  @$pb.TagNumber(6)
-  $core.String get data => $_getSZ(5);
-  @$pb.TagNumber(6)
-  set data($core.String v) { $_setString(5, v); }
-  @$pb.TagNumber(6)
-  $core.bool hasData() => $_has(5);
-  @$pb.TagNumber(6)
-  void clearData() => clearField(6);
 }
 
 class View extends $pb.GeneratedMessage {

+ 1 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-core-data-model/view_create.pbjson.dart

@@ -45,12 +45,11 @@ const CreateViewParams$json = const {
     const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'},
     const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '10': 'thumbnail'},
     const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewType', '10': 'viewType'},
-    const {'1': 'data', '3': 6, '4': 1, '5': 9, '10': 'data'},
   ],
 };
 
 /// Descriptor for `CreateViewParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSJgoJdmlld190eXBlGAUgASgOMgkuVmlld1R5cGVSCHZpZXdUeXBlEhIKBGRhdGEYBiABKAlSBGRhdGE=');
+final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSJgoJdmlld190eXBlGAUgASgOMgkuVmlld1R5cGVSCHZpZXdUeXBl');
 @$core.Deprecated('Use viewDescriptor instead')
 const View$json = const {
   '1': 'View',

+ 1 - 2
frontend/rust-lib/flowy-core/src/services/view/controller.rs

@@ -138,7 +138,7 @@ impl ViewController {
     #[tracing::instrument(level = "debug", skip(self, params), fields(doc_id = %params.doc_id), err)]
     pub(crate) async fn duplicate_view(&self, params: DocIdentifier) -> Result<(), FlowyError> {
         let view: View = ViewTableSql::read_view(&params.doc_id, &*self.database.db_connection()?)?.into();
-        let delta_data = self
+        let _delta_data = self
             .document
             .read_document_data(params, self.database.db_pool()?)
             .await?;
@@ -149,7 +149,6 @@ impl ViewController {
             desc: view.desc.clone(),
             thumbnail: "".to_owned(),
             view_type: view.view_type.clone(),
-            data: delta_data.data,
         };
 
         let _ = self.create_view_from_params(duplicate_params).await?;

+ 3 - 2
frontend/rust-lib/flowy-document/src/services/doc/revision/manager.rs

@@ -80,6 +80,7 @@ impl RevisionManager {
         debug_assert!(range.doc_id == self.doc_id);
         let revisions = self.cache.revisions_in_range(range.clone()).await?;
         let mut new_delta = RichTextDelta::new();
+        // TODO: generate delta from revision should be wrapped into function.
         for revision in revisions {
             match RichTextDelta::from_bytes(revision.delta_data) {
                 Ok(delta) => {
@@ -127,7 +128,7 @@ impl RevisionLoader {
         let revisions: Vec<Revision>;
         if records.is_empty() {
             let doc = self.server.fetch_document(&self.doc_id).await?;
-            let delta_data = Bytes::from(doc.data.clone());
+            let delta_data = Bytes::from(doc.text.clone());
             let doc_md5 = md5(&delta_data);
             let revision = Revision::new(
                 &doc.id,
@@ -174,7 +175,7 @@ fn mk_doc_from_revisions(doc_id: &str, revisions: Vec<Revision>) -> FlowyResult<
 
     Result::<Doc, FlowyError>::Ok(Doc {
         id: doc_id.to_owned(),
-        data: delta.to_json(),
+        text: delta.to_json(),
         rev_id,
         base_rev_id,
     })

+ 2 - 2
frontend/rust-lib/flowy-document/src/services/server/mod.rs

@@ -6,7 +6,7 @@ pub use server_api::*;
 // TODO: ignore mock files in production
 use crate::errors::FlowyError;
 use backend_service::configuration::ClientServerConfiguration;
-use flowy_collaboration::entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
+use flowy_collaboration::entities::doc::{CreateDocParams, Doc, DocIdentifier, ResetDocumentParams};
 use lib_infra::future::FutureResult;
 pub use server_api_mock::*;
 use std::sync::Arc;
@@ -17,7 +17,7 @@ pub trait DocumentServerAPI {
 
     fn read_doc(&self, token: &str, params: DocIdentifier) -> FutureResult<Option<Doc>, FlowyError>;
 
-    fn update_doc(&self, token: &str, params: UpdateDocParams) -> FutureResult<(), FlowyError>;
+    fn update_doc(&self, token: &str, params: ResetDocumentParams) -> FutureResult<(), FlowyError>;
 }
 
 pub(crate) fn construct_doc_server(

+ 3 - 3
frontend/rust-lib/flowy-document/src/services/server/server_api.rs

@@ -1,6 +1,6 @@
 use crate::{errors::FlowyError, services::server::DocumentServerAPI};
 use backend_service::{configuration::*, request::HttpRequestBuilder};
-use flowy_collaboration::entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
+use flowy_collaboration::entities::doc::{CreateDocParams, Doc, DocIdentifier, ResetDocumentParams};
 use lib_infra::future::FutureResult;
 
 pub struct DocServer {
@@ -24,7 +24,7 @@ impl DocumentServerAPI for DocServer {
         FutureResult::new(async move { read_doc_request(&token, params, &url).await })
     }
 
-    fn update_doc(&self, token: &str, params: UpdateDocParams) -> FutureResult<(), FlowyError> {
+    fn update_doc(&self, token: &str, params: ResetDocumentParams) -> FutureResult<(), FlowyError> {
         let token = token.to_owned();
         let url = self.config.doc_url();
         FutureResult::new(async move { update_doc_request(&token, params, &url).await })
@@ -56,7 +56,7 @@ pub async fn read_doc_request(token: &str, params: DocIdentifier, url: &str) ->
     Ok(doc)
 }
 
-pub async fn update_doc_request(token: &str, params: UpdateDocParams, url: &str) -> Result<(), FlowyError> {
+pub async fn update_doc_request(token: &str, params: ResetDocumentParams, url: &str) -> Result<(), FlowyError> {
     let _ = request_builder()
         .patch(&url.to_owned())
         .header(HEADER_TOKEN, token)

+ 4 - 4
frontend/rust-lib/flowy-document/src/services/server/server_api_mock.rs

@@ -1,6 +1,6 @@
 use flowy_collaboration::{
-    core::document::default::initial_string,
-    entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams},
+    core::document::default::initial_delta_string,
+    entities::doc::{CreateDocParams, Doc, DocIdentifier, ResetDocumentParams},
 };
 use lib_infra::future::FutureResult;
 
@@ -16,14 +16,14 @@ impl DocumentServerAPI for DocServerMock {
     fn read_doc(&self, _token: &str, params: DocIdentifier) -> FutureResult<Option<Doc>, FlowyError> {
         let doc = Doc {
             id: params.doc_id,
-            data: initial_string(),
+            text: initial_delta_string(),
             rev_id: 0,
             base_rev_id: 0,
         };
         FutureResult::new(async { Ok(Some(doc)) })
     }
 
-    fn update_doc(&self, _token: &str, _params: UpdateDocParams) -> FutureResult<(), FlowyError> {
+    fn update_doc(&self, _token: &str, _params: ResetDocumentParams) -> FutureResult<(), FlowyError> {
         FutureResult::new(async { Ok(()) })
     }
 }

+ 4 - 9
frontend/rust-lib/flowy-net/src/services/mock/ws_mock.rs

@@ -9,7 +9,6 @@ use flowy_collaboration::{
         ws::{DocumentWSData, DocumentWSDataBuilder, DocumentWSDataType, NewDocumentUser},
     },
     errors::CollaborateError,
-    RichTextDelta,
 };
 use lazy_static::lazy_static;
 use lib_infra::future::{FutureResult, FutureResultSend};
@@ -161,9 +160,9 @@ impl std::default::Default for MockDocServerPersistence {
 }
 
 impl DocumentPersistence for MockDocServerPersistence {
-    fn update_doc(&self, _doc_id: &str, _rev_id: i64, _delta: RichTextDelta) -> FutureResultSend<(), CollaborateError> {
-        unimplemented!()
-    }
+    // fn update_doc(&self, _doc_id: &str, _rev_id: i64, _delta: RichTextDelta) ->
+    // FutureResultSend<(), CollaborateError> {     unimplemented!()
+    // }
 
     fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError> {
         let inner = self.inner.clone();
@@ -227,11 +226,7 @@ impl RevisionUser for MockDocUser {
                     };
                     sender.send(msg).await.unwrap();
                 },
-                SyncResponse::NewRevision {
-                    rev_id: _,
-                    doc_id: _,
-                    doc_json: _,
-                } => {
+                SyncResponse::NewRevision(_) => {
                     // unimplemented!()
                 },
             }

+ 1 - 1
shared-lib/flowy-collaboration/src/core/document/default/mod.rs

@@ -4,7 +4,7 @@ use lib_ot::{core::DeltaBuilder, rich_text::RichTextDelta};
 pub fn initial_delta() -> RichTextDelta { DeltaBuilder::new().insert("\n").build() }
 
 #[inline]
-pub fn initial_string() -> String { initial_delta().to_json() }
+pub fn initial_delta_string() -> String { initial_delta().to_json() }
 
 #[inline]
 pub fn initial_read_me() -> RichTextDelta {

+ 1 - 1
shared-lib/flowy-collaboration/src/core/document/document.rs

@@ -63,7 +63,7 @@ impl Document {
     pub fn delta(&self) -> &RichTextDelta { &self.delta }
 
     pub fn md5(&self) -> String {
-        // Opti: calculate the md5 of delta would cause performance issues
+        // TODO: Optimize the cost of calculating the md5
         let bytes = self.to_bytes();
         format!("{:x}", md5::compute(bytes))
     }

+ 3 - 2
shared-lib/flowy-collaboration/src/core/sync/server_editor.rs

@@ -18,7 +18,8 @@ use tokio::{
 };
 
 pub trait DocumentPersistence: Send + Sync {
-    fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError>;
+    // fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) ->
+    // FutureResultSend<(), CollaborateError>;
     fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError>;
     fn create_doc(&self, revision: Revision) -> FutureResultSend<Doc, CollaborateError>;
 }
@@ -205,7 +206,7 @@ pub struct ServerDocEditor {
 
 impl ServerDocEditor {
     pub fn new(doc: Doc) -> Result<Self, OTError> {
-        let delta = RichTextDelta::from_bytes(&doc.data)?;
+        let delta = RichTextDelta::from_bytes(&doc.text)?;
         let users = DashMap::new();
         let synchronizer = Arc::new(RevisionSynchronizer::new(
             &doc.id,

+ 9 - 20
shared-lib/flowy-collaboration/src/core/sync/synchronizer.rs

@@ -26,11 +26,7 @@ pub enum SyncResponse {
     Pull(DocumentWSData),
     Push(DocumentWSData),
     Ack(DocumentWSData),
-    NewRevision {
-        rev_id: i64,
-        doc_json: String,
-        doc_id: String,
-    },
+    NewRevision(Revision),
 }
 
 pub struct RevisionSynchronizer {
@@ -71,14 +67,7 @@ impl RevisionSynchronizer {
                         &revision.doc_id,
                         &revision.rev_id.to_string(),
                     )));
-                    let rev_id = revision.rev_id;
-                    let doc_id = self.doc_id.clone();
-                    let doc_json = self.doc_json();
-                    user.receive(SyncResponse::NewRevision {
-                        rev_id,
-                        doc_id,
-                        doc_json,
-                    });
+                    user.receive(SyncResponse::NewRevision(revision));
                 } else {
                     // The server document is outdated, pull the missing revision from the client.
                     let range = RevisionRange {
@@ -105,13 +94,13 @@ impl RevisionSynchronizer {
                 let _ = self.compose_delta(server_delta)?;
 
                 //
-                let doc_id = self.doc_id.clone();
-                let doc_json = self.doc_json();
-                user.receive(SyncResponse::NewRevision {
-                    rev_id: self.rev_id(),
-                    doc_json,
-                    doc_id,
-                });
+                let _doc_id = self.doc_id.clone();
+                let _doc_json = self.doc_json();
+                // user.receive(SyncResponse::NewRevision {
+                //     rev_id: self.rev_id(),
+                //     doc_json,
+                //     doc_id,
+                // });
 
                 let cli_revision = self.mk_revision(revision.rev_id, cli_delta);
                 let data = DocumentWSDataBuilder::build_push_message(&self.doc_id, cli_revision, &id);

+ 6 - 9
shared-lib/flowy-collaboration/src/entities/doc.rs

@@ -11,7 +11,7 @@ pub struct CreateDocParams {
     pub id: String,
 
     #[pb(index = 2)]
-    pub data: RepeatedRevision,
+    pub revisions: RepeatedRevision,
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)]
@@ -20,7 +20,7 @@ pub struct Doc {
     pub id: String,
 
     #[pb(index = 2)]
-    pub data: String,
+    pub text: String,
 
     #[pb(index = 3)]
     pub rev_id: i64,
@@ -31,7 +31,7 @@ pub struct Doc {
 
 impl Doc {
     pub fn delta(&self) -> Result<RichTextDelta, OTError> {
-        let delta = RichTextDelta::from_bytes(&self.data)?;
+        let delta = RichTextDelta::from_bytes(&self.text)?;
         Ok(delta)
     }
 }
@@ -50,7 +50,7 @@ impl std::convert::TryFrom<Revision> for Doc {
 
         Ok(Doc {
             id: revision.doc_id,
-            data: doc_json,
+            text: doc_json,
             rev_id: revision.rev_id,
             base_rev_id: revision.base_rev_id,
         })
@@ -58,15 +58,12 @@ impl std::convert::TryFrom<Revision> for Doc {
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
-pub struct UpdateDocParams {
+pub struct ResetDocumentParams {
     #[pb(index = 1)]
     pub doc_id: String,
 
     #[pb(index = 2)]
-    pub data: String,
-
-    #[pb(index = 3)]
-    pub rev_id: i64,
+    pub revisions: RepeatedRevision,
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]

+ 22 - 17
shared-lib/flowy-collaboration/src/entities/revision.rs

@@ -1,3 +1,4 @@
+use crate::core::document::default::initial_delta;
 use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use lib_ot::rich_text::RichTextDelta;
@@ -41,26 +42,13 @@ impl Revision {
 
     #[allow(dead_code)]
     pub fn is_initial(&self) -> bool { self.rev_id == 0 }
-}
 
-impl std::fmt::Debug for Revision {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-        let _ = f.write_fmt(format_args!("doc_id {}, ", self.doc_id))?;
-        let _ = f.write_fmt(format_args!("base_rev_id {}, ", self.base_rev_id))?;
-        let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?;
-        match RichTextDelta::from_bytes(&self.delta_data) {
-            Ok(delta) => {
-                let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json()))?;
-            },
-            Err(e) => {
-                let _ = f.write_fmt(format_args!("delta {:?}", e))?;
-            },
-        }
-        Ok(())
+    pub fn initial_revision(user_id: &str, doc_id: &str, ty: RevType) -> Self {
+        let delta_data = initial_delta().to_bytes();
+        let md5 = format!("{:x}", md5::compute(&delta_data));
+        Revision::new(doc_id, 0, 0, delta_data, ty, user_id, md5)
     }
-}
 
-impl Revision {
     pub fn new(
         doc_id: &str,
         base_rev_id: i64,
@@ -92,6 +80,23 @@ impl Revision {
     }
 }
 
+impl std::fmt::Debug for Revision {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        let _ = f.write_fmt(format_args!("doc_id {}, ", self.doc_id))?;
+        let _ = f.write_fmt(format_args!("base_rev_id {}, ", self.base_rev_id))?;
+        let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?;
+        match RichTextDelta::from_bytes(&self.delta_data) {
+            Ok(delta) => {
+                let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json()))?;
+            },
+            Err(e) => {
+                let _ = f.write_fmt(format_args!("delta {:?}", e))?;
+            },
+        }
+        Ok(())
+    }
+}
+
 #[derive(PartialEq, Debug, Default, ProtoBuf, Clone)]
 pub struct RepeatedRevision {
     #[pb(index = 1)]

+ 1 - 1
shared-lib/flowy-collaboration/src/errors.rs

@@ -68,7 +68,7 @@ impl std::convert::From<protobuf::ProtobufError> for CollaborateError {
     fn from(e: protobuf::ProtobufError) -> Self { CollaborateError::internal().context(e) }
 }
 
-pub fn internal_error<T>(e: T) -> CollaborateError
+pub(crate) fn internal_error<T>(e: T) -> CollaborateError
 where
     T: std::fmt::Debug,
 {

+ 161 - 184
shared-lib/flowy-collaboration/src/protobuf/model/doc.rs

@@ -27,7 +27,7 @@
 pub struct CreateDocParams {
     // message fields
     pub id: ::std::string::String,
-    pub data: ::protobuf::SingularPtrField<super::revision::RepeatedRevision>,
+    pub revisions: ::protobuf::SingularPtrField<super::revision::RepeatedRevision>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -70,43 +70,43 @@ impl CreateDocParams {
         ::std::mem::replace(&mut self.id, ::std::string::String::new())
     }
 
-    // .RepeatedRevision data = 2;
+    // .RepeatedRevision revisions = 2;
 
 
-    pub fn get_data(&self) -> &super::revision::RepeatedRevision {
-        self.data.as_ref().unwrap_or_else(|| <super::revision::RepeatedRevision as ::protobuf::Message>::default_instance())
+    pub fn get_revisions(&self) -> &super::revision::RepeatedRevision {
+        self.revisions.as_ref().unwrap_or_else(|| <super::revision::RepeatedRevision as ::protobuf::Message>::default_instance())
     }
-    pub fn clear_data(&mut self) {
-        self.data.clear();
+    pub fn clear_revisions(&mut self) {
+        self.revisions.clear();
     }
 
-    pub fn has_data(&self) -> bool {
-        self.data.is_some()
+    pub fn has_revisions(&self) -> bool {
+        self.revisions.is_some()
     }
 
     // Param is passed by value, moved
-    pub fn set_data(&mut self, v: super::revision::RepeatedRevision) {
-        self.data = ::protobuf::SingularPtrField::some(v);
+    pub fn set_revisions(&mut self, v: super::revision::RepeatedRevision) {
+        self.revisions = ::protobuf::SingularPtrField::some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_data(&mut self) -> &mut super::revision::RepeatedRevision {
-        if self.data.is_none() {
-            self.data.set_default();
+    pub fn mut_revisions(&mut self) -> &mut super::revision::RepeatedRevision {
+        if self.revisions.is_none() {
+            self.revisions.set_default();
         }
-        self.data.as_mut().unwrap()
+        self.revisions.as_mut().unwrap()
     }
 
     // Take field
-    pub fn take_data(&mut self) -> super::revision::RepeatedRevision {
-        self.data.take().unwrap_or_else(|| super::revision::RepeatedRevision::new())
+    pub fn take_revisions(&mut self) -> super::revision::RepeatedRevision {
+        self.revisions.take().unwrap_or_else(|| super::revision::RepeatedRevision::new())
     }
 }
 
 impl ::protobuf::Message for CreateDocParams {
     fn is_initialized(&self) -> bool {
-        for v in &self.data {
+        for v in &self.revisions {
             if !v.is_initialized() {
                 return false;
             }
@@ -122,7 +122,7 @@ impl ::protobuf::Message for CreateDocParams {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.data)?;
+                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.revisions)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -139,7 +139,7 @@ impl ::protobuf::Message for CreateDocParams {
         if !self.id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.id);
         }
-        if let Some(ref v) = self.data.as_ref() {
+        if let Some(ref v) = self.revisions.as_ref() {
             let len = v.compute_size();
             my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
         }
@@ -152,7 +152,7 @@ impl ::protobuf::Message for CreateDocParams {
         if !self.id.is_empty() {
             os.write_string(1, &self.id)?;
         }
-        if let Some(ref v) = self.data.as_ref() {
+        if let Some(ref v) = self.revisions.as_ref() {
             os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
             os.write_raw_varint32(v.get_cached_size())?;
             v.write_to_with_cached_sizes(os)?;
@@ -201,9 +201,9 @@ impl ::protobuf::Message for CreateDocParams {
                 |m: &mut CreateDocParams| { &mut m.id },
             ));
             fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::revision::RepeatedRevision>>(
-                "data",
-                |m: &CreateDocParams| { &m.data },
-                |m: &mut CreateDocParams| { &mut m.data },
+                "revisions",
+                |m: &CreateDocParams| { &m.revisions },
+                |m: &mut CreateDocParams| { &mut m.revisions },
             ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateDocParams>(
                 "CreateDocParams",
@@ -222,7 +222,7 @@ impl ::protobuf::Message for CreateDocParams {
 impl ::protobuf::Clear for CreateDocParams {
     fn clear(&mut self) {
         self.id.clear();
-        self.data.clear();
+        self.revisions.clear();
         self.unknown_fields.clear();
     }
 }
@@ -243,7 +243,7 @@ impl ::protobuf::reflect::ProtobufValue for CreateDocParams {
 pub struct Doc {
     // message fields
     pub id: ::std::string::String,
-    pub data: ::std::string::String,
+    pub text: ::std::string::String,
     pub rev_id: i64,
     pub base_rev_id: i64,
     // special fields
@@ -288,30 +288,30 @@ impl Doc {
         ::std::mem::replace(&mut self.id, ::std::string::String::new())
     }
 
-    // string data = 2;
+    // string text = 2;
 
 
-    pub fn get_data(&self) -> &str {
-        &self.data
+    pub fn get_text(&self) -> &str {
+        &self.text
     }
-    pub fn clear_data(&mut self) {
-        self.data.clear();
+    pub fn clear_text(&mut self) {
+        self.text.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_data(&mut self, v: ::std::string::String) {
-        self.data = v;
+    pub fn set_text(&mut self, v: ::std::string::String) {
+        self.text = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_data(&mut self) -> &mut ::std::string::String {
-        &mut self.data
+    pub fn mut_text(&mut self) -> &mut ::std::string::String {
+        &mut self.text
     }
 
     // Take field
-    pub fn take_data(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.data, ::std::string::String::new())
+    pub fn take_text(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.text, ::std::string::String::new())
     }
 
     // int64 rev_id = 3;
@@ -358,7 +358,7 @@ impl ::protobuf::Message for Doc {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.text)?;
                 },
                 3 => {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
@@ -389,8 +389,8 @@ impl ::protobuf::Message for Doc {
         if !self.id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.id);
         }
-        if !self.data.is_empty() {
-            my_size += ::protobuf::rt::string_size(2, &self.data);
+        if !self.text.is_empty() {
+            my_size += ::protobuf::rt::string_size(2, &self.text);
         }
         if self.rev_id != 0 {
             my_size += ::protobuf::rt::value_size(3, self.rev_id, ::protobuf::wire_format::WireTypeVarint);
@@ -407,8 +407,8 @@ impl ::protobuf::Message for Doc {
         if !self.id.is_empty() {
             os.write_string(1, &self.id)?;
         }
-        if !self.data.is_empty() {
-            os.write_string(2, &self.data)?;
+        if !self.text.is_empty() {
+            os.write_string(2, &self.text)?;
         }
         if self.rev_id != 0 {
             os.write_int64(3, self.rev_id)?;
@@ -460,9 +460,9 @@ impl ::protobuf::Message for Doc {
                 |m: &mut Doc| { &mut m.id },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "data",
-                |m: &Doc| { &m.data },
-                |m: &mut Doc| { &mut m.data },
+                "text",
+                |m: &Doc| { &m.text },
+                |m: &mut Doc| { &mut m.text },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
                 "rev_id",
@@ -491,7 +491,7 @@ impl ::protobuf::Message for Doc {
 impl ::protobuf::Clear for Doc {
     fn clear(&mut self) {
         self.id.clear();
-        self.data.clear();
+        self.text.clear();
         self.rev_id = 0;
         self.base_rev_id = 0;
         self.unknown_fields.clear();
@@ -511,24 +511,23 @@ impl ::protobuf::reflect::ProtobufValue for Doc {
 }
 
 #[derive(PartialEq,Clone,Default)]
-pub struct UpdateDocParams {
+pub struct ResetDocumentParams {
     // message fields
     pub doc_id: ::std::string::String,
-    pub data: ::std::string::String,
-    pub rev_id: i64,
+    pub revisions: ::protobuf::SingularPtrField<super::revision::RepeatedRevision>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a UpdateDocParams {
-    fn default() -> &'a UpdateDocParams {
-        <UpdateDocParams as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a ResetDocumentParams {
+    fn default() -> &'a ResetDocumentParams {
+        <ResetDocumentParams as ::protobuf::Message>::default_instance()
     }
 }
 
-impl UpdateDocParams {
-    pub fn new() -> UpdateDocParams {
+impl ResetDocumentParams {
+    pub fn new() -> ResetDocumentParams {
         ::std::default::Default::default()
     }
 
@@ -558,50 +557,47 @@ impl UpdateDocParams {
         ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
     }
 
-    // string data = 2;
+    // .RepeatedRevision revisions = 2;
 
 
-    pub fn get_data(&self) -> &str {
-        &self.data
+    pub fn get_revisions(&self) -> &super::revision::RepeatedRevision {
+        self.revisions.as_ref().unwrap_or_else(|| <super::revision::RepeatedRevision as ::protobuf::Message>::default_instance())
     }
-    pub fn clear_data(&mut self) {
-        self.data.clear();
+    pub fn clear_revisions(&mut self) {
+        self.revisions.clear();
+    }
+
+    pub fn has_revisions(&self) -> bool {
+        self.revisions.is_some()
     }
 
     // Param is passed by value, moved
-    pub fn set_data(&mut self, v: ::std::string::String) {
-        self.data = v;
+    pub fn set_revisions(&mut self, v: super::revision::RepeatedRevision) {
+        self.revisions = ::protobuf::SingularPtrField::some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_data(&mut self) -> &mut ::std::string::String {
-        &mut self.data
+    pub fn mut_revisions(&mut self) -> &mut super::revision::RepeatedRevision {
+        if self.revisions.is_none() {
+            self.revisions.set_default();
+        }
+        self.revisions.as_mut().unwrap()
     }
 
     // Take field
-    pub fn take_data(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.data, ::std::string::String::new())
-    }
-
-    // int64 rev_id = 3;
-
-
-    pub fn get_rev_id(&self) -> i64 {
-        self.rev_id
-    }
-    pub fn clear_rev_id(&mut self) {
-        self.rev_id = 0;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_rev_id(&mut self, v: i64) {
-        self.rev_id = v;
+    pub fn take_revisions(&mut self) -> super::revision::RepeatedRevision {
+        self.revisions.take().unwrap_or_else(|| super::revision::RepeatedRevision::new())
     }
 }
 
-impl ::protobuf::Message for UpdateDocParams {
+impl ::protobuf::Message for ResetDocumentParams {
     fn is_initialized(&self) -> bool {
+        for v in &self.revisions {
+            if !v.is_initialized() {
+                return false;
+            }
+        };
         true
     }
 
@@ -613,14 +609,7 @@ impl ::protobuf::Message for UpdateDocParams {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
-                },
-                3 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int64()?;
-                    self.rev_id = tmp;
+                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.revisions)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -637,11 +626,9 @@ impl ::protobuf::Message for UpdateDocParams {
         if !self.doc_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.doc_id);
         }
-        if !self.data.is_empty() {
-            my_size += ::protobuf::rt::string_size(2, &self.data);
-        }
-        if self.rev_id != 0 {
-            my_size += ::protobuf::rt::value_size(3, self.rev_id, ::protobuf::wire_format::WireTypeVarint);
+        if let Some(ref v) = self.revisions.as_ref() {
+            let len = v.compute_size();
+            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -652,11 +639,10 @@ impl ::protobuf::Message for UpdateDocParams {
         if !self.doc_id.is_empty() {
             os.write_string(1, &self.doc_id)?;
         }
-        if !self.data.is_empty() {
-            os.write_string(2, &self.data)?;
-        }
-        if self.rev_id != 0 {
-            os.write_int64(3, self.rev_id)?;
+        if let Some(ref v) = self.revisions.as_ref() {
+            os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
+            os.write_raw_varint32(v.get_cached_size())?;
+            v.write_to_with_cached_sizes(os)?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -688,8 +674,8 @@ impl ::protobuf::Message for UpdateDocParams {
         Self::descriptor_static()
     }
 
-    fn new() -> UpdateDocParams {
-        UpdateDocParams::new()
+    fn new() -> ResetDocumentParams {
+        ResetDocumentParams::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -698,49 +684,43 @@ impl ::protobuf::Message for UpdateDocParams {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "doc_id",
-                |m: &UpdateDocParams| { &m.doc_id },
-                |m: &mut UpdateDocParams| { &mut m.doc_id },
-            ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "data",
-                |m: &UpdateDocParams| { &m.data },
-                |m: &mut UpdateDocParams| { &mut m.data },
+                |m: &ResetDocumentParams| { &m.doc_id },
+                |m: &mut ResetDocumentParams| { &mut m.doc_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
-                "rev_id",
-                |m: &UpdateDocParams| { &m.rev_id },
-                |m: &mut UpdateDocParams| { &mut m.rev_id },
+            fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::revision::RepeatedRevision>>(
+                "revisions",
+                |m: &ResetDocumentParams| { &m.revisions },
+                |m: &mut ResetDocumentParams| { &mut m.revisions },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<UpdateDocParams>(
-                "UpdateDocParams",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<ResetDocumentParams>(
+                "ResetDocumentParams",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static UpdateDocParams {
-        static instance: ::protobuf::rt::LazyV2<UpdateDocParams> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(UpdateDocParams::new)
+    fn default_instance() -> &'static ResetDocumentParams {
+        static instance: ::protobuf::rt::LazyV2<ResetDocumentParams> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(ResetDocumentParams::new)
     }
 }
 
-impl ::protobuf::Clear for UpdateDocParams {
+impl ::protobuf::Clear for ResetDocumentParams {
     fn clear(&mut self) {
         self.doc_id.clear();
-        self.data.clear();
-        self.rev_id = 0;
+        self.revisions.clear();
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for UpdateDocParams {
+impl ::std::fmt::Debug for ResetDocumentParams {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for UpdateDocParams {
+impl ::protobuf::reflect::ProtobufValue for ResetDocumentParams {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -1343,69 +1323,66 @@ impl ::protobuf::reflect::ProtobufValue for DocIdentifier {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\tdoc.proto\x1a\x0erevision.proto\"H\n\x0fCreateDocParams\x12\x0e\n\
-    \x02id\x18\x01\x20\x01(\tR\x02id\x12%\n\x04data\x18\x02\x20\x01(\x0b2\
-    \x11.RepeatedRevisionR\x04data\"`\n\x03Doc\x12\x0e\n\x02id\x18\x01\x20\
-    \x01(\tR\x02id\x12\x12\n\x04data\x18\x02\x20\x01(\tR\x04data\x12\x15\n\
-    \x06rev_id\x18\x03\x20\x01(\x03R\x05revId\x12\x1e\n\x0bbase_rev_id\x18\
-    \x04\x20\x01(\x03R\tbaseRevId\"S\n\x0fUpdateDocParams\x12\x15\n\x06doc_i\
-    d\x18\x01\x20\x01(\tR\x05docId\x12\x12\n\x04data\x18\x02\x20\x01(\tR\x04\
-    data\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\x05revId\"5\n\x08DocDelta\
-    \x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x12\n\x04data\x18\
-    \x02\x20\x01(\tR\x04data\"S\n\nNewDocUser\x12\x17\n\x07user_id\x18\x01\
-    \x20\x01(\tR\x06userId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\x03R\x05revI\
-    d\x12\x15\n\x06doc_id\x18\x03\x20\x01(\tR\x05docId\"&\n\rDocIdentifier\
-    \x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docIdJ\xe6\x07\n\x06\x12\x04\
-    \0\0\x1d\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\0\x12\x03\x01\
-    \0\x18\n\n\n\x02\x04\0\x12\x04\x03\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\
-    \x03\x08\x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x04\x04\x12\n\x0c\n\x05\x04\
-    \0\x02\0\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x04\
-    \x0b\r\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x04\x10\x11\n\x0b\n\x04\x04\0\
-    \x02\x01\x12\x03\x05\x04\x1e\n\x0c\n\x05\x04\0\x02\x01\x06\x12\x03\x05\
-    \x04\x14\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x05\x15\x19\n\x0c\n\x05\
-    \x04\0\x02\x01\x03\x12\x03\x05\x1c\x1d\n\n\n\x02\x04\x01\x12\x04\x07\0\
-    \x0c\x01\n\n\n\x03\x04\x01\x01\x12\x03\x07\x08\x0b\n\x0b\n\x04\x04\x01\
-    \x02\0\x12\x03\x08\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x08\x04\
-    \n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x08\x0b\r\n\x0c\n\x05\x04\x01\
-    \x02\0\x03\x12\x03\x08\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\t\x04\
-    \x14\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\
-    \x02\x01\x01\x12\x03\t\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\t\
-    \x12\x13\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\n\x04\x15\n\x0c\n\x05\x04\
-    \x01\x02\x02\x05\x12\x03\n\x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\
-    \n\n\x10\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\n\x13\x14\n\x0b\n\x04\
-    \x04\x01\x02\x03\x12\x03\x0b\x04\x1a\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\
-    \x03\x0b\x04\t\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\x0b\n\x15\n\x0c\n\
-    \x05\x04\x01\x02\x03\x03\x12\x03\x0b\x18\x19\n\n\n\x02\x04\x02\x12\x04\r\
-    \0\x11\x01\n\n\n\x03\x04\x02\x01\x12\x03\r\x08\x17\n\x0b\n\x04\x04\x02\
-    \x02\0\x12\x03\x0e\x04\x16\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0e\x04\
-    \n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0e\x0b\x11\n\x0c\n\x05\x04\x02\
-    \x02\0\x03\x12\x03\x0e\x14\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0f\
-    \x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x0f\x04\n\n\x0c\n\x05\
-    \x04\x02\x02\x01\x01\x12\x03\x0f\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\
-    \x12\x03\x0f\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x10\x04\x15\n\
-    \x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x10\x04\t\n\x0c\n\x05\x04\x02\x02\
-    \x02\x01\x12\x03\x10\n\x10\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x10\
-    \x13\x14\n\n\n\x02\x04\x03\x12\x04\x12\0\x15\x01\n\n\n\x03\x04\x03\x01\
-    \x12\x03\x12\x08\x10\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x13\x04\x16\n\x0c\
-    \n\x05\x04\x03\x02\0\x05\x12\x03\x13\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\
-    \x12\x03\x13\x0b\x11\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x13\x14\x15\n\
-    \x0b\n\x04\x04\x03\x02\x01\x12\x03\x14\x04\x14\n\x0c\n\x05\x04\x03\x02\
-    \x01\x05\x12\x03\x14\x04\n\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x14\
-    \x0b\x0f\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x14\x12\x13\n\n\n\x02\
-    \x04\x04\x12\x04\x16\0\x1a\x01\n\n\n\x03\x04\x04\x01\x12\x03\x16\x08\x12\
-    \n\x0b\n\x04\x04\x04\x02\0\x12\x03\x17\x04\x17\n\x0c\n\x05\x04\x04\x02\0\
-    \x05\x12\x03\x17\x04\n\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03\x17\x0b\x12\
-    \n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x17\x15\x16\n\x0b\n\x04\x04\x04\
-    \x02\x01\x12\x03\x18\x04\x15\n\x0c\n\x05\x04\x04\x02\x01\x05\x12\x03\x18\
-    \x04\t\n\x0c\n\x05\x04\x04\x02\x01\x01\x12\x03\x18\n\x10\n\x0c\n\x05\x04\
-    \x04\x02\x01\x03\x12\x03\x18\x13\x14\n\x0b\n\x04\x04\x04\x02\x02\x12\x03\
-    \x19\x04\x16\n\x0c\n\x05\x04\x04\x02\x02\x05\x12\x03\x19\x04\n\n\x0c\n\
-    \x05\x04\x04\x02\x02\x01\x12\x03\x19\x0b\x11\n\x0c\n\x05\x04\x04\x02\x02\
-    \x03\x12\x03\x19\x14\x15\n\n\n\x02\x04\x05\x12\x04\x1b\0\x1d\x01\n\n\n\
-    \x03\x04\x05\x01\x12\x03\x1b\x08\x15\n\x0b\n\x04\x04\x05\x02\0\x12\x03\
-    \x1c\x04\x16\n\x0c\n\x05\x04\x05\x02\0\x05\x12\x03\x1c\x04\n\n\x0c\n\x05\
-    \x04\x05\x02\0\x01\x12\x03\x1c\x0b\x11\n\x0c\n\x05\x04\x05\x02\0\x03\x12\
-    \x03\x1c\x14\x15b\x06proto3\
+    \n\tdoc.proto\x1a\x0erevision.proto\"R\n\x0fCreateDocParams\x12\x0e\n\
+    \x02id\x18\x01\x20\x01(\tR\x02id\x12/\n\trevisions\x18\x02\x20\x01(\x0b2\
+    \x11.RepeatedRevisionR\trevisions\"`\n\x03Doc\x12\x0e\n\x02id\x18\x01\
+    \x20\x01(\tR\x02id\x12\x12\n\x04text\x18\x02\x20\x01(\tR\x04text\x12\x15\
+    \n\x06rev_id\x18\x03\x20\x01(\x03R\x05revId\x12\x1e\n\x0bbase_rev_id\x18\
+    \x04\x20\x01(\x03R\tbaseRevId\"]\n\x13ResetDocumentParams\x12\x15\n\x06d\
+    oc_id\x18\x01\x20\x01(\tR\x05docId\x12/\n\trevisions\x18\x02\x20\x01(\
+    \x0b2\x11.RepeatedRevisionR\trevisions\"5\n\x08DocDelta\x12\x15\n\x06doc\
+    _id\x18\x01\x20\x01(\tR\x05docId\x12\x12\n\x04data\x18\x02\x20\x01(\tR\
+    \x04data\"S\n\nNewDocUser\x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06us\
+    erId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\x03R\x05revId\x12\x15\n\x06doc\
+    _id\x18\x03\x20\x01(\tR\x05docId\"&\n\rDocIdentifier\x12\x15\n\x06doc_id\
+    \x18\x01\x20\x01(\tR\x05docIdJ\xaf\x07\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\
+    \x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\0\x12\x03\x01\0\x18\n\n\n\x02\x04\
+    \0\x12\x04\x03\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x03\x08\x17\n\x0b\n\
+    \x04\x04\0\x02\0\x12\x03\x04\x04\x12\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\
+    \x04\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x04\x0b\r\n\x0c\n\x05\x04\
+    \0\x02\0\x03\x12\x03\x04\x10\x11\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x05\
+    \x04#\n\x0c\n\x05\x04\0\x02\x01\x06\x12\x03\x05\x04\x14\n\x0c\n\x05\x04\
+    \0\x02\x01\x01\x12\x03\x05\x15\x1e\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\
+    \x05!\"\n\n\n\x02\x04\x01\x12\x04\x07\0\x0c\x01\n\n\n\x03\x04\x01\x01\
+    \x12\x03\x07\x08\x0b\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x08\x04\x12\n\x0c\
+    \n\x05\x04\x01\x02\0\x05\x12\x03\x08\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
+    \x12\x03\x08\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x08\x10\x11\n\
+    \x0b\n\x04\x04\x01\x02\x01\x12\x03\t\x04\x14\n\x0c\n\x05\x04\x01\x02\x01\
+    \x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\t\x0b\x0f\n\
+    \x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\t\x12\x13\n\x0b\n\x04\x04\x01\x02\
+    \x02\x12\x03\n\x04\x15\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\n\x04\t\n\
+    \x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\n\n\x10\n\x0c\n\x05\x04\x01\x02\
+    \x02\x03\x12\x03\n\x13\x14\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\x0b\x04\
+    \x1a\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\x0b\x04\t\n\x0c\n\x05\x04\
+    \x01\x02\x03\x01\x12\x03\x0b\n\x15\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\
+    \x03\x0b\x18\x19\n\n\n\x02\x04\x02\x12\x04\r\0\x10\x01\n\n\n\x03\x04\x02\
+    \x01\x12\x03\r\x08\x1b\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0e\x04\x16\n\
+    \x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0e\x04\n\n\x0c\n\x05\x04\x02\x02\0\
+    \x01\x12\x03\x0e\x0b\x11\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0e\x14\
+    \x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0f\x04#\n\x0c\n\x05\x04\x02\
+    \x02\x01\x06\x12\x03\x0f\x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\
+    \x0f\x15\x1e\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0f!\"\n\n\n\x02\
+    \x04\x03\x12\x04\x11\0\x14\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\x10\
+    \n\x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x16\n\x0c\n\x05\x04\x03\x02\0\
+    \x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x0b\x11\
+    \n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x12\x14\x15\n\x0b\n\x04\x04\x03\
+    \x02\x01\x12\x03\x13\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x13\
+    \x04\n\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x13\x0b\x0f\n\x0c\n\x05\
+    \x04\x03\x02\x01\x03\x12\x03\x13\x12\x13\n\n\n\x02\x04\x04\x12\x04\x15\0\
+    \x19\x01\n\n\n\x03\x04\x04\x01\x12\x03\x15\x08\x12\n\x0b\n\x04\x04\x04\
+    \x02\0\x12\x03\x16\x04\x17\n\x0c\n\x05\x04\x04\x02\0\x05\x12\x03\x16\x04\
+    \n\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03\x16\x0b\x12\n\x0c\n\x05\x04\x04\
+    \x02\0\x03\x12\x03\x16\x15\x16\n\x0b\n\x04\x04\x04\x02\x01\x12\x03\x17\
+    \x04\x15\n\x0c\n\x05\x04\x04\x02\x01\x05\x12\x03\x17\x04\t\n\x0c\n\x05\
+    \x04\x04\x02\x01\x01\x12\x03\x17\n\x10\n\x0c\n\x05\x04\x04\x02\x01\x03\
+    \x12\x03\x17\x13\x14\n\x0b\n\x04\x04\x04\x02\x02\x12\x03\x18\x04\x16\n\
+    \x0c\n\x05\x04\x04\x02\x02\x05\x12\x03\x18\x04\n\n\x0c\n\x05\x04\x04\x02\
+    \x02\x01\x12\x03\x18\x0b\x11\n\x0c\n\x05\x04\x04\x02\x02\x03\x12\x03\x18\
+    \x14\x15\n\n\n\x02\x04\x05\x12\x04\x1a\0\x1c\x01\n\n\n\x03\x04\x05\x01\
+    \x12\x03\x1a\x08\x15\n\x0b\n\x04\x04\x05\x02\0\x12\x03\x1b\x04\x16\n\x0c\
+    \n\x05\x04\x05\x02\0\x05\x12\x03\x1b\x04\n\n\x0c\n\x05\x04\x05\x02\0\x01\
+    \x12\x03\x1b\x0b\x11\n\x0c\n\x05\x04\x05\x02\0\x03\x12\x03\x1b\x14\x15b\
+    \x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 4 - 5
shared-lib/flowy-collaboration/src/protobuf/proto/doc.proto

@@ -3,18 +3,17 @@ import "revision.proto";
 
 message CreateDocParams {
     string id = 1;
-    RepeatedRevision data = 2;
+    RepeatedRevision revisions = 2;
 }
 message Doc {
     string id = 1;
-    string data = 2;
+    string text = 2;
     int64 rev_id = 3;
     int64 base_rev_id = 4;
 }
-message UpdateDocParams {
+message ResetDocumentParams {
     string doc_id = 1;
-    string data = 2;
-    int64 rev_id = 3;
+    RepeatedRevision revisions = 2;
 }
 message DocDelta {
     string doc_id = 1;

+ 1 - 5
shared-lib/flowy-core-data-model/src/entities/view/view_create.rs

@@ -7,7 +7,7 @@ use crate::{
         view::{ViewName, ViewThumbnail},
     },
 };
-use flowy_collaboration::core::document::default::initial_string;
+
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use std::convert::TryInto;
 
@@ -68,9 +68,6 @@ pub struct CreateViewParams {
 
     #[pb(index = 5)]
     pub view_type: ViewType,
-
-    #[pb(index = 6)]
-    pub data: String,
 }
 
 impl CreateViewParams {
@@ -81,7 +78,6 @@ impl CreateViewParams {
             desc,
             thumbnail,
             view_type,
-            data: initial_string(),
         }
     }
 }

+ 78 - 124
shared-lib/flowy-core-data-model/src/protobuf/model/view_create.rs

@@ -387,7 +387,6 @@ pub struct CreateViewParams {
     pub desc: ::std::string::String,
     pub thumbnail: ::std::string::String,
     pub view_type: ViewType,
-    pub data: ::std::string::String,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -522,32 +521,6 @@ impl CreateViewParams {
     pub fn set_view_type(&mut self, v: ViewType) {
         self.view_type = v;
     }
-
-    // string data = 6;
-
-
-    pub fn get_data(&self) -> &str {
-        &self.data
-    }
-    pub fn clear_data(&mut self) {
-        self.data.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_data(&mut self, v: ::std::string::String) {
-        self.data = v;
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_data(&mut self) -> &mut ::std::string::String {
-        &mut self.data
-    }
-
-    // Take field
-    pub fn take_data(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.data, ::std::string::String::new())
-    }
 }
 
 impl ::protobuf::Message for CreateViewParams {
@@ -574,9 +547,6 @@ impl ::protobuf::Message for CreateViewParams {
                 5 => {
                     ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.view_type, 5, &mut self.unknown_fields)?
                 },
-                6 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
-                },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
@@ -604,9 +574,6 @@ impl ::protobuf::Message for CreateViewParams {
         if self.view_type != ViewType::Blank {
             my_size += ::protobuf::rt::enum_size(5, self.view_type);
         }
-        if !self.data.is_empty() {
-            my_size += ::protobuf::rt::string_size(6, &self.data);
-        }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
@@ -628,9 +595,6 @@ impl ::protobuf::Message for CreateViewParams {
         if self.view_type != ViewType::Blank {
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
         }
-        if !self.data.is_empty() {
-            os.write_string(6, &self.data)?;
-        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -694,11 +658,6 @@ impl ::protobuf::Message for CreateViewParams {
                 |m: &CreateViewParams| { &m.view_type },
                 |m: &mut CreateViewParams| { &mut m.view_type },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "data",
-                |m: &CreateViewParams| { &m.data },
-                |m: &mut CreateViewParams| { &mut m.data },
-            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateViewParams>(
                 "CreateViewParams",
                 fields,
@@ -720,7 +679,6 @@ impl ::protobuf::Clear for CreateViewParams {
         self.desc.clear();
         self.thumbnail.clear();
         self.view_type = ViewType::Blank;
-        self.data.clear();
         self.unknown_fields.clear();
     }
 }
@@ -1436,92 +1394,88 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     long_to_id\x18\x01\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x02\x20\
     \x01(\tR\x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x1e\n\
     \tthumbnail\x18\x04\x20\x01(\tH\0R\tthumbnail\x12&\n\tview_type\x18\x05\
-    \x20\x01(\x0e2\t.ViewTypeR\x08viewTypeB\x12\n\x10one_of_thumbnail\"\xb6\
+    \x20\x01(\x0e2\t.ViewTypeR\x08viewTypeB\x12\n\x10one_of_thumbnail\"\xa2\
     \x01\n\x10CreateViewParams\x12\x20\n\x0cbelong_to_id\x18\x01\x20\x01(\tR\
     \nbelongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04\
     desc\x18\x03\x20\x01(\tR\x04desc\x12\x1c\n\tthumbnail\x18\x04\x20\x01(\t\
     R\tthumbnail\x12&\n\tview_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08view\
-    Type\x12\x12\n\x04data\x18\x06\x20\x01(\tR\x04data\"\x97\x02\n\x04View\
-    \x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x20\n\x0cbelong_to_id\x18\
-    \x02\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04na\
-    me\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04desc\x12&\n\tview_type\x18\
-    \x05\x20\x01(\x0e2\t.ViewTypeR\x08viewType\x12\x18\n\x07version\x18\x06\
-    \x20\x01(\x03R\x07version\x12-\n\nbelongings\x18\x07\x20\x01(\x0b2\r.Rep\
-    eatedViewR\nbelongings\x12#\n\rmodified_time\x18\x08\x20\x01(\x03R\x0cmo\
-    difiedTime\x12\x1f\n\x0bcreate_time\x18\t\x20\x01(\x03R\ncreateTime\"+\n\
-    \x0cRepeatedView\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.ViewR\x05i\
-    tems*\x1e\n\x08ViewType\x12\t\n\x05Blank\x10\0\x12\x07\n\x03Doc\x10\x01J\
-    \x88\x0b\n\x06\x12\x04\0\0\"\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\
-    \x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\
-    \n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x1c\n\x0c\n\x05\x04\0\x02\0\x05\
-    \x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x17\n\x0c\
-    \n\x05\x04\0\x02\0\x03\x12\x03\x03\x1a\x1b\n\x0b\n\x04\x04\0\x02\x01\x12\
-    \x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\
-    \x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\
-    \x12\x03\x04\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x14\n\x0c\
-    \n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\
-    \x12\x03\x05\x0b\x0f\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x12\x13\n\
-    \x0b\n\x04\x04\0\x08\0\x12\x03\x06\x044\n\x0c\n\x05\x04\0\x08\0\x01\x12\
-    \x03\x06\n\x1a\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\
-    \x04\0\x02\x03\x05\x12\x03\x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\
-    \x03\x06$-\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\
-    \x02\x04\x12\x03\x07\x04\x1b\n\x0c\n\x05\x04\0\x02\x04\x06\x12\x03\x07\
-    \x04\x0c\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\r\x16\n\x0c\n\x05\x04\
-    \0\x02\x04\x03\x12\x03\x07\x19\x1a\n\n\n\x02\x04\x01\x12\x04\t\0\x10\x01\
-    \n\n\n\x03\x04\x01\x01\x12\x03\t\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\
-    \x03\n\x04\x1c\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\
-    \x04\x01\x02\0\x01\x12\x03\n\x0b\x17\n\x0c\n\x05\x04\x01\x02\0\x03\x12\
-    \x03\n\x1a\x1b\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x04\x14\n\x0c\n\
-    \x05\x04\x01\x02\x01\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x01\x02\x01\
-    \x01\x12\x03\x0b\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\x12\
-    \x13\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x01\
-    \x02\x02\x05\x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\
-    \x0c\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0c\x12\x13\n\x0b\n\
-    \x04\x04\x01\x02\x03\x12\x03\r\x04\x19\n\x0c\n\x05\x04\x01\x02\x03\x05\
-    \x12\x03\r\x04\n\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\r\x0b\x14\n\x0c\
-    \n\x05\x04\x01\x02\x03\x03\x12\x03\r\x17\x18\n\x0b\n\x04\x04\x01\x02\x04\
-    \x12\x03\x0e\x04\x1b\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0e\x04\x0c\
-    \n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\x0e\r\x16\n\x0c\n\x05\x04\x01\
-    \x02\x04\x03\x12\x03\x0e\x19\x1a\n\x0b\n\x04\x04\x01\x02\x05\x12\x03\x0f\
-    \x04\x14\n\x0c\n\x05\x04\x01\x02\x05\x05\x12\x03\x0f\x04\n\n\x0c\n\x05\
-    \x04\x01\x02\x05\x01\x12\x03\x0f\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x05\x03\
-    \x12\x03\x0f\x12\x13\n\n\n\x02\x04\x02\x12\x04\x11\0\x1b\x01\n\n\n\x03\
-    \x04\x02\x01\x12\x03\x11\x08\x0c\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x12\
-    \x04\x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\
-    \x02\x02\0\x01\x12\x03\x12\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\
-    \x12\x10\x11\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x13\x04\x1c\n\x0c\n\x05\
-    \x04\x02\x02\x01\x05\x12\x03\x13\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\
-    \x12\x03\x13\x0b\x17\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x13\x1a\x1b\
-    \n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x14\x04\x14\n\x0c\n\x05\x04\x02\x02\
-    \x02\x05\x12\x03\x14\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x14\
-    \x0b\x0f\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x14\x12\x13\n\x0b\n\x04\
-    \x04\x02\x02\x03\x12\x03\x15\x04\x14\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\
-    \x03\x15\x04\n\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x15\x0b\x0f\n\x0c\
-    \n\x05\x04\x02\x02\x03\x03\x12\x03\x15\x12\x13\n\x0b\n\x04\x04\x02\x02\
-    \x04\x12\x03\x16\x04\x1b\n\x0c\n\x05\x04\x02\x02\x04\x06\x12\x03\x16\x04\
-    \x0c\n\x0c\n\x05\x04\x02\x02\x04\x01\x12\x03\x16\r\x16\n\x0c\n\x05\x04\
-    \x02\x02\x04\x03\x12\x03\x16\x19\x1a\n\x0b\n\x04\x04\x02\x02\x05\x12\x03\
-    \x17\x04\x16\n\x0c\n\x05\x04\x02\x02\x05\x05\x12\x03\x17\x04\t\n\x0c\n\
-    \x05\x04\x02\x02\x05\x01\x12\x03\x17\n\x11\n\x0c\n\x05\x04\x02\x02\x05\
-    \x03\x12\x03\x17\x14\x15\n\x0b\n\x04\x04\x02\x02\x06\x12\x03\x18\x04\x20\
-    \n\x0c\n\x05\x04\x02\x02\x06\x06\x12\x03\x18\x04\x10\n\x0c\n\x05\x04\x02\
-    \x02\x06\x01\x12\x03\x18\x11\x1b\n\x0c\n\x05\x04\x02\x02\x06\x03\x12\x03\
-    \x18\x1e\x1f\n\x0b\n\x04\x04\x02\x02\x07\x12\x03\x19\x04\x1c\n\x0c\n\x05\
-    \x04\x02\x02\x07\x05\x12\x03\x19\x04\t\n\x0c\n\x05\x04\x02\x02\x07\x01\
-    \x12\x03\x19\n\x17\n\x0c\n\x05\x04\x02\x02\x07\x03\x12\x03\x19\x1a\x1b\n\
-    \x0b\n\x04\x04\x02\x02\x08\x12\x03\x1a\x04\x1a\n\x0c\n\x05\x04\x02\x02\
-    \x08\x05\x12\x03\x1a\x04\t\n\x0c\n\x05\x04\x02\x02\x08\x01\x12\x03\x1a\n\
-    \x15\n\x0c\n\x05\x04\x02\x02\x08\x03\x12\x03\x1a\x18\x19\n\n\n\x02\x04\
-    \x03\x12\x04\x1c\0\x1e\x01\n\n\n\x03\x04\x03\x01\x12\x03\x1c\x08\x14\n\
-    \x0b\n\x04\x04\x03\x02\0\x12\x03\x1d\x04\x1c\n\x0c\n\x05\x04\x03\x02\0\
-    \x04\x12\x03\x1d\x04\x0c\n\x0c\n\x05\x04\x03\x02\0\x06\x12\x03\x1d\r\x11\
-    \n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x1d\x12\x17\n\x0c\n\x05\x04\x03\
-    \x02\0\x03\x12\x03\x1d\x1a\x1b\n\n\n\x02\x05\0\x12\x04\x1f\0\"\x01\n\n\n\
-    \x03\x05\0\x01\x12\x03\x1f\x05\r\n\x0b\n\x04\x05\0\x02\0\x12\x03\x20\x04\
-    \x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x20\x04\t\n\x0c\n\x05\x05\0\x02\
-    \0\x02\x12\x03\x20\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03!\x04\x0c\n\
-    \x0c\n\x05\x05\0\x02\x01\x01\x12\x03!\x04\x07\n\x0c\n\x05\x05\0\x02\x01\
-    \x02\x12\x03!\n\x0bb\x06proto3\
+    Type\"\x97\x02\n\x04View\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\
+    \x20\n\x0cbelong_to_id\x18\x02\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\
+    \x18\x03\x20\x01(\tR\x04name\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04de\
+    sc\x12&\n\tview_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08viewType\x12\
+    \x18\n\x07version\x18\x06\x20\x01(\x03R\x07version\x12-\n\nbelongings\
+    \x18\x07\x20\x01(\x0b2\r.RepeatedViewR\nbelongings\x12#\n\rmodified_time\
+    \x18\x08\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcreate_time\x18\t\
+    \x20\x01(\x03R\ncreateTime\"+\n\x0cRepeatedView\x12\x1b\n\x05items\x18\
+    \x01\x20\x03(\x0b2\x05.ViewR\x05items*\x1e\n\x08ViewType\x12\t\n\x05Blan\
+    k\x10\0\x12\x07\n\x03Doc\x10\x01J\xd1\n\n\x06\x12\x04\0\0!\x01\n\x08\n\
+    \x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\
+    \x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\
+    \x1c\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\
+    \0\x01\x12\x03\x03\x0b\x17\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x1a\
+    \x1b\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\
+    \x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\
+    \x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x12\x13\n\x0b\n\x04\x04\0\
+    \x02\x02\x12\x03\x05\x04\x14\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\
+    \x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x0f\n\x0c\n\x05\x04\
+    \0\x02\x02\x03\x12\x03\x05\x12\x13\n\x0b\n\x04\x04\0\x08\0\x12\x03\x06\
+    \x044\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x06\n\x1a\n\x0b\n\x04\x04\0\
+    \x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x1d#\
+    \n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\x05\x04\0\x02\x03\
+    \x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x04\x1b\n\x0c\n\
+    \x05\x04\0\x02\x04\x06\x12\x03\x07\x04\x0c\n\x0c\n\x05\x04\0\x02\x04\x01\
+    \x12\x03\x07\r\x16\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07\x19\x1a\n\n\
+    \n\x02\x04\x01\x12\x04\t\0\x0f\x01\n\n\n\x03\x04\x01\x01\x12\x03\t\x08\
+    \x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\x1c\n\x0c\n\x05\x04\x01\x02\
+    \0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\n\x0b\x17\n\
+    \x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x1a\x1b\n\x0b\n\x04\x04\x01\x02\
+    \x01\x12\x03\x0b\x04\x14\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x0b\x04\
+    \n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\x0b\x0f\n\x0c\n\x05\x04\
+    \x01\x02\x01\x03\x12\x03\x0b\x12\x13\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\
+    \x0c\x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0c\x04\n\n\x0c\n\
+    \x05\x04\x01\x02\x02\x01\x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x02\
+    \x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\r\x04\x19\n\
+    \x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x01\x02\
+    \x03\x01\x12\x03\r\x0b\x14\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\r\x17\
+    \x18\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\x04\x1b\n\x0c\n\x05\x04\x01\
+    \x02\x04\x06\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\
+    \x0e\r\x16\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\x03\x0e\x19\x1a\n\n\n\x02\
+    \x04\x02\x12\x04\x10\0\x1a\x01\n\n\n\x03\x04\x02\x01\x12\x03\x10\x08\x0c\
+    \n\x0b\n\x04\x04\x02\x02\0\x12\x03\x11\x04\x12\n\x0c\n\x05\x04\x02\x02\0\
+    \x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x11\x0b\r\n\
+    \x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x11\x10\x11\n\x0b\n\x04\x04\x02\x02\
+    \x01\x12\x03\x12\x04\x1c\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x12\x04\
+    \n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x12\x0b\x17\n\x0c\n\x05\x04\
+    \x02\x02\x01\x03\x12\x03\x12\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\
+    \x13\x04\x14\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x13\x04\n\n\x0c\n\
+    \x05\x04\x02\x02\x02\x01\x12\x03\x13\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x02\
+    \x03\x12\x03\x13\x12\x13\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x14\x04\x14\
+    \n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\x14\x04\n\n\x0c\n\x05\x04\x02\
+    \x02\x03\x01\x12\x03\x14\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\
+    \x14\x12\x13\n\x0b\n\x04\x04\x02\x02\x04\x12\x03\x15\x04\x1b\n\x0c\n\x05\
+    \x04\x02\x02\x04\x06\x12\x03\x15\x04\x0c\n\x0c\n\x05\x04\x02\x02\x04\x01\
+    \x12\x03\x15\r\x16\n\x0c\n\x05\x04\x02\x02\x04\x03\x12\x03\x15\x19\x1a\n\
+    \x0b\n\x04\x04\x02\x02\x05\x12\x03\x16\x04\x16\n\x0c\n\x05\x04\x02\x02\
+    \x05\x05\x12\x03\x16\x04\t\n\x0c\n\x05\x04\x02\x02\x05\x01\x12\x03\x16\n\
+    \x11\n\x0c\n\x05\x04\x02\x02\x05\x03\x12\x03\x16\x14\x15\n\x0b\n\x04\x04\
+    \x02\x02\x06\x12\x03\x17\x04\x20\n\x0c\n\x05\x04\x02\x02\x06\x06\x12\x03\
+    \x17\x04\x10\n\x0c\n\x05\x04\x02\x02\x06\x01\x12\x03\x17\x11\x1b\n\x0c\n\
+    \x05\x04\x02\x02\x06\x03\x12\x03\x17\x1e\x1f\n\x0b\n\x04\x04\x02\x02\x07\
+    \x12\x03\x18\x04\x1c\n\x0c\n\x05\x04\x02\x02\x07\x05\x12\x03\x18\x04\t\n\
+    \x0c\n\x05\x04\x02\x02\x07\x01\x12\x03\x18\n\x17\n\x0c\n\x05\x04\x02\x02\
+    \x07\x03\x12\x03\x18\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x08\x12\x03\x19\x04\
+    \x1a\n\x0c\n\x05\x04\x02\x02\x08\x05\x12\x03\x19\x04\t\n\x0c\n\x05\x04\
+    \x02\x02\x08\x01\x12\x03\x19\n\x15\n\x0c\n\x05\x04\x02\x02\x08\x03\x12\
+    \x03\x19\x18\x19\n\n\n\x02\x04\x03\x12\x04\x1b\0\x1d\x01\n\n\n\x03\x04\
+    \x03\x01\x12\x03\x1b\x08\x14\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x1c\x04\
+    \x1c\n\x0c\n\x05\x04\x03\x02\0\x04\x12\x03\x1c\x04\x0c\n\x0c\n\x05\x04\
+    \x03\x02\0\x06\x12\x03\x1c\r\x11\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\
+    \x1c\x12\x17\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x1c\x1a\x1b\n\n\n\x02\
+    \x05\0\x12\x04\x1e\0!\x01\n\n\n\x03\x05\0\x01\x12\x03\x1e\x05\r\n\x0b\n\
+    \x04\x05\0\x02\0\x12\x03\x1f\x04\x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\
+    \x1f\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x1f\x0c\r\n\x0b\n\x04\x05\
+    \0\x02\x01\x12\x03\x20\x04\x0c\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x20\
+    \x04\x07\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x20\n\x0bb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 0 - 1
shared-lib/flowy-core-data-model/src/protobuf/proto/view_create.proto

@@ -13,7 +13,6 @@ message CreateViewParams {
     string desc = 3;
     string thumbnail = 4;
     ViewType view_type = 5;
-    string data = 6;
 }
 message View {
     string id = 1;

+ 1 - 1
shared-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -33,7 +33,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "UpdateUserParams"
         | "CreateDocParams"
         | "Doc"
-        | "UpdateDocParams"
+        | "ResetDocumentParams"
         | "DocDelta"
         | "NewDocUser"
         | "DocIdentifier"

+ 1 - 1
shared-lib/lib-ot/src/errors.rs

@@ -99,7 +99,7 @@ impl ErrorBuilder {
     pub fn build(mut self) -> OTError { OTError::new(self.code, &self.msg.take().unwrap_or_else(|| "".to_owned())) }
 }
 
-pub fn internal_error<T>(e: T) -> OTError
+pub(crate) fn internal_error<T>(e: T) -> OTError
 where
     T: std::fmt::Debug,
 {

+ 1 - 1
shared-lib/lib-ws/src/errors.rs

@@ -45,7 +45,7 @@ impl WSError {
     static_ws_error!(unauthorized, ErrorCode::Unauthorized);
 }
 
-pub fn internal_error<T>(e: T) -> WSError
+pub(crate) fn internal_error<T>(e: T) -> WSError
 where
     T: std::fmt::Debug,
 {