diff --git a/crates/rtss_api/src/apis/common.rs b/crates/rtss_api/src/apis/common.rs new file mode 100644 index 0000000..e73c570 --- /dev/null +++ b/crates/rtss_api/src/apis/common.rs @@ -0,0 +1,53 @@ +use async_graphql::{InputObject, InputType, OutputType, SimpleObject}; +use rtss_db::{common::TableColumn, model::DraftDataColumn}; +use rtss_dto::common::IscsStyle; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +pub trait DataOptions: InputType + OutputType + Serialize + DeserializeOwned { + fn to_data_options_filter_clause(&self) -> String; +} + +#[derive(Debug, InputObject, SimpleObject, Serialize, Deserialize)] +#[graphql(input_name = "IscsDataOptionsInput")] +pub struct IscsDataOptions { + pub style: IscsStyle, +} + +impl DataOptions for IscsDataOptions { + fn to_data_options_filter_clause(&self) -> String { + let options_column = DraftDataColumn::Options.name(); + format!( + "{options_column} @> '{}'", + serde_json::to_string(self).unwrap() + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_iscs_data_options_serialize() { + rtss_log::Logging::default().init(); + let options = IscsDataOptions { + style: IscsStyle::DaShiZhiNeng, + }; + let json = serde_json::to_string(&options).unwrap(); + println!("{}", json); + println!("{}", options.style.as_str_name()); + assert_eq!(json, r#"{"style":"DaShiZhiNeng"}"#); + let options: IscsDataOptions = serde_json::from_str(&json).unwrap(); + assert_eq!(options.style, IscsStyle::DaShiZhiNeng); + } + + #[test] + fn test_iscs_data_options_into_data_options_filter_clause() { + let options = IscsDataOptions { + style: IscsStyle::DaShiZhiNeng, + }; + let clause = options.to_data_options_filter_clause(); + println!("{clause}"); + assert_eq!(clause, r#"options @> '{"style":"DaShiZhiNeng"}'"#); + } +} diff --git a/crates/rtss_api/src/draft_data.rs b/crates/rtss_api/src/apis/draft_data.rs similarity index 62% rename from crates/rtss_api/src/draft_data.rs rename to crates/rtss_api/src/apis/draft_data.rs index 1c3914a..e4eee99 100644 --- a/crates/rtss_api/src/draft_data.rs +++ b/crates/rtss_api/src/apis/draft_data.rs @@ -1,16 +1,16 @@ use async_graphql::{Context, InputObject, Object, SimpleObject}; -use async_graphql::{InputType, OutputType}; +use base64::prelude::*; +use base64::Engine; use chrono::NaiveDateTime; -use rtss_db::common::TableColumn; -use rtss_db::model::DraftDataColumn; use rtss_db::DraftDataAccessor; use rtss_db::RtssDbAccessor; -use rtss_dto::common::{DataType, IscsStyle}; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; +use rtss_dto::common::DataType; use serde_json::Value; -use crate::pagination::PageQueryDto; +use crate::apis::PageQueryDto; + +use super::common::{DataOptions, IscsDataOptions}; +use super::PageDto; #[derive(Default)] pub struct DraftDataQuery; @@ -20,39 +20,39 @@ pub struct DraftDataMutation; #[Object] impl DraftDataQuery { - /// 分页查询全部草稿数据(系统管理用) + /// 分页查询所有草稿数据(系统管理用) async fn draft_data_paging<'ctx>( &self, ctx: &Context<'ctx>, paging: PageQueryDto, query: DraftDataFilterDto, - ) -> async_graphql::Result { + ) -> 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()) } - /// 分页查询用户的草稿数据 + /// 分页查询用户的草稿ISCS数据 async fn user_draft_iscs_data_paging<'ctx>( &self, ctx: &Context<'ctx>, paging: PageQueryDto, query: UserDraftDataFilterDto, - ) -> async_graphql::Result { + ) -> 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()) } - /// 分页查询共享的草稿数据 + /// 分页查询共享的草稿ISCS数据 async fn shared_draft_iscs_data_paging<'ctx>( &self, ctx: &Context<'ctx>, paging: PageQueryDto, query: SharedDraftDataFilterDto, - ) -> async_graphql::Result { + ) -> async_graphql::Result> { let db_accessor = ctx.data::()?; let paging_result = db_accessor .query_draft_data(query.into(), paging.into()) @@ -60,11 +60,7 @@ impl DraftDataQuery { Ok(paging_result.into()) } /// 根据id获取草稿数据 - async fn draft_data( - &self, - ctx: &Context<'_>, - id: i32, - ) -> async_graphql::Result { + async fn draft_data(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result { let db_accessor = ctx.data::()?; let draft_data = db_accessor.query_draft_data_by_id(id).await?; Ok(draft_data.into()) @@ -89,7 +85,7 @@ impl DraftDataMutation { &self, ctx: &Context<'_>, input: CreateDraftDataDto, - ) -> async_graphql::Result> { + ) -> async_graphql::Result { let db_accessor = ctx.data::()?; let draft_data = db_accessor.create_draft_data(input.into()).await?; Ok(draft_data.into()) @@ -100,22 +96,22 @@ impl DraftDataMutation { ctx: &Context<'_>, id: i32, name: String, - ) -> async_graphql::Result { + ) -> async_graphql::Result { let db_accessor = ctx.data::()?; let draft_data = db_accessor.update_draft_data_name(id, &name).await?; Ok(draft_data.into()) } /// 更新草稿数据data + /// data为base64编码的字符串 async fn update_draft_data_data( &self, ctx: &Context<'_>, id: i32, - data: Vec, - ) -> async_graphql::Result { + data: String, // base64编码的数据 + ) -> async_graphql::Result { let db_accessor = ctx.data::()?; - let draft_data = db_accessor - .update_draft_data_data(id, data.as_slice()) - .await?; + let bytes = BASE64_STANDARD.decode(data).expect("base64 decode error"); + let draft_data = db_accessor.update_draft_data_data(id, &bytes).await?; Ok(draft_data.into()) } /// 更新草稿数据共享状态 @@ -124,7 +120,7 @@ impl DraftDataMutation { ctx: &Context<'_>, id: i32, is_shared: bool, - ) -> async_graphql::Result { + ) -> 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()) @@ -145,7 +141,7 @@ impl DraftDataMutation { ctx: &Context<'_>, id: i32, release_data_id: i32, - ) -> async_graphql::Result { + ) -> async_graphql::Result { let db_accessor = ctx.data::()?; let draft_data = db_accessor .set_default_release_data_id(id, release_data_id) @@ -159,7 +155,7 @@ impl DraftDataMutation { id: i32, name: String, user_id: i32, - ) -> async_graphql::Result { + ) -> async_graphql::Result { let db_accessor = ctx.data::()?; let draft_data = db_accessor.save_as_new_draft(id, &name, user_id).await?; Ok(draft_data.into()) @@ -208,27 +204,6 @@ impl From> for rtss_db::DraftDataQuery } } -pub trait DataOptions: InputType + OutputType + Serialize + DeserializeOwned { - fn to_data_options_filter_clause(&self) -> String; -} - -#[derive(Debug, InputObject, SimpleObject, Serialize, Deserialize)] -#[graphql(input_name = "IscsDataOptionsInput")] -pub struct IscsDataOptions { - pub style: IscsStyle, -} - -impl DataOptions for IscsDataOptions { - fn to_data_options_filter_clause(&self) -> String { - let options_column = DraftDataColumn::Options.name(); - // format!("{options_column}['style'] = '\"{}\"'", self.style.as_str_name()) - format!( - "{options_column} @> '{}'", - serde_json::to_string(self).unwrap() - ) - } -} - /// 共享的草稿数据查询条件 #[derive(Debug, InputObject)] #[graphql(concrete(name = "SharedDraftIscsDataFilterDto", params(IscsDataOptions)))] @@ -274,27 +249,32 @@ impl From for rtss_db::DraftDataQuery { } #[derive(Debug, SimpleObject)] -pub struct DraftDataWithStringOptions { +pub struct DraftDataDto { pub id: i32, pub name: String, pub data_type: rtss_dto::common::DataType, pub options: Option, - pub data: Option>, + /// base64编码的数据 + pub data: Option, pub user_id: i32, + pub default_release_data_id: Option, pub is_shared: bool, pub created_at: NaiveDateTime, pub updated_at: NaiveDateTime, } -impl From for DraftDataWithStringOptions { +impl From for DraftDataDto { fn from(value: rtss_db::model::DraftDataModel) -> Self { Self { id: value.id, name: value.name, data_type: DataType::try_from(value.data_type).unwrap(), options: value.options, - data: value.data, + data: value + .data + .map(|d| base64::prelude::BASE64_STANDARD.encode(d)), user_id: value.user_id, + default_release_data_id: value.default_release_data_id, is_shared: value.is_shared, created_at: value.created_at.naive_local(), updated_at: value.updated_at.naive_local(), @@ -303,90 +283,19 @@ impl From for DraftDataWithStringOptions { } #[derive(Debug, SimpleObject)] -#[graphql(concrete(name = "DraftIscsData", params(IscsDataOptions)))] -pub struct DraftData { - pub id: i32, - pub name: String, - pub data_type: rtss_dto::common::DataType, - pub options: Option, - pub data: Option>, - pub user_id: i32, - pub is_shared: bool, - pub created_at: NaiveDateTime, - pub updated_at: NaiveDateTime, +pub struct DraftIscsDataDto { + pub draft_data: DraftDataDto, + pub options: Option, } -impl From for DraftData { +impl From for DraftIscsDataDto { fn from(value: rtss_db::model::DraftDataModel) -> Self { Self { - id: value.id, - name: value.name, - data_type: DataType::try_from(value.data_type).unwrap(), - options: value.options.map(|o| serde_json::from_value(o).unwrap()), - data: value.data, - user_id: value.user_id, - is_shared: value.is_shared, - created_at: value.created_at.naive_local(), - updated_at: value.updated_at.naive_local(), + options: value + .options + .clone() + .map(|o| serde_json::from_value(o).unwrap()), + draft_data: value.into(), } } } - -#[derive(Debug, SimpleObject)] -pub struct DraftDataPage { - pub total: i64, - pub data: Vec, -} - -impl From> for DraftDataPage { - fn from(value: rtss_db::common::PageResult) -> Self { - Self { - total: value.total, - data: value.data.into_iter().map(|m| m.into()).collect(), - } - } -} - -#[derive(Debug, SimpleObject)] -pub struct DraftIscsDataPage { - pub total: i64, - pub data: Vec>, -} - -impl From> for DraftIscsDataPage { - fn from(value: rtss_db::common::PageResult) -> Self { - Self { - total: value.total, - data: value.data.into_iter().map(|m| m.into()).collect(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_iscs_data_options_serialize() { - rtss_log::Logging::default().init(); - let options = IscsDataOptions { - style: IscsStyle::DaShiZhiNeng, - }; - let json = serde_json::to_string(&options).unwrap(); - println!("{}", json); - println!("{}", options.style.as_str_name()); - assert_eq!(json, r#"{"style":"DaShiZhiNeng"}"#); - let options: IscsDataOptions = serde_json::from_str(&json).unwrap(); - assert_eq!(options.style, IscsStyle::DaShiZhiNeng); - } - - #[test] - fn test_iscs_data_options_into_data_options_filter_clause() { - let options = IscsDataOptions { - style: IscsStyle::DaShiZhiNeng, - }; - let clause = options.to_data_options_filter_clause(); - println!("{clause}"); - assert_eq!(clause, r#"options @> '{"style":"DaShiZhiNeng"}'"#); - } -} diff --git a/crates/rtss_api/src/apis/mod.rs b/crates/rtss_api/src/apis/mod.rs new file mode 100644 index 0000000..f99b007 --- /dev/null +++ b/crates/rtss_api/src/apis/mod.rs @@ -0,0 +1,68 @@ +use async_graphql::MergedObject; +use async_graphql::{Enum, InputObject, OutputType, SimpleObject}; +use draft_data::{DraftDataMutation, DraftDataQuery}; +use release_data::{ReleaseDataMutation, ReleaseDataQuery}; + +mod common; +mod draft_data; +mod release_data; +mod simulation; + +#[derive(Default, MergedObject)] +pub struct Query(DraftDataQuery, ReleaseDataQuery); + +#[derive(Default, MergedObject)] +pub struct Mutation(DraftDataMutation, ReleaseDataMutation); + +#[derive(Enum, Copy, Clone, Default, Eq, PartialEq, Debug)] +#[graphql(remote = "rtss_db::common::SortOrder")] +pub enum SortOrder { + #[default] + Asc, + Desc, +} + +#[derive(InputObject, Debug)] +pub struct PageQueryDto { + #[graphql(default = 1)] + pub page: i32, + #[graphql(default = 10)] + pub items_per_page: i32, +} + +impl From for rtss_db::common::PageQuery { + fn from(value: PageQueryDto) -> Self { + Self { + page: value.page, + items_per_page: value.items_per_page, + } + } +} + +#[derive(Debug, SimpleObject)] +#[graphql(concrete(name = "DraftDataPageDto", params(draft_data::DraftDataDto)))] +#[graphql(concrete(name = "DraftIscsDataPageDto", params(draft_data::DraftIscsDataDto)))] +#[graphql(concrete(name = "ReleaseDataPageDto", params(release_data::ReleaseDataDto)))] +#[graphql(concrete( + name = "ReleaseIscsDataPageDto", + params(release_data::ReleaseIscsDataWithoutVersionDto) +))] +pub struct PageDto { + pub total: i64, + pub items: Vec, +} + +impl PageDto { + pub fn new(total: i64, items: Vec) -> Self { + Self { total, items } + } +} + +impl> From> for PageDto { + fn from(value: rtss_db::common::PageResult) -> Self { + Self::new( + value.total, + value.data.into_iter().map(|m| m.into()).collect(), + ) + } +} diff --git a/crates/rtss_api/src/apis/release_data.rs b/crates/rtss_api/src/apis/release_data.rs new file mode 100644 index 0000000..f066ec8 --- /dev/null +++ b/crates/rtss_api/src/apis/release_data.rs @@ -0,0 +1,214 @@ +use async_graphql::{Context, InputObject, Object, SimpleObject}; +use base64::prelude::*; +use chrono::NaiveDateTime; +use rtss_db::model::*; +use rtss_db::{model::ReleaseDataModel, ReleaseDataAccessor, RtssDbAccessor}; +use rtss_dto::common::DataType; +use serde_json::Value; + +use super::common::IscsDataOptions; +use super::{PageDto, PageQueryDto}; + +#[derive(Default)] +pub struct ReleaseDataQuery; + +#[derive(Default)] +pub struct ReleaseDataMutation; + +#[Object] +impl ReleaseDataQuery { + /// 分页查询所有发布数据(系统管理用) + async fn release_data_paging( + &self, + ctx: &Context<'_>, + page: PageQueryDto, + query: ReleaseDataFilterDto, + ) -> async_graphql::Result> { + let db_accessor = ctx.data::()?; + let paging = db_accessor + .query_release_data_list(query.into(), page.into()) + .await?; + Ok(paging.into()) + } + + /// 分页查询用户发布的ISCS数据 + async fn user_release_iscs_data_paging( + &self, + ctx: &Context<'_>, + page: PageQueryDto, + query: UserReleaseDataFilterDto, + ) -> async_graphql::Result> { + let db_accessor = ctx.data::()?; + let paging = db_accessor + .query_release_data_list(query.into(), page.into()) + .await?; + Ok(paging.into()) + } + + /// id查询发布数据 + async fn release_data( + &self, + ctx: &Context<'_>, + id: i32, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let model = db_accessor.query_release_data_with_used_version(id).await?; + Ok(model.into()) + } +} + +#[Object] +impl ReleaseDataMutation { + /// 发布到新的发布数据 + async fn release_new_from_draft( + &self, + ctx: &Context<'_>, + draft_id: i32, + name: String, + description: String, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let result = db_accessor + .release_new_from_draft(draft_id, &name, &description) + .await?; + Ok(result.into()) + } + + /// 发布到默认发布数据,需要草稿数据发布过或设置了默认发布数据id + async fn release_to_default_release_data( + &self, + ctx: &Context<'_>, + draft_id: i32, + description: String, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let result = db_accessor + .release_to_existing(draft_id, &description) + .await?; + Ok(result.into()) + } +} + +#[derive(Debug, InputObject)] +pub struct ReleaseDataFilterDto { + pub name: Option, + pub user_id: Option, + pub data_type: Option, + pub is_published: Option, +} + +#[derive(Debug, InputObject)] +pub struct UserReleaseDataFilterDto { + pub user_id: i32, + pub name: Option, + pub data_type: Option, + pub is_published: Option, +} + +impl From for rtss_db::ReleaseDataQuery { + fn from(value: UserReleaseDataFilterDto) -> Self { + Self { + name: value.name, + user_id: Some(value.user_id), + data_type: value.data_type, + is_published: value.is_published, + } + } +} + +impl From for rtss_db::ReleaseDataQuery { + fn from(value: ReleaseDataFilterDto) -> Self { + Self { + name: value.name, + user_id: value.user_id, + data_type: value.data_type, + is_published: value.is_published, + } + } +} + +#[derive(Debug, SimpleObject)] +pub struct ReleaseDataDto { + pub id: i32, + pub name: String, + pub data_type: String, + pub options: Option, + pub used_version_id: Option, + pub user_id: i32, + pub is_published: bool, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, +} + +#[derive(Debug, SimpleObject)] +pub struct ReleaseIscsDataWithoutVersionDto { + pub release_data: ReleaseDataDto, + pub options: Option, +} + +impl From for ReleaseIscsDataWithoutVersionDto { + fn from(model: ReleaseDataModel) -> Self { + Self { + options: model + .options + .clone() + .map(|o| serde_json::from_value(o).unwrap()), + release_data: model.into(), + } + } +} + +#[derive(Debug, SimpleObject)] +pub struct ReleaseDataWithUsedVersionDto { + pub release_data: ReleaseDataDto, + pub used_version: Option, +} + +#[derive(Debug, SimpleObject)] +pub struct ReleaseDataVersionDto { + pub id: i32, + pub release_data_id: i32, + pub description: String, + /// base64编码的数据 + pub data: String, + pub user_id: i32, + pub created_at: NaiveDateTime, +} + +impl From<(ReleaseDataModel, ReleaseDataVersionModel)> for ReleaseDataWithUsedVersionDto { + fn from((data, version): (ReleaseDataModel, ReleaseDataVersionModel)) -> Self { + Self { + release_data: data.into(), + used_version: Some(version.into()), + } + } +} + +impl From for ReleaseDataVersionDto { + fn from(model: ReleaseDataVersionModel) -> Self { + Self { + id: model.id, + release_data_id: model.release_data_id, + description: model.description, + data: BASE64_STANDARD.encode(model.data), + user_id: model.user_id, + created_at: model.created_at.naive_local(), + } + } +} + +impl From for ReleaseDataDto { + fn from(model: ReleaseDataModel) -> Self { + Self { + id: model.id, + name: model.name, + data_type: model.data_type.to_string(), + options: model.options, + used_version_id: model.used_version_id, + user_id: model.user_id, + is_published: model.is_published, + created_at: model.created_at.naive_local(), + updated_at: model.updated_at.naive_local(), + } + } +} diff --git a/crates/rtss_api/src/simulation.rs b/crates/rtss_api/src/apis/simulation.rs similarity index 100% rename from crates/rtss_api/src/simulation.rs rename to crates/rtss_api/src/apis/simulation.rs diff --git a/crates/rtss_api/src/lib.rs b/crates/rtss_api/src/lib.rs index 6b14c79..3f8d1c4 100644 --- a/crates/rtss_api/src/lib.rs +++ b/crates/rtss_api/src/lib.rs @@ -1,8 +1,6 @@ -mod draft_data; // mod jwt_auth; -mod pagination; +mod apis; mod server; -mod simulation; mod simulation_definition; mod sys_info; diff --git a/crates/rtss_api/src/pagination.rs b/crates/rtss_api/src/pagination.rs deleted file mode 100644 index 31275ee..0000000 --- a/crates/rtss_api/src/pagination.rs +++ /dev/null @@ -1,29 +0,0 @@ -use async_graphql::{Enum, InputObject, SimpleObject}; - -#[derive(Enum, Copy, Clone, Default, Eq, PartialEq, Debug)] -#[graphql(remote = "rtss_db::common::SortOrder")] -pub enum SortOrder { - #[default] - Asc, - Desc, -} - -#[derive(InputObject, Debug)] -pub struct PageQueryDto { - pub page: i32, - pub items_per_page: i32, -} - -impl From for rtss_db::common::PageQuery { - fn from(value: PageQueryDto) -> Self { - Self { - page: value.page, - items_per_page: value.items_per_page, - } - } -} - -#[derive(SimpleObject)] -pub struct PageDto { - pub total: i64, -} diff --git a/crates/rtss_api/src/server.rs b/crates/rtss_api/src/server.rs index 1f744cd..65c220d 100644 --- a/crates/rtss_api/src/server.rs +++ b/crates/rtss_api/src/server.rs @@ -14,7 +14,7 @@ use rtss_log::tracing::{debug, info}; use tokio::net::TcpListener; use tower_http::cors::CorsLayer; -use crate::draft_data; +use crate::apis::{Mutation, Query}; use crate::simulation_definition::MutexSimulationManager; pub struct ServerConfig { @@ -83,12 +83,6 @@ async fn graphiql() -> impl IntoResponse { pub type SimulationSchema = Schema; -#[derive(Default, MergedObject)] -pub struct Query(draft_data::DraftDataQuery); - -#[derive(Default, MergedObject)] -pub struct Mutation(draft_data::DraftDataMutation); - pub async fn new_schema(config: &ServerConfig) -> SimulationSchema { let dba = rtss_db::get_db_accessor(&config.database_url).await; Schema::build(Query::default(), Mutation::default(), EmptySubscription) diff --git a/crates/rtss_db/src/db_access/release_data.rs b/crates/rtss_db/src/db_access/release_data.rs index 2c955ab..f291800 100644 --- a/crates/rtss_db/src/db_access/release_data.rs +++ b/crates/rtss_db/src/db_access/release_data.rs @@ -175,16 +175,19 @@ impl ReleaseDataAccessor for RtssDbAccessor { // 创建发布数据 let rd_table = ReleaseDataColumn::Table.name(); let rd_insert_columns = format!( - "({}, {}, {})", + "({}, {}, {}, {})", ReleaseDataColumn::Name.name(), ReleaseDataColumn::DataType.name(), + ReleaseDataColumn::Options.name(), ReleaseDataColumn::UserId.name(), ); - let rd_insert_clause = - format!("INSERT INTO {rd_table} {rd_insert_columns} VALUES ($1, $2, $3) RETURNING *"); + let rd_insert_clause = format!( + "INSERT INTO {rd_table} {rd_insert_columns} VALUES ($1, $2, $3, $4) RETURNING *" + ); let mut rd = sqlx::query_as::<_, ReleaseDataModel>(&rd_insert_clause) .bind(name) .bind(draft.data_type as i32) + .bind(draft.options) .bind(draft.user_id) .fetch_one(&mut *tx) .await?; @@ -239,7 +242,7 @@ impl ReleaseDataAccessor for RtssDbAccessor { )); } // 查询默认发布数据 - let mut rd = self + let rd = self .query_release_data_by_id(draft.default_release_data_id.unwrap()) .await?; // 开启事务 @@ -266,18 +269,19 @@ impl ReleaseDataAccessor for RtssDbAccessor { // 更新发布数据使用的版本 let rd_table = ReleaseDataColumn::Table.name(); let used_version_id = ReleaseDataColumn::UsedVersionId.name(); + let rd_options = ReleaseDataColumn::Options.name(); let rd_updated_at = ReleaseDataColumn::UpdatedAt.name(); let rd_id = ReleaseDataColumn::Id.name(); let rd_update_clause = - format!("UPDATE {rd_table} SET {used_version_id} = $1, {rd_updated_at} = 'now()' WHERE {rd_id} = $2"); - sqlx::query(&rd_update_clause) + format!("UPDATE {rd_table} SET {used_version_id} = $1, {rd_options} = $2, {rd_updated_at} = 'now()' WHERE {rd_id} = $3 RETURNING *"); + let rd = sqlx::query_as::<_, ReleaseDataModel>(&rd_update_clause) .bind(rdv.id) + .bind(draft.options.clone()) .bind(rd.id) - .execute(&mut *tx) + .fetch_one(&mut *tx) .await?; // 成功后提交事务 tx.commit().await?; - rd.used_version_id = Some(rdv.id); Ok((rd, rdv)) } @@ -350,17 +354,16 @@ impl ReleaseDataAccessor for RtssDbAccessor { let rdv_table = ReleaseDataVersionColumn::Table.name(); // 查询列,除了data列 let rdv_columns = format!( - "{}, {}, {}, {}, {}, {}", + "{}, {}, {}, {}, {}", ReleaseDataVersionColumn::Id.name(), ReleaseDataVersionColumn::ReleaseDataId.name(), - ReleaseDataVersionColumn::Version.name(), ReleaseDataVersionColumn::Description.name(), ReleaseDataVersionColumn::UserId.name(), ReleaseDataVersionColumn::CreatedAt.name(), ); let rdv_release_id = ReleaseDataVersionColumn::ReleaseDataId.name(); // 按版本号倒序排序 - let sort = Sort::new(ReleaseDataVersionColumn::Version, SortOrder::Desc); + let sort = Sort::new(ReleaseDataVersionColumn::Id, SortOrder::Desc); let order_by_clause = sort.to_order_by_clause(); let rdv_query_clause = format!( "SELECT {rdv_columns} FROM {rdv_table} WHERE {rdv_release_id} = $1 {order_by_clause}", @@ -507,7 +510,9 @@ mod tests { use crate::{CreateDraftData, DraftDataAccessor, RtssDbAccessor}; use super::*; + use rtss_dto::common::IscsStyle; use rtss_log::tracing::Level; + use serde::{Deserialize, Serialize}; use sqlx::PgPool; #[test] @@ -543,6 +548,11 @@ mod tests { assert_eq!(query_with_all.build_filter(), expects); } + #[derive(Debug, Serialize, Deserialize)] + pub struct IscsDataOptions { + pub style: IscsStyle, + } + // You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here. #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_basic_use(pool: PgPool) -> Result<(), DbAccessError> { @@ -552,7 +562,14 @@ mod tests { let data = "test".as_bytes(); let draft = accessor .create_draft_data( - CreateDraftData::new("test", rtss_dto::common::DataType::Em, 1).with_data(data), + CreateDraftData::new("test", rtss_dto::common::DataType::Iscs, 1) + .with_options( + serde_json::to_value(IscsDataOptions { + style: IscsStyle::DaShiZhiNeng, + }) + .unwrap(), + ) + .with_data(data), ) .await?; let name = "test_release"; @@ -576,6 +593,10 @@ mod tests { assert_eq!(release_data.name, name); // 检查使用版本是刚刚发布的版本 assert_eq!(release_data.used_version_id, Some(version1.id)); + // 检查options数据 + let options: IscsDataOptions = + serde_json::from_value(release_data.options.unwrap()).unwrap(); + assert_eq!(options.style, IscsStyle::DaShiZhiNeng); // 检查版本数据 assert_eq!(version1.data, data); // 检查版本描述 @@ -694,7 +715,7 @@ mod tests { let query = ReleaseDataQuery::new().with_data_type(rtss_dto::common::DataType::Em); let page = PageQuery::new(1, 10); let page_result = accessor.query_release_data_list(query, page).await?; - assert_eq!(page_result.total, 9); + assert_eq!(page_result.total, 8); println!("分页查询发布数据测试成功"); Ok(()) diff --git a/crates/rtss_db/src/model.rs b/crates/rtss_db/src/model.rs index d8c50fa..cc3c397 100644 --- a/crates/rtss_db/src/model.rs +++ b/crates/rtss_db/src/model.rs @@ -74,7 +74,6 @@ pub(crate) enum ReleaseDataVersionColumn { Id, ReleaseDataId, Data, - Version, Description, UserId, CreatedAt, @@ -86,7 +85,6 @@ pub struct ReleaseDataVersionModel { pub release_data_id: i32, #[sqlx(default)] pub data: Vec, - pub version: i32, pub description: String, pub user_id: i32, pub created_at: DateTime, @@ -243,7 +241,6 @@ impl TableColumn for ReleaseDataVersionColumn { ReleaseDataVersionColumn::Id => "id", ReleaseDataVersionColumn::ReleaseDataId => "release_data_id", ReleaseDataVersionColumn::Data => "data", - ReleaseDataVersionColumn::Version => "version", ReleaseDataVersionColumn::Description => "description", ReleaseDataVersionColumn::UserId => "user_id", ReleaseDataVersionColumn::CreatedAt => "created_at", diff --git a/migrations/20240830095636_init.up.sql b/migrations/20240830095636_init.up.sql index ab42568..1c40a86 100644 --- a/migrations/20240830095636_init.up.sql +++ b/migrations/20240830095636_init.up.sql @@ -90,7 +90,6 @@ CREATE TABLE id SERIAL PRIMARY KEY, -- id 自增主键 release_data_id INT NOT NULL, -- 发布数据id data BYTEA NOT NULL, -- 数据 - version SERIAL NOT NULL, -- 版本号 description TEXT NOT NULL, -- 版本描述 user_id INT NOT NULL, -- 发布用户id created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 @@ -113,8 +112,6 @@ COMMENT ON COLUMN rtss.release_data_version.release_data_id IS '发布数据id'; COMMENT ON COLUMN rtss.release_data_version.data IS '数据'; -COMMENT ON COLUMN rtss.release_data_version.version IS '版本号'; - COMMENT ON COLUMN rtss.release_data_version.description IS '版本描述'; COMMENT ON COLUMN rtss.release_data_version.user_id IS '发布用户id';