#![allow(dead_code)]
use serde::{Deserialize, Serialize};
use crate::error::Result;
use crate::models::economic::{EconomicSeries, MacroObservation};
use super::build_client;
use super::models::PaginatedResponseDTO;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct EconomicDataPointDTO {
pub date: Option<String>,
pub value: Option<f64>,
pub period: Option<String>,
}
pub async fn inflation(
params: &[(&str, &str)],
) -> Result<PaginatedResponseDTO<EconomicDataPointDTO>> {
let client = build_client()?;
client.get("/v1/indicators/economy/inflation", params).await
}
pub async fn inflation_expectations(
params: &[(&str, &str)],
) -> Result<PaginatedResponseDTO<EconomicDataPointDTO>> {
let client = build_client()?;
client
.get("/v1/indicators/economy/inflation-expectations", params)
.await
}
pub async fn labor_market(
params: &[(&str, &str)],
) -> Result<PaginatedResponseDTO<EconomicDataPointDTO>> {
let client = build_client()?;
client
.get("/v1/indicators/economy/labor-market", params)
.await
}
pub async fn treasury_yields(
params: &[(&str, &str)],
) -> Result<PaginatedResponseDTO<EconomicDataPointDTO>> {
let client = build_client()?;
client
.get("/v1/indicators/economy/treasury-yields", params)
.await
}
pub async fn fetch_economic_series_response(series_id: &str) -> Result<EconomicSeries> {
use crate::error::FinanceError;
let params: &[(&str, &str)] = &[];
let paginated = match series_id {
"inflation" => inflation(params).await?,
"inflation_expectations" => inflation_expectations(params).await?,
"labor_market" => labor_market(params).await?,
"treasury_yields" => treasury_yields(params).await?,
other => {
return Err(FinanceError::InvalidParameter {
param: "series_id".to_string(),
reason: format!("Unknown economic series: {other}"),
});
}
};
Ok(points_to_series(series_id, paginated.results))
}
fn points_to_series(series_id: &str, results: Option<Vec<EconomicDataPointDTO>>) -> EconomicSeries {
EconomicSeries {
series_id: series_id.to_string(),
title: None,
units: None,
frequency: None,
observations: results
.unwrap_or_default()
.into_iter()
.map(|d| MacroObservation {
date: d.date.unwrap_or_default(),
value: d.value,
})
.collect(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn points_to_series_maps_observations() {
let points: Vec<EconomicDataPointDTO> = serde_json::from_value(serde_json::json!([
{"date": "2024-01-01", "value": 3.4, "period": "monthly"},
{"date": "2024-02-01", "value": 3.2}
]))
.unwrap();
let series = points_to_series("inflation", Some(points));
assert_eq!(series.series_id, "inflation");
assert_eq!(series.observations.len(), 2);
assert_eq!(series.observations[0].date, "2024-01-01");
assert_eq!(series.observations[0].value, Some(3.4));
}
#[test]
fn points_to_series_defaults_missing_date_and_value() {
let points: Vec<EconomicDataPointDTO> =
serde_json::from_value(serde_json::json!([{"period": "monthly"}])).unwrap();
let series = points_to_series("labor_market", Some(points));
assert_eq!(series.observations.len(), 1);
assert_eq!(series.observations[0].date, "");
assert_eq!(series.observations[0].value, None);
}
#[test]
fn points_to_series_none_results_yields_empty() {
let series = points_to_series("treasury_yields", None);
assert!(series.observations.is_empty());
}
#[tokio::test]
async fn fetch_economic_series_rejects_unknown_series_id() {
let err = fetch_economic_series_response("not-a-series")
.await
.unwrap_err();
assert!(matches!(
err,
crate::error::FinanceError::InvalidParameter { .. }
));
}
}