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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use chrono::NaiveDate;
use serde::{Deserialize, Serialize};
use crate::SeriesGroupId;
/// Metadata for a GeoFRED / Maps series group (the `geofred/series/group`
/// endpoint) — the descriptive header for a group of regional series, and the
/// span of dates it covers.
///
/// `region_type`, `season`, `units`, and `frequency` are kept as `String`: FRED
/// returns them as display/code text here, and this crate mirrors the wire
/// rather than parsing them into enums (ADR-0025).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct SeriesGroup {
/// The group's descriptive title, e.g. `"All Employees: Total Private"`.
pub title: String,
/// The group's identifier (FRED's own `series_group` field), e.g. `1223`.
#[serde(rename = "series_group")]
pub id: SeriesGroupId,
/// The region granularity as a display label, e.g. `"state"`.
pub region_type: String,
/// The seasonality, as FRED reports it here (a short code, e.g. `"NSA"`).
pub season: String,
/// The units as a display label, e.g. `"Thousands of Persons"`.
pub units: String,
/// The frequency as a display label, e.g. `"Monthly"`.
pub frequency: String,
/// The earliest date the group has data for.
pub min_date: NaiveDate,
/// The latest date the group has data for.
pub max_date: NaiveDate,
}
#[cfg(test)]
mod tests {
use super::*;
const SERIES_GROUP: &str = r#"{
"title": "All Employees: Total Private",
"region_type": "state",
"series_group": "1223",
"season": "NSA",
"units": "Thousands of Persons",
"frequency": "Monthly",
"min_date": "1990-01-01",
"max_date": "2026-05-01"
}"#;
#[test]
fn parses_group_metadata() {
let group: SeriesGroup = serde_json::from_str(SERIES_GROUP).expect("series group parses");
assert_eq!(group.id, SeriesGroupId::new("1223"));
assert_eq!(group.title, "All Employees: Total Private");
assert_eq!(group.region_type, "state");
assert_eq!(group.season, "NSA");
assert_eq!(group.min_date, NaiveDate::from_ymd_opt(1990, 1, 1).unwrap());
assert_eq!(group.max_date, NaiveDate::from_ymd_opt(2026, 5, 1).unwrap());
}
}