mod.rs 5.0 KB

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