migration.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. use crate::manager::FolderId;
  2. use crate::{
  3. event_map::WorkspaceDatabase,
  4. services::persistence::{AppTableSql, TrashTableSql, ViewTableSql, WorkspaceTableSql},
  5. };
  6. use flowy_database::kv::KV;
  7. use flowy_error::{FlowyError, FlowyResult};
  8. use flowy_folder_data_model::revision::{AppRevision, FolderRevision, ViewRevision, WorkspaceRevision};
  9. use flowy_revision::disk::SQLiteTextBlockRevisionPersistence;
  10. use flowy_revision::reset::{RevisionResettable, RevisionStructReset};
  11. use flowy_sync::client_folder::make_folder_rev_json_str;
  12. use flowy_sync::entities::revision::Revision;
  13. use flowy_sync::{client_folder::FolderPad, entities::revision::md5};
  14. use std::sync::Arc;
  15. const V1_MIGRATION: &str = "FOLDER_V1_MIGRATION";
  16. const V2_MIGRATION: &str = "FOLDER_V2_MIGRATION";
  17. #[allow(dead_code)]
  18. const V3_MIGRATION: &str = "FOLDER_V3_MIGRATION";
  19. pub(crate) struct FolderMigration {
  20. user_id: String,
  21. database: Arc<dyn WorkspaceDatabase>,
  22. }
  23. impl FolderMigration {
  24. pub fn new(user_id: &str, database: Arc<dyn WorkspaceDatabase>) -> Self {
  25. Self {
  26. user_id: user_id.to_owned(),
  27. database,
  28. }
  29. }
  30. pub fn run_v1_migration(&self) -> FlowyResult<Option<FolderPad>> {
  31. let key = md5(format!("{}{}", self.user_id, V1_MIGRATION));
  32. if KV::get_bool(&key) {
  33. return Ok(None);
  34. }
  35. let pool = self.database.db_pool()?;
  36. let conn = &*pool.get()?;
  37. let workspaces = conn.immediate_transaction::<_, FlowyError, _>(|| {
  38. let mut workspaces = WorkspaceTableSql::read_workspaces(&self.user_id, None, conn)?
  39. .into_iter()
  40. .map(WorkspaceRevision::from)
  41. .collect::<Vec<_>>();
  42. for workspace in workspaces.iter_mut() {
  43. let mut apps = AppTableSql::read_workspace_apps(&workspace.id, conn)?
  44. .into_iter()
  45. .map(AppRevision::from)
  46. .collect::<Vec<_>>();
  47. for app in apps.iter_mut() {
  48. let views = ViewTableSql::read_views(&app.id, conn)?
  49. .into_iter()
  50. .map(ViewRevision::from)
  51. .collect::<Vec<_>>();
  52. app.belongings = views;
  53. }
  54. workspace.apps = apps;
  55. }
  56. Ok(workspaces)
  57. })?;
  58. if workspaces.is_empty() {
  59. tracing::trace!("Run folder v1 migration, but workspace is empty");
  60. KV::set_bool(&key, true);
  61. return Ok(None);
  62. }
  63. let trash = conn.immediate_transaction::<_, FlowyError, _>(|| {
  64. let trash = TrashTableSql::read_all(conn)?;
  65. Ok(trash)
  66. })?;
  67. let folder = FolderPad::new(workspaces, trash)?;
  68. KV::set_bool(&key, true);
  69. tracing::trace!("Run folder v1 migration");
  70. Ok(Some(folder))
  71. }
  72. pub async fn run_v2_migration(&self, folder_id: &FolderId) -> FlowyResult<()> {
  73. let key = md5(format!("{}{}", self.user_id, V2_MIGRATION));
  74. if KV::get_bool(&key) {
  75. return Ok(());
  76. }
  77. let _ = self.migration_folder_rev_struct_if_need(folder_id).await?;
  78. KV::set_bool(&key, true);
  79. tracing::trace!("Run folder v2 migration");
  80. Ok(())
  81. }
  82. #[allow(dead_code)]
  83. pub async fn run_v3_migration(&self, folder_id: &FolderId) -> FlowyResult<()> {
  84. let key = md5(format!("{}{}", self.user_id, V3_MIGRATION));
  85. if KV::get_bool(&key) {
  86. return Ok(());
  87. }
  88. let _ = self.migration_folder_rev_struct_if_need(folder_id).await?;
  89. KV::set_bool(&key, true);
  90. tracing::trace!("Run folder v3 migration");
  91. Ok(())
  92. }
  93. pub async fn migration_folder_rev_struct_if_need(&self, folder_id: &FolderId) -> FlowyResult<()> {
  94. let object = FolderRevisionResettable {
  95. folder_id: folder_id.as_ref().to_owned(),
  96. };
  97. let pool = self.database.db_pool()?;
  98. let disk_cache = SQLiteTextBlockRevisionPersistence::new(&self.user_id, pool);
  99. let reset = RevisionStructReset::new(&self.user_id, object, Arc::new(disk_cache));
  100. reset.run().await
  101. }
  102. }
  103. pub struct FolderRevisionResettable {
  104. folder_id: String,
  105. }
  106. impl RevisionResettable for FolderRevisionResettable {
  107. fn target_id(&self) -> &str {
  108. &self.folder_id
  109. }
  110. fn target_reset_rev_str(&self, revisions: Vec<Revision>) -> FlowyResult<String> {
  111. let pad = FolderPad::from_revisions(revisions)?;
  112. let json = pad.to_json()?;
  113. Ok(json)
  114. }
  115. fn default_target_rev_str(&self) -> FlowyResult<String> {
  116. let folder = FolderRevision::default();
  117. let json = make_folder_rev_json_str(&folder)?;
  118. Ok(json)
  119. }
  120. }