trash.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. use crate::{
  2. context::DocumentRevisionKV,
  3. entities::logged_user::LoggedUser,
  4. services::folder::{
  5. app::controller::{delete_app, read_app_table},
  6. trash::persistence::{TrashTable, TRASH_TABLE},
  7. view::{delete_view, read_view_table},
  8. },
  9. util::sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
  10. };
  11. use ::protobuf::ProtobufEnum;
  12. use backend_service::errors::ServerError;
  13. use flowy_folder_data_model::protobuf::{RepeatedTrash, Trash, TrashType};
  14. use sqlx::{postgres::PgArguments, Postgres, Row};
  15. use std::sync::Arc;
  16. use uuid::Uuid;
  17. #[tracing::instrument(skip(transaction, user), err)]
  18. pub(crate) async fn create_trash(
  19. transaction: &mut DBTransaction<'_>,
  20. records: Vec<(Uuid, i32)>,
  21. user: LoggedUser,
  22. ) -> Result<(), ServerError> {
  23. for (trash_id, ty) in records {
  24. let (sql, args) = SqlBuilder::create(TRASH_TABLE)
  25. .add_field_with_arg("id", trash_id)
  26. .add_field_with_arg("user_id", &user.user_id)
  27. .add_field_with_arg("ty", ty)
  28. .build()?;
  29. let _ = sqlx::query_with(&sql, args)
  30. .execute(transaction as &mut DBTransaction<'_>)
  31. .await
  32. .map_err(map_sqlx_error)?;
  33. }
  34. Ok(())
  35. }
  36. #[tracing::instrument(skip(transaction, document_store, user), fields(delete_rows), err)]
  37. pub(crate) async fn delete_all_trash(
  38. transaction: &mut DBTransaction<'_>,
  39. document_store: &Arc<DocumentRevisionKV>,
  40. user: &LoggedUser,
  41. ) -> Result<(), ServerError> {
  42. let (sql, args) = SqlBuilder::select(TRASH_TABLE)
  43. .and_where_eq("user_id", &user.user_id)
  44. .build()?;
  45. let rows = sqlx::query_with(&sql, args)
  46. .fetch_all(transaction as &mut DBTransaction<'_>)
  47. .await
  48. .map_err(map_sqlx_error)?
  49. .into_iter()
  50. .map(|row| (row.get("id"), row.get("ty")))
  51. .collect::<Vec<(Uuid, i32)>>();
  52. tracing::Span::current().record("delete_rows", &format!("{:?}", rows).as_str());
  53. let affected_row_count = rows.len();
  54. let _ = delete_trash_associate_targets(transaction as &mut DBTransaction<'_>, document_store, rows).await?;
  55. let (sql, args) = SqlBuilder::delete(TRASH_TABLE)
  56. .and_where_eq("user_id", &user.user_id)
  57. .build()?;
  58. let result = sqlx::query_with(&sql, args)
  59. .execute(transaction as &mut DBTransaction<'_>)
  60. .await
  61. .map_err(map_sqlx_error)?;
  62. tracing::Span::current().record("affected_row", &result.rows_affected());
  63. debug_assert_eq!(affected_row_count as u64, result.rows_affected());
  64. Ok(())
  65. }
  66. #[tracing::instrument(skip(transaction, document_store), err)]
  67. pub(crate) async fn delete_trash(
  68. transaction: &mut DBTransaction<'_>,
  69. document_store: &Arc<DocumentRevisionKV>,
  70. records: Vec<(Uuid, i32)>,
  71. ) -> Result<(), ServerError> {
  72. for (trash_id, _) in records {
  73. // Read the trash_table and delete the original table according to the TrashType
  74. let (sql, args) = SqlBuilder::select(TRASH_TABLE)
  75. .add_field("*")
  76. .and_where_eq("id", trash_id)
  77. .build()?;
  78. let trash_table = sqlx::query_as_with::<Postgres, TrashTable, PgArguments>(&sql, args)
  79. .fetch_one(transaction as &mut DBTransaction<'_>)
  80. .await
  81. .map_err(map_sqlx_error)?;
  82. let _ = delete_trash_associate_targets(
  83. transaction as &mut DBTransaction<'_>,
  84. document_store,
  85. vec![(trash_table.id, trash_table.ty)],
  86. )
  87. .await?;
  88. // Delete the trash table
  89. let (sql, args) = SqlBuilder::delete(TRASH_TABLE).and_where_eq("id", &trash_id).build()?;
  90. let _ = sqlx::query_with(&sql, args)
  91. .execute(transaction as &mut DBTransaction<'_>)
  92. .await
  93. .map_err(map_sqlx_error)?;
  94. }
  95. Ok(())
  96. }
  97. #[tracing::instrument(skip(transaction, document_store, targets), err)]
  98. async fn delete_trash_associate_targets(
  99. transaction: &mut DBTransaction<'_>,
  100. document_store: &Arc<DocumentRevisionKV>,
  101. targets: Vec<(Uuid, i32)>,
  102. ) -> Result<(), ServerError> {
  103. for (id, ty) in targets {
  104. match TrashType::from_i32(ty) {
  105. None => log::error!("Parser trash type with value: {} failed", ty),
  106. Some(ty) => match ty {
  107. TrashType::Unknown => {}
  108. TrashType::View => {
  109. let _ = delete_view(transaction as &mut DBTransaction<'_>, document_store, vec![id]).await;
  110. }
  111. TrashType::App => {
  112. let _ = delete_app(transaction as &mut DBTransaction<'_>, id).await;
  113. }
  114. },
  115. }
  116. }
  117. Ok(())
  118. }
  119. pub(crate) async fn read_trash_ids(
  120. user: &LoggedUser,
  121. transaction: &mut DBTransaction<'_>,
  122. ) -> Result<Vec<String>, ServerError> {
  123. let repeated_trash = read_trash(transaction, user).await?.take_items().into_vec();
  124. let ids = repeated_trash
  125. .into_iter()
  126. .map(|trash| trash.id)
  127. .collect::<Vec<String>>();
  128. Ok(ids)
  129. }
  130. #[tracing::instrument(skip(transaction, user), err)]
  131. pub(crate) async fn read_trash(
  132. transaction: &mut DBTransaction<'_>,
  133. user: &LoggedUser,
  134. ) -> Result<RepeatedTrash, ServerError> {
  135. let (sql, args) = SqlBuilder::select(TRASH_TABLE)
  136. .add_field("*")
  137. .and_where_eq("user_id", &user.user_id)
  138. .build()?;
  139. let tables = sqlx::query_as_with::<Postgres, TrashTable, PgArguments>(&sql, args)
  140. .fetch_all(transaction as &mut DBTransaction<'_>)
  141. .await
  142. .map_err(map_sqlx_error)?;
  143. let mut trash: Vec<Trash> = vec![];
  144. for table in tables {
  145. match TrashType::from_i32(table.ty) {
  146. None => log::error!("Parser trash type with value: {} failed", table.ty),
  147. Some(ty) => match ty {
  148. TrashType::Unknown => {}
  149. TrashType::View => {
  150. trash.push(read_view_table(table.id, transaction).await?.into());
  151. }
  152. TrashType::App => {
  153. trash.push(read_app_table(table.id, transaction).await?.into());
  154. }
  155. },
  156. }
  157. }
  158. let mut repeated_trash = RepeatedTrash::default();
  159. repeated_trash.set_items(trash.into());
  160. Ok(repeated_trash)
  161. }