调整数据库表结构定义
build / build-rust (push) Successful in 1m49s
Details
build / build-rust (push) Successful in 1m49s
Details
添加feature数据库访问功能及实现 添加feature几个api接口及实现 调整数据库模型枚举字段使用枚举取代i32 添加设计文档
This commit is contained in:
parent
176d9b09e4
commit
3798572b0c
|
@ -5,7 +5,7 @@ use base64::Engine;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use rtss_db::DraftDataAccessor;
|
use rtss_db::DraftDataAccessor;
|
||||||
use rtss_db::RtssDbAccessor;
|
use rtss_db::RtssDbAccessor;
|
||||||
use rtss_dto::common::DataType;
|
use rtss_dto::common::{DataType, Role};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::apis::{PageDto, PageQueryDto};
|
use crate::apis::{PageDto, PageQueryDto};
|
||||||
|
@ -15,7 +15,7 @@ use super::common::{DataOptions, IscsDataOptions};
|
||||||
use super::release_data::ReleaseDataId;
|
use super::release_data::ReleaseDataId;
|
||||||
use super::user::UserId;
|
use super::user::UserId;
|
||||||
|
|
||||||
use crate::user_auth::{Role, RoleGuard, Token, UserAuthCache};
|
use crate::user_auth::{RoleGuard, Token, UserAuthCache};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DraftDataQuery;
|
pub struct DraftDataQuery;
|
||||||
|
@ -35,7 +35,7 @@ impl DraftDataQuery {
|
||||||
) -> async_graphql::Result<PageDto<DraftDataDto>> {
|
) -> async_graphql::Result<PageDto<DraftDataDto>> {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let paging_result = db_accessor
|
let paging_result = db_accessor
|
||||||
.query_draft_data(query.into(), paging.into())
|
.paging_query_draft_data(query.into(), paging.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(paging_result.into())
|
Ok(paging_result.into())
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ impl DraftDataQuery {
|
||||||
query.data_type = Some(DataType::Iscs);
|
query.data_type = Some(DataType::Iscs);
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let paging_result = db_accessor
|
let paging_result = db_accessor
|
||||||
.query_draft_data(query.into(), paging.into())
|
.paging_query_draft_data(query.into(), paging.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(paging_result.into())
|
Ok(paging_result.into())
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ impl DraftDataQuery {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
query.data_type = Some(DataType::Iscs);
|
query.data_type = Some(DataType::Iscs);
|
||||||
let paging_result = db_accessor
|
let paging_result = db_accessor
|
||||||
.query_draft_data(query.into(), paging.into())
|
.paging_query_draft_data(query.into(), paging.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(paging_result.into())
|
Ok(paging_result.into())
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ impl DraftDataQuery {
|
||||||
async fn draft_data_exist(
|
async fn draft_data_exist(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
|
data_type: DataType,
|
||||||
name: String,
|
name: String,
|
||||||
) -> async_graphql::Result<bool> {
|
) -> async_graphql::Result<bool> {
|
||||||
let user = ctx
|
let user = ctx
|
||||||
|
@ -94,7 +95,9 @@ impl DraftDataQuery {
|
||||||
.await?;
|
.await?;
|
||||||
let user_id = user.id_i32();
|
let user_id = user.id_i32();
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let exist = db_accessor.is_draft_data_exist(user_id, &name).await?;
|
let exist = db_accessor
|
||||||
|
.is_draft_data_exist(user_id, &data_type, &name)
|
||||||
|
.await?;
|
||||||
Ok(exist)
|
Ok(exist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +331,7 @@ impl From<rtss_db::model::DraftDataModel> for DraftDataDto {
|
||||||
Self {
|
Self {
|
||||||
id: value.id,
|
id: value.id,
|
||||||
name: value.name,
|
name: value.name,
|
||||||
data_type: DataType::try_from(value.data_type).unwrap(),
|
data_type: value.data_type,
|
||||||
options: value.options,
|
options: value.options,
|
||||||
data: value
|
data: value
|
||||||
.data
|
.data
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
use async_graphql::{
|
||||||
|
dataloader::DataLoader, ComplexObject, Context, InputObject, Object, SimpleObject,
|
||||||
|
};
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use rtss_db::{FeatureAccessor, RtssDbAccessor};
|
||||||
|
use rtss_dto::common::FeatureType;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
apis::{PageDto, PageQueryDto},
|
||||||
|
loader::RtssDbLoader,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::user::UserId;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct FeatureQuery;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct FeatureMutation;
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl FeatureQuery {
|
||||||
|
/// 分页查询特征(系统管理)
|
||||||
|
async fn feature_paging(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
page: PageQueryDto,
|
||||||
|
query: FeatureQueryDto,
|
||||||
|
) -> async_graphql::Result<PageDto<FeatureDto>> {
|
||||||
|
let dba = ctx.data::<RtssDbAccessor>()?;
|
||||||
|
let paging = dba
|
||||||
|
.paging_query_features(page.into(), &query.into())
|
||||||
|
.await?;
|
||||||
|
Ok(paging.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// id获取特征
|
||||||
|
async fn feature(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result<FeatureDto> {
|
||||||
|
let dba = ctx.data::<RtssDbAccessor>()?;
|
||||||
|
let feature = dba.get_feature(id).await?;
|
||||||
|
Ok(feature.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// id列表获取特征
|
||||||
|
async fn features(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
ids: Vec<i32>,
|
||||||
|
) -> async_graphql::Result<Vec<FeatureDto>> {
|
||||||
|
let dba = ctx.data::<RtssDbAccessor>()?;
|
||||||
|
let features = dba.get_features(ids.as_slice()).await?;
|
||||||
|
Ok(features.into_iter().map(|f| f.into()).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl FeatureMutation {
|
||||||
|
/// 上下架特征
|
||||||
|
async fn publish_feature(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
id: i32,
|
||||||
|
is_published: bool,
|
||||||
|
) -> async_graphql::Result<FeatureDto> {
|
||||||
|
let dba = ctx.data::<RtssDbAccessor>()?;
|
||||||
|
let feature = dba.set_feature_published(id, is_published).await?;
|
||||||
|
Ok(feature.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, InputObject)]
|
||||||
|
pub struct FeatureQueryDto {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub feature_type: Option<i32>,
|
||||||
|
pub is_published: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FeatureQueryDto> for rtss_db::FeaturePagingFilter {
|
||||||
|
fn from(value: FeatureQueryDto) -> Self {
|
||||||
|
Self {
|
||||||
|
name: value.name,
|
||||||
|
feature_type: value.feature_type,
|
||||||
|
is_published: value.is_published,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, SimpleObject)]
|
||||||
|
#[graphql(complex)]
|
||||||
|
pub struct FeatureDto {
|
||||||
|
pub id: i32,
|
||||||
|
pub feature_type: FeatureType,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub config: Value,
|
||||||
|
pub is_published: bool,
|
||||||
|
pub creator_id: i32,
|
||||||
|
pub updater_id: i32,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ComplexObject]
|
||||||
|
impl FeatureDto {
|
||||||
|
/// 创建用户name
|
||||||
|
async fn creator_name(&self, ctx: &Context<'_>) -> async_graphql::Result<Option<String>> {
|
||||||
|
let loader = ctx.data_unchecked::<DataLoader<RtssDbLoader>>();
|
||||||
|
let name = loader.load_one(UserId::new(self.creator_id)).await?;
|
||||||
|
Ok(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 更新用户name
|
||||||
|
async fn updater_name(&self, ctx: &Context<'_>) -> async_graphql::Result<Option<String>> {
|
||||||
|
let loader = ctx.data_unchecked::<DataLoader<RtssDbLoader>>();
|
||||||
|
let name = loader.load_one(UserId::new(self.updater_id)).await?;
|
||||||
|
Ok(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<rtss_db::model::FeatureModel> for FeatureDto {
|
||||||
|
fn from(value: rtss_db::model::FeatureModel) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.id,
|
||||||
|
feature_type: value.feature_type,
|
||||||
|
name: value.name,
|
||||||
|
description: value.description,
|
||||||
|
config: value.config,
|
||||||
|
is_published: value.is_published,
|
||||||
|
creator_id: value.creator_id,
|
||||||
|
updater_id: value.updater_id,
|
||||||
|
created_at: value.created_at.naive_local(),
|
||||||
|
updated_at: value.updated_at.naive_local(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
use async_graphql::{Enum, InputObject, MergedObject, OutputType, SimpleObject};
|
use async_graphql::{Enum, InputObject, MergedObject, OutputType, SimpleObject};
|
||||||
use draft_data::{DraftDataMutation, DraftDataQuery};
|
use draft_data::{DraftDataMutation, DraftDataQuery};
|
||||||
|
use feature::{FeatureMutation, FeatureQuery};
|
||||||
use release_data::{ReleaseDataMutation, ReleaseDataQuery};
|
use release_data::{ReleaseDataMutation, ReleaseDataQuery};
|
||||||
|
|
||||||
mod simulation_definition;
|
mod simulation_definition;
|
||||||
|
@ -9,15 +10,21 @@ use user::{UserMutation, UserQuery};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
mod draft_data;
|
mod draft_data;
|
||||||
|
mod feature;
|
||||||
mod release_data;
|
mod release_data;
|
||||||
mod simulation;
|
mod simulation;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
#[derive(Default, MergedObject)]
|
#[derive(Default, MergedObject)]
|
||||||
pub struct Query(UserQuery, DraftDataQuery, ReleaseDataQuery);
|
pub struct Query(UserQuery, DraftDataQuery, ReleaseDataQuery, FeatureQuery);
|
||||||
|
|
||||||
#[derive(Default, MergedObject)]
|
#[derive(Default, MergedObject)]
|
||||||
pub struct Mutation(UserMutation, DraftDataMutation, ReleaseDataMutation);
|
pub struct Mutation(
|
||||||
|
UserMutation,
|
||||||
|
DraftDataMutation,
|
||||||
|
ReleaseDataMutation,
|
||||||
|
FeatureMutation,
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Enum, Copy, Clone, Default, Eq, PartialEq, Debug)]
|
#[derive(Enum, Copy, Clone, Default, Eq, PartialEq, Debug)]
|
||||||
#[graphql(remote = "rtss_db::common::SortOrder")]
|
#[graphql(remote = "rtss_db::common::SortOrder")]
|
||||||
|
@ -57,6 +64,7 @@ impl From<PageQueryDto> for rtss_db::common::PageQuery {
|
||||||
name = "ReleaseIscsDataPageDto",
|
name = "ReleaseIscsDataPageDto",
|
||||||
params(release_data::ReleaseIscsDataWithoutVersionDto)
|
params(release_data::ReleaseIscsDataWithoutVersionDto)
|
||||||
))]
|
))]
|
||||||
|
#[graphql(concrete(name = "FeaturePageDto", params(feature::FeatureDto)))]
|
||||||
pub struct PageDto<T: OutputType> {
|
pub struct PageDto<T: OutputType> {
|
||||||
pub total: i64,
|
pub total: i64,
|
||||||
pub items: Vec<T>,
|
pub items: Vec<T>,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use chrono::NaiveDateTime;
|
||||||
use rtss_db::model::*;
|
use rtss_db::model::*;
|
||||||
use rtss_db::prelude::*;
|
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, Role};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::apis::draft_data::DraftDataDto;
|
use crate::apis::draft_data::DraftDataDto;
|
||||||
|
@ -18,7 +18,7 @@ use super::common::{DataOptions, IscsDataOptions};
|
||||||
use super::user::UserId;
|
use super::user::UserId;
|
||||||
use super::{PageDto, PageQueryDto};
|
use super::{PageDto, PageQueryDto};
|
||||||
|
|
||||||
use crate::user_auth::{Role, RoleGuard, Token, UserAuthCache};
|
use crate::user_auth::{RoleGuard, Token, UserAuthCache};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ReleaseDataQuery;
|
pub struct ReleaseDataQuery;
|
||||||
|
@ -38,7 +38,7 @@ impl ReleaseDataQuery {
|
||||||
) -> async_graphql::Result<PageDto<ReleaseDataDto>> {
|
) -> async_graphql::Result<PageDto<ReleaseDataDto>> {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let paging = db_accessor
|
let paging = db_accessor
|
||||||
.query_release_data_list(query.into(), page.into())
|
.paging_query_release_data_list(query.into(), page.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(paging.into())
|
Ok(paging.into())
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ impl ReleaseDataQuery {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
query.data_type = Some(DataType::Iscs);
|
query.data_type = Some(DataType::Iscs);
|
||||||
let paging = db_accessor
|
let paging = db_accessor
|
||||||
.query_release_data_list(query.into(), page.into())
|
.paging_query_release_data_list(query.into(), page.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(paging.into())
|
Ok(paging.into())
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ impl ReleaseDataQuery {
|
||||||
) -> async_graphql::Result<PageDto<ReleaseDataVersionDto>> {
|
) -> async_graphql::Result<PageDto<ReleaseDataVersionDto>> {
|
||||||
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
let db_accessor = ctx.data::<RtssDbAccessor>()?;
|
||||||
let paging = db_accessor
|
let paging = db_accessor
|
||||||
.query_release_data_version_list(data_id, page.into())
|
.paging_query_release_data_version_list(data_id, page.into())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(paging.into())
|
Ok(paging.into())
|
||||||
}
|
}
|
||||||
|
@ -422,7 +422,7 @@ impl From<ReleaseDataModel> for ReleaseDataDto {
|
||||||
Self {
|
Self {
|
||||||
id: model.id,
|
id: model.id,
|
||||||
name: model.name,
|
name: model.name,
|
||||||
data_type: DataType::try_from(model.data_type).unwrap(),
|
data_type: model.data_type,
|
||||||
options: model.options,
|
options: model.options,
|
||||||
used_version_id: model.used_version_id,
|
used_version_id: model.used_version_id,
|
||||||
user_id: model.user_id,
|
user_id: model.user_id,
|
||||||
|
|
|
@ -6,9 +6,10 @@ use rtss_db::{DbAccessError, RtssDbAccessor, UserAccessor};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
loader::RtssDbLoader,
|
loader::RtssDbLoader,
|
||||||
user_auth::{build_jwt, Claims, Role, RoleGuard, Token, UserAuthCache, UserInfoDto},
|
user_auth::{build_jwt, Claims, RoleGuard, Token, UserAuthCache, UserInfoDto},
|
||||||
UserAuthClient,
|
UserAuthClient,
|
||||||
};
|
};
|
||||||
|
use rtss_dto::common::Role;
|
||||||
|
|
||||||
use super::{PageDto, PageQueryDto};
|
use super::{PageDto, PageQueryDto};
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ impl From<rtss_db::model::UserModel> for UserDto {
|
||||||
name: value.username,
|
name: value.username,
|
||||||
mobile: value.mobile,
|
mobile: value.mobile,
|
||||||
email: value.email,
|
email: value.email,
|
||||||
roles: serde_json::from_value(value.roles).unwrap(),
|
roles: value.roles.0,
|
||||||
created_at: value.created_at.naive_local(),
|
created_at: value.created_at.naive_local(),
|
||||||
updated_at: value.updated_at.naive_local(),
|
updated_at: value.updated_at.naive_local(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,16 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_graphql::{Enum, Guard};
|
use async_graphql::Guard;
|
||||||
use axum::http::HeaderMap;
|
use axum::http::HeaderMap;
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
|
use rtss_dto::common::Role;
|
||||||
use rtss_log::tracing::error;
|
use rtss_log::tracing::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
mod jwt_auth;
|
mod jwt_auth;
|
||||||
pub use jwt_auth::*;
|
pub use jwt_auth::*;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash, Enum, Serialize, Deserialize)]
|
|
||||||
pub enum Role {
|
|
||||||
Admin,
|
|
||||||
User,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RoleGuard {
|
pub struct RoleGuard {
|
||||||
role: Role,
|
role: Role,
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,20 @@ 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 paging_query_draft_data(
|
||||||
&self,
|
&self,
|
||||||
query: DraftDataQuery,
|
query: DraftDataQuery,
|
||||||
page: PageQuery,
|
page: PageQuery,
|
||||||
) -> Result<PageResult<DraftDataModel>, DbAccessError>;
|
) -> Result<PageResult<DraftDataModel>, DbAccessError>;
|
||||||
/// 根据id查询草稿数据
|
/// 根据id查询草稿数据
|
||||||
async fn query_draft_data_by_id(&self, id: i32) -> Result<DraftDataModel, DbAccessError>;
|
async fn query_draft_data_by_id(&self, id: i32) -> Result<DraftDataModel, DbAccessError>;
|
||||||
/// 是否user_id+name的数据已存在
|
/// 是否user_id+data_type+name的数据已存在
|
||||||
async fn is_draft_data_exist(&self, user_id: i32, name: &str) -> Result<bool, DbAccessError>;
|
async fn is_draft_data_exist(
|
||||||
|
&self,
|
||||||
|
user_id: i32,
|
||||||
|
data_type: &DataType,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<bool, DbAccessError>;
|
||||||
/// 创建草稿数据基本信息
|
/// 创建草稿数据基本信息
|
||||||
async fn create_draft_data(
|
async fn create_draft_data(
|
||||||
&self,
|
&self,
|
||||||
|
@ -201,7 +206,7 @@ impl CreateDraftData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DraftDataAccessor for RtssDbAccessor {
|
impl DraftDataAccessor for RtssDbAccessor {
|
||||||
async fn query_draft_data(
|
async fn paging_query_draft_data(
|
||||||
&self,
|
&self,
|
||||||
query: DraftDataQuery,
|
query: DraftDataQuery,
|
||||||
page: PageQuery,
|
page: PageQuery,
|
||||||
|
@ -251,19 +256,25 @@ impl DraftDataAccessor for RtssDbAccessor {
|
||||||
Ok(draft_data)
|
Ok(draft_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_draft_data_exist(&self, user_id: i32, name: &str) -> Result<bool, DbAccessError> {
|
async fn is_draft_data_exist(
|
||||||
|
&self,
|
||||||
|
user_id: i32,
|
||||||
|
data_type: &DataType,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<bool, DbAccessError> {
|
||||||
let table = DraftDataColumn::Table.name();
|
let table = DraftDataColumn::Table.name();
|
||||||
let filter = format!(
|
let user_id_column = DraftDataColumn::UserId.name();
|
||||||
"WHERE {} = '{}' AND {} = {}",
|
let data_type_column = DraftDataColumn::DataType.name();
|
||||||
DraftDataColumn::Name.name(),
|
let name_column = DraftDataColumn::Name.name();
|
||||||
name,
|
let sql = format!("SELECT COUNT(*) FROM {table} WHERE {user_id_column} = $1 AND {data_type_column} = $2 AND {name_column} = $3",);
|
||||||
DraftDataColumn::UserId.name(),
|
|
||||||
user_id
|
|
||||||
);
|
|
||||||
let sql = format!("SELECT COUNT(*) FROM {table} {filter}");
|
|
||||||
// log sql
|
// log sql
|
||||||
debug!("draft data exist check sql: {}", sql);
|
debug!("draft data exist check sql: {}", sql);
|
||||||
let count: i64 = sqlx::query_scalar(&sql).fetch_one(&self.pool).await?;
|
let count: i64 = sqlx::query_scalar(&sql)
|
||||||
|
.bind(user_id)
|
||||||
|
.bind(data_type)
|
||||||
|
.bind(name)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(count > 0)
|
Ok(count > 0)
|
||||||
}
|
}
|
||||||
|
@ -274,7 +285,7 @@ impl DraftDataAccessor for RtssDbAccessor {
|
||||||
) -> Result<DraftDataModel, DbAccessError> {
|
) -> Result<DraftDataModel, DbAccessError> {
|
||||||
// 检查是否已存在
|
// 检查是否已存在
|
||||||
let exist = self
|
let exist = self
|
||||||
.is_draft_data_exist(create.user_id, &create.name)
|
.is_draft_data_exist(create.user_id, &create.data_type, &create.name)
|
||||||
.await?;
|
.await?;
|
||||||
if exist {
|
if exist {
|
||||||
return Err(DbAccessError::RowExist);
|
return Err(DbAccessError::RowExist);
|
||||||
|
@ -297,7 +308,7 @@ impl DraftDataAccessor for RtssDbAccessor {
|
||||||
// 插入数据
|
// 插入数据
|
||||||
let draft_data: DraftDataModel = sqlx::query_as(&sql)
|
let draft_data: DraftDataModel = sqlx::query_as(&sql)
|
||||||
.bind(create.name)
|
.bind(create.name)
|
||||||
.bind(create.data_type as i32)
|
.bind(create.data_type)
|
||||||
.bind(create.options)
|
.bind(create.options)
|
||||||
.bind(create.user_id)
|
.bind(create.user_id)
|
||||||
.bind(create.data)
|
.bind(create.data)
|
||||||
|
@ -411,14 +422,10 @@ impl DraftDataAccessor for RtssDbAccessor {
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
) -> Result<DraftDataModel, DbAccessError> {
|
) -> Result<DraftDataModel, DbAccessError> {
|
||||||
let draft_data = self.query_draft_data_by_id(draft_id).await?;
|
let draft_data = self.query_draft_data_by_id(draft_id).await?;
|
||||||
let create = CreateDraftData::new(
|
let create = CreateDraftData::new(name, draft_data.data_type, user_id)
|
||||||
name,
|
.with_option_options(draft_data.options)
|
||||||
DataType::try_from(draft_data.data_type).unwrap(),
|
.with_data(draft_data.data.as_ref().unwrap())
|
||||||
user_id,
|
.with_option_default_release_data_id(draft_data.default_release_data_id);
|
||||||
)
|
|
||||||
.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
|
||||||
}
|
}
|
||||||
|
@ -429,7 +436,7 @@ mod tests {
|
||||||
use crate::{SyncUserInfo, UserAccessor};
|
use crate::{SyncUserInfo, UserAccessor};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use rtss_dto::common::IscsStyle;
|
use rtss_dto::common::{IscsStyle, Role};
|
||||||
use rtss_log::tracing::Level;
|
use rtss_log::tracing::Level;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{types::chrono::Local, PgPool};
|
use sqlx::{types::chrono::Local, PgPool};
|
||||||
|
@ -439,12 +446,6 @@ mod tests {
|
||||||
pub style: IscsStyle,
|
pub style: IscsStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
enum Role {
|
|
||||||
User,
|
|
||||||
Admin,
|
|
||||||
}
|
|
||||||
|
|
||||||
// You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here.
|
// You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here.
|
||||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||||
async fn basic_use_test(pool: PgPool) -> Result<(), DbAccessError> {
|
async fn basic_use_test(pool: PgPool) -> Result<(), DbAccessError> {
|
||||||
|
@ -539,7 +540,7 @@ mod tests {
|
||||||
|
|
||||||
// 查询确认当前数据已删除
|
// 查询确认当前数据已删除
|
||||||
let page = accessor
|
let page = accessor
|
||||||
.query_draft_data(DraftDataQuery::new(), PageQuery::new(1, 100))
|
.paging_query_draft_data(DraftDataQuery::new(), PageQuery::new(1, 100))
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(page.total, 0);
|
assert_eq!(page.total, 0);
|
||||||
|
|
||||||
|
@ -574,7 +575,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
let page = accessor
|
let page = accessor
|
||||||
.query_draft_data(
|
.paging_query_draft_data(
|
||||||
DraftDataQuery::new()
|
DraftDataQuery::new()
|
||||||
.with_user_id(2)
|
.with_user_id(2)
|
||||||
.with_name("test".to_string())
|
.with_name("test".to_string())
|
||||||
|
@ -585,13 +586,13 @@ mod tests {
|
||||||
assert_eq!(page.total, 5);
|
assert_eq!(page.total, 5);
|
||||||
|
|
||||||
let page = accessor
|
let page = accessor
|
||||||
.query_draft_data(DraftDataQuery::new(), PageQuery::new(1, 100))
|
.paging_query_draft_data(DraftDataQuery::new(), PageQuery::new(1, 100))
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(page.total, 20);
|
assert_eq!(page.total, 20);
|
||||||
|
|
||||||
// 查询共享数据
|
// 查询共享数据
|
||||||
let page = accessor
|
let page = accessor
|
||||||
.query_draft_data(
|
.paging_query_draft_data(
|
||||||
DraftDataQuery::new().with_is_shared(true),
|
DraftDataQuery::new().with_is_shared(true),
|
||||||
PageQuery::new(1, 10),
|
PageQuery::new(1, 10),
|
||||||
)
|
)
|
||||||
|
@ -600,7 +601,7 @@ mod tests {
|
||||||
|
|
||||||
// 查询options
|
// 查询options
|
||||||
let page = accessor
|
let page = accessor
|
||||||
.query_draft_data(
|
.paging_query_draft_data(
|
||||||
DraftDataQuery::new().with_options(
|
DraftDataQuery::new().with_options(
|
||||||
serde_json::to_value(IscsDataOptions {
|
serde_json::to_value(IscsDataOptions {
|
||||||
style: IscsStyle::DaShiZhiNeng,
|
style: IscsStyle::DaShiZhiNeng,
|
||||||
|
|
|
@ -0,0 +1,351 @@
|
||||||
|
use rtss_dto::common::FeatureType;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{PageQuery, PageResult, TableColumn},
|
||||||
|
model::{FeatureColumn, FeatureModel},
|
||||||
|
DbAccessError,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::RtssDbAccessor;
|
||||||
|
|
||||||
|
/// 功能特性管理
|
||||||
|
#[allow(async_fn_in_trait)]
|
||||||
|
pub trait FeatureAccessor {
|
||||||
|
/// 创建功能特性
|
||||||
|
async fn create_feature(&self, feature: &CreateFeature) -> Result<FeatureModel, DbAccessError>;
|
||||||
|
/// 更新功能特性
|
||||||
|
async fn update_feature(&self, feature: &UpdateFeature) -> Result<FeatureModel, DbAccessError>;
|
||||||
|
/// 上下架功能特性
|
||||||
|
async fn set_feature_published(
|
||||||
|
&self,
|
||||||
|
feature_id: i32,
|
||||||
|
is_published: bool,
|
||||||
|
) -> Result<FeatureModel, DbAccessError>;
|
||||||
|
/// 分页查询功能特性
|
||||||
|
async fn paging_query_features(
|
||||||
|
&self,
|
||||||
|
page: PageQuery,
|
||||||
|
filter: &FeaturePagingFilter,
|
||||||
|
) -> Result<PageResult<FeatureModel>, DbAccessError>;
|
||||||
|
/// 获取id对应的功能特性
|
||||||
|
async fn get_feature(&self, id: i32) -> Result<FeatureModel, DbAccessError>;
|
||||||
|
/// 根据id列表获取功能特性基本信息
|
||||||
|
async fn get_features(&self, ids: &[i32]) -> Result<Vec<FeatureModel>, DbAccessError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FeatureAccessor for RtssDbAccessor {
|
||||||
|
async fn create_feature(&self, feature: &CreateFeature) -> Result<FeatureModel, DbAccessError> {
|
||||||
|
let table = FeatureColumn::Table.name();
|
||||||
|
let feature_type_column = FeatureColumn::FeatureType.name();
|
||||||
|
let name_column = FeatureColumn::Name.name();
|
||||||
|
let description_column = FeatureColumn::Description.name();
|
||||||
|
let config_column = FeatureColumn::Config.name();
|
||||||
|
let creator_id_column = FeatureColumn::CreatorId.name();
|
||||||
|
let updater_id_column = FeatureColumn::UpdaterId.name();
|
||||||
|
let sql = format!(
|
||||||
|
"INSERT INTO {table} ({feature_type_column}, {name_column}, {description_column}, {config_column}, {creator_id_column}, {updater_id_column}) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *",
|
||||||
|
);
|
||||||
|
let row = sqlx::query_as::<_, FeatureModel>(&sql)
|
||||||
|
.bind(feature.feature_type)
|
||||||
|
.bind(&feature.name)
|
||||||
|
.bind(&feature.description)
|
||||||
|
.bind(&feature.config)
|
||||||
|
.bind(feature.creator_id)
|
||||||
|
.bind(feature.creator_id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_feature(&self, feature: &UpdateFeature) -> Result<FeatureModel, DbAccessError> {
|
||||||
|
let table = FeatureColumn::Table.name();
|
||||||
|
let name_column = FeatureColumn::Name.name();
|
||||||
|
let description_column = FeatureColumn::Description.name();
|
||||||
|
let config_column = FeatureColumn::Config.name();
|
||||||
|
let updater_id_column = FeatureColumn::UpdaterId.name();
|
||||||
|
let update_at_column = FeatureColumn::UpdatedAt.name();
|
||||||
|
let sql = format!(
|
||||||
|
"UPDATE {table} SET {name_column} = $1, {description_column} = $2, {config_column} = $3, {updater_id_column} = $4, {update_at_column} = 'now()' WHERE id = $5 RETURNING *",
|
||||||
|
);
|
||||||
|
let row = sqlx::query_as::<_, FeatureModel>(&sql)
|
||||||
|
.bind(&feature.name)
|
||||||
|
.bind(&feature.description)
|
||||||
|
.bind(&feature.config)
|
||||||
|
.bind(feature.updater_id)
|
||||||
|
.bind(feature.id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_feature_published(
|
||||||
|
&self,
|
||||||
|
feature_id: i32,
|
||||||
|
is_published: bool,
|
||||||
|
) -> Result<FeatureModel, DbAccessError> {
|
||||||
|
let table = FeatureColumn::Table.name();
|
||||||
|
let is_published_column = FeatureColumn::IsPublished.name();
|
||||||
|
let update_at_column = FeatureColumn::UpdatedAt.name();
|
||||||
|
let sql = format!(
|
||||||
|
"UPDATE {table} SET {is_published_column} = $1, {update_at_column} = 'now()' WHERE id = $2 RETURNING *",
|
||||||
|
);
|
||||||
|
let row = sqlx::query_as::<_, FeatureModel>(&sql)
|
||||||
|
.bind(is_published)
|
||||||
|
.bind(feature_id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn paging_query_features(
|
||||||
|
&self,
|
||||||
|
page: PageQuery,
|
||||||
|
filter: &FeaturePagingFilter,
|
||||||
|
) -> Result<PageResult<FeatureModel>, DbAccessError> {
|
||||||
|
let table = FeatureColumn::Table.name();
|
||||||
|
let where_clause = filter.to_where_clause();
|
||||||
|
let total =
|
||||||
|
sqlx::query_scalar::<_, i64>(&format!("SELECT COUNT(*) FROM {table} {where_clause}",))
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
if total == 0 {
|
||||||
|
return Ok(PageResult::new(total, vec![]));
|
||||||
|
}
|
||||||
|
let update_at_column = FeatureColumn::UpdatedAt.name();
|
||||||
|
let select_columns = [
|
||||||
|
FeatureColumn::Id.name(),
|
||||||
|
FeatureColumn::FeatureType.name(),
|
||||||
|
FeatureColumn::Name.name(),
|
||||||
|
FeatureColumn::Description.name(),
|
||||||
|
FeatureColumn::IsPublished.name(),
|
||||||
|
FeatureColumn::CreatorId.name(),
|
||||||
|
FeatureColumn::UpdaterId.name(),
|
||||||
|
FeatureColumn::CreatedAt.name(),
|
||||||
|
FeatureColumn::UpdatedAt.name(),
|
||||||
|
];
|
||||||
|
let select_columns = select_columns.join(", ");
|
||||||
|
let limit_clause = page.to_limit_clause();
|
||||||
|
let sql = format!(
|
||||||
|
"SELECT {select_columns} FROM {table} {where_clause} ORDER BY {update_at_column} DESC {limit_clause}",
|
||||||
|
);
|
||||||
|
let rows = sqlx::query_as::<_, FeatureModel>(&sql)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(PageResult::new(total, rows))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_feature(&self, id: i32) -> Result<FeatureModel, DbAccessError> {
|
||||||
|
let table = FeatureColumn::Table.name();
|
||||||
|
let id_column = FeatureColumn::Id.name();
|
||||||
|
let sql = format!("SELECT * FROM {table} WHERE {id_column} = $1",);
|
||||||
|
let row = sqlx::query_as::<_, FeatureModel>(&sql)
|
||||||
|
.bind(id)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_features(&self, ids: &[i32]) -> Result<Vec<FeatureModel>, DbAccessError> {
|
||||||
|
let table = FeatureColumn::Table.name();
|
||||||
|
let id_column = FeatureColumn::Id.name();
|
||||||
|
let select_columns = [
|
||||||
|
FeatureColumn::Id.name(),
|
||||||
|
FeatureColumn::FeatureType.name(),
|
||||||
|
FeatureColumn::Name.name(),
|
||||||
|
FeatureColumn::Description.name(),
|
||||||
|
FeatureColumn::IsPublished.name(),
|
||||||
|
FeatureColumn::CreatorId.name(),
|
||||||
|
FeatureColumn::UpdaterId.name(),
|
||||||
|
FeatureColumn::CreatedAt.name(),
|
||||||
|
FeatureColumn::UpdatedAt.name(),
|
||||||
|
];
|
||||||
|
let select_columns = select_columns.join(", ");
|
||||||
|
let sql = format!("SELECT {select_columns} FROM {table} WHERE {id_column} = ANY($1)",);
|
||||||
|
let rows = sqlx::query_as::<_, FeatureModel>(&sql)
|
||||||
|
.bind(ids)
|
||||||
|
.fetch_all(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CreateFeature {
|
||||||
|
pub feature_type: FeatureType,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub config: Value,
|
||||||
|
pub creator_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UpdateFeature {
|
||||||
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub config: Value,
|
||||||
|
pub updater_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct FeaturePagingFilter {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub feature_type: Option<i32>,
|
||||||
|
pub is_published: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FeaturePagingFilter {
|
||||||
|
fn to_where_clause(&self) -> String {
|
||||||
|
let mut clauses = vec![];
|
||||||
|
if let Some(name) = &self.name {
|
||||||
|
clauses.push(format!("name like '%{}%'", name));
|
||||||
|
}
|
||||||
|
if let Some(feature_type) = self.feature_type {
|
||||||
|
clauses.push(format!("feature_type = {}", feature_type));
|
||||||
|
}
|
||||||
|
if let Some(is_published) = self.is_published {
|
||||||
|
clauses.push(format!("is_published = {}", is_published));
|
||||||
|
}
|
||||||
|
if clauses.is_empty() {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
format!("WHERE {}", clauses.join(" AND "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rtss_dto::common::Role;
|
||||||
|
use rtss_log::tracing::Level;
|
||||||
|
use sqlx::{types::chrono::Local, PgPool};
|
||||||
|
|
||||||
|
use crate::{SyncUserInfo, UserAccessor};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||||
|
async fn test_basic_use(pool: PgPool) -> Result<(), DbAccessError> {
|
||||||
|
rtss_log::Logging::default().with_level(Level::DEBUG).init();
|
||||||
|
let accessor = crate::db_access::RtssDbAccessor::new(pool);
|
||||||
|
// 同步10个用户
|
||||||
|
let mut users = vec![];
|
||||||
|
for i in 0..10 {
|
||||||
|
let user = SyncUserInfo {
|
||||||
|
id: i + 1,
|
||||||
|
name: format!("user{}", i + 1),
|
||||||
|
password: "password".to_string(),
|
||||||
|
roles: serde_json::to_value(&vec![Role::User]).unwrap(),
|
||||||
|
email: None,
|
||||||
|
mobile: None,
|
||||||
|
created_at: Local::now(),
|
||||||
|
updated_at: None,
|
||||||
|
};
|
||||||
|
users.push(user);
|
||||||
|
}
|
||||||
|
accessor.sync_user(users.as_slice()).await?;
|
||||||
|
|
||||||
|
// 创建测试
|
||||||
|
let creator_id = 1;
|
||||||
|
let create_config = Value::String("create".to_string());
|
||||||
|
let feature = CreateFeature {
|
||||||
|
feature_type: FeatureType::Ur,
|
||||||
|
name: "test".to_string(),
|
||||||
|
description: "test".to_string(),
|
||||||
|
config: create_config.clone(),
|
||||||
|
creator_id,
|
||||||
|
};
|
||||||
|
let feature = accessor.create_feature(&feature).await?;
|
||||||
|
println!("create feature: {:?}", feature);
|
||||||
|
assert_eq!(feature.creator_id, creator_id);
|
||||||
|
assert_eq!(feature.updater_id, creator_id);
|
||||||
|
assert_eq!(feature.is_published, true);
|
||||||
|
assert_eq!(feature.config, create_config);
|
||||||
|
let feature_id = feature.id;
|
||||||
|
// 获取功能特性测试
|
||||||
|
let feature = accessor.get_feature(feature_id).await?;
|
||||||
|
println!("get feature: {:?}", feature);
|
||||||
|
assert_eq!(feature.id, feature_id);
|
||||||
|
assert_eq!(feature.creator_id, creator_id);
|
||||||
|
assert_eq!(feature.updater_id, creator_id);
|
||||||
|
assert_eq!(feature.is_published, true);
|
||||||
|
assert_eq!(feature.config, create_config);
|
||||||
|
// 更新测试
|
||||||
|
let updater_id = 2;
|
||||||
|
let config = Value::String("config".to_string());
|
||||||
|
let feature = UpdateFeature {
|
||||||
|
id: feature_id,
|
||||||
|
name: "test update".to_string(),
|
||||||
|
description: "test update".to_string(),
|
||||||
|
config: config.clone(),
|
||||||
|
updater_id: updater_id,
|
||||||
|
};
|
||||||
|
let feature = accessor.update_feature(&feature).await?;
|
||||||
|
println!("update feature: {:?}", feature);
|
||||||
|
assert_eq!(feature.updater_id, updater_id);
|
||||||
|
assert_eq!(feature.config, config);
|
||||||
|
assert!(feature.updated_at > feature.created_at);
|
||||||
|
// 上下架测试
|
||||||
|
let feature = accessor.set_feature_published(feature_id, false).await?;
|
||||||
|
println!("set feature published: {:?}", feature);
|
||||||
|
assert_eq!(feature.is_published, false);
|
||||||
|
// 分页查询测试
|
||||||
|
// 创建10个功能特性,5个发布的,5个未发布的
|
||||||
|
for i in 0..10 {
|
||||||
|
let feature = CreateFeature {
|
||||||
|
feature_type: FeatureType::Ur,
|
||||||
|
name: format!("test{}", i),
|
||||||
|
description: format!("test{}", i),
|
||||||
|
config: Value::Null,
|
||||||
|
creator_id,
|
||||||
|
};
|
||||||
|
let feature = accessor.create_feature(&feature).await?;
|
||||||
|
if i < 5 {
|
||||||
|
accessor.set_feature_published(feature.id, false).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 无过滤条件分页查询测试
|
||||||
|
let filter = FeaturePagingFilter::default();
|
||||||
|
let item_per_page = 10;
|
||||||
|
let page_result = accessor
|
||||||
|
.paging_query_features(PageQuery::new(1, item_per_page), &filter)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(page_result.total, 11);
|
||||||
|
assert_eq!(page_result.data.len(), item_per_page as usize);
|
||||||
|
// 上架过滤条件分页查询测试
|
||||||
|
let filter = FeaturePagingFilter {
|
||||||
|
is_published: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let page_result = accessor
|
||||||
|
.paging_query_features(PageQuery::new(1, item_per_page), &filter)
|
||||||
|
.await?;
|
||||||
|
println!("published features: {:?}", page_result);
|
||||||
|
assert_eq!(page_result.total, 5);
|
||||||
|
assert_eq!(page_result.data.len(), 5);
|
||||||
|
// 名称过滤条件分页查询测试
|
||||||
|
let filter = FeaturePagingFilter {
|
||||||
|
name: Some("test".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let page_result = accessor
|
||||||
|
.paging_query_features(PageQuery::new(1, item_per_page), &filter)
|
||||||
|
.await?;
|
||||||
|
println!("name filter features: {:?}", page_result);
|
||||||
|
assert_eq!(page_result.total, 11);
|
||||||
|
assert_eq!(page_result.data.len(), item_per_page as usize);
|
||||||
|
|
||||||
|
// 根据id列表获取功能特性测试
|
||||||
|
let ids = page_result
|
||||||
|
.data
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.id)
|
||||||
|
.skip(5)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let features = accessor.get_features(&ids).await?;
|
||||||
|
println!("get features: {:?}", features);
|
||||||
|
assert_eq!(features.len(), ids.len());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ mod release_data;
|
||||||
pub use release_data::*;
|
pub use release_data::*;
|
||||||
mod user;
|
mod user;
|
||||||
pub use user::*;
|
pub use user::*;
|
||||||
|
mod feature;
|
||||||
|
pub use feature::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RtssDbAccessor {
|
pub struct RtssDbAccessor {
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub trait ReleaseDataAccessor {
|
||||||
user_id: Option<i32>,
|
user_id: Option<i32>,
|
||||||
) -> Result<(ReleaseDataModel, ReleaseDataVersionModel), DbAccessError>;
|
) -> Result<(ReleaseDataModel, ReleaseDataVersionModel), DbAccessError>;
|
||||||
/// 分页查询发布数据列表
|
/// 分页查询发布数据列表
|
||||||
async fn query_release_data_list(
|
async fn paging_query_release_data_list(
|
||||||
&self,
|
&self,
|
||||||
query: ReleaseDataQuery,
|
query: ReleaseDataQuery,
|
||||||
page: PageQuery,
|
page: PageQuery,
|
||||||
|
@ -53,7 +53,7 @@ pub trait ReleaseDataAccessor {
|
||||||
release_ids: &[i32],
|
release_ids: &[i32],
|
||||||
) -> Result<Vec<(i32, String)>, DbAccessError>;
|
) -> Result<Vec<(i32, String)>, DbAccessError>;
|
||||||
/// 查询发布数据所有版本信息
|
/// 查询发布数据所有版本信息
|
||||||
async fn query_release_data_version_list(
|
async fn paging_query_release_data_version_list(
|
||||||
&self,
|
&self,
|
||||||
release_id: i32,
|
release_id: i32,
|
||||||
page: PageQuery,
|
page: PageQuery,
|
||||||
|
@ -252,7 +252,7 @@ impl ReleaseDataAccessor for RtssDbAccessor {
|
||||||
}
|
}
|
||||||
// 判断发布数据名称是否已存在
|
// 判断发布数据名称是否已存在
|
||||||
if self
|
if self
|
||||||
.is_release_data_name_exist(DataType::try_from(draft.data_type).unwrap(), name)
|
.is_release_data_name_exist(draft.data_type, name)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
return Err(DbAccessError::DataError("发布数据名称已存在".to_string()));
|
return Err(DbAccessError::DataError("发布数据名称已存在".to_string()));
|
||||||
|
@ -364,7 +364,7 @@ impl ReleaseDataAccessor for RtssDbAccessor {
|
||||||
Ok((rd, rdv))
|
Ok((rd, rdv))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn query_release_data_list(
|
async fn paging_query_release_data_list(
|
||||||
&self,
|
&self,
|
||||||
query: ReleaseDataQuery,
|
query: ReleaseDataQuery,
|
||||||
page: PageQuery,
|
page: PageQuery,
|
||||||
|
@ -449,7 +449,7 @@ impl ReleaseDataAccessor for RtssDbAccessor {
|
||||||
Ok(rd)
|
Ok(rd)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn query_release_data_version_list(
|
async fn paging_query_release_data_version_list(
|
||||||
&self,
|
&self,
|
||||||
release_id: i32,
|
release_id: i32,
|
||||||
page: PageQuery,
|
page: PageQuery,
|
||||||
|
@ -633,7 +633,7 @@ impl ReleaseDataAccessor for RtssDbAccessor {
|
||||||
// 创建草稿数据
|
// 创建草稿数据
|
||||||
let draft = self
|
let draft = self
|
||||||
.create_draft_data(
|
.create_draft_data(
|
||||||
CreateDraftData::new(&name, DataType::try_from(rd.data_type).unwrap(), user_id)
|
CreateDraftData::new(&name, rd.data_type, user_id)
|
||||||
.with_option_options(rdv.options)
|
.with_option_options(rdv.options)
|
||||||
.with_data(&rdv.data)
|
.with_data(&rdv.data)
|
||||||
.with_default_release_data_id(rd.id),
|
.with_default_release_data_id(rd.id),
|
||||||
|
@ -649,7 +649,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use rtss_dto::common::IscsStyle;
|
use rtss_dto::common::{IscsStyle, Role};
|
||||||
use rtss_log::tracing::Level;
|
use rtss_log::tracing::Level;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
@ -692,12 +692,6 @@ mod tests {
|
||||||
pub style: IscsStyle,
|
pub style: IscsStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
enum Role {
|
|
||||||
User,
|
|
||||||
Admin,
|
|
||||||
}
|
|
||||||
|
|
||||||
// You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here.
|
// You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here.
|
||||||
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
#[sqlx::test(migrator = "crate::MIGRATOR")]
|
||||||
async fn test_basic_use(pool: PgPool) -> Result<(), DbAccessError> {
|
async fn test_basic_use(pool: PgPool) -> Result<(), DbAccessError> {
|
||||||
|
@ -818,7 +812,7 @@ mod tests {
|
||||||
|
|
||||||
// 查询发布数据所有版本
|
// 查询发布数据所有版本
|
||||||
let versions = accessor
|
let versions = accessor
|
||||||
.query_release_data_version_list(
|
.paging_query_release_data_version_list(
|
||||||
release_data.id,
|
release_data.id,
|
||||||
PageQuery {
|
PageQuery {
|
||||||
page: 1,
|
page: 1,
|
||||||
|
@ -871,27 +865,27 @@ mod tests {
|
||||||
// 分页查询发布数据,无条件
|
// 分页查询发布数据,无条件
|
||||||
let query = ReleaseDataQuery::new();
|
let query = ReleaseDataQuery::new();
|
||||||
let page = PageQuery::new(1, 100);
|
let page = PageQuery::new(1, 100);
|
||||||
let page_result = accessor.query_release_data_list(query, page).await?;
|
let page_result = accessor.paging_query_release_data_list(query, page).await?;
|
||||||
assert_eq!(page_result.total, 9);
|
assert_eq!(page_result.total, 9);
|
||||||
// 分页查询发布数据,按是否上架过滤
|
// 分页查询发布数据,按是否上架过滤
|
||||||
let query = ReleaseDataQuery::new().with_is_published(true);
|
let query = ReleaseDataQuery::new().with_is_published(true);
|
||||||
let page = PageQuery::new(1, 100);
|
let page = PageQuery::new(1, 100);
|
||||||
let page_result = accessor.query_release_data_list(query, page).await?;
|
let page_result = accessor.paging_query_release_data_list(query, page).await?;
|
||||||
assert_eq!(page_result.total, 8);
|
assert_eq!(page_result.total, 8);
|
||||||
// 分页查询发布数据,按名称过滤
|
// 分页查询发布数据,按名称过滤
|
||||||
let query = ReleaseDataQuery::new().with_name("test_2".to_string());
|
let query = ReleaseDataQuery::new().with_name("test_2".to_string());
|
||||||
let page = PageQuery::new(1, 10);
|
let page = PageQuery::new(1, 10);
|
||||||
let page_result = accessor.query_release_data_list(query, page).await?;
|
let page_result = accessor.paging_query_release_data_list(query, page).await?;
|
||||||
assert_eq!(page_result.total, 2);
|
assert_eq!(page_result.total, 2);
|
||||||
// 分页查询发布数据,按用户id过滤
|
// 分页查询发布数据,按用户id过滤
|
||||||
let query = ReleaseDataQuery::new().with_user_id(2);
|
let query = ReleaseDataQuery::new().with_user_id(2);
|
||||||
let page = PageQuery::new(1, 10);
|
let page = PageQuery::new(1, 10);
|
||||||
let page_result = accessor.query_release_data_list(query, page).await?;
|
let page_result = accessor.paging_query_release_data_list(query, page).await?;
|
||||||
assert_eq!(page_result.total, 2);
|
assert_eq!(page_result.total, 2);
|
||||||
// 分页查询发布数据,按数据类型过滤
|
// 分页查询发布数据,按数据类型过滤
|
||||||
let query = ReleaseDataQuery::new().with_data_type(rtss_dto::common::DataType::Em);
|
let query = ReleaseDataQuery::new().with_data_type(rtss_dto::common::DataType::Em);
|
||||||
let page = PageQuery::new(1, 10);
|
let page = PageQuery::new(1, 10);
|
||||||
let page_result = accessor.query_release_data_list(query, page).await?;
|
let page_result = accessor.paging_query_release_data_list(query, page).await?;
|
||||||
assert_eq!(page_result.total, 8);
|
assert_eq!(page_result.total, 8);
|
||||||
println!("分页查询发布数据测试成功");
|
println!("分页查询发布数据测试成功");
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
use rtss_dto::common::{DataType, FeatureType, Role};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::types::chrono::{DateTime, Local};
|
use sqlx::types::{
|
||||||
|
chrono::{DateTime, Local},
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::common::TableColumn;
|
use crate::common::TableColumn;
|
||||||
|
|
||||||
|
@ -25,7 +29,7 @@ pub struct UserModel {
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
#[sqlx(default)]
|
#[sqlx(default)]
|
||||||
pub mobile: Option<String>,
|
pub mobile: Option<String>,
|
||||||
pub roles: Value,
|
pub roles: Json<Vec<Role>>,
|
||||||
pub created_at: DateTime<Local>,
|
pub created_at: DateTime<Local>,
|
||||||
pub updated_at: DateTime<Local>,
|
pub updated_at: DateTime<Local>,
|
||||||
}
|
}
|
||||||
|
@ -50,7 +54,7 @@ pub enum DraftDataColumn {
|
||||||
pub struct DraftDataModel {
|
pub struct DraftDataModel {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub data_type: i32,
|
pub data_type: DataType,
|
||||||
#[sqlx(default)]
|
#[sqlx(default)]
|
||||||
pub options: Option<Value>,
|
pub options: Option<Value>,
|
||||||
#[sqlx(default)]
|
#[sqlx(default)]
|
||||||
|
@ -84,7 +88,7 @@ pub enum ReleaseDataColumn {
|
||||||
pub struct ReleaseDataModel {
|
pub struct ReleaseDataModel {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub data_type: i32,
|
pub data_type: DataType,
|
||||||
/// 从发布版本复制的选项,主要用于查询
|
/// 从发布版本复制的选项,主要用于查询
|
||||||
#[sqlx(default)]
|
#[sqlx(default)]
|
||||||
pub options: Option<Value>,
|
pub options: Option<Value>,
|
||||||
|
@ -130,6 +134,7 @@ pub(crate) enum FeatureColumn {
|
||||||
FeatureType,
|
FeatureType,
|
||||||
Name,
|
Name,
|
||||||
Description,
|
Description,
|
||||||
|
Config,
|
||||||
IsPublished,
|
IsPublished,
|
||||||
CreatorId,
|
CreatorId,
|
||||||
UpdaterId,
|
UpdaterId,
|
||||||
|
@ -140,9 +145,11 @@ pub(crate) enum FeatureColumn {
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
#[derive(Debug, sqlx::FromRow)]
|
||||||
pub struct FeatureModel {
|
pub struct FeatureModel {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub feature_type: i32,
|
pub feature_type: FeatureType,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
#[sqlx(default)]
|
||||||
|
pub config: Value,
|
||||||
pub is_published: bool,
|
pub is_published: bool,
|
||||||
pub creator_id: i32,
|
pub creator_id: i32,
|
||||||
pub updater_id: i32,
|
pub updater_id: i32,
|
||||||
|
@ -150,82 +157,25 @@ pub struct FeatureModel {
|
||||||
pub updated_at: DateTime<Local>,
|
pub updated_at: DateTime<Local>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 数据库表 rtss.feature_release_data 列映射
|
/// 数据库表 rtss.user_config 列映射
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) enum FeatureReleaseDataColumn {
|
pub(crate) enum UserConfigColumn {
|
||||||
Table,
|
|
||||||
FeatureId,
|
|
||||||
ReleaseDataId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
|
||||||
pub struct FeatureReleaseDataModel {
|
|
||||||
pub feature_id: i32,
|
|
||||||
pub release_data_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 数据库表 rtss.feature_group 列映射
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) enum FeatureGroupColumn {
|
|
||||||
Table,
|
|
||||||
Id,
|
|
||||||
Name,
|
|
||||||
Description,
|
|
||||||
IsPublished,
|
|
||||||
CreatorId,
|
|
||||||
UpdaterId,
|
|
||||||
CreatedAt,
|
|
||||||
UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
|
||||||
pub struct FeatureGroupModel {
|
|
||||||
pub id: i32,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub is_published: bool,
|
|
||||||
pub creator_id: i32,
|
|
||||||
pub updater_id: i32,
|
|
||||||
pub created_at: DateTime<Local>,
|
|
||||||
pub updated_at: DateTime<Local>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 数据库表 rtss.feature_group_feature 列映射
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) enum FeatureGroupFeatureColumn {
|
|
||||||
Table,
|
|
||||||
FeatureGroupId,
|
|
||||||
FeatureId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
|
||||||
pub struct FeatureGroupFeatureModel {
|
|
||||||
pub feature_group_id: i32,
|
|
||||||
pub feature_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 数据库表 rtss.feature_config 列映射
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) enum FeatureConfigColumn {
|
|
||||||
Table,
|
Table,
|
||||||
Id,
|
Id,
|
||||||
UserId,
|
UserId,
|
||||||
FeatureId,
|
ConfigType,
|
||||||
Config,
|
Config,
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
UpdatedAt,
|
UpdatedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
#[derive(Debug, sqlx::FromRow)]
|
||||||
pub struct FeatureConfigModel {
|
pub struct UserConfigModel {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub user_id: i32,
|
pub user_id: i32,
|
||||||
pub feature_id: i32,
|
pub config_type: i32,
|
||||||
pub config: Vec<u8>,
|
pub config: Value,
|
||||||
pub created_at: DateTime<Local>,
|
pub created_at: DateTime<Local>,
|
||||||
pub updated_at: DateTime<Local>,
|
pub updated_at: DateTime<Local>,
|
||||||
}
|
}
|
||||||
|
@ -304,6 +254,7 @@ impl TableColumn for FeatureColumn {
|
||||||
FeatureColumn::FeatureType => "feature_type",
|
FeatureColumn::FeatureType => "feature_type",
|
||||||
FeatureColumn::Name => "name",
|
FeatureColumn::Name => "name",
|
||||||
FeatureColumn::Description => "description",
|
FeatureColumn::Description => "description",
|
||||||
|
FeatureColumn::Config => "config",
|
||||||
FeatureColumn::IsPublished => "is_published",
|
FeatureColumn::IsPublished => "is_published",
|
||||||
FeatureColumn::CreatorId => "creator_id",
|
FeatureColumn::CreatorId => "creator_id",
|
||||||
FeatureColumn::UpdaterId => "updater_id",
|
FeatureColumn::UpdaterId => "updater_id",
|
||||||
|
@ -313,52 +264,16 @@ impl TableColumn for FeatureColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableColumn for FeatureReleaseDataColumn {
|
impl TableColumn for UserConfigColumn {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
FeatureReleaseDataColumn::Table => "rtss.feature_release_data",
|
UserConfigColumn::Table => "rtss.user_config",
|
||||||
FeatureReleaseDataColumn::FeatureId => "feature_id",
|
UserConfigColumn::Id => "id",
|
||||||
FeatureReleaseDataColumn::ReleaseDataId => "release_data_id",
|
UserConfigColumn::UserId => "user_id",
|
||||||
}
|
UserConfigColumn::ConfigType => "config_type",
|
||||||
}
|
UserConfigColumn::Config => "config",
|
||||||
}
|
UserConfigColumn::CreatedAt => "created_at",
|
||||||
|
UserConfigColumn::UpdatedAt => "updated_at",
|
||||||
impl TableColumn for FeatureGroupColumn {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
FeatureGroupColumn::Table => "rtss.feature_group",
|
|
||||||
FeatureGroupColumn::Id => "id",
|
|
||||||
FeatureGroupColumn::Name => "name",
|
|
||||||
FeatureGroupColumn::Description => "description",
|
|
||||||
FeatureGroupColumn::IsPublished => "is_published",
|
|
||||||
FeatureGroupColumn::CreatorId => "creator_id",
|
|
||||||
FeatureGroupColumn::UpdaterId => "updater_id",
|
|
||||||
FeatureGroupColumn::CreatedAt => "created_at",
|
|
||||||
FeatureGroupColumn::UpdatedAt => "updated_at",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TableColumn for FeatureGroupFeatureColumn {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
FeatureGroupFeatureColumn::Table => "rtss.feature_group_feature",
|
|
||||||
FeatureGroupFeatureColumn::FeatureGroupId => "feature_group_id",
|
|
||||||
FeatureGroupFeatureColumn::FeatureId => "feature_id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TableColumn for FeatureConfigColumn {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
FeatureConfigColumn::Table => "rtss.feature_config",
|
|
||||||
FeatureConfigColumn::Id => "id",
|
|
||||||
FeatureConfigColumn::UserId => "user_id",
|
|
||||||
FeatureConfigColumn::FeatureId => "feature_id",
|
|
||||||
FeatureConfigColumn::Config => "config",
|
|
||||||
FeatureConfigColumn::CreatedAt => "created_at",
|
|
||||||
FeatureConfigColumn::UpdatedAt => "updated_at",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,22 @@ fn main() {
|
||||||
}
|
}
|
||||||
Config::new()
|
Config::new()
|
||||||
.out_dir("src/pb")
|
.out_dir("src/pb")
|
||||||
.type_attribute("common.DataType", "#[derive(sqlx::Type)]")
|
.type_attribute(
|
||||||
.type_attribute("common.DataType", "#[derive(async_graphql::Enum)]")
|
"common.Role",
|
||||||
.type_attribute("common.IscsStyle", "#[derive(async_graphql::Enum)]")
|
"#[derive(sqlx::Type, async_graphql::Enum, serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
|
.type_attribute(
|
||||||
|
"common.DataType",
|
||||||
|
"#[derive(sqlx::Type, async_graphql::Enum, serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
.type_attribute(
|
.type_attribute(
|
||||||
"common.IscsStyle",
|
"common.IscsStyle",
|
||||||
"#[derive(serde::Serialize, serde::Deserialize)]",
|
"#[derive(async_graphql::Enum, serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
|
.type_attribute(
|
||||||
|
"common.FeatureType",
|
||||||
|
"#[derive(sqlx::Type, async_graphql::Enum, serde::Serialize, serde::Deserialize)]",
|
||||||
)
|
)
|
||||||
.type_attribute("common.FeatureType", "#[derive(sqlx::Type)]")
|
|
||||||
.compile_protos(
|
.compile_protos(
|
||||||
&[
|
&[
|
||||||
"../../rtss-proto-msg/src/em_data.proto",
|
"../../rtss-proto-msg/src/em_data.proto",
|
||||||
|
|
|
@ -88,10 +88,59 @@ pub struct CommonInfo {
|
||||||
#[prost(message, repeated, tag = "4")]
|
#[prost(message, repeated, tag = "4")]
|
||||||
pub child_transforms: ::prost::alloc::vec::Vec<ChildTransform>,
|
pub child_transforms: ::prost::alloc::vec::Vec<ChildTransform>,
|
||||||
}
|
}
|
||||||
|
/// 用户角色
|
||||||
|
#[derive(
|
||||||
|
sqlx::Type,
|
||||||
|
async_graphql::Enum,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
::prost::Enumeration,
|
||||||
|
)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum Role {
|
||||||
|
/// 未知
|
||||||
|
Unknown = 0,
|
||||||
|
/// 系统管理员
|
||||||
|
Admin = 1,
|
||||||
|
/// 普通用户
|
||||||
|
User = 2,
|
||||||
|
}
|
||||||
|
impl Role {
|
||||||
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
|
///
|
||||||
|
/// The values are not transformed in any way and thus are considered stable
|
||||||
|
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||||
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Role::Unknown => "Role_Unknown",
|
||||||
|
Role::Admin => "Role_Admin",
|
||||||
|
Role::User => "Role_User",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
|
match value {
|
||||||
|
"Role_Unknown" => Some(Self::Unknown),
|
||||||
|
"Role_Admin" => Some(Self::Admin),
|
||||||
|
"Role_User" => Some(Self::User),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// 数据类型
|
/// 数据类型
|
||||||
#[derive(
|
#[derive(
|
||||||
sqlx::Type,
|
sqlx::Type,
|
||||||
async_graphql::Enum,
|
async_graphql::Enum,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
Clone,
|
Clone,
|
||||||
Copy,
|
Copy,
|
||||||
Debug,
|
Debug,
|
||||||
|
@ -108,10 +157,6 @@ pub enum DataType {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
/// 电子地图数据
|
/// 电子地图数据
|
||||||
Em = 1,
|
Em = 1,
|
||||||
/// IBP数据
|
|
||||||
Ibp = 2,
|
|
||||||
/// PSL数据
|
|
||||||
Psl = 3,
|
|
||||||
/// ISCS数据
|
/// ISCS数据
|
||||||
Iscs = 4,
|
Iscs = 4,
|
||||||
}
|
}
|
||||||
|
@ -124,8 +169,6 @@ impl DataType {
|
||||||
match self {
|
match self {
|
||||||
DataType::Unknown => "DataType_Unknown",
|
DataType::Unknown => "DataType_Unknown",
|
||||||
DataType::Em => "DataType_Em",
|
DataType::Em => "DataType_Em",
|
||||||
DataType::Ibp => "DataType_Ibp",
|
|
||||||
DataType::Psl => "DataType_Psl",
|
|
||||||
DataType::Iscs => "DataType_Iscs",
|
DataType::Iscs => "DataType_Iscs",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,8 +177,6 @@ impl DataType {
|
||||||
match value {
|
match value {
|
||||||
"DataType_Unknown" => Some(Self::Unknown),
|
"DataType_Unknown" => Some(Self::Unknown),
|
||||||
"DataType_Em" => Some(Self::Em),
|
"DataType_Em" => Some(Self::Em),
|
||||||
"DataType_Ibp" => Some(Self::Ibp),
|
|
||||||
"DataType_Psl" => Some(Self::Psl),
|
|
||||||
"DataType_Iscs" => Some(Self::Iscs),
|
"DataType_Iscs" => Some(Self::Iscs),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -170,28 +211,40 @@ impl IscsStyle {
|
||||||
pub fn as_str_name(&self) -> &'static str {
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
IscsStyle::Unknown => "IscsStyle_Unknown",
|
IscsStyle::Unknown => "IscsStyle_Unknown",
|
||||||
IscsStyle::DaShiZhiNeng => "DaShiZhiNeng",
|
IscsStyle::DaShiZhiNeng => "IscsStyle_DaShiZhiNeng",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
"IscsStyle_Unknown" => Some(Self::Unknown),
|
"IscsStyle_Unknown" => Some(Self::Unknown),
|
||||||
"DaShiZhiNeng" => Some(Self::DaShiZhiNeng),
|
"IscsStyle_DaShiZhiNeng" => Some(Self::DaShiZhiNeng),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// 功能特性类型
|
/// 功能特性类型
|
||||||
#[derive(
|
#[derive(
|
||||||
sqlx::Type, Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration,
|
sqlx::Type,
|
||||||
|
async_graphql::Enum,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
::prost::Enumeration,
|
||||||
)]
|
)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum FeatureType {
|
pub enum FeatureType {
|
||||||
/// 未知
|
/// 未知
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
/// 仿真
|
/// 城轨信号系统仿真(Urban Rail)
|
||||||
Simulation = 1,
|
Ur = 1,
|
||||||
/// 运行图编制
|
/// 运行图编制
|
||||||
RunPlan = 2,
|
RunPlan = 2,
|
||||||
}
|
}
|
||||||
|
@ -203,7 +256,7 @@ impl FeatureType {
|
||||||
pub fn as_str_name(&self) -> &'static str {
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
FeatureType::Unknown => "FeatureType_Unknown",
|
FeatureType::Unknown => "FeatureType_Unknown",
|
||||||
FeatureType::Simulation => "FeatureType_Simulation",
|
FeatureType::Ur => "FeatureType_Ur",
|
||||||
FeatureType::RunPlan => "FeatureType_RunPlan",
|
FeatureType::RunPlan => "FeatureType_RunPlan",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +264,7 @@ impl FeatureType {
|
||||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
"FeatureType_Unknown" => Some(Self::Unknown),
|
"FeatureType_Unknown" => Some(Self::Unknown),
|
||||||
"FeatureType_Simulation" => Some(Self::Simulation),
|
"FeatureType_Ur" => Some(Self::Ur),
|
||||||
"FeatureType_RunPlan" => Some(Self::RunPlan),
|
"FeatureType_RunPlan" => Some(Self::RunPlan),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,12 @@
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct IscsGraphicStorage {
|
pub struct IscsGraphicStorage {
|
||||||
#[prost(message, optional, tag = "1")]
|
#[prost(message, repeated, tag = "1")]
|
||||||
pub canvas: ::core::option::Option<super::common::Canvas>,
|
pub cctv_of_station_control_storages: ::prost::alloc::vec::Vec<
|
||||||
|
CctvOfStationControlStorage,
|
||||||
|
>,
|
||||||
#[prost(message, repeated, tag = "2")]
|
#[prost(message, repeated, tag = "2")]
|
||||||
pub arrows: ::prost::alloc::vec::Vec<Arrow>,
|
pub fas_platform_alarm_storages: ::prost::alloc::vec::Vec<FasPlatformAlarmStorage>,
|
||||||
#[prost(message, repeated, tag = "3")]
|
|
||||||
pub iscs_texts: ::prost::alloc::vec::Vec<IscsText>,
|
|
||||||
#[prost(message, repeated, tag = "4")]
|
|
||||||
pub rects: ::prost::alloc::vec::Vec<Rect>,
|
|
||||||
#[prost(message, repeated, tag = "5")]
|
|
||||||
pub cctv_buttons: ::prost::alloc::vec::Vec<CctvButton>,
|
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
@ -177,3 +173,33 @@ pub struct TemperatureDetector {
|
||||||
#[prost(string, tag = "2")]
|
#[prost(string, tag = "2")]
|
||||||
pub code: ::prost::alloc::string::String,
|
pub code: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct CctvOfStationControlStorage {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub station_name: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub canvas: ::core::option::Option<super::common::Canvas>,
|
||||||
|
#[prost(message, repeated, tag = "3")]
|
||||||
|
pub arrows: ::prost::alloc::vec::Vec<Arrow>,
|
||||||
|
#[prost(message, repeated, tag = "4")]
|
||||||
|
pub iscs_texts: ::prost::alloc::vec::Vec<IscsText>,
|
||||||
|
#[prost(message, repeated, tag = "5")]
|
||||||
|
pub rects: ::prost::alloc::vec::Vec<Rect>,
|
||||||
|
#[prost(message, repeated, tag = "6")]
|
||||||
|
pub cctv_buttons: ::prost::alloc::vec::Vec<CctvButton>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct FasPlatformAlarmStorage {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub station_name: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub canvas: ::core::option::Option<super::common::Canvas>,
|
||||||
|
#[prost(message, repeated, tag = "3")]
|
||||||
|
pub arrows: ::prost::alloc::vec::Vec<Arrow>,
|
||||||
|
#[prost(message, repeated, tag = "4")]
|
||||||
|
pub iscs_texts: ::prost::alloc::vec::Vec<IscsText>,
|
||||||
|
#[prost(message, repeated, tag = "5")]
|
||||||
|
pub rects: ::prost::alloc::vec::Vec<Rect>,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
# 系统设计
|
||||||
|
|
||||||
|
## 数据库设计
|
||||||
|
- 核心数据如下图所示
|
||||||
|
|
||||||
|
![alt text](image-1.png)
|
||||||
|
|
||||||
|
- 所有数据从草稿数据开始,草稿数据发布为发布数据,功能定义引用发布数据,同时功能还可以引用其他功能实现功能目录树/功能组/功能包
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -14,6 +14,38 @@ CREATE TABLE
|
||||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP -- 更新时间
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP -- 更新时间
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 创建用户名称索引
|
||||||
|
CREATE INDEX ON rtss.user (username);
|
||||||
|
|
||||||
|
-- 创建用户邮箱索引
|
||||||
|
CREATE INDEX ON rtss.user (email);
|
||||||
|
|
||||||
|
-- 创建用户手机号索引
|
||||||
|
CREATE INDEX ON rtss.user (mobile);
|
||||||
|
|
||||||
|
-- 创建用户角色索引
|
||||||
|
CREATE INDEX ON rtss.user USING GIN (roles);
|
||||||
|
|
||||||
|
-- 注释用户表
|
||||||
|
COMMENT ON TABLE rtss.user IS '用户表';
|
||||||
|
|
||||||
|
-- 注释用户表字段
|
||||||
|
COMMENT ON COLUMN rtss.user.id IS 'id 自增主键';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.username IS '用户名';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.password IS '密码';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.email IS '邮箱';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.mobile IS '手机号';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.roles IS '角色列表';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.created_at IS '创建时间';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.user.updated_at IS '更新时间';
|
||||||
|
|
||||||
-- 创建草稿数据表
|
-- 创建草稿数据表
|
||||||
CREATE TABLE
|
CREATE TABLE
|
||||||
rtss.draft_data (
|
rtss.draft_data (
|
||||||
|
@ -28,7 +60,7 @@ CREATE TABLE
|
||||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
|
||||||
FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键
|
FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键
|
||||||
UNIQUE (name, user_id) -- 一个用户的草稿名称唯一
|
UNIQUE (name, data_type, user_id) -- 一个用户的某个类型的草稿名称唯一
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 创建草稿数据用户索引
|
-- 创建草稿数据用户索引
|
||||||
|
@ -78,6 +110,18 @@ CREATE TABLE
|
||||||
UNIQUE(data_type, name) -- 数据类型和名称唯一
|
UNIQUE(data_type, name) -- 数据类型和名称唯一
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 创建发布数据名称索引
|
||||||
|
CREATE INDEX ON rtss.release_data (name);
|
||||||
|
|
||||||
|
-- 创建发布数据用户索引
|
||||||
|
CREATE INDEX ON rtss.release_data (user_id);
|
||||||
|
|
||||||
|
-- 创建发布数据类型索引
|
||||||
|
CREATE INDEX ON rtss.release_data (data_type);
|
||||||
|
|
||||||
|
-- 创建发布数据配置项索引
|
||||||
|
CREATE INDEX ON rtss.release_data USING GIN (options);
|
||||||
|
|
||||||
-- 注释发布数据表
|
-- 注释发布数据表
|
||||||
COMMENT ON TABLE rtss.release_data IS '发布数据表';
|
COMMENT ON TABLE rtss.release_data IS '发布数据表';
|
||||||
|
|
||||||
|
@ -114,6 +158,15 @@ CREATE TABLE
|
||||||
FOREIGN KEY (release_data_id) REFERENCES rtss.release_data (id) ON DELETE CASCADE
|
FOREIGN KEY (release_data_id) REFERENCES rtss.release_data (id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 创建发布数据版本发布数据索引
|
||||||
|
CREATE INDEX ON rtss.release_data_version (release_data_id);
|
||||||
|
|
||||||
|
-- 创建发布数据版本用户索引
|
||||||
|
CREATE INDEX ON rtss.release_data_version (user_id);
|
||||||
|
|
||||||
|
-- 创建发布数据版本配置项索引
|
||||||
|
CREATE INDEX ON rtss.release_data_version USING GIN (options);
|
||||||
|
|
||||||
-- 创建发布数据当前版本外键
|
-- 创建发布数据当前版本外键
|
||||||
ALTER TABLE rtss.release_data ADD FOREIGN KEY (used_version_id) REFERENCES rtss.release_data_version (id) ON DELETE SET NULL;
|
ALTER TABLE rtss.release_data ADD FOREIGN KEY (used_version_id) REFERENCES rtss.release_data_version (id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
@ -145,6 +198,7 @@ CREATE TABLE
|
||||||
feature_type INT NOT NULL, -- feature类型
|
feature_type INT NOT NULL, -- feature类型
|
||||||
name VARCHAR(128) NOT NULL UNIQUE, -- feature名称
|
name VARCHAR(128) NOT NULL UNIQUE, -- feature名称
|
||||||
description TEXT NOT NULL, -- feature描述
|
description TEXT NOT NULL, -- feature描述
|
||||||
|
config JSONB NOT NULL, -- feature配置
|
||||||
is_published BOOLEAN NOT NULL DEFAULT TRUE, -- 是否上架
|
is_published BOOLEAN NOT NULL DEFAULT TRUE, -- 是否上架
|
||||||
creator_id INT NOT NULL, -- 创建用户id
|
creator_id INT NOT NULL, -- 创建用户id
|
||||||
updater_id INT NOT NULL, -- 更新用户id
|
updater_id INT NOT NULL, -- 更新用户id
|
||||||
|
@ -154,6 +208,12 @@ CREATE TABLE
|
||||||
FOREIGN KEY (updater_id) REFERENCES rtss.user (id) ON DELETE CASCADE -- 用户外键
|
FOREIGN KEY (updater_id) REFERENCES rtss.user (id) ON DELETE CASCADE -- 用户外键
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 创建feature类型索引
|
||||||
|
CREATE INDEX ON rtss.feature (feature_type);
|
||||||
|
|
||||||
|
-- 创建feature名称索引
|
||||||
|
CREATE INDEX ON rtss.feature (name);
|
||||||
|
|
||||||
-- 注释仿真feature表
|
-- 注释仿真feature表
|
||||||
COMMENT ON TABLE rtss.feature IS 'feature表';
|
COMMENT ON TABLE rtss.feature IS 'feature表';
|
||||||
|
|
||||||
|
@ -166,6 +226,8 @@ COMMENT ON COLUMN rtss.feature.name IS 'feature名称';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature.description IS 'feature描述';
|
COMMENT ON COLUMN rtss.feature.description IS 'feature描述';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN rtss.feature.config IS 'feature配置';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature.is_published IS '是否上架';
|
COMMENT ON COLUMN rtss.feature.is_published IS '是否上架';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature.creator_id IS '创建用户id';
|
COMMENT ON COLUMN rtss.feature.creator_id IS '创建用户id';
|
||||||
|
@ -174,95 +236,36 @@ COMMENT ON COLUMN rtss.feature.created_at IS '创建时间';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature.updated_at IS '更新时间';
|
COMMENT ON COLUMN rtss.feature.updated_at IS '更新时间';
|
||||||
|
|
||||||
-- 创建仿真feature和发布数据关联表
|
-- 创建用户配置表
|
||||||
CREATE TABLE
|
CREATE TABLE
|
||||||
rtss.feature_release_data (
|
rtss.user_config (
|
||||||
feature_id INT NOT NULL, -- 仿真feature id
|
|
||||||
release_data_id INT NOT NULL, -- 发布数据id
|
|
||||||
PRIMARY KEY (feature_id, release_data_id),
|
|
||||||
FOREIGN KEY (feature_id) REFERENCES rtss.feature (id) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (release_data_id) REFERENCES rtss.release_data (id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 注释仿真feature和发布数据关联表
|
|
||||||
COMMENT ON TABLE rtss.feature_release_data IS '仿真feature和发布数据关联表';
|
|
||||||
|
|
||||||
-- 注释仿真feature和发布数据关联表字段
|
|
||||||
COMMENT ON COLUMN rtss.feature_release_data.feature_id IS '仿真feature id';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_release_data.release_data_id IS '发布数据id';
|
|
||||||
|
|
||||||
-- 创建feature group表
|
|
||||||
CREATE TABLE
|
|
||||||
rtss.feature_group (
|
|
||||||
id SERIAL PRIMARY KEY, -- id 自增主键
|
|
||||||
name VARCHAR(128) NOT NULL UNIQUE, -- feature group名称
|
|
||||||
description TEXT NOT NULL, -- feature group描述
|
|
||||||
is_published BOOLEAN NOT NULL DEFAULT TRUE, -- 是否上架
|
|
||||||
creator_id INT NOT NULL, -- 创建用户id
|
|
||||||
updater_id INT NOT NULL, -- 更新用户id
|
|
||||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
|
||||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
|
|
||||||
FOREIGN KEY (creator_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键
|
|
||||||
FOREIGN KEY (updater_id) REFERENCES rtss.user (id) ON DELETE CASCADE -- 用户外键
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 注释仿真feature group表
|
|
||||||
COMMENT ON TABLE rtss.feature_group IS 'feature group表';
|
|
||||||
|
|
||||||
-- 注释仿真feature group表字段
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.id IS 'id 自增主键';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.name IS 'feature group名称';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.description IS 'feature group描述';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.is_published IS '是否上架';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.creator_id IS '创建用户id';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.created_at IS '创建时间';
|
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_group.updated_at IS '更新时间';
|
|
||||||
|
|
||||||
-- 创建feature group和feature关联表
|
|
||||||
CREATE TABLE
|
|
||||||
rtss.feature_group_feature (
|
|
||||||
feature_group_id INT NOT NULL, -- feature group id
|
|
||||||
feature_id INT NOT NULL, -- feature id
|
|
||||||
PRIMARY KEY (feature_id, feature_group_id),
|
|
||||||
FOREIGN KEY (feature_id) REFERENCES rtss.feature (id) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (feature_group_id) REFERENCES rtss.feature_group (id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 注释仿真feature group和feature关联表
|
|
||||||
COMMENT ON TABLE rtss.feature_group_feature IS '仿真feature group和feature关联表';
|
|
||||||
|
|
||||||
-- 创建用户feature配置表
|
|
||||||
CREATE TABLE
|
|
||||||
rtss.feature_config (
|
|
||||||
id SERIAL PRIMARY KEY, -- id 自增主键
|
id SERIAL PRIMARY KEY, -- id 自增主键
|
||||||
user_id INT NOT NULL, -- 用户id
|
user_id INT NOT NULL, -- 用户id
|
||||||
feature_id INT NOT NULL, -- 仿真feature id
|
config_type INT NOT NULL, -- 配置类型
|
||||||
config BYTEA NOT NULL, -- 配置
|
config BYTEA NOT NULL, -- 配置
|
||||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
|
||||||
FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键
|
FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE -- 用户外键
|
||||||
FOREIGN KEY (feature_id) REFERENCES rtss.feature (id) ON DELETE CASCADE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- 创建用户配置用户索引
|
||||||
|
CREATE INDEX ON rtss.user_config (user_id);
|
||||||
|
|
||||||
|
-- 创建用户配置类型索引
|
||||||
|
CREATE INDEX ON rtss.user_config (config_type);
|
||||||
|
|
||||||
-- 注释用户feature配置表
|
-- 注释用户feature配置表
|
||||||
COMMENT ON TABLE rtss.feature_config IS '用户feature配置表';
|
COMMENT ON TABLE rtss.user_config IS '用户feature配置表';
|
||||||
|
|
||||||
-- 注释用户feature配置表字段
|
-- 注释用户feature配置表字段
|
||||||
COMMENT ON COLUMN rtss.feature_config.id IS 'id 自增主键';
|
COMMENT ON COLUMN rtss.user_config.id IS 'id 自增主键';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_config.user_id IS '用户id';
|
COMMENT ON COLUMN rtss.user_config.user_id IS '用户id';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_config.feature_id IS '仿真feature id';
|
COMMENT ON COLUMN rtss.user_config.config_type IS '配置类型';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_config.config IS '配置';
|
COMMENT ON COLUMN rtss.user_config.config IS '配置';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_config.created_at IS '创建时间';
|
COMMENT ON COLUMN rtss.user_config.created_at IS '创建时间';
|
||||||
|
|
||||||
COMMENT ON COLUMN rtss.feature_config.updated_at IS '更新时间';
|
COMMENT ON COLUMN rtss.user_config.updated_at IS '更新时间';
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1672a8c0e2b41c4076c1dc9ec852f425dcba21c3
|
Subproject commit 02d9ad3b44876fc470e460bb6975c3d08f698b1b
|
Loading…
Reference in New Issue