878 lines
29 KiB
Rust
878 lines
29 KiB
Rust
use crate::models::{CreateSetting, Setting, SettingFilter, SettingHistory, UpdateSetting};
|
|
use crate::services::query_builder::DynamicQueryBuilder;
|
|
use anyhow::{anyhow, Result};
|
|
use chrono::{DateTime, Utc};
|
|
use sea_query::extension::postgres::PgExpr;
|
|
use sea_query::{Expr, Iden, Order, PostgresQueryBuilder, Query};
|
|
use sea_query_binder::SqlxBinder;
|
|
use serde_json::Value;
|
|
use sqlx::{PgPool, Row};
|
|
use std::collections::HashMap;
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Iden, Clone)]
|
|
enum Settings {
|
|
Table,
|
|
Id,
|
|
Key,
|
|
Value,
|
|
ValueType,
|
|
Description,
|
|
Category,
|
|
IsEncrypted,
|
|
IsSystem,
|
|
IsEditable,
|
|
CreatedAt,
|
|
UpdatedAt,
|
|
CreatedBy,
|
|
UpdatedBy,
|
|
}
|
|
|
|
#[derive(Iden, Clone)]
|
|
enum SettingsHistory {
|
|
Table,
|
|
Id,
|
|
SettingId,
|
|
OldValue,
|
|
NewValue,
|
|
ChangedBy,
|
|
ChangeReason,
|
|
CreatedAt,
|
|
}
|
|
|
|
pub struct SettingsService {
|
|
pool: PgPool,
|
|
query_builder: DynamicQueryBuilder,
|
|
}
|
|
|
|
impl SettingsService {
|
|
pub fn new(pool: PgPool) -> Self {
|
|
let query_builder = DynamicQueryBuilder::new(pool.clone());
|
|
Self {
|
|
pool,
|
|
query_builder,
|
|
}
|
|
}
|
|
|
|
/// 获取数据库连接池的引用(用于事务)
|
|
pub fn get_pool(&self) -> &PgPool {
|
|
&self.pool
|
|
}
|
|
|
|
/// 创建新的配置项
|
|
pub async fn create_setting(
|
|
&self,
|
|
create_setting: CreateSetting,
|
|
user_id: Uuid,
|
|
) -> Result<Setting> {
|
|
// 检查key是否已存在
|
|
let existing = sqlx::query!("SELECT id FROM settings WHERE key = $1", create_setting.key)
|
|
.fetch_optional(&self.pool)
|
|
.await?;
|
|
|
|
if existing.is_some() {
|
|
return Err(anyhow!(
|
|
"Setting with key '{}' already exists",
|
|
create_setting.key
|
|
));
|
|
}
|
|
|
|
let setting = sqlx::query_as!(
|
|
Setting,
|
|
r#"
|
|
INSERT INTO settings (key, value, value_type, description, category, is_encrypted, is_system, is_editable, created_by)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
RETURNING id, key, value, value_type, description, category, is_encrypted, is_system, is_editable,
|
|
created_at as "created_at: DateTime<Utc>",
|
|
updated_at as "updated_at: DateTime<Utc>",
|
|
created_by, updated_by
|
|
"#,
|
|
create_setting.key,
|
|
create_setting.value,
|
|
create_setting.value_type,
|
|
create_setting.description,
|
|
create_setting.category,
|
|
create_setting.is_encrypted.unwrap_or(false),
|
|
create_setting.is_system.unwrap_or(false),
|
|
create_setting.is_editable.unwrap_or(true),
|
|
user_id
|
|
)
|
|
.fetch_one(&self.pool)
|
|
.await?;
|
|
|
|
Ok(setting)
|
|
}
|
|
|
|
/// 根据key获取配置项
|
|
pub async fn get_setting_by_key(&self, key: &str) -> Result<Option<Setting>> {
|
|
let setting = sqlx::query_as!(
|
|
Setting,
|
|
r#"
|
|
SELECT id, key, value, value_type, description, category, is_encrypted, is_system, is_editable,
|
|
created_at as "created_at: DateTime<Utc>",
|
|
updated_at as "updated_at: DateTime<Utc>",
|
|
created_by, updated_by
|
|
FROM settings WHERE key = $1
|
|
"#,
|
|
key
|
|
)
|
|
.fetch_optional(&self.pool)
|
|
.await?;
|
|
|
|
Ok(setting)
|
|
}
|
|
|
|
/// 根据ID获取配置项
|
|
pub async fn get_setting_by_id(&self, id: Uuid) -> Result<Option<Setting>> {
|
|
let setting = sqlx::query_as!(
|
|
Setting,
|
|
r#"
|
|
SELECT id, key, value, value_type, description, category, is_encrypted, is_system, is_editable,
|
|
created_at as "created_at: DateTime<Utc>",
|
|
updated_at as "updated_at: DateTime<Utc>",
|
|
created_by, updated_by
|
|
FROM settings WHERE id = $1
|
|
"#,
|
|
id
|
|
)
|
|
.fetch_optional(&self.pool)
|
|
.await?;
|
|
|
|
Ok(setting)
|
|
}
|
|
|
|
/// 获取所有配置项
|
|
pub async fn get_all_settings(&self) -> Result<Vec<Setting>> {
|
|
let settings = sqlx::query_as!(
|
|
Setting,
|
|
r#"
|
|
SELECT id, key, value, value_type, description, category, is_encrypted, is_system, is_editable,
|
|
created_at as "created_at: DateTime<Utc>",
|
|
updated_at as "updated_at: DateTime<Utc>",
|
|
created_by, updated_by
|
|
FROM settings ORDER BY category, key
|
|
"#
|
|
)
|
|
.fetch_all(&self.pool)
|
|
.await?;
|
|
|
|
Ok(settings)
|
|
}
|
|
|
|
/// 根据过滤条件获取配置项 (使用 sea-query 构建动态查询)
|
|
pub async fn get_settings_with_filter(&self, filter: &SettingFilter) -> Result<Vec<Setting>> {
|
|
let mut query = Query::select();
|
|
query
|
|
.columns([
|
|
Settings::Id,
|
|
Settings::Key,
|
|
Settings::Value,
|
|
Settings::ValueType,
|
|
Settings::Description,
|
|
Settings::Category,
|
|
Settings::IsEncrypted,
|
|
Settings::IsSystem,
|
|
Settings::IsEditable,
|
|
Settings::CreatedAt,
|
|
Settings::UpdatedAt,
|
|
Settings::CreatedBy,
|
|
Settings::UpdatedBy,
|
|
])
|
|
.from(Settings::Table);
|
|
|
|
// 动态添加过滤条件
|
|
if let Some(category) = &filter.category {
|
|
query.and_where(Expr::col(Settings::Category).eq(category));
|
|
}
|
|
|
|
if let Some(is_system) = &filter.is_system {
|
|
query.and_where(Expr::col(Settings::IsSystem).eq(*is_system));
|
|
}
|
|
|
|
if let Some(is_editable) = &filter.is_editable {
|
|
query.and_where(Expr::col(Settings::IsEditable).eq(*is_editable));
|
|
}
|
|
|
|
if let Some(search) = &filter.search {
|
|
let search_pattern = format!("%{}%", search);
|
|
query.and_where(
|
|
Expr::col(Settings::Key)
|
|
.ilike(&search_pattern)
|
|
.or(Expr::col(Settings::Description).ilike(&search_pattern)),
|
|
);
|
|
}
|
|
|
|
// 添加排序
|
|
query
|
|
.order_by(Settings::Category, sea_query::Order::Asc)
|
|
.order_by(Settings::Key, sea_query::Order::Asc);
|
|
|
|
// 构建并执行查询
|
|
let (sql, values) = query.build_sqlx(PostgresQueryBuilder);
|
|
let rows = sqlx::query_with(&sql, values).fetch_all(&self.pool).await?;
|
|
|
|
let mut settings = Vec::new();
|
|
for row in rows {
|
|
let setting = Setting {
|
|
id: row.get("id"),
|
|
key: row.get("key"),
|
|
value: row.get("value"),
|
|
value_type: row.get("value_type"),
|
|
description: row.get("description"),
|
|
category: row.get("category"),
|
|
is_encrypted: row.get("is_encrypted"),
|
|
is_system: row.get("is_system"),
|
|
is_editable: row.get("is_editable"),
|
|
created_at: row.get("created_at"),
|
|
updated_at: row.get("updated_at"),
|
|
created_by: row.get("created_by"),
|
|
updated_by: row.get("updated_by"),
|
|
};
|
|
settings.push(setting);
|
|
}
|
|
|
|
Ok(settings)
|
|
}
|
|
|
|
/// 更新配置项
|
|
pub async fn update_setting(
|
|
&self,
|
|
id: Uuid,
|
|
update_setting: UpdateSetting,
|
|
user_id: Uuid,
|
|
) -> Result<Setting> {
|
|
let setting = self.get_setting_by_id(id).await?;
|
|
let setting = setting.ok_or_else(|| anyhow!("Setting not found"))?;
|
|
|
|
if !setting.is_editable.unwrap_or(false) {
|
|
return Err(anyhow!("Setting is not editable"));
|
|
}
|
|
|
|
let updated_setting = sqlx::query_as!(
|
|
Setting,
|
|
r#"
|
|
UPDATE settings
|
|
SET value = COALESCE($1, value),
|
|
description = COALESCE($2, description),
|
|
category = COALESCE($3, category),
|
|
is_editable = COALESCE($4, is_editable),
|
|
updated_by = $5,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = $6
|
|
RETURNING id, key, value, value_type, description, category, is_encrypted, is_system, is_editable,
|
|
created_at as "created_at: DateTime<Utc>",
|
|
updated_at as "updated_at: DateTime<Utc>",
|
|
created_by, updated_by
|
|
"#,
|
|
update_setting.value,
|
|
update_setting.description,
|
|
update_setting.category,
|
|
update_setting.is_editable,
|
|
user_id,
|
|
id
|
|
)
|
|
.fetch_one(&self.pool)
|
|
.await?;
|
|
|
|
Ok(updated_setting)
|
|
}
|
|
|
|
/// 删除配置项
|
|
pub async fn delete_setting(&self, id: Uuid) -> Result<bool> {
|
|
let setting = self.get_setting_by_id(id).await?;
|
|
let setting = setting.ok_or_else(|| anyhow!("Setting not found"))?;
|
|
|
|
if setting.is_system.unwrap_or(false) {
|
|
return Err(anyhow!("Cannot delete system settings"));
|
|
}
|
|
|
|
let result = sqlx::query!("DELETE FROM settings WHERE id = $1", id)
|
|
.execute(&self.pool)
|
|
.await?;
|
|
|
|
Ok(result.rows_affected() > 0)
|
|
}
|
|
|
|
/// 批量更新配置项
|
|
pub async fn batch_update_settings(
|
|
&self,
|
|
updates: Vec<(String, Value)>,
|
|
user_id: Uuid,
|
|
) -> Result<Vec<Setting>> {
|
|
let mut updated_settings = Vec::new();
|
|
|
|
for (key, value) in updates {
|
|
if let Some(setting) = self.get_setting_by_key(&key).await? {
|
|
if !setting.is_editable.unwrap_or(false) {
|
|
continue; // 跳过不可编辑的配置
|
|
}
|
|
|
|
let value_str = serde_json::to_string(&value)?;
|
|
let updated_setting = sqlx::query_as!(
|
|
Setting,
|
|
r#"
|
|
UPDATE settings
|
|
SET value = $1, updated_by = $2, updated_at = CURRENT_TIMESTAMP
|
|
WHERE key = $3
|
|
RETURNING id, key, value, value_type, description, category, is_encrypted, is_system, is_editable,
|
|
created_at as "created_at: DateTime<Utc>",
|
|
updated_at as "updated_at: DateTime<Utc>",
|
|
created_by, updated_by
|
|
"#,
|
|
value_str,
|
|
user_id,
|
|
key
|
|
)
|
|
.fetch_one(&self.pool)
|
|
.await?;
|
|
|
|
updated_settings.push(updated_setting);
|
|
}
|
|
}
|
|
|
|
Ok(updated_settings)
|
|
}
|
|
|
|
/// 获取配置历史
|
|
pub async fn get_setting_history(&self, setting_id: Uuid) -> Result<Vec<SettingHistory>> {
|
|
let history = sqlx::query_as!(
|
|
SettingHistory,
|
|
r#"
|
|
SELECT id, setting_id, old_value, new_value, changed_by, change_reason,
|
|
created_at as "created_at: DateTime<Utc>"
|
|
FROM settings_history
|
|
WHERE setting_id = $1
|
|
ORDER BY created_at DESC
|
|
"#,
|
|
setting_id
|
|
)
|
|
.fetch_all(&self.pool)
|
|
.await?;
|
|
|
|
Ok(history)
|
|
}
|
|
|
|
/// 获取配置分类列表
|
|
pub async fn get_categories(&self) -> Result<Vec<String>> {
|
|
let categories = sqlx::query!("SELECT DISTINCT category FROM settings ORDER BY category")
|
|
.fetch_all(&self.pool)
|
|
.await?;
|
|
|
|
Ok(categories
|
|
.into_iter()
|
|
.map(|row| row.category.unwrap_or("".to_string()))
|
|
.collect())
|
|
}
|
|
|
|
/// 获取配置项数量统计
|
|
pub async fn get_settings_stats(&self) -> Result<HashMap<String, i64>> {
|
|
let stats = sqlx::query!(
|
|
r#"
|
|
SELECT
|
|
category,
|
|
COUNT(*) as count,
|
|
COUNT(CASE WHEN is_system = true THEN 1 END) as system_count,
|
|
COUNT(CASE WHEN is_editable = true THEN 1 END) as editable_count
|
|
FROM settings
|
|
GROUP BY category
|
|
ORDER BY category
|
|
"#
|
|
)
|
|
.fetch_all(&self.pool)
|
|
.await?;
|
|
|
|
let mut result = HashMap::new();
|
|
for row in stats {
|
|
result.insert(
|
|
format!("{}_total", row.category.as_ref().unwrap()),
|
|
row.count.unwrap_or(0),
|
|
);
|
|
result.insert(
|
|
format!("{}_system", row.category.as_ref().unwrap()),
|
|
row.system_count.unwrap_or(0),
|
|
);
|
|
result.insert(
|
|
format!("{}_editable", row.category.as_ref().unwrap()),
|
|
row.editable_count.unwrap_or(0),
|
|
);
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
/// 重置配置到默认值
|
|
pub async fn reset_to_defaults(&self, user_id: Uuid) -> Result<Vec<Setting>> {
|
|
// 这里可以实现重置逻辑,比如从配置文件重新加载默认值
|
|
// 暂时返回空列表
|
|
Ok(Vec::new())
|
|
}
|
|
|
|
/// 导出配置 (使用 sea-query 构建动态查询)
|
|
pub async fn export_settings(&self, category: Option<&str>) -> Result<Vec<Setting>> {
|
|
let mut query = Query::select();
|
|
query
|
|
.columns([
|
|
Settings::Id,
|
|
Settings::Key,
|
|
Settings::Value,
|
|
Settings::ValueType,
|
|
Settings::Description,
|
|
Settings::Category,
|
|
Settings::IsEncrypted,
|
|
Settings::IsSystem,
|
|
Settings::IsEditable,
|
|
Settings::CreatedAt,
|
|
Settings::UpdatedAt,
|
|
Settings::CreatedBy,
|
|
Settings::UpdatedBy,
|
|
])
|
|
.from(Settings::Table);
|
|
|
|
// 根据分类过滤
|
|
if let Some(cat) = category {
|
|
query.and_where(Expr::col(Settings::Category).eq(cat));
|
|
}
|
|
|
|
// 添加排序
|
|
query
|
|
.order_by(Settings::Category, sea_query::Order::Asc)
|
|
.order_by(Settings::Key, sea_query::Order::Asc);
|
|
|
|
// 构建并执行查询
|
|
let (sql, values) = query.build_sqlx(PostgresQueryBuilder);
|
|
let rows = sqlx::query_with(&sql, values).fetch_all(&self.pool).await?;
|
|
|
|
let mut settings = Vec::new();
|
|
for row in rows {
|
|
let setting = Setting {
|
|
id: row.get("id"),
|
|
key: row.get("key"),
|
|
value: row.get("value"),
|
|
value_type: row.get("value_type"),
|
|
description: row.get("description"),
|
|
category: row.get("category"),
|
|
is_encrypted: row.get("is_encrypted"),
|
|
is_system: row.get("is_system"),
|
|
is_editable: row.get("is_editable"),
|
|
created_at: row.get("created_at"),
|
|
updated_at: row.get("updated_at"),
|
|
created_by: row.get("created_by"),
|
|
updated_by: row.get("updated_by"),
|
|
};
|
|
settings.push(setting);
|
|
}
|
|
|
|
Ok(settings)
|
|
}
|
|
|
|
/// 导入配置
|
|
pub async fn import_settings(
|
|
&self,
|
|
settings: Vec<CreateSetting>,
|
|
user_id: Uuid,
|
|
) -> Result<Vec<Setting>> {
|
|
let mut imported_settings = Vec::new();
|
|
|
|
for create_setting in settings {
|
|
// 检查是否已存在
|
|
if let Some(existing) = self.get_setting_by_key(&create_setting.key).await? {
|
|
// 如果存在且可编辑,则更新
|
|
if existing.is_editable.unwrap_or(false) {
|
|
let update_setting = UpdateSetting {
|
|
value: create_setting.value,
|
|
description: create_setting.description,
|
|
category: Some(create_setting.category),
|
|
is_editable: Some(create_setting.is_editable.unwrap_or(true)),
|
|
};
|
|
let updated = self
|
|
.update_setting(existing.id, update_setting, user_id)
|
|
.await?;
|
|
imported_settings.push(updated);
|
|
}
|
|
} else {
|
|
// 如果不存在,则创建
|
|
let new_setting = self.create_setting(create_setting, user_id).await?;
|
|
imported_settings.push(new_setting);
|
|
}
|
|
}
|
|
|
|
Ok(imported_settings)
|
|
}
|
|
|
|
/// 分页查询配置项 (sea-query 分页示例)
|
|
pub async fn get_settings_paginated(
|
|
&self,
|
|
filter: &SettingFilter,
|
|
page: u64,
|
|
page_size: u64,
|
|
) -> Result<(Vec<Setting>, u64)> {
|
|
let offset = (page - 1) * page_size;
|
|
|
|
// 查询总数
|
|
let mut count_query = Query::select();
|
|
count_query
|
|
.expr(Expr::col(Settings::Id).count())
|
|
.from(Settings::Table);
|
|
|
|
// 应用过滤条件
|
|
self.apply_filter_conditions(&mut count_query, filter);
|
|
|
|
let (count_sql, count_values) = count_query.build_sqlx(PostgresQueryBuilder);
|
|
let total_count: i64 = sqlx::query_scalar_with(&count_sql, count_values)
|
|
.fetch_one(&self.pool)
|
|
.await?;
|
|
|
|
// 查询数据
|
|
let mut data_query = Query::select();
|
|
data_query
|
|
.columns([
|
|
Settings::Id,
|
|
Settings::Key,
|
|
Settings::Value,
|
|
Settings::ValueType,
|
|
Settings::Description,
|
|
Settings::Category,
|
|
Settings::IsEncrypted,
|
|
Settings::IsSystem,
|
|
Settings::IsEditable,
|
|
Settings::CreatedAt,
|
|
Settings::UpdatedAt,
|
|
Settings::CreatedBy,
|
|
Settings::UpdatedBy,
|
|
])
|
|
.from(Settings::Table);
|
|
|
|
self.apply_filter_conditions(&mut data_query, filter);
|
|
|
|
data_query
|
|
.order_by(Settings::Category, sea_query::Order::Asc)
|
|
.order_by(Settings::Key, sea_query::Order::Asc)
|
|
.limit(page_size)
|
|
.offset(offset);
|
|
|
|
let (sql, values) = data_query.build_sqlx(PostgresQueryBuilder);
|
|
let rows = sqlx::query_with(&sql, values).fetch_all(&self.pool).await?;
|
|
|
|
let mut settings = Vec::new();
|
|
for row in rows {
|
|
let setting = Setting {
|
|
id: row.get("id"),
|
|
key: row.get("key"),
|
|
value: row.get("value"),
|
|
value_type: row.get("value_type"),
|
|
description: row.get("description"),
|
|
category: row.get("category"),
|
|
is_encrypted: row.get("is_encrypted"),
|
|
is_system: row.get("is_system"),
|
|
is_editable: row.get("is_editable"),
|
|
created_at: row.get("created_at"),
|
|
updated_at: row.get("updated_at"),
|
|
created_by: row.get("created_by"),
|
|
updated_by: row.get("updated_by"),
|
|
};
|
|
settings.push(setting);
|
|
}
|
|
|
|
Ok((settings, total_count as u64))
|
|
}
|
|
|
|
/// 高级搜索配置项 (复杂条件查询示例)
|
|
pub async fn advanced_search_settings(
|
|
&self,
|
|
search_term: Option<&str>,
|
|
categories: Option<Vec<String>>,
|
|
value_types: Option<Vec<String>>,
|
|
is_system: Option<bool>,
|
|
date_range: Option<(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::Utc>)>,
|
|
) -> Result<Vec<Setting>> {
|
|
let mut query = Query::select();
|
|
query
|
|
.columns([
|
|
Settings::Id,
|
|
Settings::Key,
|
|
Settings::Value,
|
|
Settings::ValueType,
|
|
Settings::Description,
|
|
Settings::Category,
|
|
Settings::IsEncrypted,
|
|
Settings::IsSystem,
|
|
Settings::IsEditable,
|
|
Settings::CreatedAt,
|
|
Settings::UpdatedAt,
|
|
Settings::CreatedBy,
|
|
Settings::UpdatedBy,
|
|
])
|
|
.from(Settings::Table);
|
|
|
|
// 搜索关键词
|
|
if let Some(term) = search_term {
|
|
let search_pattern = format!("%{}%", term);
|
|
query.and_where(
|
|
Expr::col(Settings::Key)
|
|
.ilike(&search_pattern)
|
|
.or(Expr::col(Settings::Description).ilike(&search_pattern))
|
|
.or(Expr::col(Settings::Value).ilike(&search_pattern)),
|
|
);
|
|
}
|
|
|
|
// 多个分类
|
|
if let Some(cats) = categories {
|
|
if !cats.is_empty() {
|
|
query.and_where(Expr::col(Settings::Category).is_in(cats));
|
|
}
|
|
}
|
|
|
|
// 多个值类型
|
|
if let Some(types) = value_types {
|
|
if !types.is_empty() {
|
|
query.and_where(Expr::col(Settings::ValueType).is_in(types));
|
|
}
|
|
}
|
|
|
|
// 系统设置
|
|
if let Some(sys) = is_system {
|
|
query.and_where(Expr::col(Settings::IsSystem).eq(sys));
|
|
}
|
|
|
|
// 日期范围
|
|
if let Some((start_date, end_date)) = date_range {
|
|
query.and_where(
|
|
Expr::col(Settings::CreatedAt)
|
|
.gte(start_date)
|
|
.and(Expr::col(Settings::CreatedAt).lte(end_date)),
|
|
);
|
|
}
|
|
|
|
query
|
|
.order_by(Settings::Category, sea_query::Order::Asc)
|
|
.order_by(Settings::Key, sea_query::Order::Asc);
|
|
|
|
let (sql, values) = query.build_sqlx(PostgresQueryBuilder);
|
|
let rows = sqlx::query_with(&sql, values).fetch_all(&self.pool).await?;
|
|
|
|
let mut settings = Vec::new();
|
|
for row in rows {
|
|
let setting = Setting {
|
|
id: row.get("id"),
|
|
key: row.get("key"),
|
|
value: row.get("value"),
|
|
value_type: row.get("value_type"),
|
|
description: row.get("description"),
|
|
category: row.get("category"),
|
|
is_encrypted: row.get("is_encrypted"),
|
|
is_system: row.get("is_system"),
|
|
is_editable: row.get("is_editable"),
|
|
created_at: row.get("created_at"),
|
|
updated_at: row.get("updated_at"),
|
|
created_by: row.get("created_by"),
|
|
updated_by: row.get("updated_by"),
|
|
};
|
|
settings.push(setting);
|
|
}
|
|
|
|
Ok(settings)
|
|
}
|
|
|
|
/// 批量操作 (动态更新多个配置项)
|
|
pub async fn batch_update_by_conditions(
|
|
&self,
|
|
conditions: &SettingFilter,
|
|
updates: HashMap<String, serde_json::Value>,
|
|
user_id: Uuid,
|
|
) -> Result<u64> {
|
|
// 构建更新查询
|
|
let mut update_query = Query::update();
|
|
update_query.table(Settings::Table);
|
|
|
|
// 添加更新字段
|
|
for (field, value) in updates {
|
|
match field.as_str() {
|
|
"description" => {
|
|
if let Some(desc) = value.as_str() {
|
|
update_query.value(Settings::Description, desc);
|
|
}
|
|
}
|
|
"category" => {
|
|
if let Some(cat) = value.as_str() {
|
|
update_query.value(Settings::Category, cat);
|
|
}
|
|
}
|
|
"is_editable" => {
|
|
if let Some(editable) = value.as_bool() {
|
|
update_query.value(Settings::IsEditable, editable);
|
|
}
|
|
}
|
|
_ => {} // 忽略未知字段
|
|
}
|
|
}
|
|
|
|
update_query.value(Settings::UpdatedBy, user_id);
|
|
|
|
// 应用过滤条件
|
|
self.apply_filter_conditions(&mut update_query, conditions);
|
|
|
|
let (sql, values) = update_query.build_sqlx(PostgresQueryBuilder);
|
|
let result = sqlx::query_with(&sql, values).execute(&self.pool).await?;
|
|
|
|
Ok(result.rows_affected())
|
|
}
|
|
|
|
/// 辅助方法:应用过滤条件到查询
|
|
fn apply_filter_conditions<T>(&self, query: &mut T, filter: &SettingFilter)
|
|
where
|
|
T: sea_query::QueryStatementWriter + sea_query::ConditionalStatement,
|
|
{
|
|
if let Some(category) = &filter.category {
|
|
query.and_where(Expr::col(Settings::Category).eq(category));
|
|
}
|
|
|
|
if let Some(is_system) = &filter.is_system {
|
|
query.and_where(Expr::col(Settings::IsSystem).eq(*is_system));
|
|
}
|
|
|
|
if let Some(is_editable) = &filter.is_editable {
|
|
query.and_where(Expr::col(Settings::IsEditable).eq(*is_editable));
|
|
}
|
|
|
|
if let Some(search) = &filter.search {
|
|
let search_pattern = format!("%{}%", search);
|
|
query.and_where(
|
|
Expr::col(Settings::Key)
|
|
.ilike(&search_pattern)
|
|
.or(Expr::col(Settings::Description).ilike(&search_pattern)),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 使用查询构建器的简化过滤查询示例
|
|
pub async fn get_settings_with_builder(&self, filter: &SettingFilter) -> Result<Vec<Setting>> {
|
|
let rows = self
|
|
.query_builder
|
|
.select(Settings::Table)
|
|
.columns([
|
|
Settings::Id,
|
|
Settings::Key,
|
|
Settings::Value,
|
|
Settings::ValueType,
|
|
Settings::Description,
|
|
Settings::Category,
|
|
Settings::IsEncrypted,
|
|
Settings::IsSystem,
|
|
Settings::IsEditable,
|
|
Settings::CreatedAt,
|
|
Settings::UpdatedAt,
|
|
Settings::CreatedBy,
|
|
Settings::UpdatedBy,
|
|
])
|
|
.condition_option(Settings::Category, filter.category.clone())
|
|
.condition_option(Settings::IsSystem, filter.is_system)
|
|
.condition_option(Settings::IsEditable, filter.is_editable)
|
|
.search_like(
|
|
vec![Settings::Key, Settings::Description],
|
|
filter.search.as_deref(),
|
|
)
|
|
.order_by(Settings::Category, Order::Asc)
|
|
.order_by(Settings::Key, Order::Asc)
|
|
.fetch_all()
|
|
.await?;
|
|
|
|
let mut settings = Vec::new();
|
|
for row in rows {
|
|
let setting = Setting {
|
|
id: row.get("id"),
|
|
key: row.get("key"),
|
|
value: row.get("value"),
|
|
value_type: row.get("value_type"),
|
|
description: row.get("description"),
|
|
category: row.get("category"),
|
|
is_encrypted: row.get("is_encrypted"),
|
|
is_system: row.get("is_system"),
|
|
is_editable: row.get("is_editable"),
|
|
created_at: row.get("created_at"),
|
|
updated_at: row.get("updated_at"),
|
|
created_by: row.get("created_by"),
|
|
updated_by: row.get("updated_by"),
|
|
};
|
|
settings.push(setting);
|
|
}
|
|
|
|
Ok(settings)
|
|
}
|
|
|
|
/// 使用查询构建器的分页查询示例
|
|
pub async fn get_settings_paginated_with_builder(
|
|
&self,
|
|
filter: &SettingFilter,
|
|
page: u64,
|
|
page_size: u64,
|
|
) -> Result<(Vec<Setting>, i64)> {
|
|
// 获取总数
|
|
let total_count = self
|
|
.query_builder
|
|
.select(Settings::Table)
|
|
.condition_option(Settings::Category, filter.category.clone())
|
|
.condition_option(Settings::IsSystem, filter.is_system)
|
|
.condition_option(Settings::IsEditable, filter.is_editable)
|
|
.search_like(
|
|
vec![Settings::Key, Settings::Description],
|
|
filter.search.as_deref(),
|
|
)
|
|
.count()
|
|
.await?;
|
|
|
|
// 获取分页数据
|
|
let rows = self
|
|
.query_builder
|
|
.select(Settings::Table)
|
|
.columns([
|
|
Settings::Id,
|
|
Settings::Key,
|
|
Settings::Value,
|
|
Settings::ValueType,
|
|
Settings::Description,
|
|
Settings::Category,
|
|
Settings::IsEncrypted,
|
|
Settings::IsSystem,
|
|
Settings::IsEditable,
|
|
Settings::CreatedAt,
|
|
Settings::UpdatedAt,
|
|
Settings::CreatedBy,
|
|
Settings::UpdatedBy,
|
|
])
|
|
.condition_option(Settings::Category, filter.category.clone())
|
|
.condition_option(Settings::IsSystem, filter.is_system)
|
|
.condition_option(Settings::IsEditable, filter.is_editable)
|
|
.search_like(
|
|
vec![Settings::Key, Settings::Description],
|
|
filter.search.as_deref(),
|
|
)
|
|
.order_by(Settings::Category, Order::Asc)
|
|
.order_by(Settings::Key, Order::Asc)
|
|
.paginate(page, page_size)
|
|
.fetch_all()
|
|
.await?;
|
|
|
|
let mut settings = Vec::new();
|
|
for row in rows {
|
|
let setting = Setting {
|
|
id: row.get("id"),
|
|
key: row.get("key"),
|
|
value: row.get("value"),
|
|
value_type: row.get("value_type"),
|
|
description: row.get("description"),
|
|
category: row.get("category"),
|
|
is_encrypted: row.get("is_encrypted"),
|
|
is_system: row.get("is_system"),
|
|
is_editable: row.get("is_editable"),
|
|
created_at: row.get("created_at"),
|
|
updated_at: row.get("updated_at"),
|
|
created_by: row.get("created_by"),
|
|
updated_by: row.get("updated_by"),
|
|
};
|
|
settings.push(setting);
|
|
}
|
|
|
|
Ok((settings, total_count))
|
|
}
|
|
}
|