use chrono::{DateTime, FixedOffset, NaiveDate, NaiveTime}; use serde::{Deserialize, Serialize}; use sqlx::SqlitePool; use crate::model::waterlevel::Waterlevel; pub async fn update(db: &SqlitePool) -> Result<(), String> { let mut tx = db.begin().await.unwrap(); // 1. Delete water levels starting from yesterday Waterlevel::delete_all(&mut tx).await; // 2. Fetch let station = fetch()?; for d in station.data { let (Some(max), Some(min), Some(mittel), Some(tumax), Some(tumin), Some(tumittel)) = (d.max, d.min, d.mittel, d.tumax, d.tumin, d.tumittel) else { println!("Ignored invalid values: {d:?}"); continue; }; let Ok(datetime): Result, _> = d.timestamp.parse() else { return Err("Failed to parse datetime from hydro json".into()); }; let date: NaiveDate = datetime.naive_utc().date(); // Extract time component and format as string let time: NaiveTime = datetime.naive_utc().time(); let time_str = time.format("%H:%M").to_string(); Waterlevel::create( &mut tx, date, time_str, max, min, mittel, tumax, tumin, tumittel, ) .await? } // 3. Save in DB tx.commit().await.unwrap(); Ok(()) } #[derive(Serialize, Deserialize, Debug, Clone)] struct Station { station_no: String, station_latitude: String, station_longitude: String, parametertype_name: String, ts_shortname: String, ts_name: String, ts_unitname: String, ts_unitsymbol: String, ts_precision: String, rows: String, columns: String, data: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] struct Data { timestamp: String, max: Option, min: Option, mittel: Option, tumax: Option, tumin: Option, tumittel: Option, } fn fetch() -> Result { let url = "https://hydro.ooe.gv.at/daten/internet/stations/OG/207068/S/forecast.json"; match ureq::get(url).call() { Ok(response) => { let forecast: Result, _> = response.into_json(); if let Ok(data) = forecast { if data.len() == 1 { return Ok(data[0].clone()); } else { return Err(format!( "Expected 1 station (Linz); got {} while fetching from {url}. Maybe the hydro data format changed?", data.len() )); } } else { return Err(format!( "Failed to parse the json received by {url}: {}", forecast.err().unwrap() )); } } Err(_) => { return Err(format!( "Could not fetch {url}, do you have internet? Maybe their server is down?" )); } } } //#[cfg(test)] //mod test { // use crate::testdb; // // use super::*; // #[sqlx::test] // fn test_fetch_succ() { // let pool = testdb!(); // fetch(); // } //}