From 03a70bbdb953a46bb771e1f6962125ad6b969d58 Mon Sep 17 00:00:00 2001
From: appflowy <annie@appflowy.io>
Date: Tue, 16 Aug 2022 11:37:34 +0800
Subject: [PATCH] chore: update grid migration

---
 .../src/services/persistence/migration.rs     |  20 +--
 frontend/rust-lib/flowy-grid/src/manager.rs   |   2 +-
 .../src/services/persistence/migration.rs     | 114 ++++++------------
 3 files changed, 49 insertions(+), 87 deletions(-)

diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs
index b8be0b1e19..7b211fb54a 100644
--- a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs
+++ b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs
@@ -5,15 +5,12 @@ use crate::{
 };
 use flowy_database::kv::KV;
 use flowy_error::{FlowyError, FlowyResult};
-
 use flowy_folder_data_model::revision::{AppRevision, FolderRevision, ViewRevision, WorkspaceRevision};
 use flowy_revision::disk::SQLiteTextBlockRevisionPersistence;
 use flowy_revision::reset::{RevisionResettable, RevisionStructReset};
-
 use flowy_sync::client_folder::make_folder_rev_json_str;
 use flowy_sync::entities::revision::Revision;
 use flowy_sync::{client_folder::FolderPad, entities::revision::md5};
-
 use std::sync::Arc;
 
 const V1_MIGRATION: &str = "FOLDER_V1_MIGRATION";
