mod.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. mod migration;
  2. pub mod rev_sqlite;
  3. pub mod version_1;
  4. mod version_2;
  5. use crate::{
  6. event_map::WorkspaceDatabase,
  7. manager::FolderId,
  8. services::{folder_editor::FolderEditor, persistence::migration::FolderMigration},
  9. };
  10. use flowy_database::ConnectionPool;
  11. use flowy_error::{FlowyError, FlowyResult};
  12. use flowy_http_model::revision::Revision;
  13. use flowy_revision::disk::{RevisionDiskCache, RevisionState, SyncRecord};
  14. use flowy_sync::client_folder::FolderPad;
  15. use folder_rev_model::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
  16. use crate::services::persistence::rev_sqlite::SQLiteFolderRevisionPersistence;
  17. use flowy_sync::server_folder::FolderOperationsBuilder;
  18. use std::sync::Arc;
  19. use tokio::sync::RwLock;
  20. pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*};
  21. pub trait FolderPersistenceTransaction {
  22. fn create_workspace(&self, user_id: &str, workspace_rev: WorkspaceRevision) -> FlowyResult<()>;
  23. fn read_workspaces(&self, user_id: &str, workspace_id: Option<String>) -> FlowyResult<Vec<WorkspaceRevision>>;
  24. fn update_workspace(&self, changeset: WorkspaceChangeset) -> FlowyResult<()>;
  25. fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()>;
  26. fn create_app(&self, app_rev: AppRevision) -> FlowyResult<()>;
  27. fn update_app(&self, changeset: AppChangeset) -> FlowyResult<()>;
  28. fn read_app(&self, app_id: &str) -> FlowyResult<AppRevision>;
  29. fn read_workspace_apps(&self, workspace_id: &str) -> FlowyResult<Vec<AppRevision>>;
  30. fn delete_app(&self, app_id: &str) -> FlowyResult<AppRevision>;
  31. fn move_app(&self, app_id: &str, from: usize, to: usize) -> FlowyResult<()>;
  32. fn create_view(&self, view_rev: ViewRevision) -> FlowyResult<()>;
  33. fn read_view(&self, view_id: &str) -> FlowyResult<ViewRevision>;
  34. fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<ViewRevision>>;
  35. fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()>;
  36. fn delete_view(&self, view_id: &str) -> FlowyResult<ViewRevision>;
  37. fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()>;
  38. fn create_trash(&self, trashes: Vec<TrashRevision>) -> FlowyResult<()>;
  39. fn read_trash(&self, trash_id: Option<String>) -> FlowyResult<Vec<TrashRevision>>;
  40. fn delete_trash(&self, trash_ids: Option<Vec<String>>) -> FlowyResult<()>;
  41. }
  42. pub struct FolderPersistence {
  43. database: Arc<dyn WorkspaceDatabase>,
  44. folder_editor: Arc<RwLock<Option<Arc<FolderEditor>>>>,
  45. }
  46. impl FolderPersistence {
  47. pub fn new(database: Arc<dyn WorkspaceDatabase>, folder_editor: Arc<RwLock<Option<Arc<FolderEditor>>>>) -> Self {
  48. Self {
  49. database,
  50. folder_editor,
  51. }
  52. }
  53. #[deprecated(
  54. since = "0.0.3",
  55. note = "please use `begin_transaction` instead, this interface will be removed in the future"
  56. )]
  57. #[allow(dead_code)]
  58. pub fn begin_transaction_v_1<F, O>(&self, f: F) -> FlowyResult<O>
  59. where
  60. F: for<'a> FnOnce(Box<dyn FolderPersistenceTransaction + 'a>) -> FlowyResult<O>,
  61. {
  62. //[[immediate_transaction]]
  63. // https://sqlite.org/lang_transaction.html
  64. // IMMEDIATE cause the database connection to start a new write immediately,
  65. // without waiting for a write statement. The BEGIN IMMEDIATE might fail
  66. // with SQLITE_BUSY if another write transaction is already active on another
  67. // database connection.
  68. //
  69. // EXCLUSIVE is similar to IMMEDIATE in that a write transaction is started
  70. // immediately. EXCLUSIVE and IMMEDIATE are the same in WAL mode, but in
  71. // other journaling modes, EXCLUSIVE prevents other database connections from
  72. // reading the database while the transaction is underway.
  73. let conn = self.database.db_connection()?;
  74. conn.immediate_transaction::<_, FlowyError, _>(|| f(Box::new(V1Transaction(&conn))))
  75. }
  76. pub async fn begin_transaction<F, O>(&self, f: F) -> FlowyResult<O>
  77. where
  78. F: FnOnce(Arc<dyn FolderPersistenceTransaction>) -> FlowyResult<O>,
  79. {
  80. match self.folder_editor.read().await.clone() {
  81. None => Err(FlowyError::internal().context("FolderEditor should be initialized after user login in.")),
  82. Some(editor) => f(editor),
  83. }
  84. }
  85. pub fn db_pool(&self) -> FlowyResult<Arc<ConnectionPool>> {
  86. self.database.db_pool()
  87. }
  88. pub async fn initialize(&self, user_id: &str, folder_id: &FolderId) -> FlowyResult<()> {
  89. let migrations = FolderMigration::new(user_id, self.database.clone());
  90. if let Some(migrated_folder) = migrations.run_v1_migration()? {
  91. self.save_folder(user_id, folder_id, migrated_folder).await?;
  92. }
  93. let _ = migrations.run_v2_migration(folder_id).await?;
  94. let _ = migrations.run_v3_migration(folder_id).await?;
  95. Ok(())
  96. }
  97. pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> {
  98. let pool = self.database.db_pool()?;
  99. let json = folder.to_json()?;
  100. let delta_data = FolderOperationsBuilder::new().insert(&json).build().json_bytes();
  101. let revision = Revision::initial_revision(folder_id.as_ref(), delta_data);
  102. let record = SyncRecord {
  103. revision,
  104. state: RevisionState::Sync,
  105. write_to_disk: true,
  106. };
  107. let disk_cache = mk_text_block_revision_disk_cache(user_id, pool);
  108. disk_cache.delete_and_insert_records(folder_id.as_ref(), None, vec![record])
  109. }
  110. }
  111. pub fn mk_text_block_revision_disk_cache(
  112. user_id: &str,
  113. pool: Arc<ConnectionPool>,
  114. ) -> Arc<dyn RevisionDiskCache<Arc<ConnectionPool>, Error = FlowyError>> {
  115. Arc::new(SQLiteFolderRevisionPersistence::new(user_id, pool))
  116. }