use sqlx::{PgPool, postgres::PgPoolOptions}; use std::env; use std::error::Error; // 从 models 模块引入 WeatherData 结构体 use crate::models::{WeatherData, WeatherDataBrief, WeatherListResponse}; // 这个函数封装了所有与数据库交互的逻辑 pub async fn insert_weather_data(pool: &PgPool, weather_data: &WeatherData) -> Result { // 1. 根据 openid 查询 user_id let user_id = match sqlx::query_as::<_, (i32,)>("SELECT id FROM users WHERE openid = $1") .bind(&weather_data.openid) .fetch_optional(pool) .await { Ok(Some((id,))) => id, Ok(None) => { return Err(format!("未找到openid为 {} 的用户", weather_data.openid)); } Err(e) => { return Err(format!("查询用户失败: {}", e)); } }; // 2. 准备插入数据的 SQL 语句 let insert_query = r#" INSERT INTO weather_data ( user_id, title, date, hour, min, longitude, latitude, daysincejanfirst, theta, solardeclination, sunaltitude, overallcloudiness, lowcloudiness, cloudindex, solarradiationlevel, hasmeasuredwindspeed, measuredwindspeed, convertedwindspeed, measurementheight, areatype, pointwindspeed, atmosphericstability, suitabilitydegree, winddirection, averagewinddirection, winddirectionstandarddeviation, windspeed, averagewindspeed, windspeedsuitability, winddirectionsuitability, overallsuitability, inspectiontype, assignmentnumber, calculatedwindspeed ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34 ) RETURNING id "#; // 转换经纬度为字符串 let longitude_str = weather_data.longitude.to_string(); let latitude_str = weather_data.latitude.to_string(); // 3. 执行插入操作 let inserted_id = match sqlx::query_as::<_, (i32,)>(insert_query) .bind(user_id) .bind(&weather_data.title) .bind(weather_data.date) // NaiveDate 类型,sqlx 会自动处理 .bind(weather_data.hours) .bind(weather_data.min) .bind(&longitude_str) .bind(&latitude_str) .bind(weather_data.day_since_jan_first) .bind(weather_data.theta) .bind(weather_data.solar_declination) .bind(weather_data.sun_altitude) .bind(&weather_data.overall_cloudiness) .bind(&weather_data.low_cloudiness) .bind(&weather_data.cloud_index) .bind(weather_data.solar_radiation_level as i32) .bind(weather_data.has_measured_wind_speed) .bind(weather_data.measured_wind_speed) .bind(weather_data.converted_wind_speed as i32) .bind(weather_data.measurement_height) .bind(&weather_data.area_type) .bind(weather_data.point_wind_speed) .bind(&weather_data.atmospheric_stability) .bind(&weather_data.suitability_degree) .bind( serde_json::to_value(&weather_data.wind_direction) .map_err(|e| format!("JSON 序列化失败: {}", e))?, ) .bind(weather_data.average_wind_direction) .bind(weather_data.wind_direction_standard_deviation) .bind( serde_json::to_value(&weather_data.wind_speed) .map_err(|e| format!("JSON 序列化失败: {}", e))?, ) .bind(weather_data.average_wind_speed) .bind(&weather_data.wind_speed_suitability) .bind(&weather_data.wind_direction_suitability) .bind(&weather_data.overall_suitability) .bind(&weather_data.inspection_type) .bind(&weather_data.assignment_number) .bind(weather_data.calculated_wind_speed) .fetch_one(pool) .await { Ok((id,)) => id, Err(e) => { return Err(format!("插入数据失败: {}", e)); } }; // 4. 成功,返回插入的 ID Ok(inserted_id) } pub async fn create_pool() -> Result> { // 加载环境变量,非致命错误处理 if let Err(e) = dotenvy::dotenv() { eprintln!("警告: 无法加载.env文件 - {}", e); } // 获取数据库URL并提供友好错误信息 let database_url = env::var("DATABASE_URL").map_err(|_| "环境变量DATABASE_URL未设置,请在.env文件中配置")?; // 配置连接池参数 let pool = PgPoolOptions::new() .max_connections(20) // 根据应用需求调整最大连接数 .acquire_timeout(std::time::Duration::from_secs(30)) // 获取连接的超时时间 .connect(&database_url) .await .map_err(|e| format!("数据库连接失败: {}", e))?; Ok(pool) } // 在db.rs中添加以下函数 // 获取天气数据详情 pub async fn get_weather_details(pool: &PgPool, weather_id: i32) -> Result { let query = r#" SELECT wd.id, wd.title, wd.date, wd.hour, wd.min, wd.longitude::float8 as longitude, wd.latitude::float8 as latitude, wd.daysincejanfirst, wd.theta, wd.solardeclination, wd.sunaltitude, wd.overallcloudiness, wd.lowcloudiness, wd.cloudindex, wd.solarradiationlevel, wd.hasmeasuredwindspeed, wd.measuredwindspeed, wd.convertedwindspeed, wd.measurementheight, wd.areatype, wd.pointwindspeed, wd.atmosphericstability, wd.suitabilitydegree, wd.winddirection, wd.averagewinddirection, wd.winddirectionstandarddeviation, wd.windspeed, wd.averagewindspeed, wd.windspeedsuitability, wd.winddirectionsuitability, wd.overallsuitability, wd.inspectiontype, wd.assignmentnumber, wd.calculatedwindspeed, u.openid FROM weather_data wd JOIN users u ON wd.user_id = u.id WHERE wd.id = $1 "#; let row = match sqlx::query_as::<_, WeatherData>(query) .bind(weather_id) .fetch_optional(pool) .await { Ok(Some(row)) => row, Ok(None) => return Err(format!("未找到ID为 {} 的天气数据", weather_id)), Err(e) => return Err(format!("查询天气数据失败: {}", e)), }; Ok(row) } // 替换db.rs中的get_weather_list函数 pub async fn get_weather_list( pool: &PgPool, user_id: i32, page: i32, limit: i32, ) -> Result { let offset = (page - 1) * limit; // 1. 查询符合条件的总条数 let total_query = r#" SELECT COUNT(*) as total FROM weather_data WHERE user_id = $1 "#; let total = match sqlx::query_as::<_, (i64,)>(total_query) .bind(user_id) .fetch_one(pool) .await { Ok((count,)) => count, Err(e) => return Err(format!("查询总条数失败: {}", e)), }; // 2. 查询当前页数据列表 let list_query = r#" SELECT wd.id, wd.title, wd.date, wd.hour, wd.min, wd.longitude, wd.latitude FROM weather_data wd WHERE wd.user_id = $1 ORDER BY wd.date DESC, wd.hour DESC, wd.min DESC LIMIT $2 OFFSET $3 "#; let list = match sqlx::query_as::<_, WeatherDataBrief>(list_query) .bind(user_id) .bind(limit) .bind(offset) .fetch_all(pool) .await { Ok(data) => data, Err(e) => return Err(format!("查询天气数据列表失败: {}", e)), }; // 3. 包装结果并返回 Ok(WeatherListResponse { list, total }) } // 删除天气数据 pub async fn delete_weather_data( pool: &PgPool, weather_id: i32, user_id: i32, ) -> Result<(), String> { // 先检查数据是否存在且属于当前用户 let query_check = r#" SELECT id FROM weather_data WHERE id = $1 AND user_id = $2 "#; let exists = match sqlx::query_as::<_, (i32,)>(query_check) .bind(weather_id) .bind(user_id) .fetch_optional(pool) .await { Ok(Some(_)) => true, Ok(None) => return Err(format!("未找到ID为 {} 的天气数据或无权限删除", weather_id)), Err(e) => return Err(format!("检查天气数据失败: {}", e)), }; if !exists { return Err(format!("未找到ID为 {} 的天气数据或无权限删除", weather_id)); } // 执行删除操作 let query_delete = r#" DELETE FROM weather_data WHERE id = $1 AND user_id = $2 "#; match sqlx::query(query_delete) .bind(weather_id) .bind(user_id) .execute(pool) .await { Ok(_) => Ok(()), Err(e) => Err(format!("删除天气数据失败: {}", e)), } }