@@ -35,7 +32,7 @@ impl FolderMigration {
     }
 
     pub fn run_v1_migration(&self) -> FlowyResult<Option<FolderPad>> {
-        let key = md5(format!("{}{}", self.user_id, V1_MIGRATION));
+        let key = migration_flag_key(&self.user_id, V1_MIGRATION);
         if KV::get_bool(&key) {
             return Ok(None);
         }
@@ -86,28 +83,29 @@ impl FolderMigration {
     }
 
     pub async fn run_v2_migration(&self, folder_id: &FolderId) -> FlowyResult<()> {
-        let key = md5(format!("{}{}", self.user_id, V2_MIGRATION));
+        let key = migration_flag_key(&self.user_id, V2_MIGRATION);
         if KV::get_bool(&key) {
             return Ok(());
         }
-        let _ = self.migration_folder_rev_struct_if_need(folder_id).await?;
+        let _ = self.migration_folder_rev_struct(folder_id).await?;
         KV::set_bool(&key, true);
         tracing::trace!("Run folder v2 migration");
         Ok(())
     }
+
     #[allow(dead_code)]
     pub async fn run_v3_migration(&self, folder_id: &FolderId) -> FlowyResult<()> {
-        let key = md5(format!("{}{}", self.user_id, V3_MIGRATION));
+        let key = migration_flag_key(&self.user_id, V3_MIGRATION);
         if KV::get_bool(&key) {
             return Ok(());
         }
-        let _ = self.migration_folder_rev_struct_if_need(folder_id).await?;
+        let _ = self.migration_folder_rev_struct(folder_id).await?;
         KV::set_bool(&key, true);
         tracing::trace!("Run folder v3 migration");
         Ok(())
     }
 
-    pub async fn migration_folder_rev_struct_if_need(&self, folder_id: &FolderId) -> FlowyResult<()> {
+    pub async fn migration_folder_rev_struct(&self, folder_id: &FolderId) -> FlowyResult<()> {
         let object = FolderRevisionResettable {
             folder_id: folder_id.as_ref().to_owned(),
         };
@@ -119,6 +117,10 @@ impl FolderMigration {
     }
 }
 
+fn migration_flag_key(user_id: &str, version: &str) -> String {
+    md5(format!("{}{}", user_id, version,))
+}
+
 pub struct FolderRevisionResettable {
     folder_id: String,
 }
diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs
index 048fc58415..9e4556b793 100644
--- a/frontend/rust-lib/flowy-grid/src/manager.rs
+++ b/frontend/rust-lib/flowy-grid/src/manager.rs
@@ -96,7 +96,7 @@ impl GridManager {
     pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<GridRevisionEditor>> {
         let grid_id = grid_id.as_ref();
         tracing::Span::current().record("grid_id", &grid_id);
-        let _ = self.migration.migration_grid_if_need(grid_id).await;
+        let _ = self.migration.run_v1_migration(grid_id).await;
         self.get_or_create_grid_editor(grid_id).await
     }
 
diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs
index bf3aa7adfb..cb99d8eb6d 100644
--- a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs
@@ -1,19 +1,17 @@
 use crate::manager::GridUser;
-
 use crate::services::persistence::GridDatabase;
 use flowy_database::kv::KV;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::GridRevision;
-use flowy_revision::disk::{RevisionRecord, SQLiteGridRevisionPersistence};
-use flowy_revision::{mk_grid_block_revision_disk_cache, RevisionLoader, RevisionPersistence};
+use flowy_revision::disk::SQLiteGridRevisionPersistence;
+use flowy_revision::reset::{RevisionResettable, RevisionStructReset};
 use flowy_sync::client_grid::{make_grid_rev_json_str, GridRevisionPad};
 use flowy_sync::entities::revision::Revision;
-
-use lib_ot::core::TextDeltaBuilder;
-use serde::{Deserialize, Serialize};
-use std::str::FromStr;
+use flowy_sync::util::md5;
 use std::sync::Arc;
 
+const V1_MIGRATION: &str = "GRID_V1_MIGRATION";
+
 pub(crate) struct GridMigration {
     user: Arc<dyn GridUser>,
     database: Arc<dyn GridDatabase>,
@@ -24,90 +22,52 @@ impl GridMigration {
         Self { user, database }
     }
 
-    pub async fn migration_grid_if_need(&self, grid_id: &str) -> FlowyResult<()> {
-        match KV::get_str(grid_id) {
-            None => {
-                let _ = self.reset_grid_rev(grid_id).await?;
-                let _ = self.save_migrate_record(grid_id)?;
-            }
-            Some(s) => {
-                let mut record = MigrationGridRecord::from_str(&s)?;
-                let empty_json = self.empty_grid_rev_json()?;
-                if record.len < empty_json.len() {
-                    let _ = self.reset_grid_rev(grid_id).await?;
-                    record.len = empty_json.len();
-                    KV::set_str(grid_id, record.to_string());
-                }
-            }
-        }
-        Ok(())
-    }
-
-    async fn reset_grid_rev(&self, grid_id: &str) -> FlowyResult<()> {
+    pub async fn run_v1_migration(&self, grid_id: &str) -> FlowyResult<()> {
         let user_id = self.user.user_id()?;
-        let pool = self.database.db_pool()?;
-        let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?;
-        let json = grid_rev_pad.json_str()?;
-        let delta_data = TextDeltaBuilder::new().insert(&json).build().json_bytes();
-        let revision = Revision::initial_revision(&user_id, grid_id, delta_data);
-        let record = RevisionRecord::new(revision);
-        //
-        let disk_cache = mk_grid_block_revision_disk_cache(&user_id, pool);
-        let _ = disk_cache.delete_and_insert_records(grid_id, None, vec![record]);
+        let key = migration_flag_key(&user_id, V1_MIGRATION, grid_id);
+        if KV::get_bool(&key) {
+            return Ok(());
+        }
+        let _ = self.migration_grid_rev_struct(grid_id).await?;
+        tracing::trace!("Run grid:{} v1 migration", grid_id);
+        KV::set_bool(&key, true);
         Ok(())
     }
 
-    fn save_migrate_record(&self, grid_id: &str) -> FlowyResult<()> {
-        let empty_json_str = self.empty_grid_rev_json()?;
-        let record = MigrationGridRecord {
+    pub async fn migration_grid_rev_struct(&self, grid_id: &str) -> FlowyResult<()> {
+        let object = GridRevisionResettable {
             grid_id: grid_id.to_owned(),
-            len: empty_json_str.len(),
         };
-        KV::set_str(grid_id, record.to_string());
-        Ok(())
-    }
-
-    fn empty_grid_rev_json(&self) -> FlowyResult<String> {
-        let empty_grid_rev = GridRevision::default();
-        let empty_json = make_grid_rev_json_str(&empty_grid_rev)?;
-        Ok(empty_json)
-    }
-
-    async fn get_grid_revision_pad(&self, grid_id: &str) -> FlowyResult<GridRevisionPad> {
-        let pool = self.database.db_pool()?;
         let user_id = self.user.user_id()?;
+        let pool = self.database.db_pool()?;
         let disk_cache = SQLiteGridRevisionPersistence::new(&user_id, pool);
-        let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, disk_cache));
-        let (revisions, _) = RevisionLoader {
-            object_id: grid_id.to_owned(),
-            user_id,
-            cloud: None,
-            rev_persistence,
-        }
-        .load()
-        .await?;
-
-        let pad = GridRevisionPad::from_revisions(revisions)?;
-        Ok(pad)
+        let reset = RevisionStructReset::new(&user_id, object, Arc::new(disk_cache));
+        reset.run().await
     }
 }
 
-#[derive(Serialize, Deserialize)]
-struct MigrationGridRecord {
+fn migration_flag_key(user_id: &str, version: &str, grid_id: &str) -> String {
+    md5(format!("{}{}{}", user_id, version, grid_id,))
+}
+
+pub struct GridRevisionResettable {
     grid_id: String,
-    len: usize,
 }
 
-impl FromStr for MigrationGridRecord {
-    type Err = serde_json::Error;
+impl RevisionResettable for GridRevisionResettable {
+    fn target_id(&self) -> &str {
+        &self.grid_id
+    }
 
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        serde_json::from_str::<MigrationGridRecord>(s)
-    }
-}
-
-impl ToString for MigrationGridRecord {
-    fn to_string(&self) -> String {
-        serde_json::to_string(self).unwrap_or_else(|_| "".to_string())
+    fn target_reset_rev_str(&self, revisions: Vec<Revision>) -> FlowyResult<String> {
+        let pad = GridRevisionPad::from_revisions(revisions)?;
+        let json = pad.json_str()?;
+        Ok(json)
+    }
+
+    fn default_target_rev_str(&self) -> FlowyResult<String> {
+        let grid_rev = GridRevision::default();
+        let json = make_grid_rev_json_str(&grid_rev)?;
+        Ok(json)
     }
 }