view.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. use crate::{
  2. entities::workspace::{ViewTable, VIEW_TABLE},
  3. services::{
  4. doc::{create_doc_with_transaction, delete_doc},
  5. trash::read_trash_ids,
  6. user::LoggedUser,
  7. view::sql_builder::*,
  8. },
  9. sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
  10. };
  11. use backend_service::errors::{invalid_params, ServerError};
  12. use chrono::Utc;
  13. use flowy_collaboration::protobuf::CreateDocParams;
  14. use flowy_core_data_model::{
  15. parser::{
  16. app::AppId,
  17. view::{ViewDesc, ViewName, ViewThumbnail},
  18. },
  19. protobuf::{CreateViewParams, RepeatedView, View},
  20. };
  21. use sqlx::{postgres::PgArguments, Postgres};
  22. use uuid::Uuid;
  23. pub(crate) async fn update_view(
  24. transaction: &mut DBTransaction<'_>,
  25. view_id: Uuid,
  26. name: Option<String>,
  27. desc: Option<String>,
  28. thumbnail: Option<String>,
  29. ) -> Result<(), ServerError> {
  30. let (sql, args) = SqlBuilder::update(VIEW_TABLE)
  31. .add_some_arg("name", name)
  32. .add_some_arg("description", desc)
  33. .add_some_arg("thumbnail", thumbnail)
  34. .add_some_arg("modified_time", Some(Utc::now()))
  35. .and_where_eq("id", view_id)
  36. .build()?;
  37. sqlx::query_with(&sql, args)
  38. .execute(transaction)
  39. .await
  40. .map_err(map_sqlx_error)?;
  41. Ok(())
  42. }
  43. #[tracing::instrument(skip(transaction), err)]
  44. pub(crate) async fn delete_view(transaction: &mut DBTransaction<'_>, view_ids: Vec<Uuid>) -> Result<(), ServerError> {
  45. for view_id in view_ids {
  46. let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;
  47. let _ = sqlx::query_with(&sql, args)
  48. .execute(transaction as &mut DBTransaction<'_>)
  49. .await
  50. .map_err(map_sqlx_error)?;
  51. let _ = delete_doc(transaction, view_id).await?;
  52. }
  53. Ok(())
  54. }
  55. #[tracing::instrument(name = "create_view", level = "debug", skip(transaction), err)]
  56. pub(crate) async fn create_view(
  57. transaction: &mut DBTransaction<'_>,
  58. params: CreateViewParams,
  59. ) -> Result<View, ServerError> {
  60. let name = ViewName::parse(params.name).map_err(invalid_params)?;
  61. let belong_to_id = AppId::parse(params.belong_to_id).map_err(invalid_params)?;
  62. let thumbnail = ViewThumbnail::parse(params.thumbnail).map_err(invalid_params)?;
  63. let desc = ViewDesc::parse(params.desc).map_err(invalid_params)?;
  64. let (sql, args, view) = NewViewSqlBuilder::new(belong_to_id.as_ref())
  65. .name(name.as_ref())
  66. .desc(desc.as_ref())
  67. .thumbnail(thumbnail.as_ref())
  68. .view_type(params.view_type)
  69. .build()?;
  70. let view = create_view_with_args(transaction, sql, args, view, params.data).await?;
  71. Ok(view)
  72. }
  73. pub(crate) async fn create_view_with_args(
  74. transaction: &mut DBTransaction<'_>,
  75. sql: String,
  76. args: PgArguments,
  77. view: View,
  78. view_data: String,
  79. ) -> Result<View, ServerError> {
  80. let _ = sqlx::query_with(&sql, args)
  81. .execute(transaction as &mut DBTransaction<'_>)
  82. .await
  83. .map_err(map_sqlx_error)?;
  84. let mut create_doc_params = CreateDocParams::new();
  85. create_doc_params.set_data(view_data);
  86. create_doc_params.set_id(view.id.clone());
  87. let _ = create_doc_with_transaction(transaction, create_doc_params).await?;
  88. Ok(view)
  89. }
  90. pub(crate) async fn read_view(
  91. user: &LoggedUser,
  92. view_id: Uuid,
  93. transaction: &mut DBTransaction<'_>,
  94. ) -> Result<View, ServerError> {
  95. let table = read_view_table(view_id, transaction as &mut DBTransaction<'_>).await?;
  96. let read_trash_ids = read_trash_ids(user, transaction).await?;
  97. if read_trash_ids.contains(&table.id.to_string()) {
  98. return Err(ServerError::record_not_found());
  99. }
  100. let mut views = RepeatedView::default();
  101. views.set_items(
  102. read_view_belong_to_id(&table.id.to_string(), &user, transaction)
  103. .await?
  104. .into(),
  105. );
  106. let mut view: View = table.into();
  107. view.set_belongings(views);
  108. Ok(view)
  109. }
  110. pub(crate) async fn read_view_table(
  111. view_id: Uuid,
  112. transaction: &mut DBTransaction<'_>,
  113. ) -> Result<ViewTable, ServerError> {
  114. let (sql, args) = SqlBuilder::select(VIEW_TABLE)
  115. .add_field("*")
  116. .and_where_eq("id", view_id)
  117. .build()?;
  118. let table = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
  119. .fetch_one(transaction as &mut DBTransaction<'_>)
  120. .await
  121. .map_err(map_sqlx_error)?;
  122. Ok(table)
  123. }
  124. // transaction must be commit from caller
  125. pub(crate) async fn read_view_belong_to_id<'c>(
  126. id: &str,
  127. user: &LoggedUser,
  128. transaction: &mut DBTransaction<'_>,
  129. ) -> Result<Vec<View>, ServerError> {
  130. // TODO: add index for app_table
  131. let (sql, args) = SqlBuilder::select(VIEW_TABLE)
  132. .add_field("*")
  133. .and_where_eq("belong_to_id", id)
  134. .build()?;
  135. let mut tables = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
  136. .fetch_all(transaction as &mut DBTransaction<'_>)
  137. .await
  138. .map_err(map_sqlx_error)?;
  139. let read_trash_ids = read_trash_ids(user, transaction).await?;
  140. tables.retain(|table| !read_trash_ids.contains(&table.id.to_string()));
  141. let views = tables.into_iter().map(|table| table.into()).collect::<Vec<View>>();
  142. Ok(views)
  143. }