use sqlx::{PgPool, postgres::PgPoolOptions}; use std::env; use std::error::Error; // 从 models 模块引入 WeatherData 结构体 use crate::models::WeatherData; // 这个函数封装了所有与数据库交互的逻辑 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) }