Completed loading ts_data from specification.

[?]
Jul 13, 2021, 4:26 AM
SPSFTMLRZE2R4EBAAQKWBUZDRYZ36S2VFTBIJRE6XS7JMKELV4AQC

Dependencies

  • [2] UKQAGL5F Checked ts_json toolchain.
  • [3] JTX5OHWH Added USA CPI.
  • [4] IKPVWWLK Filter unemployment rate series.
  • [5] 5POF332L Working on fn cpi_included().
  • [6] 4QOTH75I Fixed UI specification code.
  • [7] A6ZAYJNB Debugging DataSelector
  • [8] UUD3CJZL Making error handling more comprehensive.
  • [9] XI5ALEH6 Take advantage of keytree FromStr functionality.
  • [10] SAHJYVNB Removed checking functionality.
  • [11] GQVS55HI Finished generate_ts_spec() function.
  • [12] U4VCAFXQ Added data_type to TSSpec key.
  • [13] 2SABVMY3 Finished into_json() functionality.
  • [14] UCSU3QE4 Created keytree generator for u and cpi.
  • [15] CUADTSHQ Save csv data as multiple files.
  • [16] AT753JPO Selected US unemployment series.
  • [17] 77SIQZ3E Separating out spec generation.
  • [18] GUXZCEWW Added Country enum.
  • [19] TTR5IFSG Working on building generic TSSpec.
  • [*] 4MG5JFXT First record.

