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 { // 检查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", updated_at as "updated_at: DateTime", 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> { 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", updated_at as "updated_at: DateTime", 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> { 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", updated_at as "updated_at: DateTime", 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> { 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", updated_at as "updated_at: DateTime", 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> { 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 { 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", updated_at as "updated_at: DateTime", 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 { 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> { 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", updated_at as "updated_at: DateTime", 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> { 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" 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> { 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> { 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> { // 这里可以实现重置逻辑,比如从配置文件重新加载默认值 // 暂时返回空列表 Ok(Vec::new()) } /// 导出配置 (使用 sea-query 构建动态查询) pub async fn export_settings(&self, category: Option<&str>) -> Result> { 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, user_id: Uuid, ) -> Result> { 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, 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>, value_types: Option>, is_system: Option, date_range: Option<(chrono::DateTime, chrono::DateTime)>, ) -> Result> { 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, user_id: Uuid, ) -> Result { // 构建更新查询 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(&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> { 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, 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)) } }