migration.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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, ViewRevision, WorkspaceRevision};
  9. use flowy_revision::disk::SQLiteTextBlockRevisionPersistence;
  10. use flowy_revision::{RevisionLoader, RevisionPersistence};
  11. use flowy_sync::{client_folder::FolderPad, entities::revision::md5};
  12. use std::sync::Arc;
  13. const V1_MIGRATION: &str = "FOLDER_V1_MIGRATION";
  14. const V2_MIGRATION: &str = "FOLDER_V2_MIGRATION";
  15. pub(crate) struct FolderMigration {
  16. user_id: String,
  17. database: Arc<dyn WorkspaceDatabase>,
  18. }
  19. impl FolderMigration {
  20. pub fn new(user_id: &str, database: Arc<dyn WorkspaceDatabase>) -> Self {
  21. Self {
  22. user_id: user_id.to_owned(),
  23. database,
  24. }
  25. }
  26. pub fn run_v1_migration(&self) -> FlowyResult<Option<FolderPad>> {
  27. let key = md5(format!("{}{}", self.user_id, V1_MIGRATION));
  28. if KV::get_bool(&key) {
  29. return Ok(None);
  30. }
  31. let pool = self.database.db_pool()?;
  32. let conn = &*pool.get()?;
  33. let workspaces = conn.immediate_transaction::<_, FlowyError, _>(|| {
  34. let mut workspaces = WorkspaceTableSql::read_workspaces(&self.user_id, None, conn)?
  35. .into_iter()
  36. .map(WorkspaceRevision::from)
  37. .collect::<Vec<_>>();
  38. for workspace in workspaces.iter_mut() {
  39. let mut apps = AppTableSql::read_workspace_apps(&workspace.id, conn)?
  40. .into_iter()
  41. .map(AppRevision::from)
  42. .collect::<Vec<_>>();
  43. for app in apps.iter_mut() {
  44. let views = ViewTableSql::read_views(&app.id, conn)?
  45. .into_iter()
  46. .map(ViewRevision::from)
  47. .collect::<Vec<_>>();
  48. app.belongings = views;
  49. }
  50. workspace.apps = apps;
  51. }
  52. Ok(workspaces)
  53. })?;
  54. if workspaces.is_empty() {
  55. tracing::trace!("Run folder v1 migration, but workspace is empty");
  56. KV::set_bool(&key, true);
  57. return Ok(None);
  58. }
  59. let trash = conn.immediate_transaction::<_, FlowyError, _>(|| {
  60. let trash = TrashTableSql::read_all(conn)?;
  61. Ok(trash)
  62. })?;
  63. let folder = FolderPad::new(workspaces, trash)?;
  64. KV::set_bool(&key, true);
  65. tracing::trace!("Run folder v1 migration");
  66. Ok(Some(folder))
  67. }
  68. pub async fn run_v2_migration(&self, user_id: &str, folder_id: &FolderId) -> FlowyResult<Option<FolderPad>> {
  69. let key = md5(format!("{}{}", self.user_id, V2_MIGRATION));
  70. if KV::get_bool(&key) {
  71. return Ok(None);
  72. }
  73. let pool = self.database.db_pool()?;
  74. let disk_cache = SQLiteTextBlockRevisionPersistence::new(user_id, pool);
  75. let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
  76. let (revisions, _) = RevisionLoader {
  77. object_id: folder_id.as_ref().to_owned(),
  78. user_id: self.user_id.clone(),
  79. cloud: None,
  80. rev_persistence,
  81. }
  82. .load()
  83. .await?;
  84. if revisions.is_empty() {
  85. tracing::trace!("Run folder v2 migration, but revision is empty");
  86. KV::set_bool(&key, true);
  87. return Ok(None);
  88. }
  89. let pad = FolderPad::from_revisions(revisions)?;
  90. KV::set_bool(&key, true);
  91. tracing::trace!("Run folder v2 migration");
  92. Ok(Some(pad))
  93. }
  94. }