Removed checking functionality.

[?]
Jul 7, 2021, 5:54 AM
SAHJYVNBUBBIUBI4ZMAXK4QJFOT54M5UA3W2HQMTNDSP3GGCRX7QC

Dependencies

  • [2] TTR5IFSG Working on building generic TSSpec.
  • [3] 5POF332L Working on fn cpi_included().
  • [4] LURDUHBI Finished series filter for CPI.
  • [5] 2SABVMY3 Finished into_json() functionality.
  • [6] GUXZCEWW Added Country enum.
  • [7] AT753JPO Selected US unemployment series.
  • [8] IKPVWWLK Filter unemployment rate series.
  • [9] CUADTSHQ Save csv data as multiple files.
  • [10] 77SIQZ3E Separating out spec generation.
  • [11] UCSU3QE4 Created keytree generator for u and cpi.
  • [12] U4VCAFXQ Added data_type to TSSpec key.
  • [13] XI5ALEH6 Take advantage of keytree FromStr functionality.
  • [14] AIFRDCG2 Split off countries mod into a separate crate.
  • [15] JTX5OHWH Added USA CPI.
  • [16] LVMGQJGH Finished framework for checking series specifications with data.
  • [17] 4QOTH75I Fixed UI specification code.
  • [18] 4MG5JFXT First record.
  • [19] GQVS55HI Finished generate_ts_spec() function.

