草稿数据添加是否共享字段
All checks were successful
build / build-rust (push) Successful in 2m17s

添加草稿数据相关管理接口
This commit is contained in:
soul-walker 2024-09-18 15:10:11 +08:00
parent e0169dfc06
commit 875788a71d
5 changed files with 161 additions and 20 deletions

View File

@ -14,7 +14,7 @@ pub struct DraftDataMutation;
#[Object] #[Object]
impl DraftDataQuery { impl DraftDataQuery {
/// 分页查询草稿数据 /// 分页查询全部草稿数据(系统管理用)
async fn draft_data_paging<'ctx>( async fn draft_data_paging<'ctx>(
&self, &self,
ctx: &Context<'ctx>, ctx: &Context<'ctx>,
@ -27,6 +27,32 @@ impl DraftDataQuery {
.await?; .await?;
Ok(paging_result.into()) Ok(paging_result.into())
} }
/// 分页查询用户的草稿数据
async fn user_draft_data_paging<'ctx>(
&self,
ctx: &Context<'ctx>,
paging: PageQueryDto,
query: UserDraftDataFilterDto,
) -> async_graphql::Result<DraftDataPage> {
let db_accessor = ctx.data::<RtssDbAccessor>()?;
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<DraftDataPage> {
let db_accessor = ctx.data::<RtssDbAccessor>()?;
let paging_result = db_accessor
.query_draft_data(query.into(), paging.into())
.await?;
Ok(paging_result.into())
}
/// 根据id获取草稿数据 /// 根据id获取草稿数据
async fn draft_data(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result<DraftData> { async fn draft_data(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result<DraftData> {
let db_accessor = ctx.data::<RtssDbAccessor>()?; let db_accessor = ctx.data::<RtssDbAccessor>()?;
@ -82,6 +108,17 @@ impl DraftDataMutation {
.await?; .await?;
Ok(draft_data.into()) Ok(draft_data.into())
} }
/// 更新草稿数据共享状态
async fn update_draft_data_shared(
&self,
ctx: &Context<'_>,
id: i32,
is_shared: bool,
) -> async_graphql::Result<DraftData> {
let db_accessor = ctx.data::<RtssDbAccessor>()?;
let draft_data = db_accessor.set_draft_data_shared(id, is_shared).await?;
Ok(draft_data.into())
}
/// 删除草稿数据 /// 删除草稿数据
async fn delete_draft_data( async fn delete_draft_data(
&self, &self,
@ -123,12 +160,52 @@ impl DraftDataMutation {
pub struct CreateDraftDataDto { pub struct CreateDraftDataDto {
pub name: String, pub name: String,
pub data_type: rtss_dto::common::DataType, pub data_type: rtss_dto::common::DataType,
pub data: Vec<u8>,
pub user_id: i32, pub user_id: i32,
} }
impl From<CreateDraftDataDto> for rtss_db::CreateDraftData { impl From<CreateDraftDataDto> for rtss_db::CreateDraftData {
fn from(value: CreateDraftDataDto) -> Self { 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<String>,
pub data_type: Option<rtss_dto::common::DataType>,
pub is_shared: Option<bool>,
}
impl From<UserDraftDataFilterDto> 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<i32>,
pub name: Option<String>,
pub data_type: Option<rtss_dto::common::DataType>,
}
impl From<SharedDraftDataFilterDto> 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<i32>, pub user_id: Option<i32>,
pub name: Option<String>, pub name: Option<String>,
pub data_type: Option<rtss_dto::common::DataType>, pub data_type: Option<rtss_dto::common::DataType>,
pub is_shared: Option<bool>,
} }
impl From<DraftDataFilterDto> for rtss_db::DraftDataQuery { impl From<DraftDataFilterDto> for rtss_db::DraftDataQuery {
@ -146,6 +224,7 @@ impl From<DraftDataFilterDto> for rtss_db::DraftDataQuery {
user_id: value.user_id, user_id: value.user_id,
name: value.name, name: value.name,
data_type: value.data_type, 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_type: rtss_dto::common::DataType,
pub data: Option<Vec<u8>>, pub data: Option<Vec<u8>>,
pub user_id: i32, pub user_id: i32,
pub is_shared: bool,
pub created_at: DateTime<Local>, pub created_at: DateTime<Local>,
pub updated_at: DateTime<Local>, pub updated_at: DateTime<Local>,
} }
@ -169,6 +249,7 @@ impl From<rtss_db::model::DraftDataModel> for DraftData {
data_type: DataType::try_from(value.data_type).unwrap(), data_type: DataType::try_from(value.data_type).unwrap(),
data: value.data, data: value.data,
user_id: value.user_id, user_id: value.user_id,
is_shared: value.is_shared,
created_at: value.created_at, created_at: value.created_at,
updated_at: value.updated_at, updated_at: value.updated_at,
} }

View File

@ -14,7 +14,7 @@ use super::RtssDbAccessor;
/// 草稿数据管理 /// 草稿数据管理
#[allow(async_fn_in_trait)] #[allow(async_fn_in_trait)]
pub trait DraftDataAccessor { pub trait DraftDataAccessor {
/// 查询用户草稿数据 /// 查询所有草稿数据
async fn query_draft_data( async fn query_draft_data(
&self, &self,
query: DraftDataQuery, query: DraftDataQuery,
@ -41,6 +41,12 @@ pub trait DraftDataAccessor {
id: i32, id: i32,
data: &[u8], data: &[u8],
) -> Result<DraftDataModel, DbAccessError>; ) -> Result<DraftDataModel, DbAccessError>;
/// 设置草稿数据共享
async fn set_draft_data_shared(
&self,
id: i32,
is_shared: bool,
) -> Result<DraftDataModel, DbAccessError>;
/// 删除草稿数据 /// 删除草稿数据
async fn delete_draft_data(&self, id: &[i32]) -> Result<(), DbAccessError>; async fn delete_draft_data(&self, id: &[i32]) -> Result<(), DbAccessError>;
/// 设置默认发布数据id /// 设置默认发布数据id
@ -63,9 +69,14 @@ pub struct DraftDataQuery {
pub user_id: Option<i32>, pub user_id: Option<i32>,
pub name: Option<String>, pub name: Option<String>,
pub data_type: Option<DataType>, pub data_type: Option<DataType>,
pub is_shared: Option<bool>,
} }
impl DraftDataQuery { impl DraftDataQuery {
pub fn new() -> Self {
Default::default()
}
pub fn with_user_id(mut self, user_id: i32) -> Self { pub fn with_user_id(mut self, user_id: i32) -> Self {
self.user_id = Some(user_id); self.user_id = Some(user_id);
self self
@ -81,6 +92,11 @@ impl DraftDataQuery {
self self
} }
pub fn with_is_shared(mut self, is_shared: bool) -> Self {
self.is_shared = Some(is_shared);
self
}
fn build_filter(&self) -> String { fn build_filter(&self) -> String {
let mut filters = vec![]; let mut filters = vec![];
if let Some(user_id) = self.user_id { if let Some(user_id) = self.user_id {
@ -100,6 +116,13 @@ impl DraftDataQuery {
data_type as i32 data_type as i32
)); ));
} }
if let Some(is_shared) = self.is_shared {
filters.push(format!(
"{} = {}",
DraftDataColumn::IsShared.name(),
is_shared
));
}
if filters.is_empty() { if filters.is_empty() {
"".to_string() "".to_string()
} else { } else {
@ -283,6 +306,27 @@ impl DraftDataAccessor for RtssDbAccessor {
Ok(draft_data) Ok(draft_data)
} }
async fn set_draft_data_shared(
&self,
id: i32,
is_shared: bool,
) -> Result<DraftDataModel, DbAccessError> {
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> { async fn delete_draft_data(&self, ids: &[i32]) -> Result<(), DbAccessError> {
let table = DraftDataColumn::Table.name(); let table = DraftDataColumn::Table.name();
let id_column = DraftDataColumn::Id.name(); let id_column = DraftDataColumn::Id.name();
@ -384,6 +428,10 @@ mod tests {
println!("{:?}", get_by_id); println!("{:?}", get_by_id);
assert!(get_by_id.data.unwrap() == data); 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测试 // save as new draft测试
let new_draft = accessor.save_as_new_draft(res.id, "new draft", 11).await?; let new_draft = accessor.save_as_new_draft(res.id, "new draft", 11).await?;
println!("{:?}", new_draft); println!("{:?}", new_draft);
@ -412,6 +460,7 @@ mod tests {
user_id: None, user_id: None,
name: None, name: None,
data_type: None, data_type: None,
is_shared: None,
}, },
PageQuery::new(1, 100), PageQuery::new(1, 100),
) )
@ -422,36 +471,40 @@ mod tests {
// 分四个user_id各插入5条数据 // 分四个user_id各插入5条数据
for i in 1..5 { for i in 1..5 {
for j in 1..6 { for j in 1..6 {
accessor let draft = accessor
.create_draft_data(CreateDraftData::new(&format!("test{}", j), DataType::Em, i)) .create_draft_data(CreateDraftData::new(&format!("test{}", j), DataType::Em, i))
.await?; .await?;
if i == 1 {
accessor.set_draft_data_shared(draft.id, true).await?;
}
} }
} }
let page = accessor let page = accessor
.query_draft_data( .query_draft_data(
DraftDataQuery { DraftDataQuery::new()
user_id: Some(1), .with_user_id(1)
name: Some("test".to_string()), .with_name("test".to_string())
data_type: Some(DataType::Em), .with_data_type(DataType::Em),
},
PageQuery::new(1, 10), PageQuery::new(1, 10),
) )
.await?; .await?;
assert_eq!(page.total, 5); assert_eq!(page.total, 5);
let page = accessor let page = accessor
.query_draft_data( .query_draft_data(DraftDataQuery::new(), PageQuery::new(1, 100))
DraftDataQuery {
user_id: None,
name: None,
data_type: None,
},
PageQuery::new(1, 100),
)
.await?; .await?;
assert_eq!(page.total, 20); 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(()) Ok(())
} }
} }

View File

@ -62,7 +62,7 @@ pub trait ReleaseDataAccessor {
name: &str, name: &str,
) -> Result<ReleaseDataModel, DbAccessError>; ) -> Result<ReleaseDataModel, DbAccessError>;
/// 上架/下架发布数据 /// 上架/下架发布数据
async fn update_release_data_published( async fn set_release_data_published(
&self, &self,
release_id: i32, release_id: i32,
is_published: bool, is_published: bool,
@ -430,7 +430,7 @@ impl ReleaseDataAccessor for RtssDbAccessor {
Ok(rd) Ok(rd)
} }
async fn update_release_data_published( async fn set_release_data_published(
&self, &self,
release_id: i32, release_id: i32,
is_published: bool, is_published: bool,
@ -614,7 +614,7 @@ mod tests {
// 测试更新发布数据上架状态 // 测试更新发布数据上架状态
let release_data = accessor let release_data = accessor
.update_release_data_published(release_data.id, false) .set_release_data_published(release_data.id, false)
.await?; .await?;
assert_eq!(release_data.is_published, false); assert_eq!(release_data.is_published, false);
assert!(release_data.updated_at > release_data.created_at); assert!(release_data.updated_at > release_data.created_at);

View File

@ -12,6 +12,7 @@ pub(crate) enum DraftDataColumn {
Data, Data,
DefaultReleaseDataId, DefaultReleaseDataId,
UserId, UserId,
IsShared,
CreatedAt, CreatedAt,
UpdatedAt, UpdatedAt,
} }
@ -26,6 +27,8 @@ pub struct DraftDataModel {
#[sqlx(default)] #[sqlx(default)]
pub default_release_data_id: Option<i32>, pub default_release_data_id: Option<i32>,
pub user_id: i32, pub user_id: i32,
#[sqlx(default)]
pub is_shared: bool,
pub created_at: DateTime<Local>, pub created_at: DateTime<Local>,
pub updated_at: DateTime<Local>, pub updated_at: DateTime<Local>,
} }
@ -201,6 +204,7 @@ impl TableColumn for DraftDataColumn {
DraftDataColumn::Data => "data", DraftDataColumn::Data => "data",
DraftDataColumn::DefaultReleaseDataId => "default_release_data_id", DraftDataColumn::DefaultReleaseDataId => "default_release_data_id",
DraftDataColumn::UserId => "user_id", DraftDataColumn::UserId => "user_id",
DraftDataColumn::IsShared => "is_shared",
DraftDataColumn::CreatedAt => "created_at", DraftDataColumn::CreatedAt => "created_at",
DraftDataColumn::UpdatedAt => "updated_at", DraftDataColumn::UpdatedAt => "updated_at",
} }

View File

@ -10,6 +10,7 @@ CREATE TABLE
data BYTEA, -- 草稿数据 data BYTEA, -- 草稿数据
default_release_data_id INT NULL, -- 默认发布数据id default_release_data_id INT NULL, -- 默认发布数据id
user_id INT NOT 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()', -- 创建时间 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT 'now()', -- 创建时间
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT 'now()', -- 更新时间 updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT 'now()', -- 更新时间
UNIQUE (name, user_id) -- 一个用户的草稿名称唯一 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.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.created_at IS '创建时间';
COMMENT ON COLUMN rtss.draft_data.updated_at IS '更新时间'; COMMENT ON COLUMN rtss.draft_data.updated_at IS '更新时间';