Change contents

  • edit in src/ui.rs at line 2
    [3.104]
    [3.104]
    #![allow(dead_code)]
  • edit in src/ui.rs at line 20
    [3.378]
    [3.0]
    data_from_file,
  • replacement in src/ui.rs at line 269
    [3.4128][3.4128:4171]()
    _ => Err(parse_transform1(s)),
    [3.4128]
    [3.4171]
    _ => Err(parse_transform1(file!(), line!(), s)),
  • replacement in src/ui.rs at line 286
    [3.4457][3.4457:4500]()
    _ => Err(parse_transform2(s)),
    [3.4457]
    [3.4843]
    _ => {
    Err(parse_transform2(file!(), line!(), s))
    },
  • replacement in src/ui.rs at line 311
    [3.4747][3.4747:4836]()
    Err(data_type_mismatch(&self.data_type.to_string(), &data_type.to_string()))
    [3.4747]
    [3.4836]
    Err(
    data_type_mismatch(
    file!(),
    line!(),
    &self.data_type.to_string(),
    &data_type.to_string()
    )
    )
  • replacement in src/ui.rs at line 327
    [3.5014][3.150:268]()
    let series_spec = data_spec.get_series_spec(&self.series_id);
    series_spec.time_series_data(root_path)
    [3.5014]
    [3.5113]
    let series_spec = match data_spec.get_series_spec(&self.series_id) {
    Some(series_spec) => series_spec,
    None => {
    return Err(
    series_id_not_in_dataspec(
    file!(),
    line!(),
    &self.series_id.to_string()
    )
    )
    },
    };
    data_from_file(
    series_spec.country,
    series_spec.data_type,
    series_spec.series_id,
    root_path
    )
  • edit in src/ts.rs at line 1
    [3.7119]
    [3.7581]
    #![allow(dead_code)]
  • replacement in src/ts.rs at line 12
    [3.7725][3.7725:7761]()
    use keytree::{KeyTree, KeyTreeRef};
    [3.7725]
    [3.7781]
    use keytree::{
    KeyTree,
    KeyTreeRef,
    };
  • edit in src/ts.rs at line 27
    [3.5280]
    [3.5280]
    data_from_file,
  • edit in src/ts.rs at line 30
    [3.312]
    [3.5294]
    meta_from_file,
  • replacement in src/ts.rs at line 32
    [3.5297][3.47:78](),[3.7929][3.47:78](),[3.7995][3.7995:7998]()
    use crate::error::{
    Error,
    };
    [3.5297]
    [3.7998]
    use crate::error::*;
    // --- Client-facing data-structures --------------------------------------------------------------
    /// `(DataType, Country)` key to lookup data or spec.
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub struct PageKey {
    ///
    pub country: Country,
    ///
    pub data_type: DataType,
    ///
    pub index: usize,
    }
    impl PageKey {
    /// Return a new `PageKey`.
    pub fn new(country: Country, data_type: DataType, index: usize) -> Self {
    PageKey { country, data_type, index }
    }
    }
    impl<'a> TryInto<PageKey> for KeyTreeRef<'a> {
    type Error = keytree::Error;
  • replacement in src/ts.rs at line 59
    [3.7999][3.7999:8099]()
    // -- "ts_spec.keytree" ---------------------------------------------------------------------------
    [3.7999]
    [3.8099]
    fn try_into(self) -> Result<PageKey, Self::Error> {
    Ok(PageKey {
    index: self.value("key::index")?,
    data_type: self.value("key::data_type")?,
    country: self.value("key::country")?,
    })
    }
    }
  • replacement in src/ts.rs at line 68
    [3.8100][3.111:217](),[3.217][3.327:626](),[3.327][3.327:626]()
    /// Top-level time-series specification data-structure.
    ///
    /// It can be serialized into something like,
    /// ```text
    /// ts_spec:
    /// page:
    /// data_type: u
    /// country: Australia
    /// graphic:
    /// series:
    /// id: AUSURANAA
    /// id: AUSURAQS
    /// id: AUSURHARMADSMEI
    /// id: AUSURHARMMDSMEI
    /// ```
    [3.8100]
    [2.0]
    /// Represents a series of graphics to be plotted on one page. A `PageKey` is a combination of
    /// `Country` and `DataType`. It is served to the client as one chunk of JSON.
    // GraphicJson. Json holds the JSON serialization as a String. PageJson is the largest component
    // that is serializable into JSON.
  • replacement in src/ts.rs at line 73
    [2.17][3.626:666](),[3.626][3.626:666]()
    pub struct TSSpec(pub Vec<TSPageSpec>);
    [2.17]
    [3.8147]
    pub struct TSData(pub HashMap<PageKey, String>);
  • replacement in src/ts.rs at line 75
    [3.8148][3.667:681]()
    impl TSSpec {
    [3.8148]
    [3.8166]
    impl TSData {
  • replacement in src/ts.rs at line 77
    [3.8167][3.218:255](),[3.255][3.711:738](),[3.711][3.711:738]()
    pub (crate) fn new() -> TSSpec {
    TSSpec(Vec::new())
    [3.8167]
    [3.8231]
    /// Build time-series data from a time-series specification.
    pub fn from_spec(spec: &Spec, root_path: &str) -> Result<Self, Error> {
    spec
    .into_data(root_path)
  • replacement in src/ts.rs at line 83
    [3.8238][3.256:311](),[3.786][3.8288:8314](),[3.311][3.8288:8314](),[3.8288][3.8288:8314]()
    pub (crate) fn push(&mut self, item: TSPageSpec) {
    self.0.push(item)
    [3.8238]
    [3.8314]
    pub (crate) fn new() -> TSData {
    TSData(HashMap::new())
  • replacement in src/ts.rs at line 87
    [3.788][3.5298:5365](),[3.363][3.831:980](),[3.5365][3.831:980](),[3.831][3.831:980]()
    /// Read from file.
    pub fn from_file(path: &str) -> Self {
    let ts_spec = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&ts_spec).unwrap();
    kt.to_ref().try_into().unwrap()
    [3.788]
    [3.364]
    pub (crate) fn insert(&mut self, key: &PageKey, value: String) {
    match self.0.get_mut(key) {
    Some(_) => {
    println!("Tried to insert page_key: {:?} twice.", key);
    panic!();
    },
    None => {
    self.0.insert(*key, value);
    },
    }
  • edit in src/ts.rs at line 98
    [3.370]
    [3.370]
    }
  • replacement in src/ts.rs at line 100
    [3.371][3.371:727](),[3.727][3.313:343](),[3.343][3.771:868](),[3.771][3.771:868]()
    /// ts_spec:
    /// page:
    /// data_type: u
    /// country: Australia
    /// graphic:
    /// series:
    /// id: AUSURANAA
    /// id: AUSURAQS
    /// id: AUSURHARMADSMEI
    /// id: AUSURHARMMDSMEI
    pub fn into_json(
    &self,
    data_spec: &DataSpec,
    root_path: &str) -> Result<TSJson, Error>
    {
    let mut ts_json = TSJson::new();
    [3.371]
    [3.868]
    /// Converts specification data into `TSData`.
    pub struct Json(Vec<PageJson>);
  • edit in src/ts.rs at line 103
    [3.869]
    [3.344]
    impl Json {
  • replacement in src/ts.rs at line 105
    [3.345][3.869:943](),[3.869][3.869:943]()
    for page_spec in &self.0 {
    let key = page_spec.key();
    [3.345]
    [3.943]
    pub (crate) fn into_data(&self) -> Result<TSData, Error> {
  • replacement in src/ts.rs at line 107
    [3.944][3.944:1002]()
    let mut value: Vec<GraphicJson> = Vec::new();
    [3.944]
    [3.5366]
    let mut ts_data = TSData::new();
  • edit in src/ts.rs at line 109
    [3.5367]
    [3.346]
    for page_json in &self.0 {
  • replacement in src/ts.rs at line 111
    [3.347][3.1002:1154](),[3.5367][3.1002:1154](),[3.1002][3.1002:1154]()
    for graphic in &page_spec.graphics {
    let json = graphic.into_json(data_spec, root_path)?;
    value.push(json);
    [3.347]
    [3.1154]
    let key = PageKey::new(
    page_json.country,
    page_json.data_type,
    page_json.index
    );
    let value = match serde_json::to_string(&page_json) {
    Ok(s) => s,
    Err(err) => {
    eprintln!("{}", err.to_string());
    panic!();
    },
  • replacement in src/ts.rs at line 125
    [3.1170][3.1170:1211]()
    ts_json.insert(&key, value);
    [3.1170]
    [3.1211]
    ts_data.insert(&key, value);
  • replacement in src/ts.rs at line 128
    [3.1221][3.1221:1241]()
    Ok(ts_json)
    [3.1221]
    [3.980]
    Ok(ts_data)
    }
    pub (crate) fn new() -> Self {
    Json(Vec::new())
    }
    pub (crate) fn push(&mut self, page_json: PageJson) {
    self.0.push(page_json);
  • replacement in src/ts.rs at line 141
    [3.8323][3.987:1017](),[3.1017][3.8357:8441](),[3.8357][3.8357:8441](),[3.8441][3.1018:1131]()
    impl IntoKeyTree for TSSpec {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "ts_spec");
    for page in &self.0 {
    kt.push_keytree(1, page.keytree());
    [3.8323]
    [3.8557]
    #[derive(Debug, Serialize)]
    /// Serializable into JSON data for a time-series HTML page.
    pub struct PageJson {
    country: Country,
    data_type: DataType,
    index: usize,
    graphics: Vec<GraphicJson>,
    }
    impl PageJson {
    pub (crate) fn new(country: Country, data_type: DataType, index: usize) -> Self {
    PageJson {
    country, data_type, index, graphics: Vec::new()
  • edit in src/ts.rs at line 155
    [3.8567][3.8567:8578]()
    kt
  • edit in src/ts.rs at line 156
    [3.8584][3.8584:8586]()
    }
  • replacement in src/ts.rs at line 157
    [3.8587][3.1132:1178](),[3.1178][3.2152:2185](),[3.2185][3.8661:8662](),[3.8661][3.8661:8662](),[3.8662][3.2186:2241](),[3.2241][3.1874:1945](),[3.1945][3.1296:1325](),[3.1296][3.1296:1325]()
    impl<'a> TryInto<TSSpec> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<TSSpec, Self::Error> {
    let page_vec: Vec<TSPageSpec> = self.vec_at("ts_spec::page")?;
    Ok(TSSpec(page_vec))
    [3.8587]
    [3.8825]
    pub (crate) fn push(&mut self, graphic_json: GraphicJson) {
    self.graphics.push(graphic_json);
  • replacement in src/ts.rs at line 162
    [3.8834][3.1326:1353](),[3.1353][3.2242:2246](),[3.2246][3.1353:1426](),[3.1353][3.1353:1426](),[3.1426][3.5368:5376](),[3.5376][3.1438:1448](),[3.1438][3.1438:1448](),[3.1448][3.5377:5407](),[3.5407][3.348:370](),[3.370][3.5407:5802](),[3.5407][3.5407:5802](),[3.5802][3.1691:1699](),[3.1691][3.1691:1699](),[3.1699][3.371:388](),[3.388][3.1699:1723](),[3.1699][3.1699:1723]()
    /// Component of `TSSpec`.
    ///
    /// Mirrored with a keytree specification which is the `country:` key in
    /// ```
    /// page:
    /// country: Australia
    /// data_type: u
    /// index: 0
    /// graphic:
    /// series:
    /// series_id: AUSURANAA
    /// data_type: u
    /// series:
    /// data_type: u
    /// series_id: AUSURAQS
    /// series:
    /// data_type: u
    /// series_id: AUSURHARMADSMEI
    /// series:
    /// data_type: u
    /// series_id: AUSURHARMMDSMEI
    /// ```
    #[derive(Debug)]
    pub struct TSPageSpec {
    [3.8834]
    [3.2247]
    /// GraphicJson is the largest component that is serializable into JSON.
    #[derive(Debug, Serialize)]
    pub struct GraphicJson {
  • replacement in src/ts.rs at line 166
    [3.2255][3.1723:1752](),[3.1723][3.1723:1752](),[3.1752][3.389:427](),[3.427][3.2256:2264](),[3.1752][3.2256:2264](),[3.2264][3.5803:5830]()
    pub country: Country,
    ///
    pub data_type: DataType,
    ///
    pub index: usize,
    [3.2255]
    [3.2265]
    pub height: Option<f32>,
  • replacement in src/ts.rs at line 168
    [3.1782][3.8890:8930](),[3.2273][3.8890:8930](),[3.8890][3.8890:8930]()
    pub graphics: Vec<TSGraphicSpec>,
    [3.2273]
    [3.8930]
    pub series: Vec<(RegularTimeSeries<1>, SeriesMetaData)>,
  • replacement in src/ts.rs at line 171
    [3.8933][3.1783:1801](),[3.1801][3.2274:2352](),[3.2352][3.1870:1891](),[3.1870][3.1870:1891](),[3.1891][3.2353:2390](),[3.2390][3.428:467](),[3.467][3.5831:5867](),[3.2390][3.5831:5867](),[3.5867][3.2429:2463](),[3.2429][3.2429:2463]()
    impl TSPageSpec {
    pub (crate) fn new(key: PageKey, graphics: Vec<TSGraphicSpec>) -> Self {
    TSPageSpec {
    country: key.country,
    data_type: key.data_type,
    index: key.index,
    graphics: graphics,
    [3.8933]
    [3.9110]
    impl GraphicJson {
    pub (crate) fn new() -> Self {
    GraphicJson {
    height: None,
    series: Vec::new(),
  • replacement in src/ts.rs at line 179
    [3.1965][3.5868:5981]()
    pub (crate) fn push(&mut self, ts_graphic_spec: TSGraphicSpec) {
    self.graphics.push(ts_graphic_spec)
    [3.1965]
    [3.5981]
    pub (crate) fn push(&mut self, time_series: RegularTimeSeries<1>, meta: SeriesMetaData) {
    self.series.push((time_series, meta))
  • edit in src/ts.rs at line 182
    [3.5987]
    [3.5987]
    }
  • replacement in src/ts.rs at line 184
    [3.5988][3.2464:2507](),[3.1965][3.2464:2507](),[3.2507][3.2000:2018](),[3.2000][3.2000:2018](),[3.2018][3.2508:2546](),[3.2546][3.468:508](),[3.508][3.5989:6025](),[3.2546][3.5989:6025]()
    pub (crate) fn key(&self) -> PageKey {
    PageKey {
    country: self.country,
    data_type: self.data_type,
    index: self.index,
    [3.5988]
    [3.2092]
    // === Time-series Specification ==================================================================
    /// Time-series specification.
    /// ```
    /// ts_spec:
    /// page:
    /// country: Australia
    /// data_type: u
    /// index: 0
    /// graphic:
    /// series:
    /// data_type: u
    /// series_id: AUSURAMS
    /// series:
    /// data_type: u
    /// series_id: AUSURANAA
    /// ```
    pub struct Spec(Vec<PageSpec>);
    impl Spec {
    // The Spec components do not map well to Json components.
    // 1. Json is not serializable - it is a HashMap which maps PageKeys to Strings to serve.
    // 2. PageJson does not exists. PageSpec.into_json creates a Vec<GraphicJson>.
    pub (crate) fn into_data(&self, root_path: &str) -> Result<TSData, Error> {
    let mut json = Json::new();
    for page_spec in &self.0 {
    let mut page_json = PageJson::new(
    page_spec.country,
    page_spec.data_type,
    page_spec.index,
    );
    for graphic_spec in &page_spec.graphics {
    let mut graphic_json = GraphicJson::new();
    for series_spec in &graphic_spec.seriess {
    let rts = data_from_file(
    page_spec.country,
    series_spec.data_type,
    series_spec.series_id.clone(),
    root_path,
    )?;
    let meta = meta_from_file(
    page_spec.country,
    series_spec.data_type,
    series_spec.series_id.clone(),
    root_path,
    );
    graphic_json.push(rts, meta);
    }
    page_json.push(graphic_json);
    }
    json.push(page_json);
  • edit in src/ts.rs at line 251
    [3.2102]
    [3.2102]
    // Now we have a Json datastructure which we can iterate over the pages, serialize, generate
    // keys, and build a TSData Hashmap.
    json.into_data()
  • edit in src/ts.rs at line 258
    [3.2108][3.9126:9128](),[3.9126][3.9126:9128]()
    }
  • replacement in src/ts.rs at line 259
    [3.9129][3.2109:2143](),[3.2143][3.9166:9207](),[3.9166][3.9166:9207]()
    impl IntoKeyTree for TSPageSpec {
    fn keytree(&self) -> KeyTreeString {
    [3.9129]
    [3.9207]
    /// Read in ts specification from file.
    /// ```
    /// let ts_spec = ts::Spec::from_file("ts_spec.keytree");
    /// ```
    pub fn from_file(path: &str) -> Result<Self, Error> {
    let source_spec = match fs::read_to_string(path) {
    Ok(ss) => ss,
    Err(err) => { return Err(
    failed_to_read_file(
    file!(),
    line!(),
    &err.to_string()
    ))
    },
    };
    let kt = KeyTree::parse(&source_spec).unwrap();
    kt.to_ref().try_into().map_err(|err: keytree::error::Error| {
    keytree_error(file!(), line!(), &err.to_string())
    })
    }
  • replacement in src/ts.rs at line 280
    [3.9208][3.9208:9251]()
    let mut kt = KeyTreeString::new();
    [3.9208]
    [3.9251]
    pub (crate) fn new() -> Self {
    Spec(Vec::new())
    }
  • replacement in src/ts.rs at line 284
    [3.9252][3.2144:2176](),[3.2176][3.509:701](),[3.2314][3.9348:9460](),[3.701][3.9348:9460](),[3.9348][3.9348:9460]()
    kt.push_key(0, "page");
    kt.push_value(1, "country", &self.country.to_string());
    kt.push_value(1, "data_type", &self.data_type.to_string());
    kt.push_value(1, "index", &self.index.to_string());
    for graphic in &self.graphics {
    kt.push_keytree(1, graphic.keytree());
    }
    kt
    [3.9252]
    [3.9460]
    pub (crate) fn push(&mut self, page_spec: PageSpec) {
    self.0.push(page_spec)
  • replacement in src/ts.rs at line 289
    [3.9469][3.2315:2365]()
    impl<'a> TryInto<TSPageSpec> for KeyTreeRef<'a> {
    [3.9469]
    [3.2587]
    impl<'a> TryInto<Spec> for KeyTreeRef<'a> {
  • replacement in src/ts.rs at line 292
    [3.9547][3.2621:2680](),[3.9734][3.2624:2648](),[3.2648][3.6026:6080](),[3.6080][3.702:758](),[3.758][3.6080:6187](),[3.6080][3.6080:6187](),[3.2120][3.9841:9852](),[3.6187][3.9841:9852](),[3.9841][3.9841:9852]()
    fn try_into(self) -> Result<TSPageSpec, Self::Error> {
    Ok(TSPageSpec {
    country: self.value("page::country")?,
    data_type: self.value("page::data_type")?,
    index: self.value("page::index")?,
    graphics: self.vec_at("page::graphic")?,
    })
    [3.9547]
    [3.9852]
    fn try_into(self) -> Result<Spec, keytree::Error> {
    Ok(Spec(self.vec_at("ts_spec::page")?))
  • replacement in src/ts.rs at line 297
    [3.9861][3.2681:2708]()
    /// Component of `TSSpec`.
    [3.9861]
    [3.6188]
    // There are two important functions that need to be built.
    // 1. SeriesSpec.into_json(). This is done in lib.rs.
    // 2. PageJason.into_data()
    /// Component of time-series specification.
  • replacement in src/ts.rs at line 303
    [3.6196][3.6196:6517]()
    /// graphic:
    /// series:
    /// series_id: AUSURANAA
    /// data_type: u
    /// series:
    /// data_type: u
    /// series_id: AUSURAQS
    /// series:
    /// data_type: u
    /// series_id: AUSURHARMADSMEI
    /// series:
    /// data_type: u
    /// series_id: AUSURHARMMDSMEI
    [3.6196]
    [3.6517]
    /// page:
    /// country: Australia
    /// data_type: u
    /// index: 0
    /// graphic:
    /// series:
    /// data_type: u
    /// series_id: AUSURAMS
    /// series:
    /// data_type: u
    /// series_id: AUSURANAA
  • replacement in src/ts.rs at line 315
    [3.6525][3.759:776](),[3.776][3.9937:9964](),[3.2712][3.9937:9964](),[3.6525][3.9937:9964](),[3.9937][3.9937:9964](),[3.9964][3.2713:2714](),[3.2714][3.777:818](),[3.818][3.9964:9993](),[3.2754][3.9964:9993](),[3.9964][3.9964:9993](),[3.9993][3.2755:2794](),[3.2794][3.6526:6562]()
    #[derive(Debug)]
    pub struct TSGraphicSpec {
    /// Height in pixels of the graphic.
    pub height: Option<f32>,
    /// e.g. [ AUSURHARMADSMEI, ... ]
    pub series: Vec<TSSeriesSpec>,
    [3.6525]
    [3.10060]
    pub struct PageSpec {
    country: Country,
    data_type: DataType,
    index: usize,
    graphics: Vec<GraphicSpec>,
  • edit in src/ts.rs at line 321
    [3.10062][3.10062:10084]()
    impl TSGraphicSpec {
  • replacement in src/ts.rs at line 322
    [3.2796][3.2796:2831](),[3.2831][3.10111:10161](),[3.10111][3.10111:10161](),[3.10161][3.6563:6595](),[3.6595][3.10197:10213](),[3.10197][3.10197:10213]()
    pub (crate) fn new() -> Self {
    TSGraphicSpec {
    height: None,
    series: Vec::new(),
    }
    }
    [3.2796]
    [3.10213]
    impl PageSpec {
  • replacement in src/ts.rs at line 324
    [3.10214][3.6596:6688]()
    pub (crate) fn push(&mut self, series: TSSeriesSpec) {
    self.series.push(series)
    [3.10214]
    [3.2880]
    ///
    pub fn new(
    country: Country,
    data_type: DataType,
    index: usize,
    graphics: Vec<GraphicSpec>) -> Self
    {
    PageSpec { country, data_type, index, graphics }
  • replacement in src/ts.rs at line 333
    [3.2886][3.2886:2932](),[3.2932][3.819:849](),[3.849][3.2976:3038](),[3.2976][3.2976:3038]()
    pub (crate) fn into_json(
    &self,
    data_spec: &DataSpec,
    root_path: &str) -> Result<GraphicJson, Error>
    {
    [3.2886]
    [3.3038]
    }
  • replacement in src/ts.rs at line 335
    [3.3039][3.3039:3095](),[3.3095][3.850:901]()
    let mut series_json = SeriesJson::new();
    for (series_id, _) in &data_spec.reverse {
    [3.3039]
    [3.3139]
    impl<'a> TryInto<PageSpec> for KeyTreeRef<'a> {
    type Error = keytree::Error;
  • replacement in src/ts.rs at line 338
    [3.3140][3.902:1098](),[3.1098][3.3294:3347](),[3.6884][3.3294:3347](),[3.3294][3.3294:3347]()
    let series_spec = data_spec.get_series_spec(series_id);
    let ts = series_spec.time_series_data(root_path)?;
    let meta = series_spec.meta(root_path);
    series_json.push(ts, meta);
    }
    [3.3140]
    [3.3347]
    fn try_into(self) -> Result<PageSpec, keytree::Error> {
  • replacement in src/ts.rs at line 340
    [3.3359][3.3359:3459]()
    GraphicJson {
    height: self.height,
    series: series_json,
    [3.3359]
    [3.3459]
    PageSpec {
    country: self.value("page::country")?,
    data_type: self.value("page::data_type")?,
    index: self.value("page::index")?,
    graphics: self.vec_at("page::graphic")?,
  • replacement in src/ts.rs at line 350
    [3.10307][3.10307:10428]()
    impl IntoKeyTree for TSGraphicSpec {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    [3.10307]
    [3.10428]
    /// Component of time-series specification.
    /// ```
    /// graphic:
    /// series:
    /// data_type: u
    /// series_id: AUSURAMS
    /// series:
    /// data_type: u
    /// series_id: AUSURANAA
    /// ```
    pub struct GraphicSpec {
    height: Option<f32>,
    seriess: Vec<self::SeriesSpec>,
    }
  • replacement in src/ts.rs at line 365
    [3.10429][3.10429:10508](),[3.10508][3.1099:1160](),[3.1160][3.10572:10583](),[3.10572][3.10572:10583](),[3.10617][3.6885:6922](),[3.6922][3.1161:1211]()
    kt.push_key(0, "graphic");
    if let Some(height) = self.height {
    kt.push_value(1, "height", &height.to_string());
    };
    for series in &self.series {
    kt.push_keytree(1, series.keytree());
    [3.10429]
    [3.10698]
    impl GraphicSpec {
    pub (crate) fn new() -> Self {
    GraphicSpec {
    height: None,
    seriess: Vec::new(),
  • replacement in src/ts.rs at line 371
    [3.10708][3.10708:10719]()
    kt
    [3.10708]
    [3.10719]
    }
    pub (crate) fn push(&mut self, series_spec: self::SeriesSpec) {
    self.seriess.push(series_spec)
  • replacement in src/ts.rs at line 378
    [3.10728][3.10728:10781]()
    impl<'a> TryInto<TSGraphicSpec> for KeyTreeRef<'a> {
    [3.10728]
    [3.3484]
    impl<'a> TryInto<GraphicSpec> for KeyTreeRef<'a> {
  • replacement in src/ts.rs at line 381
    [3.10806][3.3518:3580]()
    fn try_into(self) -> Result<TSGraphicSpec, Self::Error> {
    [3.10806]
    [3.10862]
    fn try_into(self) -> Result<GraphicSpec, keytree::Error> {
  • replacement in src/ts.rs at line 383
    [3.10874][3.10874:10902](),[3.10902][3.2121:2181](),[3.2181][3.6973:7030]()
    TSGraphicSpec {
    height: self.opt_value("graphic::height")?,
    series: self.vec_at("graphic::series")?,
    [3.10874]
    [3.7030]
    GraphicSpec{
    height: self.opt_value("graphic::height")?,
    seriess: self.vec_at("graphic::series")?,
  • replacement in src/ts.rs at line 391
    [3.7063][3.7063:7109]()
    /// Component of `TSGraphicSpec`.
    /// ```text
    [3.7063]
    [3.7109]
    // This is differentiated from lib::SeriesSpec in that is is just for interacting with
    //
    /// Component of time-series specification.
    /// ```
  • replacement in src/ts.rs at line 396
    [3.7121][3.7121:7177]()
    /// data_type: u
    /// series_id: AUSURHARMADSMEI
    [3.7121]
    [3.7177]
    /// data_type: u
    /// series_id: AUSURAMS
  • replacement in src/ts.rs at line 399
    [3.7185][3.1212:1229](),[3.1229][3.7185:7219](),[3.7185][3.7185:7219]()
    #[derive(Debug)]
    pub struct TSSeriesSpec {
    ///
    [3.7185]
    [3.7219]
    pub struct SeriesSpec {
  • replacement in src/ts.rs at line 404
    [3.7274][3.7274:7327]()
    impl TSSeriesSpec {
    /// Return a new `TSSeries`.
    [3.7274]
    [3.7327]
    impl SeriesSpec {
    ///
  • replacement in src/ts.rs at line 407
    [3.7394][3.7394:7417]()
    TSSeriesSpec {
    [3.7394]
    [3.7417]
    SeriesSpec {
  • replacement in src/ts.rs at line 414
    [3.7482][3.7482:7534]()
    impl<'a> TryInto<TSSeriesSpec> for KeyTreeRef<'a> {
    [3.7482]
    [3.7534]
    impl<'a> TryInto<SeriesSpec> for KeyTreeRef<'a> {
  • replacement in src/ts.rs at line 417
    [3.7568][3.7568:7629]()
    fn try_into(self) -> Result<TSSeriesSpec, Self::Error> {
    [3.7568]
    [3.7629]
    fn try_into(self) -> Result<SeriesSpec, keytree::Error> {
  • replacement in src/ts.rs at line 419
    [3.7641][3.7641:7668]()
    TSSeriesSpec {
    [3.7641]
    [3.7668]
    SeriesSpec{
  • edit in src/ts.rs at line 424
    [3.11035][3.11035:11044](),[3.11044][3.7791:7946](),[3.7946][3.1230:1366](),[3.1366][3.8088:8099](),[3.8088][3.8088:8099]()
    }
    }
    impl IntoKeyTree for TSSeriesSpec {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "series");
    kt.push_value(1, "data_type", &self.data_type.to_string());
    kt.push_value(1, "series_id", &self.series_id.to_string());
    kt
  • edit in src/ts.rs at line 429
    [3.8110][3.11044:11144](),[3.11044][3.11044:11144]()
    // --- Client-facing data-structures --------------------------------------------------------------
  • replacement in src/ts.rs at line 430
    [3.11145][3.11145:11319](),[3.11319][3.8111:8177](),[3.3636][3.2822:2823](),[3.8177][3.2822:2823](),[3.2822][3.2822:2823](),[3.2823][3.3637:3651](),[3.3651][3.2902:2903](),[3.2902][3.2902:2903](),[3.2903][3.3652:3726](),[3.3726][3.2903:2904](),[3.2903][3.2903:2904](),[3.2904][3.3727:3980](),[3.3980][3.8178:8351](),[3.8351][3.4033:4043](),[3.4033][3.4033:4043](),[3.4043][3.2937:2946](),[3.2937][3.2937:2946](),[3.2946][3.11377:11439](),[3.11377][3.11377:11439](),[3.11439][3.8352:8380](),[3.8380][3.11460:11485](),[3.11460][3.11460:11485](),[3.11485][3.4044:4052](),[3.4052][3.11485:11514](),[3.11485][3.11485:11514](),[3.11514][3.4053:4061](),[3.4061][3.11514:11615](),[3.11514][3.11514:11615](),[3.11615][3.8381:8409](),[3.8409][3.4062:4446](),[3.11636][3.4062:4446](),[3.4446][3.11715:11772](),[3.11715][3.11715:11772](),[3.11772][3.4447:4498](),[3.4498][3.11816:11837](),[3.11816][3.11816:11837](),[3.11837][3.4499:4507](),[3.4507][3.1367:1396](),[3.1396][3.4508:4516](),[3.8436][3.4508:4516](),[3.11866][3.4508:4516](),[3.4516][3.1397:1435](),[3.1435][3.8437:8509](),[3.4516][3.8437:8509](),[3.8509][3.1436:1560](),[3.1560][3.8601:8607](),[3.8601][3.8601:8607](),[3.8607][3.11892:11942](),[3.11892][3.11892:11942](),[3.11942][3.4517:4550](),[3.4550][3.11966:11967](),[3.11966][3.11966:11967](),[3.11967][3.4551:4607](),[3.12353][3.12353:12374](),[3.12374][3.8608:8659](),[3.8659][3.1561:1616](),[3.1616][3.2299:2352](),[3.8659][3.2299:2352](),[3.2299][3.2299:2352](),[3.2352][3.12438:12459](),[3.12438][3.12438:12459]()
    /// Represents a series of graphics to be plotted on one page. A `PageKey` is a combination of
    /// `Country` and `DataType`. It is served to the client as one chunk of JSON.
    #[derive(Debug)]
    pub struct TSJson(pub HashMap<PageKey, String>);
    impl TSJson {
    pub (crate) fn new() -> TSJson {
    TSJson(HashMap::new())
    }
    pub (crate) fn insert(&mut self, key: &PageKey, value: Vec<GraphicJson>) {
    match self.0.get_mut(key) {
    Some(_) => {
    println!("Tried to insert page_key: {:?} twice.", key);
    panic!();
    },
    None => {
    self.0.insert(
    *key,
    serde_json::to_string(&value).unwrap(),
    );
    },
    }
    }
    }
    /// Respresents a graphic to be served to the client as JSON.
    #[derive(Debug, Serialize)]
    pub struct GraphicJson {
    ///
    pub height: Option<f32>,
    ///
    pub series: SeriesJson,
    }
    /// `SeriesJson` is a time-series to be served to the client as JSON.
    #[derive(Debug, Serialize)]
    pub struct SeriesJson(Vec<(RegularTimeSeries<1>, SeriesMetaData)>);
    impl SeriesJson {
    /// Create a new, empty `SeriesJson`.
    pub fn new() -> Self {
    SeriesJson(Vec::new())
    }
    /// Push time-series data and associated meta-data onto `SeriesJson`.
    pub fn push(&mut self, ts: RegularTimeSeries<1>, meta: SeriesMetaData) {
    self.0.push((ts, meta));
    }
    }
    /// `(DataType, Country)` key to lookup data or spec.
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub struct PageKey {
    ///
    pub country: Country,
    ///
    pub data_type: DataType,
    ///
    pub index: usize,
    }
    impl PageKey {
    /// Return a new `PageKey`.
    pub fn new(country: Country, data_type: DataType, index: usize) -> Self {
    PageKey { country, data_type, index }
    }
    }
    impl<'a> TryInto<PageKey> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<PageKey, Self::Error> {
    Ok(PageKey {
    index: self.value("key::index")?,
    data_type: self.value("key::data_type")?,
    country: self.value("key::country")?,
    })
    }
    }
    [3.11145]
  • edit in src/main.rs at line 1
    [3.10]
    [3.0]
    #![allow(unused_imports)]
    use std::time::SystemTime;
    use time::{
    Duration,
    OffsetDateTime,
    };
  • replacement in src/main.rs at line 23
    [3.8935][3.9632:9637](),[3.9632][3.9632:9637](),[3.9637][2.18:147]()
    let data_spec = DataSpec::from_file("source_data.keytree").unwrap();
    let ts_spec = TSSpec::from_file("ts_spec.keytree");
    [3.8935]
    [3.220]
    // Step 1
    // println!("{}", DataSelector::from_file("series_selector.keytree")
    // .into_data_spec()
    // .unwrap()
    // .keytree());
  • replacement in src/main.rs at line 31
    [3.221][2.148:208](),[3.324][3.1753:1755](),[2.208][3.1753:1755](),[3.274][3.1753:1755](),[3.1753][3.1753:1755]()
    let ts_json = ts_spec.into_json(&data_spec, &root_dir);
    }
    [3.221]
    [3.1755]
    // println!("{}", DataSelector::from_file("germany_selector.keytree")
    // .into_data_spec()
    // .unwrap()
    // .keytree());
    // println!("{}", DataSelector::from_file("austria_selector.keytree")
    // .into_data_spec()
    // .unwrap()
    // .keytree());
    // (paste this)
    // Step 2
    let data_spec = DataSpec::from_file("source_data.keytree").unwrap();
    // data_spec.update_write(&root_dir).unwrap();
  • edit in src/main.rs at line 48
    [3.1756]
    [3.10087]
    // Step 3
  • edit in src/main.rs at line 50
    [3.10088]
    // println!("{}", data_spec.generic_ts_spec().keytree());
    // (paste this)
    // Step 4
    let ts_spec = ts::Spec::from_file("ts_spec.keytree").unwrap();
    let ts_data = TSData::from_spec(&ts_spec, &root_dir).unwrap();
    dbg!(&ts_data);
    // Fred::series_observations("AUSURTOTMDSMEI").unwrap();
    // JSON does have "." as first value. What should we do? drop_until_parsable ? Or just define
    // dates?
    // We have to know where the parsing happens.
    // It happens in "TimeSeries::<1>::from_csv(&path)"
    }
  • replacement in src/lib.rs at line 86
    [3.10152][3.10152:10167]()
    //! to resume.
    [3.10152]
    [3.10167]
    //! to resume. To update the data files due to a change of the DataSpec,
    //! ```
    //! let date = OffsetDateTime::now_utc() - Duration::days(3);
    //! data_spec
    //! .update_write(date.into(), &root_dir)
    //! .unwrap();
    //! ```
  • replacement in src/lib.rs at line 118
    [3.10708][2.599:670]()
    //! let ts_json = ts_spec.into_json(&data_spec, "/full/path/to/data");
    [3.10708]
    [3.7687]
    //! let ts_json = ts_spec.into_json(&data_spec, "/full/path/to/data").unwrap();
  • edit in src/lib.rs at line 136
    [3.2304]
    [3.10718]
    use std::file;
  • edit in src/lib.rs at line 139
    [3.2318]
    [3.2353]
    use std::line;
    use std::path::Path;
  • edit in src/lib.rs at line 144
    [3.10780]
    [3.477]
    use walkdir::WalkDir;
  • edit in src/lib.rs at line 157
    [3.2475]
    [3.2475]
    DatePoint,
    DateRange,
  • replacement in src/lib.rs at line 167
    [3.2548][3.2548:2613]()
    TSGraphicSpec,
    TSPageSpec,
    TSSeriesSpec,
    TSSpec,
    [3.2548]
    [3.2613]
    PageSpec,
    Spec,
  • edit in src/lib.rs at line 170
    [3.2616]
    [3.2424]
    /// Return the pathname of a data file.
    pub fn data_path(
    root_path: &str,
    data_type: DataType,
    country: Country,
    series_id: SeriesId,
    extension: &str) -> String
    {
    format!(
    "{}/{}/{}/{}.{}",
    root_path,
    data_type,
    country.as_path(),
    series_id,
    extension,
    )
    }
  • replacement in src/lib.rs at line 210
    [3.2651][3.2651:2793]()
    let year = s[..4].parse().map_err(|_| parse_date("failed"))?;
    let month = s[5..7].parse().map_err(|_| parse_date("failed"))?;
    [3.2651]
    [3.2793]
    let year = s[..4].parse().map_err(|_| parse_date(file!(), line!(), "failed"))?;
    let month = s[5..7].parse().map_err(|_| parse_date(file!(), line!(), "failed"))?;
  • replacement in src/lib.rs at line 265
    [3.3347][3.3347:3394]()
    _ => Err(parse_datatype(s)),
    [3.3347]
    [3.15738]
    _ => Err(parse_datatype(file!(), line!(), s)),
  • replacement in src/lib.rs at line 285
    [3.17081][3.11583:11630]()
    pub fn title(series_id: &SeriesId) -> String {
    [3.17081]
    [3.5241]
    pub fn title(series_id: &str) -> Result<String, Error> {
    let sid = SeriesId::from_str(series_id).unwrap();
  • replacement in src/lib.rs at line 288
    [3.5272][3.11631:11694]()
    let seriess = match Fred::series(&series_id.to_string()) {
    [3.5272]
    [3.17132]
    let seriess = match Fred::series(&sid.to_string()) {
  • replacement in src/lib.rs at line 290
    [3.17170][3.17170:17258]()
    Err(err) => {
    println!("{}", err);
    panic!();
    },
    [3.17170]
    [3.17258]
    Err(err) => { return Err(fred_error(file!(), line!(), &err.to_string())) },
  • replacement in src/lib.rs at line 295
    [3.5371][3.5371:5377]()
    s
    [3.5371]
    [3.5377]
    Ok(s)
  • replacement in src/lib.rs at line 331
    [3.3248][3.3248:3523]()
    pub fn get_series_spec(&self, series_id: &SeriesId) -> SeriesSpec {
    let key = self.reverse.get(&series_id).unwrap();
    let seriess = self.map.get(&key).unwrap();
    (*seriess.iter().find(|series| &series.series_id == series_id).unwrap()).clone()
    }
    [3.3248]
    [2.965]
    pub fn get_series_spec(&self, series_id: &SeriesId) -> Option<SeriesSpec> {
  • replacement in src/lib.rs at line 333
    [2.966][2.966:1137](),[2.1137][3.3523:3524](),[3.3523][3.3523:3524](),[3.3524][2.1138:1337]()
    /// Test if a key `(DataType, Country)` has a `SeriesId`.
    pub fn key_has_series_id(&self, key: (DataType, Country), series_id: &SeriesId) -> Result<bool, Error> {
    let series_specs = match self.map.get(&key) {
    Some(series_specs) => series_specs,
    None => { return Err(key_not_in_dataspec(&key.0.to_string(), &key.1.to_string())) },
    [2.966]
    [2.1337]
    let key = match self.reverse.get(&series_id) {
    Some(key) => key,
    None => { return None },
  • replacement in src/lib.rs at line 337
    [2.1348][2.1348:1425]()
    Ok(series_specs.iter().any(|series| &series.series_id == series_id))
    [2.1348]
    [2.1425]
    let seriess = self.map.get(&key).unwrap();
    match seriess.iter().find(|&series| {
    &series.series_id == series_id
    }) {
    Some(series_spec) => Some(series_spec.clone()),
    None => None,
    }
  • replacement in src/lib.rs at line 396
    [3.4927][3.4927:5019]()
    /// Build a generic `TSSpec` from `Self`.
    pub fn generic_ts_spec(&self) -> TSSpec {
    [3.4927]
    [3.5019]
    /// Build a generic `Spec` from `Self`.
    pub fn generic_ts_spec(&self) -> ts::Spec {
  • replacement in src/lib.rs at line 399
    [3.5020][3.5020:5061]()
    let mut ts_spec = TSSpec::new();
    [3.5020]
    [3.5061]
    let mut ts_spec = ts::Spec::new();
  • replacement in src/lib.rs at line 403
    [3.5133][3.5133:5193]()
    let mut ts_graphic_spec = TSGraphicSpec::new();
    [3.5133]
    [3.5193]
    let mut ts_graphic_spec = ts::GraphicSpec::new();
  • replacement in src/lib.rs at line 406
    [3.5240][3.5240:5296]()
    let ts_series_spec = TSSeriesSpec::new(
    [3.5240]
    [3.5296]
    let ts_series_spec = ts::SeriesSpec::new(
  • replacement in src/lib.rs at line 414
    [3.5544][3.5544:5625]()
    let ts_page_spec = TSPageSpec::new(page_key, vec!(ts_graphic_spec));
    [3.5544]
    [3.5625]
    let ts_page_spec = ts::PageSpec::new(
    *country,
    *data_type,
    0,
    vec!(ts_graphic_spec),
    );
  • replacement in src/lib.rs at line 440
    [3.684][3.684:763]()
    Err(err) => { return Err(failed_to_read_file(&err.to_string())) },
    [3.684]
    [3.763]
    Err(err) => { return Err(
    failed_to_read_file(
    file!(),
    line!(),
    &err.to_string()
    ))
    },
  • replacement in src/lib.rs at line 449
    [3.6131][3.775:877]()
    kt.to_ref().try_into().map_err(|err: keytree::error::Error| keytree_error(&err.to_string()))
    [3.6131]
    [3.6171]
    kt.to_ref().try_into().map_err(|err: keytree::error::Error| {
    keytree_error(file!(), line!(), &err.to_string())
    })
  • replacement in src/lib.rs at line 462
    [3.6502][3.6502:6545]()
    pub fn write(&self, root_path: &str) {
    [3.6502]
    [3.878]
    pub fn write(&self, root_path: &str) -> Result<(), Error> {
  • replacement in src/lib.rs at line 465
    [3.969][3.969:1072]()
    series_spec.write_data(root_path);
    series_spec.write_meta(root_path);
    [3.969]
    [3.1072]
    series_spec.write_data(root_path)?;
    series_spec.write_meta(root_path)?;
    }
    }
    Ok(())
    }
    // Need to keep a record of all files and remove files that shouldn't exist.
    //
    // i.e. its not sufficient to check if a file exists. We need to check if a file remains. So we
    // need to create a file list.
    /// Only make requests and updata data to Fred for files that are in `DataSpec` but do not exist
    /// as data files.
    pub fn update_write(&self, root_path: &str) -> Result<(), Error> {
    for (_, series_specs) in &self.map {
    for series_spec in series_specs {
    if !series_spec.exists(root_path)? {
    series_spec.write_data(root_path)?;
    series_spec.write_meta(root_path)?;
    }
    }
    }
    self.remove_old(root_path)?;
    Ok(())
    }
    /// Run through data files, query and remove any files that are not in directory.
    pub fn remove_old(&self, root_path: &str) -> Result<(), Error> {
    for entry in WalkDir::new(root_path) {
    let entry = entry.unwrap();
    if entry.file_type().is_dir() { continue };
    let pathbuf = entry.path();
    let mut path_iter = pathbuf.iter().rev().map(|os_str| os_str.to_str().unwrap());
    let mut file_parts = path_iter.next().unwrap().split('.');
    let file_stem = file_parts.next().unwrap();
    let file_ext = file_parts.next().unwrap();
    if (file_ext != "csv") && (file_ext != "meta") {
    println!("Unknown file [{}]", pathbuf.to_str().unwrap());
    panic!();
  • edit in src/lib.rs at line 511
    [3.1086]
    [3.6750]
    let series_id = SeriesId::new(file_stem);
    match self.get_series_spec(&series_id) {
    Some(_) => {},
    None => {
    match fs::remove_file(entry.path()) {
    Ok(_) => {},
    Err(_) => {
    return Err(file_error(file!(), line!()))
    },
    }
    },
    };
  • edit in src/lib.rs at line 526
    [3.6760]
    [3.6760]
    Ok(())
  • replacement in src/lib.rs at line 531
    [3.6919][2.1433:1500]()
    pub fn resume_write(&self, series_id: &str, root_path: &str) {
    [3.6919]
    [2.1500]
    pub fn resume_write(&self, series_id: &str, root_path: &str) -> Result<(), Error> {
  • replacement in src/lib.rs at line 533
    [2.1544][2.1544:1601]()
    for ((data_type, country), series_specs) in self
    [2.1544]
    [2.1601]
    for (_, series_specs) in self
  • replacement in src/lib.rs at line 536
    [2.1638][2.1638:1962]()
    .skip_while(|((data_type, country), series_specs)| {
    match self.key_has_series_id((*data_type, *country), &sid) {
    Err(err) => {
    println!("{}", err);
    panic!();
    },
    Ok(is_true) => !is_true,
    [2.1638]
    [2.1962]
    .skip_while(|_| {
    match self.get_series_spec(&sid) {
    Some(series_spec) => sid != series_spec.series_id,
    None => true,
  • replacement in src/lib.rs at line 544
    [2.2051][2.2051:2154]()
    series_spec.write_data(root_path);
    series_spec.write_meta(root_path);
    [2.2051]
    [2.2154]
    series_spec.write_data(root_path)?;
    series_spec.write_meta(root_path)?;
  • edit in src/lib.rs at line 548
    [3.7251]
    [3.7251]
    Ok(())
  • edit in src/lib.rs at line 551
    [3.2484][3.7258:7259]()
  • replacement in src/lib.rs at line 575
    [3.7857][3.7857:7874]()
    #[derive(Clone)]
    [3.7857]
    [3.7874]
    #[derive(Clone, Debug)]
  • edit in src/lib.rs at line 589
    [3.1253]
    [3.1253]
    /// Check if a file exists.
    pub fn exists(&self, root_path: &str) -> Result<bool, Error> {
    let csv_path = data_path(
    root_path,
    self.data_type,
    self.country,
    self.series_id.clone(),
    "csv",
    );
    let meta_path = data_path(
    root_path,
    self.data_type,
    self.country,
    self.series_id.clone(),
    "meta",
    );
    Ok(
    Path::new(&csv_path).exists() &&
    Path::new(&meta_path).exists()
    )
    }
  • replacement in src/lib.rs at line 621
    [3.1582][3.1582:1669]()
    None => { return Err(series_id_not_in_dataspec(&series_id.to_string())) },
    [3.1582]
    [3.1669]
    None => { return Err(
    series_id_not_in_dataspec(
    file!(),
    line!(),
    &series_id.to_string()
    )
    )},
  • replacement in src/lib.rs at line 643
    [3.8092][3.8092:8201]()
    /// Return the meta data for a `SeriesSpec`.
    pub fn meta(&self, root_path: &str) -> SeriesMetaData {
    [3.8092]
    [3.8201]
    /// Use `Self` to make a Fred request for series data, and return a `RegularTimeSeries`.
    pub fn into_time_series(&self) -> Result<RegularTimeSeries<1>, Error> {
    // Select the observation data from the FRED data.
    let observations = match Fred::series_observations(&self.series_id.to_string()) {
    Ok(series_obs) => series_obs.observations,
    Err(err) => { return Err(fred_error(file!(), line!(), &err.to_string())) },
    };
  • replacement in src/lib.rs at line 652
    [3.8202][3.8202:8389]()
    let path = &format!(
    "{}/{}/{}/{}.meta",
    root_path,
    self.data_type,
    self.country.as_path(),
    self.series_id,
    );
    [3.8202]
    [3.8389]
    // We need to build a RegularTimeSeries here, and then use RegularTimeSeries here
    // to build csv file.
    // Data is parsed into a RegularTimeSeries
  • replacement in src/lib.rs at line 656
    [3.8390][3.8390:8547]()
    let meta_str = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&meta_str).unwrap();
    kt.to_ref().try_into().unwrap()
    }
    [3.8390]
    [3.8547]
    // Want power to drop_first
  • replacement in src/lib.rs at line 658
    [3.8548][3.8548:8695]()
    /// Return the time-series data for `series_id`.
    pub fn time_series_data(&self, root_path: &str) -> Result<RegularTimeSeries<1>, Error> {
    [3.8548]
    [3.8695]
    let mut v = Vec::new();
  • replacement in src/lib.rs at line 660
    [3.8696][3.8696:8882]()
    let path = &format!(
    "{}/{}/{}/{}.csv",
    root_path,
    self.data_type,
    self.country.as_path(),
    self.series_id,
    );
    [3.8696]
    [3.8882]
    // Drop the first n items
    let skip = match self.drop_first {
    None => 0,
    Some(n) => n,
    };
    for (i, obs) in observations.iter().enumerate().skip(skip) {
    let date = MonthlyDate::from_str(&obs.date)?;
    let value: f32 = match obs.value.parse() {
    Ok(n) => n,
    Err(_) => {
    let err = parse_fred_value_failed(
    file!(),
    line!(),
    &self.data_type.to_string(),
    &self.country.to_string(),
    &self.series_id.to_string(),
    &format!(
    "{}, {}",
    obs.date,
    obs.value,
    ),
    i + 1,
    );
    self.soft_parse(observations, err);
    unreachable!();
    },
    };
  • replacement in src/lib.rs at line 691
    [3.8883][3.8883:9125]()
    match TimeSeries::<1>::from_csv(&path) {
    Ok(ts) => {
    match ts.try_into() {
    Ok(rts) => Ok(rts),
    Err(err) => Err(from_time_series(&err.to_string())),
    }
    [3.8883]
    [3.9125]
    let date_point = DatePoint::<1>::new(date.0, [value]);
    v.push(date_point)
    }
    let ts = TimeSeries::new(v);
    let rts = match ts.try_into() {
    Ok(rts) => {
    rts
    },
    Err(_) => {
    let err = expected_regular_time_series(
    file!(),
    line!(),
    &self.data_type.to_string(),
    &self.country.to_string(),
    &self.series_id.to_string(),
    );
    self.soft_parse(observations, err);
    unreachable!();
  • replacement in src/lib.rs at line 710
    [3.9140][3.9140:9205]()
    Err(err) => Err(from_time_series(&err.to_string())),
    [3.9140]
    [3.9205]
    };
    Ok(rts)
    }
    /// Parse observations into string for debugging and exit.
    pub fn soft_parse(&self, observations: fred_api::Observations, err: Error) {
    for (i, obs) in observations.iter().enumerate() {
    eprintln!(
    "{} {}, {}",
    i + 1,
    obs.date,
    obs.value,
    )
  • edit in src/lib.rs at line 724
    [3.9215]
    [3.9215]
    eprintln!("{}", err);
    std::process::exit(1);
  • edit in src/lib.rs at line 728
    [3.9222]
    [3.9222]
    /// Fetches data as specified in `source_data.keytree` and saves to disk.
    pub fn write_data(&self, root_path: &str) -> Result<(), Error> {
  • edit in src/lib.rs at line 731
    [3.9223]
    [3.2044]
    let rts = self.into_time_series()?;
  • replacement in src/lib.rs at line 733
    [3.2045][3.9223:9350](),[3.9223][3.9223:9350]()
    /// Fetches data as specified in `checked_data.keytree` and saves to disk.
    pub fn write_data(&self, root_path: &str) {
    [3.2045]
    [3.9350]
    let mut csv = String::new();
    for date_point in rts.iter(DateRange::new(None, None)) {
    let date = date_point.date();
    let date_str = format!(
    "{}-{:02}-01",
    date.year(),
    date.month(),
    );
  • replacement in src/lib.rs at line 742
    [3.9351][3.9351:9840]()
    // Select the observation data from the FRED data.
    let observations = match Fred::series_observations(&self.series_id.to_string()) {
    Ok(series_obs) => series_obs.observations,
    Err(err) => {
    println!("{}", err);
    panic! ();
    },
    };
    let mut data = String::new();
    for obs in observations.iter() {
    data.push_str(&obs.to_string());
    data.push('\n');
    [3.9351]
    [3.9840]
    let line = format!(
    "{}, {}\n",
    date_str,
    date_point.value(0),
    );
    csv.push_str(&line);
  • replacement in src/lib.rs at line 763
    [3.10152][3.10152:10200]()
    fs::create_dir_all(&dir_path).unwrap();
    [3.10152]
    [3.10200]
    if let Err(err) = fs::create_dir_all(&dir_path) {
    return Err(
    failed_to_create_dir(
    file!(),
    line!(),
    &err.to_string()
    )
    )
    }
  • replacement in src/lib.rs at line 773
    [3.10201][3.10201:10288]()
    println!("Writing {}", filename);
    fs::write(filename, &data).unwrap();
    [3.10201]
    [3.10288]
    println!(
    "Writing {}", filename);
    if let Err(_) = fs::write(filename, &csv) {
    return Err(
    failed_to_write_file(
    file!(),
    line!(),
    filename,
    )
    )
    };
    Ok(())
  • replacement in src/lib.rs at line 787
    [3.10295][3.10295:10432]()
    /// Fetches data as specified in `checked_data.keytree` and saves meta_data to disk.
    pub fn write_meta(&self, root_path: &str) {
    [3.10295]
    [3.10432]
    /// Fetches data as specified in `source_data.keytree` and saves meta_data to disk.
    pub fn write_meta(&self, root_path: &str) -> Result<(), Error> {
  • replacement in src/lib.rs at line 804
    [3.11208][3.11208:11313]()
    Err(err) => {
    println!("{}", err);
    panic! ();
    },
    [3.11208]
    [3.11313]
    Err(err) => { return Err(
    fred_error(
    file!(),
    line!(),
    &err.to_string()
    )
    )},
  • edit in src/lib.rs at line 829
    [3.11759]
    [3.11759]
    Ok(())
  • replacement in src/lib.rs at line 947
    [3.15547][3.15547:15603]()
    // self.time_stamp = Some(TimeStamp::now());
    [3.15547]
    /// Read csv data from file and return a time-series.
    pub fn data_from_file(
    country: Country,
    data_type: DataType,
    series_id: SeriesId,
    root_path: &str) -> Result<RegularTimeSeries<1>, Error>
    {
    let path = data_path(
    root_path,
    data_type,
    country,
    series_id.clone(),
    "csv"
    );
    match TimeSeries::<1>::from_csv(&path) {
    Ok(ts) => {
    match ts.try_into() {
    Ok(rts) => Ok(rts),
    Err(err) => {
    Err(time_series_from_csv_failed(
    file!(),
    line!(),
    &data_type.to_string(),
    &country.to_string(),
    &series_id.to_string(),
    &err.to_string(),
    ))
    },
    }
    },
    Err(err) => Err(time_series_from_csv_failed(
    file!(),
    line!(),
    &data_type.to_string(),
    &country.to_string(),
    &series_id.to_string(),
    &err.to_string(),
    ))
    }
    }
    /// Return the meta data for a `SeriesSpec`.
    pub fn meta_from_file(
    country: Country,
    data_type: DataType,
    series_id: SeriesId,
    root_path: &str) -> SeriesMetaData
    {
    let path = data_path(
    root_path,
    data_type,
    country,
    series_id.clone(),
    "meta"
    );
    let meta_str = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&meta_str).unwrap();
    kt.to_ref().try_into().unwrap()
    }
  • edit in Cargo.toml at line 18
    [3.12246]
    walkdir = "2.3.2"