Change contents

  • file deletion: build_spec.rs (-xw-xw-x--)
    [3.6][3.21250:21265](),[3.21265][3.21266:21266]()
    //! Builds generic specifications.
    use std::convert::TryInto;
    use std::fs;
    use countries::Country;
    use fred_api::{
    Fred,
    SeriesItems,
    };
    use keytree::{
    KeyTree,
    KeyTreeRef,
    };
    use keytree::Error;
    use keytree::serialize::{
    IntoKeyTree,
    KeyTreeString,
    };
    /// Return all the countries with good data as a `Vec`.
    pub fn countries_with_data() -> Vec<Country> {
    vec!(
    Country::Australia,
    Country::Austria,
    Country::Belgium,
    Country::Canada,
    Country::Chile,
    Country::CzechRepublic,
    Country::Denmark,
    Country::Estonia,
    Country::Finland,
    Country::France,
    Country::Germany,
    Country::Greece,
    Country::Ireland,
    Country::Israel,
    Country::Italy,
    Country::Japan,
    Country::Latvia,
    Country::Netherlands,
    Country::NewZealand,
    Country::Norway,
    Country::Poland,
    Country::Serbia,
    Country::SouthKorea,
    Country::Spain,
    Country::Sweden,
    Country::Switzerland,
    Country::UnitedKingdom,
    Country::UnitedStates,
    )
    }
    /// Returns relevant CPI series for a country, by pre-selecting series titles for each country.
    ///
    /// ```
    /// ```
    let titles = match country {
    Country::Australia => {
    vec!(
    "Consumer Price Index: All items: Total: Total for Australia",
    "Consumer Price Index: All Items for Australia",
    "Consumer Price Index in Australia (DISCONTINUED)",
    "Consumer Price Index: Total All Items for Australia",
    "Consumer Price Index for Australia",
    "Inflation, consumer prices for Australia",
    )
    }
    Country::Austria => {
    vec!(
    "Consumer Price Index for Austria",
    "Consumer Price Index: All items: Total: Total for Austria",
    "Consumer Price Index: All Items for Austria",
    "Consumer Price Index in Austria (DISCONTINUED)",
    "Consumer Price Index: Harmonized Prices: Total All Items for Austria",
    "Consumer Price Index: Harmonized Prices: Total All Items for Austria // (DISCONTINUED)",
    "Consumer Price Index: Total All Items for Austria",
    "Harmonized Index of Consumer Prices: All Items for Austria",
    "Harmonized Index of Consumer Prices in Austria (DISCONTINUED)",
    "Inflation, consumer prices for Austria",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for // Austria",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Austria (DISCONTINUED)",
    )
    }
    Country::Belgium => {
    vec!(
    "Consumer Price Index for Belgium",
    "Consumer Price Index: Harmonized Prices: Total All Items for Belgium",
    "Consumer Price Index: Harmonized Prices: Total All Items for Belgium (DISCONTINUED)",
    "Consumer Price Index: Total All Items for Belgium",
    "Harmonized Index of Consumer Prices: All Items for Belgium",
    "Harmonized Index of Consumer Prices in Belgium (DISCONTINUED)",
    "Consumer Price Index: All Items for Belgium",
    "Consumer Price Index in Belgium (DISCONTINUED)",
    "Consumer Price Index: All items: Total: Total for Belgium",
    )
    }
    Country::Canada => {
    vec!(
    "Inflation, consumer prices for Canada",
    "Consumer Price Index for Canada",
    "Consumer Price Index: Total All Items for Canada",
    "Consumer Price Index in Canada (DISCONTINUED)",
    "Consumer Price Index of All Items in Canada",
    "Consumer Price Index: All items: Total: Total for Canada",
    )
    }
    Country::Chile => {
    vec!(
    "Consumer Price Index for Chile",
    "Inflation, consumer prices for Chile",
    "Consumer Price Index: Total All Items for Chile",
    "Consumer Price Index: All Items for Chile",
    "Consumer Price Index: All items: Total: Total for Chile",
    )
    }
    Country::CzechRepublic => {
    vec!(
    "Consumer Price Index for Czech Republic",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Czech Republic",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Czech Republic (DISCONTINUED)",
    "Consumer Price Index: All Items for Czech Republic",
    "Consumer Price Index: All items: Total: Total for the Czech Republic",
    "Consumer Price Index: Harmonized Prices: Total All Items for the Czech Republic",
    "Consumer Price Index: Harmonized Prices: Total All Items for the Czech Republic (DISCONTINUED)",
    "Consumer Price Index: Total All Items for the Czech Republic",
    "Harmonized Index of Consumer Prices: All Items for Czech Republic",
    )
    }
    Country::Denmark => {
    vec!(
    "Inflation, consumer prices for Denmark",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Denmark",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Denmark (DISCONTINUED)",
    "Harmonized Index of Consumer Prices in Denmark (DISCONTINUED)",
    "Consumer Price Index: All Items for Denmark",
    "Consumer Price Index in Denmark (DISCONTINUED)",
    "Consumer Price Index: All items: Total: Total for Denmark",
    "Consumer Price Index for Denmark",
    "Consumer Price Index: Total All Items for Denmark",
    "Harmonized Index of Consumer Prices: All Items for Denmark",
    )
    }
    Country::Estonia => {
    vec!(
    "Inflation, consumer prices for Estonia",
    "Consumer Price Index: All items: Total: Total for Estonia",
    "Consumer Price Index for Estonia",
    "Consumer Price Index: Harmonized Prices: Total All Items for Estonia",
    "Consumer Price Index: Harmonized Prices: Total All Items for Estonia (DISCONTINUED)",
    "Consumer Price Index: Total All Items for Estonia",
    "Harmonized Index of Consumer Prices: All Items for Estonia",
    )
    }
    Country::Finland => {
    vec!(
    "Inflation, consumer prices for Finland",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Finland",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Finland (DISCONTINUED)",
    "Consumer Price Index: All Items for Finland",
    "Consumer Price Index: OECD Groups: Services: Total for Finland",
    "Consumer Price Index: All items: Total: Total for Finland",
    "Consumer Price Index: Harmonized Prices: Total All Items for Finland (DISCONTINUED)",
    "Consumer Price Index for Finland",
    "Consumer Price Index: Harmonized Prices: Total All Items for Finland",
    "Consumer Price Index: Total All Items for Finland",
    "Harmonized Index of Consumer Prices: All Items for Finland",
    )
    }
    Country::France => {
    vec!(
    "Harmonized Index of Consumer Prices in France (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for France (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for France",
    "Consumer Price Index in France (DISCONTINUED)",
    "Consumer Price Index of All Items in France",
    "Consumer Price Index: All items: Total: Total for France",
    "Inflation, consumer prices for France",
    "Consumer Price Index for France",
    "Consumer Price Index: Harmonized Prices: Total All Items for France (DISCONTINUED)",
    "Consumer Price Index: Harmonized Prices: Total All Items for France",
    "Consumer Price Index: Total All Items for France",
    )
    }
    Country::Germany => {
    vec!(
    "Inflation, consumer prices for Germany",
    "Harmonized Index of Consumer Prices in Germany (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Germany (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Germany",
    "Consumer Price Index in Germany (DISCONTINUED)",
    "Consumer Price Index of All Items in Germany",
    "Consumer Price Index: All items: Total: Total for Germany",
    "Consumer Price Index for Germany",
    "Consumer Price Index: Harmonized Prices: Total All Items for Germany (DISCONTINUED)",
    "Consumer Price Index: Harmonized Prices: Total All Items for Germany",
    "Consumer Price Index: Total All Items for Germany",
    "Harmonized Index of Consumer Prices: All Items for Germany (including former GDR from 1991)",
    )
    }
    Country::Greece => {
    vec!(
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Greece",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Greece (DISCONTINUED)",
    "Consumer Price Index: All Items for Greece",
    "Consumer Price Index: All items: Total: Total for Greece",
    "Inflation, consumer prices for Greece",
    "Consumer Price Index for Greece",
    "Consumer Price Index: Harmonized Prices: Total All Items for Greece",
    "Consumer Price Index: Harmonized Prices: Total All Items for Greece (DISCONTINUED)",
    "Consumer Price Index: Total All Items for Greece",
    "Harmonized Index of Consumer Prices: All Items for Greece",
    )
    }
    Country::Ireland => {
    vec!(
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Ireland",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Ireland (DISCONTINUED)",
    "Consumer Price Index: OECD Groups: Services: Total for Ireland",
    // "Consumer Price Index: All Items for Ireland", // Does not parse
    // "Consumer Price Index: All items: Total: Total for Ireland", // Does not parse
    "Consumer Price Index: Harmonized Prices: Total All Items for Ireland (DISCONTINUED)",
    "Consumer Price Index for Ireland",
    "Consumer Price Index: Harmonized Prices: Total All Items for Ireland",
    "Harmonized Index of Consumer Prices: All Items for Ireland",
    )
    }
    Country::Israel => {
    vec!(
    "Consumer Price Index: All Items for Israel",
    "Consumer Price Index: All items: Total: Total for Israel",
    "Consumer Price Index for Israel",
    "Inflation, consumer prices for Israel",
    "Consumer Price Index: Total All Items for Israel",
    )
    }
    Country::Italy => {
    vec!(
    "Harmonized Index of Consumer Prices in Italy (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Italy (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Italy",
    "Consumer Price Index: Food for Italy",
    "Consumer Price Index in Italy (DISCONTINUED)",
    "Consumer Price Index of All Items in Italy",
    "Consumer Price Index: All items: Total: Total for Italy",
    "Inflation, consumer prices for Italy",
    "Consumer Price Index for Italy",
    "Consumer Price Index: Harmonized Prices: Total All Items for Italy (DISCONTINUED)",
    "Consumer Price Index: Harmonized Prices: Total All Items for Italy",
    "Consumer Price Index: Total All Items for Italy",
    "Harmonized Index of Consumer Prices: All Items for Italy",
    )
    }
    Country::Japan => {
    vec!(
    "Harmonized Index of Consumer Prices in Japan (DISCONTINUED)",
    "Consumer Price Index in Japan (DISCONTINUED)",
    "Consumer Price Index of All Items in Japan",
    "Consumer Price Index: All items: Total: Total for Japan",
    "Inflation, consumer prices for Japan",
    "Not Seasonally Adjusted",
    )
    }
    Country::Latvia => {
    vec!(
    "Consumer Price Index: All items: Total: Total for Latvia",
    "Inflation, consumer prices for Latvia",
    "Harmonized Index of Consumer Prices: Unprocessed Food for Latvia",
    "Consumer Price Index for Latvia",
    )
    }
    Country::Netherlands => {
    vec!(
    "Harmonized Index of Consumer Prices in Netherlands (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Netherlands (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Netherlands",
    "Consumer Price Index in Netherlands (DISCONTINUED)",
    "Consumer Price Index: All Items for Netherlands",
    "Consumer Price Index: All items: Total: Total for the Netherlands",
    "Consumer Price Index for Netherlands",
    "Consumer Price Index: Harmonized Prices: Total All Items for the Netherlands",
    "Consumer Price Index: Harmonized Prices: Total All Items for the Netherlands (DISCONTINUED)",
    "Consumer Price Index: Total All Items for the Netherlands",
    "Harmonized Index of Consumer Prices: All Items for Netherlands",
    )
    }
    Country::NewZealand => {
    vec!(
    "Consumer Price Index: All Items for New Zealand",
    "Consumer Price Index: All Items Excluding Food and Energy for New Zealand",
    "Consumer Price Index: All items: Total: Total for New Zealand",
    "Consumer Price Index for New Zealand",
    "Inflation, consumer prices for New Zealand",
    "Consumer Price Index: Total All Items for New Zealand",
    )
    }
    Country::Norway => {
    vec!(
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Norway",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Norway (DISCONTINUED)",
    "Consumer Price Index: All Items for Norway",
    "Consumer Price Index in Norway (DISCONTINUED)",
    "Consumer Price Index: All items: Total: Total for Norway",
    "Consumer Price Index: Harmonized Prices: Total All Items for Norway (DISCONTINUED)",
    "Consumer Price Index for Norway",
    "Consumer Price Index: Harmonized Prices: Total All Items for Norway",
    "Consumer Price Index: Total All Items for Norway",
    "Harmonized Index of Consumer Prices: All Items for Norway",
    )
    }
    Country::Poland => {
    vec!(
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Poland",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Poland (DISCONTINUED)",
    "Consumer Price Index: Food for Poland",
    "Consumer Price Index: All Items for Poland",
    "Consumer Price Index: All items: Total: Total for Poland",
    "Inflation, consumer prices for Poland",
    "Consumer Price Index for Poland",
    "Consumer Price Index: Total All Items for Poland",
    "Harmonized Index of Consumer Prices: All Items for Poland",
    )
    }
    Country::Serbia => {
    vec!(
    "Consumer Price Index for Serbia",
    "Inflation, consumer prices for Serbia",
    )
    }
    Country::SouthKorea => {
    vec!(
    "Consumer Price Index: All Items for Korea",
    "Consumer Price Index: All items: Total: Total for the Republic of Korea",
    "Inflation, consumer prices for the Republic of Korea",
    "Consumer Price Index for Republic of Korea",
    "Consumer Price Index: Total All Items for the Republic of Korea",
    )
    }
    Country::Spain => {
    vec!(
    "Inflation, consumer prices for Spain",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Spain (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Spain",
    "Consumer Price Index in Spain (DISCONTINUED)",
    "Consumer Price Index: All Items for Spain",
    "Consumer Price Index: All items: Total: Total for Spain",
    "Consumer Price Index for Spain",
    "Consumer Price Index: Harmonized Prices: Total All Items for Spain (DISCONTINUED)",
    "Consumer Price Index: Harmonized Prices: Total All Items for Spain",
    "Consumer Price Index: Total All Items for Spain",
    "Harmonized Index of Consumer Prices: All Items for Spain",
    )
    }
    Country::Sweden => {
    vec!(
    "Harmonized Index of Consumer Prices in Sweden (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Sweden",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Sweden (DISCONTINUED)",
    "Consumer Price Index: All Items for Sweden",
    "Consumer Price Index in Sweden (DISCONTINUED)",
    "Consumer Price Index: All items: Total: Total for Sweden",
    "Consumer Price Index: Harmonized Prices: Total All Items for Sweden",
    "Consumer Price Index: Harmonized Prices: Total All Items for Sweden (DISCONTINUED)",
    "Consumer Price Index for Sweden",
    "Consumer Price Index: Total, Net All Items for Sweden (DISCONTINUED)",
    "Consumer Price Index: Total All Items for Sweden",
    "Harmonized Index of Consumer Prices: All Items for Sweden",
    )
    }
    Country::Switzerland => {
    vec!(
    "Consumer Price Index: Harmonized Prices: Total All Items for Switzerland",
    "Consumer Price Index: Harmonized Prices: Total All Items for Switzerland (DISCONTINUED)",
    "Consumer Price Index for Switzerland",
    "Consumer Price Index: Total All Items for Switzerland",
    "Harmonized Index of Consumer Prices: All Items for Switzerland",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Switzerland",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for Switzerland (DISCONTINUED)",
    )
    }
    Country::UnitedKingdom => {
    vec!(
    "Harmonized Index of Consumer Prices in the United Kingdom (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for United Kingdom (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for United Kingdom",
    "Consumer Price Index in the United Kingdom (DISCONTINUED)",
    "Consumer Price Index of All Items in the United Kingdom",
    "Consumer Price Index: All Items for United Kingdom",
    "Consumer Price Index: All items: Total: Total for the United Kingdom",
    "Inflation, consumer prices for the United Kingdom",
    "Consumer Price Index for United Kingdom",
    "Consumer Price Index in the United Kingdom",
    "Consumer Price Inflation in the United Kingdom",
    "Consumer Price Index: Harmonized Prices: Total All Items for the United Kingdom (DISCONTINUED)",
    "Consumer Price Index: Harmonized Prices: Total All Items for the United Kingdom",
    "Consumer Price Index: Total All Items for the United Kingdom",
    "Harmonized Index of Consumer Prices: All Items for United Kingdom",
    )
    }
    Country::UnitedStates => {
    vec!(
    "Harmonized Index of Consumer Prices: All Items for United States",
    "Consumer Price Index: Total All Items for the United States",
    "Consumer Price Index: Harmonized Prices: Total All Items for the United States",
    "Consumer Price Index: Harmonized Prices: Total All Items for the United States (DISCONTINUED)",
    "Research Consumer Price Index: All Items",
    "Consumer Price Index for United States",
    "Flexible Price Consumer Price Index",
    "Inflation, consumer prices for the United States",
    "Consumer Price Index, All Items for United States",
    "Rate of Change (6 Month Span at Annual Rate), Consumer Price Index, All Items (Centered) for United States",
    "Median Consumer Price Index",
    "Sticky Price Consumer Price Index",
    "16% Trimmed-Mean Consumer Price Index",
    "Consumer Price Index: All Items for the United States",
    "Consumer Price Index of All Items in United States",
    "Consumer Price Index in the United States (DISCONTINUED)",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for the United States",
    "Consumer Price Index: All Items (Harmonized Index of Consumer Prices) for the United States (DISCONTINUED)",
    "Harmonized Index of Consumer Prices in the United States (DISCONTINUED)",
    )
    }
    _ => panic!(),
    };
    match country {
    Country::UnitedStates => {
    match Fred::tags_series("cpi;usa") {
    Ok(tags_series) => {
    tags_series.seriess
    .equals_one_of(titles)
    },
    Err(json_error) => {
    println!("{}", json_error);
    panic!();
    },
    }
    },
    _ => {
    Ok(tags_series) => {
    tags_series.seriess
    .equals_one_of(titles)
    },
    Err(json_error) => {
    println!("{}", json_error);
    panic!();
    },
    }
    },
    }
    }
    format!(
    "{};{}",
    tag,
    country.to_string().to_lowercase()
    )
    }
    /// Return relevant unemployment rate series for a country.
    /// ```
    /// ```
    if let Country::UnitedStates = country {
    // Need to use a different search technique for US data.
    let exclude_phrase = vec!(
    "Male",
    "Female",
    "Men",
    "Women",
    "Youth",
    );
    let one_of = vec!(
    "Unemployment Rate for United States",
    "Unemployment Rate: Aged 15 and Over: All Persons for the United States",
    "Unemployment Rate: Aged 15-74: All Persons for the United States",
    "Harmonized Unemployment Rate: Total: All Persons for the United States",
    "Unemployment Rate - 18 Years and Over",
    );
    let tag_series = Fred::tags_series("unemployment;rate;usa;nation").unwrap().seriess;
    tag_series
    .exclude_phrases(exclude_phrase)
    .equals_one_of(one_of)
    } else {
    let (exclude_phrase, include_phrase) = match country {
    Country::Australia => {
    (
    vec!(
    "Male",
    "Female",
    "55-64",
    "25-54",
    "15-24",
    "20 to 24",
    "Youth",
    "Women",
    "Teenagers",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::Austria => {
    (
    vec!(
    "Male",
    "Female",
    "55-64",
    "25-54",
    "15-24",
    "15-64", // series includes 15-74
    "20 to 24",
    "Youth",
    "Women",
    "Teenagers",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::Belgium => {
    (
    vec!(
    "Male",
    "Female",
    "55-64",
    "25-54",
    "15-24",
    "15-64", // series includes 15-74
    "20 to 24",
    "Youth",
    "Women",
    "Teenagers",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::Canada => {
    (
    vec!(
    "Male",
    "Female",
    "15-64",
    "55-64",
    "25-54",
    "15-24",
    "20 to 24",
    "Youth",
    "Women",
    "Teenagers",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::Chile => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::CzechRepublic => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::Denmark => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate"
    ),
    )
    }
    Country::Estonia => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Finland => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::France => {
    (
    vec!(
    "Male",
    "Men",
    "Female",
    "Women",
    "Youth",
    "Teenagers",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Germany => {
    (
    vec!(
    "Male",
    "Men",
    "Female",
    "Youth",
    "Women",
    "Teenagers",
    "20 to 24",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Greece => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Ireland => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Israel => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Italy => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "Men",
    "Women",
    "Teenagers",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Japan => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "Men",
    "Women",
    "Teenagers",
    "20 to 24",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Latvia => {
    (
    vec!(
    "Youth",
    "Male",
    "Female",
    "25 and over",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "nemployment",
    ),
    )
    }
    Country::Netherlands => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "Women",
    "Teenagers",
    "Men",
    "20 to 24",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::NewZealand => {
    (
    vec!(
    "Male",
    "Female",
    "55-64",
    "25-54",
    "15-24",
    "Youth",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Norway => {
    (
    vec!(
    "Male",
    "Female",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Poland => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Serbia => {
    (
    vec!(
    ),
    vec!(
    "",
    ),
    )
    }
    Country::SouthKorea => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Spain => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Sweden => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "Men",
    "Women",
    "Teenagers",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    "20 to 24",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::Switzerland => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    Country::UnitedKingdom => {
    (
    vec!(
    "Male",
    "Female",
    "Youth",
    "Men",
    "Women",
    "Teenagers",
    "20 to 24",
    "15-24",
    "15-64",
    "25-54",
    "55-64",
    ),
    vec!(
    "Rate",
    ),
    )
    }
    _ => panic!(),
    };
    match Fred::tags_series(&to_tag("unemployment", country)) {
    Ok(tags_series) => {
    tags_series.seriess
    .exclude_phrases(exclude_phrase)
    .only_include(include_phrase)
    },
    Err(err) => {
    println!("{}", err);
    panic!();
    },
    }
    }
    }
    /// ```
    /// seriess:
    /// series:
    /// data_type: u
    /// country: Australia
    /// ```
    let mut seriess = DataSpec(Vec::new());
    for country in countries_with_data() {
    seriess
    }
    /// ```
    /// series:
    /// data_type: u
    /// country: United States
    /// id: LRUNTTTTUSQ156S
    /// ```
    pub struct DataSpec(pub Vec<SourceSeries>);
    impl DataSpec {
    /// Read in keytree data from file.
    pub fn from_file(path: &str) -> Self {
    let source_spec = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&source_spec).unwrap();
    kt.to_ref().try_into().unwrap()
    }
    }
    impl<'a> TryInto<DataSpec> for KeyTreeRef<'a> {
    type Error = Error;
    fn try_into(self) -> Result<DataSpec, Error> {
    Ok(
    )
    }
    }
    impl IntoKeyTree for DataSpec {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "seriess");
    for series in &self.0 {
    kt.push_keytree(1, series.keytree());
    }
    kt
    }
    }
    pub struct SourceSeries {
    ///
    ///
    }
    impl IntoKeyTree for SourceSeries {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "series");
    kt.push_keyvalue(1, "data_type", &self.data_type.to_string());
    kt.push_keyvalue(1, "country", &self.country.to_string());
    kt
    }
    }
    impl<'a> TryInto<SourceSeries> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<SourceSeries, keytree::Error> {
    Ok(
    SourceSeries{
    }
    )
    }
    }
    data_type: self.value("series::data_type")?,
    country: self.value("series::country")?,
    series_id: self.value("series::series_id")?,
    kt.push_keyvalue(1, "series_id", &self.series_id.to_string());
    pub series_id: SeriesId,
    pub country: Country,
    ///
    pub data_type: DataType,
    ///
    DataSpec(self.vec_at("seriess:series")?)
    /// Append `other` to `Self`.
    pub fn append(&mut self, other: &mut DataSpec) {
    self.0.append(&mut other.0)
    }
    /// A generic specification of all data series. Output looks like
    seriess.append(&mut data_spec_for_country(DataType::U, country));
    }
    for country in countries_with_data() {
    seriess.append(&mut data_spec_for_country(DataType::Cpi, country));
    }
    for country in countries_with_data() {
    seriess.append(&mut data_spec_for_country(DataType::Inf, country));
    }
    pub fn build_generic_data_spec() -> DataSpec {
    /// series_id: AUSURAMS
    /// Build a generic specification of one datatype and country.
    pub fn data_spec_for_country(data_type: DataType, country: Country) -> DataSpec {
    let mut seriess = DataSpec(Vec::new());
    match data_type {
    DataType::U => {
    for series_item in generic_u_series_spec(country).iter() {
    seriess.0.push(
    SourceSeries {
    data_type: DataType::U,
    country,
    series_id: SeriesId::new(&series_item.id.clone()),
    }
    )
    }
    println!("{} {}", country, data_type);
    },
    DataType::Inf => {
    for series_item in generic_inf_series_spec(country).iter() {
    seriess.0.push(
    SourceSeries {
    data_type: DataType::Inf,
    country,
    series_id: SeriesId::new(&series_item.id.clone()),
    }
    )
    }
    println!("{} {}", country, data_type);
    },
    DataType::Cpi => {
    for series_item in generic_cpi_series_spec(country).iter() {
    seriess.0.push(
    SourceSeries {
    data_type: DataType::Cpi,
    country,
    series_id: SeriesId::new(&series_item.id.clone()),
    }
    )
    }
    println!("{} {}", country, data_type);
    },
    DataType::Int => {},
    }
    seriess
    }
    /// Build a generic specification for all data. Output looks like
    pub fn generic_u_series_spec(country: Country) -> SeriesItems {
    /// println!("{}", unemployment_series(Country::Canada, "u_series.keytree"));
    }
    /// Return relevant inflation rate series for a country. This function first selects all series with
    /// a certain tag pattern, and then applies required phrases and exclusionary phrases.
    /// ```
    /// println!("{}", generic_inf_series_spec(Country::Canada));
    /// ```
    pub fn generic_inf_series_spec(country: Country) -> SeriesItems {
    if let Country::UnitedStates = country {
    // Need to use a different search technique for US data.
    let exclude_phrase = vec!(
    "Producer Price Index",
    "Projections",
    "Export Price Index",
    "Implicit Price Deflator",
    "Employment Cost Index",
    "Contributions to",
    "Inflation Expectation",
    "Equity Market",
    "excluding food and energy",
    "Excluding Food and Energy",
    "excluding Food and Energy",
    "Urban",
    "Sticky",
    "Opinion",
    "Consumer Price Index",
    "Personal Consumption",
    "Private Consumption",
    );
    // let one_of = vec!(
    // "Unemployment Rate for United States",
    // "Unemployment Rate: Aged 15 and Over: All Persons for the United States",
    // "Unemployment Rate: Aged 15-74: All Persons for the United States",
    // "Harmonized Unemployment Rate: Total: All Persons for the United States",
    // "Unemployment Rate - 18 Years and Over",
    // );
    let tag_series = Fred::tags_series("inflation;usa;nation").unwrap().seriess;
    tag_series
    .exclude_phrases(exclude_phrase)
    // .equals_one_of(one_of)
    } else {
    let (exclude_phrase, include_phrase) = match country {
    Country::Australia => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Austria => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Belgium => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Canada => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Chile => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::CzechRepublic => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Denmark => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Estonia => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Finland => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::France => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Germany => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Greece => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Ireland => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Israel => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Italy => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Japan => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Latvia => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Netherlands => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::NewZealand => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Norway => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Poland => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Serbia => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::SouthKorea => {
    (
    vec!(
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Spain => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Sweden => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::Switzerland => {
    (
    vec!(
    "Opinion",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::UnitedKingdom => {
    (
    vec!(
    "Opinion",
    "Consumer Price Inflation",
    ),
    vec!(
    "Inflation",
    ),
    )
    },
    Country::UnitedStates => {
    (
    vec!(
    ),
    vec!(
    "",
    ),
    )
    },
    _ => {
    panic!()
    },
    };
    match Fred::tags_series(&to_tag("inflation", country)) {
    Ok(tags_series) => {
    tags_series.seriess
    .exclude_phrases(exclude_phrase)
    .only_include(include_phrase)
    },
    Err(err) => {
    println!("{}", err);
    panic!();
    },
    }
    }
    fn to_tag(tag: &str, country: Country) -> String {
    match Fred::tags_series(&to_tag("cpi", country)) {
    pub fn generic_cpi_series_spec(country: Country) -> SeriesItems {
    /// println!("{}", generic_cpi_series_spec(Country::NewZealand, "cpi_series.keytree"));
    use crate::{
    DataType,
    SeriesId,
    };
  • file move: serve_ui.rs (-xw-xw-x--)ui.rs (-xw-xw-x--)
    [3.6]
    [3.14]
  • edit in src/ui.rs at line 16
    [3.364]
    [3.364]
    DataSpec,
  • edit in src/ui.rs at line 20
    [3.31][2.78:134]()
    };
    use crate::check_data::{
    IndexedCheckedDataSpec,
  • replacement in src/ui.rs at line 85
    [2.1478][2.1478:1522]()
    data_spec: &IndexedCheckedDataSpec,
    [2.1478]
    [2.1522]
    data_spec: &DataSpec,
  • replacement in src/ui.rs at line 87
    [2.1572][2.1572:1579]()
    {
    [2.1572]
    [2.1579]
    {
  • replacement in src/ui.rs at line 145
    [2.1943][2.1943:1987]()
    data_spec: &IndexedCheckedDataSpec,
    [2.1943]
    [2.1987]
    data_spec: &DataSpec,
  • replacement in src/ui.rs at line 210
    [2.2875][2.2875:2914]()
    data: &IndexedCheckedDataSpec,
    [2.2875]
    [2.2914]
    data: &DataSpec,
  • replacement in src/ui.rs at line 312
    [2.4905][2.4905:4944]()
    data: &IndexedCheckedDataSpec,
    [2.4905]
    [2.4944]
    data_spec: &DataSpec,
  • replacement in src/ui.rs at line 315
    [2.5014][2.5014:5113]()
    data.time_series_data(
    self.series_id.clone(),
    root_path
    )
    [2.5014]
    [2.5113]
    let series_spec = data_spec.get_series_spec(&self.series_id);
    series_spec.time_series_data(root_path)
  • file move: serve_ts.rs (-xw-xw-x--)ts.rs (-xw-xw-x--)
    [3.6]
    [3.7119]
  • edit in src/ts.rs at line 20
    [2.5266]
    [2.5266]
    DataSpec,
  • edit in src/ts.rs at line 23
    [2.5294]
    [2.5294]
    SeriesMetaData,
  • edit in src/ts.rs at line 27
    [3.78][3.78:81](),[3.81][3.7929:7954](),[3.7929][3.7929:7954](),[3.7954][3.82:110](),[3.110][3.7975:7995](),[3.7975][3.7975:7995]()
    };
    use crate::check_data::{
    IndexedCheckedDataSpec,
    SeriesMetaData,
  • replacement in src/ts.rs at line 77
    [3.727][3.727:771]()
    data_spec: &IndexedCheckedDataSpec,
    [3.727]
    [3.771]
    data_spec: &DataSpec,
  • edit in src/ts.rs at line 82
    [3.869]
    [3.869]
  • edit in src/ts.rs at line 88
    [2.5367]
    [3.1002]
  • edit in src/ts.rs at line 98
    [3.986][3.1242:2151]()
    // // We don't want to pass off responsibility to the struct's components, as we need
    // // to use the h HashMap, so we loop down to series.
    // /// Build from a `TSSpec`.
    // pub fn new(ts_spec: TSSpec, data_spec: IndexCheckedDataSpec) -> Self {
    // let ts_spec = TSSpec::from_file("ts_spec.keytree");
    // // loop through pages in ts_spec
    // let page_json = PageJson::new(
    // let h: HashMap<String, usize> = HashMap::new();
    // for (i, series) in data_spec.0.enumerate() {
    // for series
    // h.insert(series.id, i);
    // }
    // let ts:
    // let mut builder = TSJson(HashMap::new());
    // for ts_page in ts_spec.pages() {
    // let page_json = ts_page.to_page_json()
    // builder.insert(page_json.key(), page_json);
    // }
    //
    // PageJson(builder)
    // }
  • edit in src/ts.rs at line 126
    [2.5407]
    [2.5407]
    /// data_type: u
  • edit in src/ts.rs at line 142
    [3.1699]
    [3.1699]
    #[derive(Debug)]
  • edit in src/ts.rs at line 146
    [3.1752]
    [3.2256]
    ///
    pub data_type: DataType,
  • edit in src/ts.rs at line 159
    [3.2390]
    [2.5831]
    data_type: key.data_type,
  • edit in src/ts.rs at line 172
    [3.2546]
    [2.5989]
    data_type: self.data_type,
  • replacement in src/ts.rs at line 184
    [3.2176][3.2176:2243]()
    kt.push_keyvalue(1, "country", &self.country.to_string());
    [3.2176]
    [3.9348]
    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());
  • edit in src/ts.rs at line 200
    [2.6080]
    [2.6080]
    data_type: self.value("page::data_type")?,
  • edit in src/ts.rs at line 223
    [2.6525]
    [3.9937]
    #[derive(Debug)]
  • replacement in src/ts.rs at line 226
    [3.2714][3.2714:2754]()
    /// Heigh in pixels of the graphic.
    [3.2714]
    [3.9964]
    /// Height in pixels of the graphic.
  • replacement in src/ts.rs at line 248
    [3.2932][3.2932:2976]()
    data_spec: &IndexedCheckedDataSpec,
    [3.2932]
    [3.2976]
    data_spec: &DataSpec,
  • replacement in src/ts.rs at line 254
    [3.3095][2.6689:6726]()
    for series in &self.series {
    [3.3095]
    [3.3139]
    for (series_id, _) in &data_spec.reverse {
  • replacement in src/ts.rs at line 256
    [3.3140][2.6727:6814](),[2.6814][3.3220:3221](),[3.3220][3.3220:3221](),[3.3221][2.6815:6884]()
    let ts = data_spec.time_series_data(series.series_id.clone(), root_path)?;
    let meta = data_spec.meta(&series.series_id, root_path);
    [3.3140]
    [3.3294]
    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);
  • replacement in src/ts.rs at line 279
    [3.10508][3.10508:10572]()
    kt.push_keyvalue(1, "height", &height.to_string());
    [3.10508]
    [3.10572]
    kt.push_value(1, "height", &height.to_string());
  • edit in src/ts.rs at line 281
    [3.10583][3.10583:10617]()
    kt.push_key(1, "series");
  • replacement in src/ts.rs at line 282
    [2.6922][2.6922:6972]()
    kt.push_keytree(2, series.keytree());
    [2.6922]
    [3.10698]
    kt.push_keytree(1, series.keytree());
  • edit in src/ts.rs at line 307
    [2.7185]
    [2.7185]
    #[derive(Debug)]
  • replacement in src/ts.rs at line 342
    [2.7946][2.7946:8088]()
    kt.push_keyvalue(1, "data_type", &self.data_type.to_string());
    kt.push_keyvalue(1, "series_id", &self.series_id.to_string());
    [2.7946]
    [2.8088]
    kt.push_value(1, "data_type", &self.data_type.to_string());
    kt.push_value(1, "series_id", &self.series_id.to_string());
  • replacement in src/ts.rs at line 408
    [3.4507][2.8410:8436]()
    pub country: Country,
    [3.4507]
    [3.4508]
    pub country: Country,
  • edit in src/ts.rs at line 410
    [3.4516]
    [2.8437]
    pub data_type: DataType,
    ///
  • replacement in src/ts.rs at line 417
    [2.8509][2.8509:8601]()
    pub fn new(country: Country, index: usize) -> Self {
    PageKey { country, index }
    [2.8509]
    [2.8601]
    pub fn new(country: Country, data_type: DataType, index: usize) -> Self {
    PageKey { country, data_type, index }
  • edit in src/ts.rs at line 428
    [2.8659]
    [3.2299]
    data_type: self.value("key::data_type")?,
  • replacement in src/main.rs at line 9
    [2.8799][3.12577:12605](),[3.12577][3.12577:12605](),[3.12605][2.8800:8880]()
    use ui_data::build_spec::*;
    use ui_data::check_data::*;
    use ui_data::serve_ts::*;
    use ui_data::serve_ui::*;
    [2.8799]
    [3.110]
    use ui_data::ts::*;
    use ui_data::ui::*;
  • replacement in src/main.rs at line 15
    [3.9637][2.8936:9118]()
    // Read in the data specification.
    let data_spec = CheckedDataSpec::from_file("checked_data.keytree").into_indexed();
    let ts_spec = TSSpec::from_file("ts_spec.keytree");
    [3.9637]
    [3.10087]
    let spec = DataSpec::from_file("source_data.keytree");
    println!("{}", spec.keytree());
    }
  • edit in src/main.rs at line 20
    [3.10088][2.9119:9179](),[3.11873][3.292:294](),[3.1553][3.292:294](),[3.150][3.292:294](),[3.3051][3.292:294](),[3.1266][3.292:294](),[3.351][3.292:294](),[3.797][3.292:294](),[2.9179][3.292:294](),[3.10186][3.292:294](),[3.12788][3.292:294](),[3.87][3.292:294](),[3.292][3.292:294]()
    let ts_json = ts_spec.into_json(&data_spec, &root_dir);
    }
  • replacement in src/lib.rs at line 33
    [3.12570][2.9467:9526]()
    //! println!("{}", build_generic_data_spec().keytree());
    [3.12570]
    [3.12621]
    //! println!("{}", generic_data_spec().keytree());
  • edit in src/lib.rs at line 64
    [3.5474][2.9527:9584]()
    //! ## Step 3. Check the data in the data specification.
  • replacement in src/lib.rs at line 65
    [3.12793][3.5511:6126](),[3.6126][2.9585:9648]()
    //! The saved data will look something like
    //! ```text
    //! seriess:
    //! series:
    //! data_type: u
    //! country: Australia
    //! id: AUSURAMS
    //! error: ok
    //! time_stamp: 2021-06-20 9:33:39
    //! series:
    //! data_type: u
    //! country: Australia
    //! id: AUSURANAA
    //! error: ok
    //! time_stamp: 2021-06-20 9:33:41
    //! series:
    //! data_type: u
    //! country: Australia
    //! id: AUSURAQS
    //! error: ok
    //! time_stamp: 2021-06-20 9:33:42
    //! ```
    //! Check each data series, to see if the data is well-formed.
    [3.12793]
    [2.9648]
    //! ## Step 3. Use the data specification to write data to file.
  • replacement in src/lib.rs at line 67
    [2.9656][2.9656:9759]()
    //! let spec = DataSpec::from_file("source_data.keytree");
    //! println!("{}", spec.check().keytree());
    [2.9656]
    [2.9759]
    //! let checked = DataSpec::from_file("source_data.keytree");
    //! source.write("/full/path/to/data");
  • edit in src/lib.rs at line 70
    [2.9767][2.9767:9828]()
    //! Save the output specification in `checked_data.keytree`.
  • edit in src/lib.rs at line 71
    [3.12877][2.9829:9894](),[3.6167][3.12975:12979](),[2.9894][3.12975:12979](),[3.12917][3.12975:12979](),[3.12975][3.12975:12979](),[3.6221][3.6221:6229](),[3.6229][2.9895:10018]()
    //! ## Step 4. Use the data specification to write data to file.
    //!
    //! ```
    //! let checked = CheckedDataSpec::from_file("checked_data.keytree");
    //! checked.write("/full/path/to/data");
    //! ```
    //!
  • replacement in src/lib.rs at line 73
    [3.6383][2.10072:10144]()
    //! checked.resume_write(Series::new("GBRURNAA"), "/full/path/to/data")
    [3.6383]
    [2.10144]
    //! source.resume_write(Series::new("GBRURNAA"), "/full/path/to/data")
  • replacement in src/lib.rs at line 82
    [2.10363][2.10363:10405]()
    //! ```text
    //! checked.generic_ts_spec()
    [2.10363]
    [3.6636]
    //! ```
    //! let data_spec = DataSpec::from_file("checked_data.keytree").into_indexed();
    //! println!("{}", data_spec.generic_ts_spec().keytree());
  • replacement in src/lib.rs at line 119
    [3.7802][3.13208:13228](),[3.799][3.13208:13228](),[3.13228][3.7803:7808](),[3.7808][3.13165:13185](),[3.13228][3.13165:13185](),[3.13165][3.13165:13185](),[3.13185][3.7809:7810]()
    pub mod build_spec;
    ///
    pub mod check_data;
    [3.7802]
    [3.7810]
    pub mod fred;
  • replacement in src/lib.rs at line 122
    [3.7829][3.7829:7830]()
    [3.7829]
    [3.7830]
    ///
    pub mod ts;
  • replacement in src/lib.rs at line 125
    [3.7834][3.13229:13247](),[3.13185][3.13229:13247]()
    pub mod serve_ts;
    [3.7834]
    [3.7835]
    pub mod ui;
  • replacement in src/lib.rs at line 127
    [3.7836][3.4180:4198](),[3.4198][3.10717:10718](),[3.13268][3.10717:10718](),[3.10717][3.10717:10718]()
    pub mod serve_ui;
    [3.7836]
    [3.10718]
    use std::collections::BTreeMap;
    use std::convert::TryInto;
  • edit in src/lib.rs at line 130
    [3.10732]
    [3.2353]
    use std::fs;
  • edit in src/lib.rs at line 135
    [3.478]
    [3.478]
    use countries::Country;
  • edit in src/lib.rs at line 137
    [3.498]
    [3.2377]
    use keytree::{
    KeyTree,
    KeyTreeRef,
    };
    use keytree::serialize::{
    IntoKeyTree,
    KeyTreeString,
    };
    use time_series::{
    RegularTimeSeries,
    TimeSeries,
    };
  • edit in src/lib.rs at line 152
    [3.2424]
    [3.2424]
    use crate::ts::{
    PageKey,
    TSGraphicSpec,
    TSPageSpec,
    TSSeriesSpec,
    TSSpec,
    };
  • replacement in src/lib.rs at line 188
    [3.2902][2.11169:11225]()
    #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)]
    [3.2902]
    [3.2902]
    #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
  • replacement in src/lib.rs at line 213
    [2.11502][3.10809:10867](),[3.1795][3.10809:10867]()
    /// Unemployment rate, Interest rate, Inflation rate etc.
    [2.11502]
    [2.11503]
    /// Unemployment rate, interest rate, inflation rate etc.
  • edit in src/lib.rs at line 253
    [3.15904][3.12136:12137]()
  • edit in src/lib.rs at line 283
    [3.12089]
    [3.2482]
    }
    // Its better for DataSpec to be a Vec, but we need to index into the Vec, so
    // we wrap it with an index.
    /// A generic specification of all data series. Output looks like
    /// ```
    /// series:
    /// data_type: u
    /// country: United States
    /// id: LRUNTTTTUSQ156S
    /// ```
    pub struct DataSpec {
    map: BTreeMap<(DataType, Country), Vec<SeriesSpec>>,
    reverse: BTreeMap<SeriesId, (DataType, Country)>,
    }
    impl DataSpec {
    /// Get a `SeriesSpec` from a `SeriesId`.
    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()
    }
    ///
    pub fn append(&mut self, other: &mut DataSpec) {
    self.map.append(&mut other.map);
    self.reverse.append(&mut other.reverse);
    }
    ///
    pub fn new() -> Self {
    DataSpec {
    map: BTreeMap::new(),
    reverse: BTreeMap::new(),
    }
    }
    /// Return a `DataSpec` built from a collection of `SeriesSpec`.
    pub fn from_vec(v: Vec<SeriesSpec>) -> Self {
    let mut data_spec = DataSpec::new();
    for series_spec in v {
    data_spec.insert(&series_spec);
    }
    data_spec
    }
    /// Insert a `SeriesSpec`.
    pub fn insert(&mut self, series_spec: &SeriesSpec) {
    match self.map.get_mut(&(series_spec.data_type, series_spec.country)) {
    None => {
    self.map.insert(
    (series_spec.data_type, series_spec.country),
    vec!(series_spec.clone())
    );
    self.reverse.insert(
    series_spec.series_id.clone(),
    (series_spec.data_type, series_spec.country),
    );
    },
    Some(value) => {
    value.push(series_spec.clone());
    self.reverse.insert(
    series_spec.series_id.clone(),
    (series_spec.data_type, series_spec.country),
    );
    },
    }
    }
    /// Build a generic `TSSpec` from `Self`.
    pub fn generic_ts_spec(&self) -> TSSpec {
    let mut ts_spec = TSSpec::new();
    for ((data_type, country), series_specs) in self.map.iter() {
    let mut ts_graphic_spec = TSGraphicSpec::new();
    for series_spec in series_specs {
    let ts_series_spec = TSSeriesSpec::new(
    series_spec.data_type,
    series_spec.series_id.clone()
    );
    ts_graphic_spec.push(ts_series_spec);
    };
    let page_key = PageKey::new(*country, *data_type, 0);
    let ts_page_spec = TSPageSpec::new(page_key, vec!(ts_graphic_spec));
    ts_spec.push(ts_page_spec);
    }
    ts_spec
    }
    // /// Append `other` to `Self`.
    // pub fn append(&mut self, other: &mut DataSpec) {
    // self.0.append(&mut other.0)
    // }
    // fn series_from_index(&self, i: usize) -> &Series {
    // &self.0[i]
    // }
    /// Read in keytree data from file.
    pub fn from_file(path: &str) -> Self {
    let source_spec = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&source_spec).unwrap();
    kt.to_ref().try_into().unwrap()
    }
    /// Save FRED data to disk as csv, using full path. Will fail if an existing filepath is
    /// encountered.
    /// ```
    /// let mut source = DataSpec::from_file("checked_data.keytree");
    /// source.write(&root_dir);
    /// ```
    /// To path from root is "/{data_type}/{country}/LRUNTTTTSIQ156S.csv"
    ///
    pub fn write(&self, root_path: &str) {
    for (series_id, _) in &self.reverse {
    let series_spec = self.get_series_spec(&series_id);
    series_spec.write_data(root_path);
    series_spec.write_meta(root_path);
    }
    }
    /// Same as `write()` except that it starts in the specification at `series_id`. Useful if there
    /// is a break in the connection when writing.
    pub fn resume_write(&self, series_id: SeriesId, root_path: &str) {
    for (series_id, _) in self.reverse.iter().skip_while(|(id, _)| id != &&series_id) {
    let series_spec = self.get_series_spec(series_id);
    series_spec.write_data(root_path);
    series_spec.write_meta(root_path);
    }
    }
  • edit in src/lib.rs at line 424
    [3.2484]
    [3.12090]
    impl<'a> TryInto<DataSpec> for KeyTreeRef<'a> {
    type Error = keytree::Error;
  • edit in src/lib.rs at line 429
    [3.12091]
    fn try_into(self) -> Result<DataSpec, Self::Error> {
    let v: Vec<SeriesSpec> = self.vec_at("series::series")?;
    Ok(DataSpec::from_vec(v))
    }
    }
    impl IntoKeyTree for DataSpec {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "seriess");
    for (series_id, _) in &self.reverse {
    let series_spec = self.get_series_spec(series_id);
    kt.push_keytree(1, series_spec.keytree());
    }
    kt
    }
    }
    ///
    #[derive(Clone)]
    pub struct SeriesSpec {
    ///
    pub data_type: DataType,
    ///
    pub country: Country,
    ///
    pub series_id: SeriesId,
    ///
    pub drop_first: Option<usize>,
    }
    impl SeriesSpec {
    /// Return the meta data for a `SeriesSpec`.
    pub fn meta(&self, root_path: &str) -> SeriesMetaData {
    let path = &format!(
    "{}/{}/{}/{}.meta",
    root_path,
    self.data_type,
    self.country.as_path(),
    self.series_id,
    );
    let meta_str = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&meta_str).unwrap();
    kt.to_ref().try_into().unwrap()
    }
    /// Return the time-series data for `series_id`.
    pub fn time_series_data(&self, root_path: &str) -> Result<RegularTimeSeries<1>, Error> {
    let path = &format!(
    "{}/{}/{}/{}.csv",
    root_path,
    self.data_type,
    self.country.as_path(),
    self.series_id,
    );
    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())),
    }
    },
    Err(err) => Err(from_time_series(&err.to_string())),
    }
    }
    /// Fetches data as specified in `checked_data.keytree` and saves to disk.
    pub fn write_data(&self, root_path: &str) {
    // 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');
    }
    let dir_path = &format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    self.country.as_path(),
    );
    let filename = &format!(
    "{}/{}.csv",
    dir_path,
    self.series_id,
    );
    fs::create_dir_all(&dir_path).unwrap();
    println!("Writing {}", filename);
    fs::write(filename, &data).unwrap();
    }
    /// Fetches data as specified in `checked_data.keytree` and saves meta_data to disk.
    pub fn write_meta(&self, root_path: &str) {
    let meta = match Fred::series(&self.series_id.to_string()) {
    Ok(series) => {
    let series_item = series.seriess.iter().next().unwrap();
    SeriesMetaData {
    realtime: series.realtime_start.clone(),
    series_id: self.series_id.clone(),
    title: series_item.title.clone(),
    observation_start: series_item.observation_start.clone(),
    observation_end: series_item.observation_end.clone(),
    frequency: series_item.frequency.clone(),
    seasonal_adjustment: series_item.seasonal_adjustment.clone(),
    }
    },
    Err(err) => {
    println!("{}", err);
    panic! ();
    },
    };
    let dir_path = &format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    self.country.as_path(),
    );
    let filename = &format!(
    "{}/{}.meta",
    dir_path,
    self.series_id,
    );
    fs::create_dir_all(&dir_path).unwrap();
    println!("Writing {}", filename);
    fs::write(filename, &meta.keytree().to_string()).unwrap();
    }
    }
    impl IntoKeyTree for SeriesSpec {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "series");
    kt.push_value(1, "data_type", &self.data_type);
    kt.push_value(1, "country", &self.country);
    kt.push_value(1, "series_id", &self.series_id);
    kt.push_opt_value(1, "drop_first", self.drop_first);
    kt
    }
    }
    impl<'a> TryInto<SeriesSpec> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<SeriesSpec, keytree::Error> {
    Ok(
    SeriesSpec{
    data_type: self.value("series::data_type")?,
    country: self.value("series::country")?,
    series_id: self.value("series::series_id")?,
    drop_first: self.opt_value("series::drop_first")?,
    }
    )
    }
    }
    /// Source meta-data is stored in a file as a String:
    ///
    /// ```text
    /// series:
    /// realtime_start: 2021-06-03
    /// realtime_end: 2021-06-03
    /// series_items:
    /// series_item:
    /// realtime: 2021-06-03
    /// series_id: AUSCPALTT01IXNBQ
    /// title: Consumer Price Index: All items: Total: Total for Australia
    /// observation_start: 1960-01-01
    /// observation_end: 2021-01-01
    /// frequency: Quarterly
    /// seasonal_adjustment: Not Seasonally Adjusted
    /// notes: (see JSON data for notes)
    /// ```
    #[derive(Debug, Serialize)]
    pub struct SeriesMetaData {
    realtime: String,
    series_id: SeriesId,
    title: String,
    observation_start: String,
    observation_end: String,
    frequency: String,
    seasonal_adjustment: String,
    }
    impl SeriesMetaData {
    ///
    pub fn from_file(
    data_type: DataType,
    country: Country,
    series_id: SeriesId,
    root_path: &str) -> Result<Self, Error>
    {
    let path = &format!(
    "{}/{}/{}/{}.meta",
    root_path,
    data_type,
    country,
    series_id,
    );
    let meta_str = fs::read_to_string(&path).unwrap();
    let kt = KeyTree::parse(&meta_str).unwrap();
    Ok(kt.to_ref().try_into().unwrap())
    }
    }
    impl<'a> TryInto<SeriesMetaData> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<SeriesMetaData, Self::Error> {
    Ok(
    SeriesMetaData {
    realtime: self.value("series_meta::realtime")?,
    series_id: self.value("series_meta::series_id")?,
    title: self.value("series_meta::title")?,
    observation_start: self.value("series_meta::observation_start")?,
    observation_end: self.value("series_meta::observation_end")?,
    frequency: self.value("series_meta::frequency")?,
    seasonal_adjustment: self.value("series_meta::seasonal_adjustment")?,
    }
    )
    }
    }
    impl IntoKeyTree for SeriesMetaData {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "series_meta");
    kt.push_value(1, "realtime", &self.realtime);
    kt.push_value(1, "series_id", &self.series_id.to_string());
    kt.push_value(1, "title", &self.title);
    kt.push_value(1, "observation_start", &self.observation_start);
    kt.push_value(1, "observation_end", &self.observation_end);
    kt.push_value(1, "frequency", &self.frequency);
    kt.push_value(1, "seasonal_adjustment", &self.seasonal_adjustment);
    kt
    }
    }
    // self.time_stamp = Some(TimeStamp::now());
  • replacement in src/check_data.rs at line 44
    [3.8234][3.13522:13567](),[3.13522][3.13522:13567]()
    pub fn check(&self) -> CheckedDataSpec {
    [3.8234]
    [3.13567]
    pub fn into_checked(&self) -> CheckedDataSpec {
  • replacement in src/check_data.rs at line 48
    [3.13529][2.11814:11934](),[2.11934][3.13530:13557](),[3.13753][3.13530:13557](),[3.13557][3.13785:13848](),[3.13785][3.13785:13848](),[3.13848][2.11935:12172](),[2.12172][3.13558:13600](),[3.14061][3.13558:13600](),[3.13600][3.14061:14248](),[3.14061][3.14061:14248](),[3.14248][2.12173:12409](),[2.12409][3.13601:13643](),[3.14460][3.13601:13643](),[3.13643][3.14460:14567](),[3.14460][3.14460:14567]()
    println!("{}", series_spec.series_id);
    match Fred::series(&series_spec.series_id.to_string()) {
    Ok(_) => {
    let checked_series = CheckedSourceSeries {
    data_type: series_spec.data_type,
    country: series_spec.country,
    series_id: series_spec.series_id.clone(),
    error: "ok".to_string(),
    time_stamp: None,
    };
    builder.0.push(checked_series);
    },
    Err(err) => {
    let checked_series = CheckedSourceSeries {
    data_type: series_spec.data_type,
    country: series_spec.country,
    series_id: series_spec.series_id.clone(),
    error: err.to_string(),
    time_stamp: None,
    };
    builder.0.push(checked_series);
    }
    }
    [3.13529]
    [3.14567]
    let checked_series = CheckedSourceSeries {
    data_type: series_spec.data_type,
    country: series_spec.country,
    series_id: series_spec.series_id.clone(),
    drop_first: None,
    };
    builder.0.push(checked_series);
  • edit in src/check_data.rs at line 60
    [3.8244][3.8244:8482](),[3.8482][2.12410:12448](),[2.12448][3.8518:8551](),[3.8518][3.8518:8551]()
    // Its better for CheckedDataSpec to be a Vec, but we need to index into the Vec, so
    // we wrap it with an index.
    /// `CheckedDataSpec` wrapped in an index for faster lookup.
    pub struct IndexedCheckedDataSpec {
    data: CheckedDataSpec,
    index: HashMap<SeriesId, usize>,
    }
    impl IndexedCheckedDataSpec {
  • edit in src/check_data.rs at line 61
    [2.12450][2.12450:14782](),[2.14782][3.8551:8552](),[3.8551][3.8551:8552](),[3.8552][2.14783:14996](),[2.14996][3.8552:8649](),[3.8552][3.8552:8649](),[3.8649][2.14997:15026](),[2.15026][3.8676:8847](),[3.8676][3.8676:8847](),[3.8847][2.15027:15133](),[2.15133][3.8941:9099](),[3.8941][3.8941:9099](),[3.9099][3.3441:3465](),[3.3465][2.15134:15227](),[2.15227][3.3546:3560](),[3.3546][3.3546:3560](),[3.3560][3.9233:9366](),[3.9233][3.9233:9366](),[3.9366][2.15228:15274](),[2.15274][3.9402:9505](),[3.9402][3.9402:9505](),[3.9505][2.15275:15369](),[3.3644][3.9637:9700](),[2.15369][3.9637:9700](),[3.9637][3.9637:9700](),[3.9700][2.15370:15452](),[2.15452][3.9779:10118](),[3.9779][3.9779:10118](),[3.10118][2.15453:15485](),[2.15485][3.10149:10210](),[3.10149][3.10149:10210](),[3.10210][2.15486:15532](),[2.15532][3.10246:10432](),[3.10246][3.10246:10432](),[3.10432][3.14593:14602](),[3.14593][3.14593:14602]()
    /// Get data_type and country of a given series_id.
    pub (crate) fn get(&self, series_id: SeriesId) -> (DataType, Country) {
    let index = self.index.get(&series_id).unwrap();
    let data_type = self.data.0[*index].data_type;
    let country = self.data.0[*index].country;
    (data_type, country)
    }
    /// Return a generic time-series graphics specification.
    ///
    /// ```text
    /// ts_spec:
    /// page:
    /// country: Australia
    /// 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
    /// ```
    /// TSSpec
    /// TSPageSpec
    /// country
    /// index
    /// TSGraphicSpec
    /// height
    /// TSSeriesSpec
    ///
    /// IndexedCheckedDataSpec
    /// CheckedDataSpec
    /// CheckedSourceSeries
    /// DataType
    /// Country
    /// SeriesId
    ///
    pub fn generic_ts_spec(&self) -> TSSpec {
    let mut map: BTreeMap<(DataType, Country), Vec<SeriesId>> = BTreeMap::new();
    for (series_id, _) in self.index.iter() {
    let (data_type, country) = self.get(series_id.clone());
    match map.get_mut(&(data_type, country)) {
    Some(value) => value.push(series_id.clone()),
    None => {
    map.insert((data_type, country), vec!(series_id.clone()));
    },
    };
    }
    // build TSSpec
    let ts_spec = TSSpec::new();
    for ((data_type, country), series_ids) in map {
    let mut ts_spec = TSSpec::new();
    let mut ts_graphic_spec = TSGraphicSpec::new();
    for series_id in series_ids {
    let ts_series_spec = TSSeriesSpec::new(data_type, series_id);
    ts_graphic_spec.push(ts_series_spec);
    };
    let page_key = PageKey::new(country, 0);
    let mut ts_page_spec = TSPageSpec::new(page_key, vec!(ts_graphic_spec));
    ts_spec.push(ts_page_spec);
    };
    ts_spec
    }
    /// Return the time-series data for `series_id`.
    pub fn time_series_data(
    &self,
    series_id: SeriesId,
    root_path: &str) -> Result<RegularTimeSeries<1>, Error>
    {
    let i = match self.index.get(&series_id) {
    Some(i) => i,
    None => {
    println!("Series {} not found in IndexedCheckedDataSpec::index.", series_id.to_string());
    panic!();
    },
    };
    let checked_series = self.data.series_from_index(*i);
    if checked_series.error != "ok" {
    return Err(
    spec_has_error_status(&series_id.to_string(), &checked_series.error.clone())
    )
    };
    let path = &format!(
    "{}/{}/{}/{}.csv",
    root_path,
    checked_series.data_type,
    checked_series.country.as_path(),
    series_id,
    );
    Ok(
    TimeSeries::<1>::from_csv(&path).try_into()
    .map_err(|_| time_series_not_regular(&checked_series.series_id.to_string()))?
    )
    }
    /// Return the meta-data for `series_id`.
    pub fn meta(&self, series_id: &SeriesId, root_path: &str) -> SeriesMetaData {
    let i = match self.index.get(&series_id) {
    Some(i) => i,
    None => {
    println!("Series {} not found in IndexedCheckedDataSpec::index.", series_id);
    panic!();
    },
    };
    let checked_series = self.data.series_from_index(*i);
    let path = &format!(
    "{}/{}/{}/{}.meta",
    root_path,
    checked_series.data_type,
    checked_series.country.as_path(),
    series_id,
    );
    let meta_str = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&meta_str).unwrap();
    kt.to_ref().try_into().unwrap()
    }
    }
  • edit in src/check_data.rs at line 69
    [3.13746][3.14779:14803](),[3.14779][3.14779:14803](),[3.10434][3.10434:10527](),[3.10527][3.14803:15050](),[3.14803][3.14803:15050](),[3.15050][2.15533:15801](),[2.15801][3.15059:15060](),[3.15059][3.15059:15060](),[3.15060][3.13747:13873](),[3.13873][2.15802:15914](),[2.15914][3.13915:14010](),[3.13915][3.13915:14010](),[3.14010][2.15915:16316](),[2.16316][3.14057:14058](),[3.14057][3.14057:14058](),[3.14058][2.16317:16451](),[2.16451][3.14094:14189](),[3.14094][3.14094:14189](),[3.14230][3.10528:10658](),[3.10658][2.16452:16514](),[2.16514][3.10718:10773](),[3.10718][3.10718:10773](),[3.10773][2.16515:16566](),[2.16566][3.10817:10915](),[3.10817][3.10817:10915](),[3.10915][3.14230:14236](),[3.14230][3.14230:14236](),[3.15413][3.15413:15415]()
    impl CheckedDataSpec {
    fn series_from_index(&self, i: usize) -> &CheckedSourceSeries {
    &self.0[i]
    }
    /// Read in keytree data from file.
    pub fn from_file(path: &str) -> Self {
    let source_spec = fs::read_to_string(path).unwrap();
    let kt = KeyTree::parse(&source_spec).unwrap();
    kt.to_ref().try_into().unwrap()
    }
    // We need to change the arrangement. We update the checked_data.keytree from files. We have a
    // resume function which takes the same checked_data.keytree and writes from a SeriesId. We have
    // another function with goes through the files to update the time-stamp.
    /// Save FRED data to disk as csv, using full path. Will fail if an existing filepath is
    /// encountered.
    /// ```
    /// let mut checked = CheckedDataSpec::from_file("checked_data.keytree");
    /// checked.write(&root_dir);
    /// ```
    /// To path from root is "/{data_type}/{country}/LRUNTTTTSIQ156S.csv"
    ///
    pub fn write(&self, root_path: &str) {
    for series in &self.0 {
    series.write_data(root_path);
    series.write_meta(root_path);
    }
    }
    /// Same as `write()` except that it starts in the specification at `series_id`. Useful if there
    /// is a break in the connection when writing.
    pub fn resume_write(&self, series_id: SeriesId, root_path: &str) {
    for series in self.0.iter().skip_while( | checked |{
    checked.series_id != series_id
    })
    {
    series.write_data(root_path);
    series.write_meta(root_path);
    }
    }
    /// Wrap CheckedDataSpec with an index into its inner `Vec`.
    pub fn into_indexed(self) -> IndexedCheckedDataSpec {
    let mut h: HashMap<SeriesId, usize> = HashMap::new();
    for (i, series) in self.0.iter().enumerate() {
    h.insert(series.series_id.clone(), i);
    }
    IndexedCheckedDataSpec {
    data: self,
    index: h
    }
    }
    }
  • edit in src/check_data.rs at line 97
    [3.15677][3.11084:11085]()
  • edit in src/check_data.rs at line 99
    [3.15706][3.11094:11095]()
  • edit in src/check_data.rs at line 101
    [2.16630][3.11104:11199](),[3.15734][3.11104:11199](),[3.11199][3.15734:15762](),[3.15734][3.15734:15762](),[3.15762][3.11200:11201]()
    /// Used to track problems and to check that data is consistent before serving to client.
    pub error: String,
  • replacement in src/check_data.rs at line 102
    [3.11209][3.3707:3746]()
    pub time_stamp: Option<TimeStamp>,
    [3.11209]
    [3.3746]
    pub drop_first: Option<usize>,
  • edit in src/check_data.rs at line 105
    [3.3749][3.3749:3834]()
    /// A timestamp.
    #[derive(Clone, Debug)]
    pub struct TimeStamp(time::OffsetDateTime);
  • edit in src/check_data.rs at line 106
    [3.3835][3.3835:4313](),[3.4313][3.15815:15845](),[3.11259][3.15815:15845](),[3.15815][3.15815:15845](),[3.15845][3.3687:3688](),[3.15846][3.15846:15925](),[3.15925][2.16631:16679](),[2.16679][3.15977:16042](),[3.15977][3.15977:16042](),[3.16042][2.16680:16770](),[2.16770][3.16113:16765](),[3.16113][3.16113:16765](),[3.16765][2.16771:16803](),[2.16803][3.16790:16805](),[3.16790][3.16790:16805](),[3.4368][3.16868:16950](),[3.11346][3.16868:16950](),[3.16868][3.16868:16950](),[3.16950][2.16804:16851](),[2.16851][3.16950:17105](),[3.16950][3.16950:17105](),[3.17105][2.16852:16900](),[2.16900][3.17157:17158](),[3.17157][3.17157:17158](),[3.17158][2.16901:16970](),[2.16970][3.17208:17418](),[3.17208][3.17208:17418](),[3.17418][2.16971:17039](),[2.17039][3.17479:18261](),[3.17479][3.17479:18261](),[3.18261][2.17040:17068](),[2.17068][3.18282:18342](),[3.18282][3.18282:18342](),[3.18342][2.17069:17111](),[2.17111][3.18342:18415](),[3.18342][3.18342:18415](),[3.18415][3.16027:16030](),[3.16027][3.16027:16030]()
    impl TimeStamp {
    fn format(self, format: &str) -> String {
    self.0.format(format)
    }
    fn now() -> Self {
    let inner = OffsetDateTime::now_utc();
    TimeStamp(inner)
    }
    }
    impl FromStr for TimeStamp {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
    match OffsetDateTime::parse(s, "%Y %T") {
    Ok(stamp) => Ok(TimeStamp(stamp)),
    Err(_) => Err(parse_timestamp(s)),
    }
    }
    }
    impl CheckedSourceSeries {
    /// Fetches data as specified in `checked_data.keytree` and saves to disk.
    pub fn write_data(&self, root_path: &str) {
    // 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');
    }
    if &self.error == "ok" {
    let dir_path = &format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    self.country.as_path(),
    );
    let filename = &format!(
    "{}/{}.csv",
    dir_path,
    self.series_id,
    );
    fs::create_dir_all(&dir_path).unwrap();
    println!("Writing {}", filename);
    fs::write(filename, &data).unwrap();
    }
    }
    /// Fetches data as specified in `checked_data.keytree` and saves meta_data to disk.
    pub fn write_meta(&self, root_path: &str) {
    let meta = match Fred::series(&self.series_id.to_string()) {
    Ok(series) => {
    let series_item = series.seriess.iter().next().unwrap();
    SeriesMetaData {
    realtime: series.realtime_start.clone(),
    series_id: self.series_id.clone(),
    title: series_item.title.clone(),
    observation_start: series_item.observation_start.clone(),
    observation_end: series_item.observation_end.clone(),
    frequency: series_item.frequency.clone(),
    seasonal_adjustment: series_item.seasonal_adjustment.clone(),
    }
    },
    Err(err) => {
    println!("{}", err);
    panic! ();
    },
    };
    let dir_path = &format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    self.country.as_path(),
    );
    let filename = &format!(
    "{}/{}.meta",
    dir_path,
    self.series_id,
    );
    fs::create_dir_all(&dir_path).unwrap();
    println!("Writing {}", filename);
    fs::write(filename, &meta.keytree().to_string()).unwrap();
    }
    }
  • replacement in src/check_data.rs at line 110
    [3.16191][3.16191:16329](),[3.16329][2.17112:17183](),[2.17183][3.16374:16425](),[3.16374][3.16374:16425](),[3.16425][3.18416:18467](),[3.18467][3.4369:4421](),[3.4421][3.18511:18613](),[3.18511][3.18511:18613]()
    kt.push_keyvalue(1, "data_type", &self.data_type.to_string());
    kt.push_keyvalue(1, "country", &self.country.to_string());
    kt.push_keyvalue(1, "series_id", &self.series_id.to_string());
    kt.push_keyvalue(1, "error", &self.error);
    let time_stamp = match &self.time_stamp {
    Some(ts) => ts.clone().format("%F %T"),
    None => String::new(),
    };
    kt.push_keyvalue(1, "time_stamp", &time_stamp);
    [3.16191]
    [3.16425]
    kt.push_value(1, "data_type", &self.data_type.to_string());
    kt.push_value(1, "country", &self.country.to_string());
    kt.push_value(1, "series_id", &self.series_id.to_string());
    kt.push_opt_value(1, "drop_first", self.drop_first);
  • replacement in src/check_data.rs at line 136
    [2.17314][3.4829:4962](),[3.4829][3.4829:4962](),[3.4962][3.17066:17098](),[3.18917][3.17066:17098](),[3.17066][3.17066:17098](),[3.17098][3.18918:19201](),[3.19201][2.17315:17372](),[2.17372][3.19258:19648](),[3.19258][3.19258:19648](),[3.19648][2.17373:17401](),[2.17401][3.19669:19719](),[3.19669][3.19669:19719](),[3.19719][2.17402:17427](),[2.17427][3.19735:19874](),[3.19735][3.19735:19874](),[3.19874][3.11420:11529](),[3.11529][2.17428:17457](),[2.17457][3.11556:11939](),[3.11556][3.11556:11939](),[3.11939][3.19874:19929](),[3.19874][3.19874:19929](),[3.19929][3.11940:11973](),[3.11973][3.19953:19954](),[3.19953][3.19953:19954](),[3.19954][3.11974:12037](),[3.12037][3.20011:20052](),[3.20011][3.20011:20052](),[3.20052][3.4963:5041](),[3.5041][2.17458:17537](),[2.17537][3.5113:5528](),[3.5113][3.5113:5528]()
    error: self.value("series::error")?,
    time_stamp: self.opt_value("series::time_stamp")?,
    }
    )
    }
    }
    /// Source meta-data is stored in a file as a String:
    ///
    /// ```text
    /// series:
    /// realtime_start: 2021-06-03
    /// realtime_end: 2021-06-03
    /// series_items:
    /// series_item:
    /// realtime: 2021-06-03
    /// series_id: AUSCPALTT01IXNBQ
    /// title: Consumer Price Index: All items: Total: Total for Australia
    /// observation_start: 1960-01-01
    /// observation_end: 2021-01-01
    /// frequency: Quarterly
    /// seasonal_adjustment: Not Seasonally Adjusted
    /// notes: (see JSON data for notes)
    /// ```
    #[derive(Debug, Serialize)]
    pub struct SeriesMetaData {
    realtime: String,
    series_id: SeriesId,
    title: String,
    observation_start: String,
    observation_end: String,
    frequency: String,
    seasonal_adjustment: String,
    }
    impl SeriesMetaData {
    ///
    pub fn from_file(
    data_type: DataType,
    country: Country,
    series_id: SeriesId,
    root_path: &str) -> Result<Self, Error>
    {
    let path = &format!(
    "{}/{}/{}/{}.meta",
    root_path,
    data_type,
    country,
    series_id,
    );
    let meta_str = fs::read_to_string(&path).unwrap();
    let kt = KeyTree::parse(&meta_str).unwrap();
    Ok(kt.to_ref().try_into().unwrap())
    }
    }
    impl<'a> TryInto<SeriesMetaData> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<SeriesMetaData, Self::Error> {
    Ok(
    SeriesMetaData {
    realtime: self.value("series_meta::realtime")?,
    series_id: self.value("series_meta::series_id")?,
    title: self.value("series_meta::title")?,
    observation_start: self.value("series_meta::observation_start")?,
    observation_end: self.value("series_meta::observation_end")?,
    frequency: self.value("series_meta::frequency")?,
    seasonal_adjustment: self.value("series_meta::seasonal_adjustment")?,
    [2.17314]
    [3.20596]
    drop_first: self.opt_value("series::drop_first")?,
  • edit in src/check_data.rs at line 142
    [3.20629][3.20629:20848](),[3.20848][2.17538:17609](),[2.17609][3.20893:21249](),[3.20893][3.20893:21249](),[3.21249][2.17610:17666]()
    impl IntoKeyTree for SeriesMetaData {
    fn keytree(&self) -> KeyTreeString {
    let mut kt = KeyTreeString::new();
    kt.push_key(0, "series_meta");
    kt.push_keyvalue(1, "realtime", &self.realtime);
    kt.push_keyvalue(1, "series_id", &self.series_id.to_string());
    kt.push_keyvalue(1, "title", &self.title);
    kt.push_keyvalue(1, "observation_start", &self.observation_start);
    kt.push_keyvalue(1, "observation_end", &self.observation_end);
    kt.push_keyvalue(1, "frequency", &self.frequency);
    kt.push_keyvalue(1, "seasonal_adjustment", &self.seasonal_adjustment);
    kt
    }
    }
    // self.time_stamp = Some(TimeStamp::now());