use chrono::DateTime; use serde::{Deserialize, Serialize}; use sqlx::SqlitePool; use crate::model::weather::Weather; pub async fn update(db: &SqlitePool, api_key: &str) -> Result<(), String> { let mut tx = db.begin().await.unwrap(); // 1. Delete weather data Weather::delete_all(&mut tx).await; // 2. Fetch let data = fetch(api_key)?; for d in data.daily { let Some(date) = DateTime::from_timestamp(d.dt, 0) else { println!("Skipping {} because convertion to datetime failed", d.dt); continue; }; let max_temp = d.temp.max; let wind_gust = d.wind_gust; let Some(rain_mm) = d.rain else { println!( "Skipping weather import of {} as there's no rain prognosed", date ); continue; }; Weather::create( &mut tx, date.naive_utc().into(), max_temp, wind_gust, rain_mm, ) .await? } // 3. Save in DB tx.commit().await.unwrap(); Ok(()) } #[derive(Serialize, Deserialize, Debug, Clone)] struct Data { lat: f64, lon: f64, timezone: String, timezone_offset: i64, daily: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] struct Daily { dt: i64, sunrise: i64, sunset: i64, moonrise: i64, moonset: i64, moon_phase: f64, summary: String, temp: Temp, feels_like: FeelsLike, pressure: i64, humidity: i64, dew_point: f64, wind_speed: f64, wind_deg: i64, wind_gust: f64, weather: Vec, clouds: i64, pop: f64, rain: Option, uvi: f64, } #[derive(Serialize, Deserialize, Debug, Clone)] struct Temp { day: f64, min: f64, max: f64, night: f64, eve: f64, morn: f64, } #[derive(Serialize, Deserialize, Debug, Clone)] struct FeelsLike { day: f64, night: f64, eve: f64, morn: f64, } #[derive(Serialize, Deserialize, Debug, Clone)] struct DailyWeather { id: i64, main: String, description: String, icon: String, } fn fetch(api_key: &str) -> Result { let url = format!("https://api.openweathermap.org/data/3.0/onecall?lat=48.31970&lon=14.29451&units=metric&exclude=current,minutely,hourly,alert&appid={api_key}"); match ureq::get(&url).call() { Ok(response) => { let data: Result = response.into_json(); if let Ok(data) = data { return Ok(data); } else { return Err(format!( "Failed to parse the json received by {url}: {}", data.err().unwrap() )); } } Err(_) => { return Err(format!( "Could not fetch {url}, do you have internet? Maybe their server is down?" )); } } }