Compare commits
2 Commits
6ddc4fd110
...
e8fa4d119c
Author | SHA1 | Date | |
---|---|---|---|
|
e8fa4d119c | ||
|
df4c9940f3 |
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -160,10 +160,13 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"fast_chemail",
|
"fast_chemail",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-timer",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"handlebars",
|
"handlebars",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"lru",
|
||||||
"mime",
|
"mime",
|
||||||
"multer",
|
"multer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@ -1158,6 +1161,12 @@ version = "0.3.30"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-timer"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
@ -1544,6 +1553,15 @@ version = "0.4.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2978,15 +2996,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-http"
|
name = "tower-http"
|
||||||
version = "0.5.2"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
checksum = "41515cc9e193536d93fd0dbbea0c73819c08eca76e0b30909a325c3ec90985bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
|
||||||
"http-body-util",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
|
@ -12,8 +12,8 @@ chrono = { version = "0.4.38", features = ["serde"] }
|
|||||||
axum = "0.7.5"
|
axum = "0.7.5"
|
||||||
axum-extra = { version = "0.9.3", features = ["typed-header"] }
|
axum-extra = { version = "0.9.3", features = ["typed-header"] }
|
||||||
# jsonwebtoken = "9.3.0"
|
# jsonwebtoken = "9.3.0"
|
||||||
tower-http = { version = "0.5.0", features = ["cors"] }
|
tower-http = { version = "0.6.0", features = ["cors"] }
|
||||||
async-graphql = { version = "7.0.7", features = ["chrono"] }
|
async-graphql = { version = "7.0.7", features = ["chrono", "dataloader"] }
|
||||||
async-graphql-axum = "7.0.6"
|
async-graphql-axum = "7.0.6"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
sysinfo = "0.31.3"
|
sysinfo = "0.31.3"
|
||||||
|
@ -112,7 +112,9 @@ impl DraftDataMutation {
|
|||||||
data: String, // base64编码的数据
|
data: String, // base64编码的数据
|
||||||
) -> async_graphql::Result<DraftDataDto> {
|
) -> async_graphql::Result<DraftDataDto> {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let bytes = BASE64_STANDARD.decode(data).expect("base64 decode error");
|
let bytes = BASE64_STANDARD
|
||||||
|
.decode(data)
|
||||||
|
.map_err(|e| async_graphql::Error::new(format!("base64 decode error: {}", e)))?;
|
||||||
let draft_data = db_accessor.update_draft_data_data(id, &bytes).await?;
|
let draft_data = db_accessor.update_draft_data_data(id, &bytes).await?;
|
||||||
Ok(draft_data.into())
|
Ok(draft_data.into())
|
||||||
}
|
}
|
||||||
@ -303,3 +305,17 @@ impl From<rtss_db::model::DraftDataModel> for DraftIscsDataDto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_base64() {
|
||||||
|
let data = b"hello world";
|
||||||
|
let encoded = BASE64_STANDARD.encode(data);
|
||||||
|
let decoded = BASE64_STANDARD.decode(&encoded).unwrap();
|
||||||
|
assert_eq!(data, decoded.as_slice());
|
||||||
|
println!("encoded: {}, decoded: {:?}", encoded, decoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use async_graphql::MergedObject;
|
use async_graphql::dataloader::DataLoader;
|
||||||
|
use async_graphql::{EmptySubscription, MergedObject, Schema};
|
||||||
use async_graphql::{Enum, InputObject, OutputType, SimpleObject};
|
use async_graphql::{Enum, InputObject, OutputType, SimpleObject};
|
||||||
use draft_data::{DraftDataMutation, DraftDataQuery};
|
use draft_data::{DraftDataMutation, DraftDataQuery};
|
||||||
use release_data::{ReleaseDataMutation, ReleaseDataQuery};
|
use release_data::{ReleaseDataMutation, ReleaseDataQuery};
|
||||||
|
|
||||||
|
use crate::simulation_definition::MutexSimulationManager;
|
||||||
|
use crate::ServerConfig;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
mod draft_data;
|
mod draft_data;
|
||||||
mod release_data;
|
mod release_data;
|
||||||
@ -70,3 +74,25 @@ impl<T: OutputType, M: Into<T>> From<rtss_db::common::PageResult<M>> for PageDto
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RtssDbLoader {
|
||||||
|
pub(crate) db_accessor: rtss_db::RtssDbAccessor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RtssDbLoader {
|
||||||
|
pub fn new(db_accessor: rtss_db::RtssDbAccessor) -> Self {
|
||||||
|
Self { db_accessor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RtssAppSchema = Schema<Query, Mutation, EmptySubscription>;
|
||||||
|
|
||||||
|
pub async fn new_schema(config: &ServerConfig) -> RtssAppSchema {
|
||||||
|
let dba = rtss_db::get_db_accessor(&config.database_url).await;
|
||||||
|
let loader = RtssDbLoader::new(dba.clone());
|
||||||
|
Schema::build(Query::default(), Mutation::default(), EmptySubscription)
|
||||||
|
.data(dba)
|
||||||
|
.data(DataLoader::new(loader, tokio::spawn))
|
||||||
|
.data(MutexSimulationManager::default())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
use async_graphql::{Context, InputObject, Object, SimpleObject};
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use async_graphql::dataloader::*;
|
||||||
|
use async_graphql::{ComplexObject, Context, InputObject, Object, SimpleObject};
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use rtss_db::model::*;
|
use rtss_db::model::*;
|
||||||
|
use rtss_db::prelude::*;
|
||||||
use rtss_db::{model::ReleaseDataModel, ReleaseDataAccessor, RtssDbAccessor};
|
use rtss_db::{model::ReleaseDataModel, ReleaseDataAccessor, RtssDbAccessor};
|
||||||
use rtss_dto::common::DataType;
|
use rtss_dto::common::DataType;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@ -9,7 +14,7 @@ use serde_json::Value;
|
|||||||
use crate::apis::draft_data::DraftDataDto;
|
use crate::apis::draft_data::DraftDataDto;
|
||||||
|
|
||||||
use super::common::{DataOptions, IscsDataOptions};
|
use super::common::{DataOptions, IscsDataOptions};
|
||||||
use super::{PageDto, PageQueryDto};
|
use super::{PageDto, PageQueryDto, RtssDbLoader};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ReleaseDataQuery;
|
pub struct ReleaseDataQuery;
|
||||||
@ -59,6 +64,17 @@ impl ReleaseDataQuery {
|
|||||||
Ok(model.into())
|
Ok(model.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 是否已经存在相同name的发布数据
|
||||||
|
async fn is_release_data_name_exists(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
name: String,
|
||||||
|
) -> async_graphql::Result<bool> {
|
||||||
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
|
let result = db_accessor.is_release_data_name_exist(&name).await?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
/// 查询发布数据的版本
|
/// 查询发布数据的版本
|
||||||
async fn release_data_version_paging(
|
async fn release_data_version_paging(
|
||||||
&self,
|
&self,
|
||||||
@ -162,12 +178,12 @@ impl ReleaseDataMutation {
|
|||||||
async fn create_draft_data_from_release_data_version(
|
async fn create_draft_data_from_release_data_version(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
release_data_id: i32,
|
|
||||||
version_id: i32,
|
version_id: i32,
|
||||||
|
user_id: i32,
|
||||||
) -> async_graphql::Result<DraftDataDto> {
|
) -> async_graphql::Result<DraftDataDto> {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let result = db_accessor
|
let result = db_accessor
|
||||||
.create_draft_from_release_version(release_data_id, version_id)
|
.create_draft_from_release_version(version_id, user_id)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(result.into())
|
Ok(result.into())
|
||||||
}
|
}
|
||||||
@ -215,6 +231,7 @@ impl From<ReleaseDataFilterDto> for rtss_db::ReleaseDataQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, SimpleObject)]
|
#[derive(Debug, SimpleObject)]
|
||||||
|
#[graphql(complex)]
|
||||||
pub struct ReleaseDataDto {
|
pub struct ReleaseDataDto {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -227,6 +244,53 @@ pub struct ReleaseDataDto {
|
|||||||
pub updated_at: NaiveDateTime,
|
pub updated_at: NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[ComplexObject]
|
||||||
|
impl ReleaseDataDto {
|
||||||
|
async fn description(&self, ctx: &Context<'_>) -> async_graphql::Result<Option<String>> {
|
||||||
|
if let Some(version_id) = self.used_version_id {
|
||||||
|
let loader = ctx.data_unchecked::<DataLoader<RtssDbLoader>>();
|
||||||
|
let description = loader
|
||||||
|
.load_one(ReleaseDataVersionId::new(version_id))
|
||||||
|
.await?;
|
||||||
|
Ok(description)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
pub struct ReleaseDataVersionId {
|
||||||
|
pub id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReleaseDataVersionId {
|
||||||
|
pub fn new(id: i32) -> Self {
|
||||||
|
Self { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loader<ReleaseDataVersionId> for RtssDbLoader {
|
||||||
|
type Value = String;
|
||||||
|
type Error = Arc<DbAccessError>;
|
||||||
|
|
||||||
|
async fn load(
|
||||||
|
&self,
|
||||||
|
keys: &[ReleaseDataVersionId],
|
||||||
|
) -> Result<HashMap<ReleaseDataVersionId, Self::Value>, Self::Error> {
|
||||||
|
let ids: Vec<i32> = keys.iter().map(|k| k.id).collect();
|
||||||
|
let rows = self
|
||||||
|
.db_accessor
|
||||||
|
.query_release_data_version_descriptions(ids.as_slice())
|
||||||
|
.await?;
|
||||||
|
let map: HashMap<ReleaseDataVersionId, String> = rows
|
||||||
|
.into_iter()
|
||||||
|
.map(|r| (ReleaseDataVersionId { id: r.0 }, r.1))
|
||||||
|
.collect();
|
||||||
|
Ok(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, SimpleObject)]
|
#[derive(Debug, SimpleObject)]
|
||||||
pub struct ReleaseIscsDataWithoutVersionDto {
|
pub struct ReleaseIscsDataWithoutVersionDto {
|
||||||
pub release_data: ReleaseDataDto,
|
pub release_data: ReleaseDataDto,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
use async_graphql::{EmptySubscription, Schema};
|
|
||||||
use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
|
use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::http::HeaderMap;
|
use axum::http::HeaderMap;
|
||||||
@ -14,8 +13,7 @@ use rtss_log::tracing::{debug, info};
|
|||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tower_http::cors::CorsLayer;
|
use tower_http::cors::CorsLayer;
|
||||||
|
|
||||||
use crate::apis::{Mutation, Query};
|
use crate::apis::RtssAppSchema;
|
||||||
use crate::simulation_definition::MutexSimulationManager;
|
|
||||||
|
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub database_url: String,
|
pub database_url: String,
|
||||||
@ -36,7 +34,7 @@ impl ServerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serve(config: ServerConfig) -> anyhow::Result<()> {
|
pub async fn serve(config: ServerConfig) -> anyhow::Result<()> {
|
||||||
let schema = new_schema(&config).await;
|
let schema = crate::apis::new_schema(&config).await;
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(graphiql).post(graphql_handler))
|
.route("/", get(graphiql).post(graphql_handler))
|
||||||
@ -59,7 +57,7 @@ pub async fn serve(config: ServerConfig) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn graphql_handler(
|
async fn graphql_handler(
|
||||||
State(schema): State<SimulationSchema>,
|
State(schema): State<RtssAppSchema>,
|
||||||
_headers: HeaderMap,
|
_headers: HeaderMap,
|
||||||
req: GraphQLRequest,
|
req: GraphQLRequest,
|
||||||
) -> GraphQLResponse {
|
) -> GraphQLResponse {
|
||||||
@ -80,13 +78,3 @@ async fn graphql_handler(
|
|||||||
async fn graphiql() -> impl IntoResponse {
|
async fn graphiql() -> impl IntoResponse {
|
||||||
Html(playground_source(GraphQLPlaygroundConfig::new("/")))
|
Html(playground_source(GraphQLPlaygroundConfig::new("/")))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SimulationSchema = Schema<Query, Mutation, EmptySubscription>;
|
|
||||||
|
|
||||||
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)
|
|
||||||
.data(dba)
|
|
||||||
.data(MutexSimulationManager::default())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
|
@ -178,6 +178,14 @@ impl CreateDraftData {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_option_default_release_data_id(
|
||||||
|
mut self,
|
||||||
|
default_release_data_id: Option<i32>,
|
||||||
|
) -> Self {
|
||||||
|
self.default_release_data_id = default_release_data_id;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_default_release_data_id(mut self, default_release_data_id: i32) -> Self {
|
pub fn with_default_release_data_id(mut self, default_release_data_id: i32) -> Self {
|
||||||
self.default_release_data_id = Some(default_release_data_id);
|
self.default_release_data_id = Some(default_release_data_id);
|
||||||
self
|
self
|
||||||
@ -400,7 +408,10 @@ impl DraftDataAccessor for RtssDbAccessor {
|
|||||||
DataType::try_from(draft_data.data_type).unwrap(),
|
DataType::try_from(draft_data.data_type).unwrap(),
|
||||||
user_id,
|
user_id,
|
||||||
)
|
)
|
||||||
.with_data(draft_data.data.as_ref().unwrap());
|
.with_option_options(draft_data.options)
|
||||||
|
.with_data(draft_data.data.as_ref().unwrap())
|
||||||
|
.with_option_default_release_data_id(draft_data.default_release_data_id);
|
||||||
|
|
||||||
self.create_draft_data(create).await
|
self.create_draft_data(create).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -472,7 +483,12 @@ mod tests {
|
|||||||
println!("{:?}", new_draft);
|
println!("{:?}", new_draft);
|
||||||
assert_eq!(new_draft.name, "new draft");
|
assert_eq!(new_draft.name, "new draft");
|
||||||
assert_eq!(new_draft.user_id, 11);
|
assert_eq!(new_draft.user_id, 11);
|
||||||
|
assert_eq!(new_draft.options, res.options);
|
||||||
assert_eq!(new_draft.data.unwrap(), data);
|
assert_eq!(new_draft.data.unwrap(), data);
|
||||||
|
assert_eq!(
|
||||||
|
new_draft.default_release_data_id,
|
||||||
|
res.default_release_data_id
|
||||||
|
);
|
||||||
|
|
||||||
// delete测试
|
// delete测试
|
||||||
accessor.delete_draft_data(&[res.id, new_draft.id]).await?;
|
accessor.delete_draft_data(&[res.id, new_draft.id]).await?;
|
||||||
|
@ -3,6 +3,7 @@ pub use draft_data::*;
|
|||||||
mod release_data;
|
mod release_data;
|
||||||
pub use release_data::*;
|
pub use release_data::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct RtssDbAccessor {
|
pub struct RtssDbAccessor {
|
||||||
pool: sqlx::PgPool,
|
pool: sqlx::PgPool,
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,11 @@ pub trait ReleaseDataAccessor {
|
|||||||
&self,
|
&self,
|
||||||
version_id: i32,
|
version_id: i32,
|
||||||
) -> Result<ReleaseDataVersionModel, DbAccessError>;
|
) -> Result<ReleaseDataVersionModel, DbAccessError>;
|
||||||
|
/// 根据id列表查询发布版本数据description
|
||||||
|
async fn query_release_data_version_descriptions(
|
||||||
|
&self,
|
||||||
|
version_ids: &[i32],
|
||||||
|
) -> Result<Vec<(i32, String)>, DbAccessError>;
|
||||||
/// 查询发布数据详情
|
/// 查询发布数据详情
|
||||||
async fn query_release_data_with_used_version(
|
async fn query_release_data_with_used_version(
|
||||||
&self,
|
&self,
|
||||||
@ -445,6 +450,25 @@ impl ReleaseDataAccessor for RtssDbAccessor {
|
|||||||
Ok(rdv)
|
Ok(rdv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn query_release_data_version_descriptions(
|
||||||
|
&self,
|
||||||
|
version_ids: &[i32],
|
||||||
|
) -> Result<Vec<(i32, String)>, DbAccessError> {
|
||||||
|
// 查询发布数据版本
|
||||||
|
let rdv_table = ReleaseDataVersionColumn::Table.name();
|
||||||
|
let rdv_id = ReleaseDataVersionColumn::Id.name();
|
||||||
|
let rdv_description = ReleaseDataVersionColumn::Description.name();
|
||||||
|
let select_columns = format!("{rdv_id}, {rdv_description}");
|
||||||
|
let rdv_query_clause =
|
||||||
|
format!("SELECT {select_columns} FROM {rdv_table} WHERE {rdv_id} = ANY($1)",);
|
||||||
|
let rdv = sqlx::query_as::<_, (i32, String)>(&rdv_query_clause)
|
||||||
|
.bind(version_ids)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(rdv)
|
||||||
|
}
|
||||||
|
|
||||||
async fn query_release_data_with_used_version(
|
async fn query_release_data_with_used_version(
|
||||||
&self,
|
&self,
|
||||||
release_id: i32,
|
release_id: i32,
|
||||||
@ -780,6 +804,17 @@ mod tests {
|
|||||||
assert_eq!(page_result.total, 8);
|
assert_eq!(page_result.total, 8);
|
||||||
println!("分页查询发布数据测试成功");
|
println!("分页查询发布数据测试成功");
|
||||||
|
|
||||||
|
// 测试根据数据版本id查询descriptions
|
||||||
|
let version_ids: Vec<i32> = page_result
|
||||||
|
.data
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| d.used_version_id.unwrap())
|
||||||
|
.collect();
|
||||||
|
let description_map = accessor
|
||||||
|
.query_release_data_version_descriptions(version_ids.as_slice())
|
||||||
|
.await?;
|
||||||
|
println!("{:?}", description_map);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use thiserror::Error;
|
|||||||
pub enum DbAccessError {
|
pub enum DbAccessError {
|
||||||
#[error("未知的数据库访问错误")]
|
#[error("未知的数据库访问错误")]
|
||||||
Unknown,
|
Unknown,
|
||||||
#[error("sqlx 错误: {0}")]
|
#[error("数据访问错误: {0}")]
|
||||||
SqlxError(#[from] sqlx::Error),
|
SqlxError(#[from] sqlx::Error),
|
||||||
#[error("数据已存在")]
|
#[error("数据已存在")]
|
||||||
RowExist,
|
RowExist,
|
||||||
|
Loading…
Reference in New Issue
Block a user