use crate::{Frequency, HourlyLazyFrame, LatLon, Meteostat, MeteostatError, RequiredData};
use bon::bon;
pub struct HourlyClient<'a> {
client: &'a Meteostat,
}
#[bon]
impl<'a> HourlyClient<'a> {
pub(crate) const fn new(client: &'a Meteostat) -> Self {
Self { client }
}
#[builder(start_fn = station)]
#[doc(hidden)]
pub async fn build_station(
&self,
#[builder(start_fn)] station: &str,
required_data: Option<RequiredData>,
) -> Result<HourlyLazyFrame, MeteostatError> {
let frame = self
.client
.data_from_station()
.station(station)
.maybe_required_data(required_data)
.frequency(Frequency::Hourly)
.call()
.await?;
Ok(HourlyLazyFrame::new(frame))
}
#[builder(start_fn = location)]
#[doc(hidden)]
pub async fn build_location(
&self,
#[builder(start_fn)] coordinate: LatLon,
max_distance_km: Option<f64>,
station_limit: Option<usize>,
required_data: Option<RequiredData>,
) -> Result<HourlyLazyFrame, MeteostatError> {
let frame = self
.client
.data_from_location()
.location(coordinate)
.maybe_max_distance_km(max_distance_km)
.maybe_station_limit(station_limit)
.maybe_required_data(required_data)
.frequency(Frequency::Hourly)
.call()
.await?;
Ok(HourlyLazyFrame::new(frame))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Month, RequiredData, Year};
fn berlin_location() -> LatLon {
LatLon(52.520008, 13.404954)
}
#[tokio::test]
async fn test_hourly_from_station_for_period() -> Result<(), MeteostatError> {
let client = Meteostat::new().await?;
let data = client
.hourly()
.station("06240") .call()
.await?
.get_for_period(Year(2023))?
.frame
.collect()?;
assert!(data.height() > 0, "Expected some hourly data for 2023");
Ok(())
}
#[tokio::test]
async fn test_hourly_from_station_with_filter() -> Result<(), MeteostatError> {
let client = Meteostat::new().await?;
let data = client
.hourly()
.station("06240") .required_data(RequiredData::FullYear(2023))
.call()
.await?
.get_for_period(Year(2023))?
.frame
.collect()?;
assert!(
data.height() > 5000,
"Expected >5000 hours of data for 2023 after inventory filter"
);
Ok(())
}
#[tokio::test]
async fn test_hourly_from_station_at_specific_datetime() -> Result<(), MeteostatError> {
let client = Meteostat::new().await?;
let data = client
.hourly()
.station("06240") .call()
.await?
.get_at(chrono::DateTime::parse_from_rfc3339("2023-07-15T12:00:00Z").unwrap())?
.frame
.collect()?;
assert!(data.height() <= 1, "Expected 0 or 1 row for specific hour");
Ok(())
}
#[tokio::test]
async fn test_hourly_from_location_for_period() -> Result<(), MeteostatError> {
let client = Meteostat::new().await?;
let data = client
.hourly()
.location(berlin_location())
.call() .await?
.get_for_period(Month(2023, 7))? .frame
.collect()?;
assert!(
data.height() > 0,
"Expected some hourly data for Berlin area in July 2023"
);
Ok(())
}
}