diff --git a/crates/rtss_api/src/draft_data.rs b/crates/rtss_api/src/draft_data.rs index 25b5927..3c01cf1 100644 --- a/crates/rtss_api/src/draft_data.rs +++ b/crates/rtss_api/src/draft_data.rs @@ -14,7 +14,7 @@ pub struct DraftDataMutation; #[Object] impl DraftDataQuery { - /// 分页查询草稿数据 + /// 分页查询全部草稿数据(系统管理用) async fn draft_data_paging<'ctx>( &self, ctx: &Context<'ctx>, @@ -27,6 +27,32 @@ impl DraftDataQuery { .await?; Ok(paging_result.into()) } + /// 分页查询用户的草稿数据 + async fn user_draft_data_paging<'ctx>( + &self, + ctx: &Context<'ctx>, + paging: PageQueryDto, + query: UserDraftDataFilterDto, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let paging_result = db_accessor + .query_draft_data(query.into(), paging.into()) + .await?; + Ok(paging_result.into()) + } + /// 分页查询共享的草稿数据 + async fn shared_draft_data_paging<'ctx>( + &self, + ctx: &Context<'ctx>, + paging: PageQueryDto, + query: SharedDraftDataFilterDto, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let paging_result = db_accessor + .query_draft_data(query.into(), paging.into()) + .await?; + Ok(paging_result.into()) + } /// 根据id获取草稿数据 async fn draft_data(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result { let db_accessor = ctx.data::()?; @@ -82,6 +108,17 @@ impl DraftDataMutation { .await?; Ok(draft_data.into()) } + /// 更新草稿数据共享状态 + async fn update_draft_data_shared( + &self, + ctx: &Context<'_>, + id: i32, + is_shared: bool, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let draft_data = db_accessor.set_draft_data_shared(id, is_shared).await?; + Ok(draft_data.into()) + } /// 删除草稿数据 async fn delete_draft_data( &self, @@ -123,12 +160,52 @@ impl DraftDataMutation { pub struct CreateDraftDataDto { pub name: String, pub data_type: rtss_dto::common::DataType, + pub data: Vec, pub user_id: i32, } impl From for rtss_db::CreateDraftData { fn from(value: CreateDraftDataDto) -> Self { - Self::new(&value.name, value.data_type, value.user_id) + Self::new(&value.name, value.data_type, value.user_id).with_data(value.data.as_slice()) + } +} + +/// 用户的草稿数据查询条件 +#[derive(Debug, InputObject)] +pub struct UserDraftDataFilterDto { + pub user_id: i32, + pub name: Option, + pub data_type: Option, + pub is_shared: Option, +} + +impl From for rtss_db::DraftDataQuery { + fn from(value: UserDraftDataFilterDto) -> Self { + Self { + user_id: Some(value.user_id), + name: value.name, + data_type: value.data_type, + is_shared: value.is_shared, + } + } +} + +/// 共享的草稿数据查询条件 +#[derive(Debug, InputObject)] +pub struct SharedDraftDataFilterDto { + pub user_id: Option, + pub name: Option, + pub data_type: Option, +} + +impl From for rtss_db::DraftDataQuery { + fn from(value: SharedDraftDataFilterDto) -> Self { + Self { + user_id: value.user_id, + name: value.name, + data_type: value.data_type, + is_shared: Some(true), + } } } @@ -138,6 +215,7 @@ pub struct DraftDataFilterDto { pub user_id: Option, pub name: Option, pub data_type: Option, + pub is_shared: Option, } impl From for rtss_db::DraftDataQuery { @@ -146,6 +224,7 @@ impl From for rtss_db::DraftDataQuery { user_id: value.user_id, name: value.name, data_type: value.data_type, + is_shared: value.is_shared, } } } @@ -157,6 +236,7 @@ pub struct DraftData { pub data_type: rtss_dto::common::DataType, pub data: Option>, pub user_id: i32, + pub is_shared: bool, pub created_at: DateTime, pub updated_at: DateTime, } @@ -169,6 +249,7 @@ impl From for DraftData { data_type: DataType::try_from(value.data_type).unwrap(), data: value.data, user_id: value.user_id, + is_shared: value.is_shared, created_at: value.created_at, updated_at: value.updated_at, } diff --git a/crates/rtss_db/src/db_access/draft_data.rs b/crates/rtss_db/src/db_access/draft_data.rs index 1c5d8d3..e91eda2 100644 --- a/crates/rtss_db/src/db_access/draft_data.rs +++ b/crates/rtss_db/src/db_access/draft_data.rs @@ -14,7 +14,7 @@ use super::RtssDbAccessor; /// 草稿数据管理 #[allow(async_fn_in_trait)] pub trait DraftDataAccessor { - /// 查询用户草稿数据 + /// 查询所有草稿数据 async fn query_draft_data( &self, query: DraftDataQuery, @@ -41,6 +41,12 @@ pub trait DraftDataAccessor { id: i32, data: &[u8], ) -> Result; + /// 设置草稿数据共享 + async fn set_draft_data_shared( + &self, + id: i32, + is_shared: bool, + ) -> Result; /// 删除草稿数据 async fn delete_draft_data(&self, id: &[i32]) -> Result<(), DbAccessError>; /// 设置默认发布数据id @@ -63,9 +69,14 @@ pub struct DraftDataQuery { pub user_id: Option, pub name: Option, pub data_type: Option, + pub is_shared: Option, } impl DraftDataQuery { + pub fn new() -> Self { + Default::default() + } + pub fn with_user_id(mut self, user_id: i32) -> Self { self.user_id = Some(user_id); self @@ -81,6 +92,11 @@ impl DraftDataQuery { self } + pub fn with_is_shared(mut self, is_shared: bool) -> Self { + self.is_shared = Some(is_shared); + self + } + fn build_filter(&self) -> String { let mut filters = vec![]; if let Some(user_id) = self.user_id { @@ -100,6 +116,13 @@ impl DraftDataQuery { data_type as i32 )); } + if let Some(is_shared) = self.is_shared { + filters.push(format!( + "{} = {}", + DraftDataColumn::IsShared.name(), + is_shared + )); + } if filters.is_empty() { "".to_string() } else { @@ -283,6 +306,27 @@ impl DraftDataAccessor for RtssDbAccessor { Ok(draft_data) } + async fn set_draft_data_shared( + &self, + id: i32, + is_shared: bool, + ) -> Result { + let table = DraftDataColumn::Table.name(); + let is_shared_column = DraftDataColumn::IsShared.name(); + let updated_at_column = DraftDataColumn::UpdatedAt.name(); + let id_column = DraftDataColumn::Id.name(); + let sql = format!("UPDATE {table} SET {is_shared_column} = $1, {updated_at_column} = 'now()' WHERE {id_column} = $2 RETURNING *",); + // log sql + debug!("set shared sql: {}", sql); + let draft_data = sqlx::query_as(&sql) + .bind(is_shared) + .bind(id) + .fetch_one(&self.pool) + .await?; + + Ok(draft_data) + } + async fn delete_draft_data(&self, ids: &[i32]) -> Result<(), DbAccessError> { let table = DraftDataColumn::Table.name(); let id_column = DraftDataColumn::Id.name(); @@ -384,6 +428,10 @@ mod tests { println!("{:?}", get_by_id); assert!(get_by_id.data.unwrap() == data); + // set shared测试 + let get_by_id = accessor.set_draft_data_shared(res.id, true).await?; + assert!(get_by_id.is_shared); + // save as new draft测试 let new_draft = accessor.save_as_new_draft(res.id, "new draft", 11).await?; println!("{:?}", new_draft); @@ -412,6 +460,7 @@ mod tests { user_id: None, name: None, data_type: None, + is_shared: None, }, PageQuery::new(1, 100), ) @@ -422,36 +471,40 @@ mod tests { // 分四个user_id各插入5条数据 for i in 1..5 { for j in 1..6 { - accessor + let draft = accessor .create_draft_data(CreateDraftData::new(&format!("test{}", j), DataType::Em, i)) .await?; + if i == 1 { + accessor.set_draft_data_shared(draft.id, true).await?; + } } } let page = accessor .query_draft_data( - DraftDataQuery { - user_id: Some(1), - name: Some("test".to_string()), - data_type: Some(DataType::Em), - }, + DraftDataQuery::new() + .with_user_id(1) + .with_name("test".to_string()) + .with_data_type(DataType::Em), PageQuery::new(1, 10), ) .await?; assert_eq!(page.total, 5); let page = accessor - .query_draft_data( - DraftDataQuery { - user_id: None, - name: None, - data_type: None, - }, - PageQuery::new(1, 100), - ) + .query_draft_data(DraftDataQuery::new(), PageQuery::new(1, 100)) .await?; assert_eq!(page.total, 20); + // 查询共享数据 + let page = accessor + .query_draft_data( + DraftDataQuery::new().with_is_shared(true), + PageQuery::new(1, 10), + ) + .await?; + assert_eq!(page.total, 5); + Ok(()) } } diff --git a/crates/rtss_db/src/db_access/release_data.rs b/crates/rtss_db/src/db_access/release_data.rs index 657266c..2c955ab 100644 --- a/crates/rtss_db/src/db_access/release_data.rs +++ b/crates/rtss_db/src/db_access/release_data.rs @@ -62,7 +62,7 @@ pub trait ReleaseDataAccessor { name: &str, ) -> Result; /// 上架/下架发布数据 - async fn update_release_data_published( + async fn set_release_data_published( &self, release_id: i32, is_published: bool, @@ -430,7 +430,7 @@ impl ReleaseDataAccessor for RtssDbAccessor { Ok(rd) } - async fn update_release_data_published( + async fn set_release_data_published( &self, release_id: i32, is_published: bool, @@ -614,7 +614,7 @@ mod tests { // 测试更新发布数据上架状态 let release_data = accessor - .update_release_data_published(release_data.id, false) + .set_release_data_published(release_data.id, false) .await?; assert_eq!(release_data.is_published, false); assert!(release_data.updated_at > release_data.created_at); diff --git a/crates/rtss_db/src/model.rs b/crates/rtss_db/src/model.rs index 378d4ec..132f63a 100644 --- a/crates/rtss_db/src/model.rs +++ b/crates/rtss_db/src/model.rs @@ -12,6 +12,7 @@ pub(crate) enum DraftDataColumn { Data, DefaultReleaseDataId, UserId, + IsShared, CreatedAt, UpdatedAt, } @@ -26,6 +27,8 @@ pub struct DraftDataModel { #[sqlx(default)] pub default_release_data_id: Option, pub user_id: i32, + #[sqlx(default)] + pub is_shared: bool, pub created_at: DateTime, pub updated_at: DateTime, } @@ -201,6 +204,7 @@ impl TableColumn for DraftDataColumn { DraftDataColumn::Data => "data", DraftDataColumn::DefaultReleaseDataId => "default_release_data_id", DraftDataColumn::UserId => "user_id", + DraftDataColumn::IsShared => "is_shared", DraftDataColumn::CreatedAt => "created_at", DraftDataColumn::UpdatedAt => "updated_at", } diff --git a/migrations/20240830095636_init.up.sql b/migrations/20240830095636_init.up.sql index 9cc145e..8841666 100644 --- a/migrations/20240830095636_init.up.sql +++ b/migrations/20240830095636_init.up.sql @@ -10,6 +10,7 @@ CREATE TABLE data BYTEA, -- 草稿数据 default_release_data_id INT NULL, -- 默认发布数据id user_id INT NOT NULL, -- 创建用户id + is_shared BOOLEAN NOT NULL DEFAULT FALSE, -- 是否共享 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT 'now()', -- 创建时间 updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT 'now()', -- 更新时间 UNIQUE (name, user_id) -- 一个用户的草稿名称唯一 @@ -35,6 +36,8 @@ COMMENT ON COLUMN rtss.draft_data.data IS '草稿数据'; COMMENT ON COLUMN rtss.draft_data.user_id IS '创建用户id'; +COMMENT ON COLUMN rtss.draft_data.is_shared IS '是否共享'; + COMMENT ON COLUMN rtss.draft_data.created_at IS '创建时间'; COMMENT ON COLUMN rtss.draft_data.updated_at IS '更新时间';