Completed loading ts_data from specification.
[?]
Jul 13, 2021, 4:26 AM
SPSFTMLRZE2R4EBAAQKWBUZDRYZ36S2VFTBIJRE6XS7JMKELV4AQCDependencies
- [2]
UKQAGL5FChecked ts_json toolchain. - [3]
JTX5OHWHAdded USA CPI. - [4]
IKPVWWLKFilter unemployment rate series. - [5]
5POF332LWorking on fn cpi_included(). - [6]
4QOTH75IFixed UI specification code. - [7]
A6ZAYJNBDebugging DataSelector - [8]
UUD3CJZLMaking error handling more comprehensive. - [9]
XI5ALEH6Take advantage of keytree FromStr functionality. - [10]
SAHJYVNBRemoved checking functionality. - [11]
GQVS55HIFinished generate_ts_spec() function. - [12]
U4VCAFXQAdded data_type to TSSpec key. - [13]
2SABVMY3Finished into_json() functionality. - [14]
UCSU3QE4Created keytree generator for u and cpi. - [15]
CUADTSHQSave csv data as multiple files. - [16]
AT753JPOSelected US unemployment series. - [17]
77SIQZ3ESeparating out spec generation. - [18]
GUXZCEWWAdded Country enum. - [19]
TTR5IFSGWorking on building generic TSSpec. - [*]
4MG5JFXTFirst record.
Change contents
- edit in src/ui.rs at line 2
#![allow(dead_code)] - edit in src/ui.rs at line 20
data_from_file, - replacement in src/ui.rs at line 269
_ => Err(parse_transform1(s)),_ => Err(parse_transform1(file!(), line!(), s)), - replacement in src/ui.rs at line 286
_ => Err(parse_transform2(s)),_ => {Err(parse_transform2(file!(), line!(), s))}, - replacement in src/ui.rs at line 311
Err(data_type_mismatch(&self.data_type.to_string(), &data_type.to_string()))Err(data_type_mismatch(file!(),line!(),&self.data_type.to_string(),&data_type.to_string())) - replacement in src/ui.rs at line 327
let series_spec = data_spec.get_series_spec(&self.series_id);series_spec.time_series_data(root_path)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
#![allow(dead_code)] - replacement in src/ts.rs at line 12
use keytree::{KeyTree, KeyTreeRef};use keytree::{KeyTree,KeyTreeRef,}; - edit in src/ts.rs at line 27
data_from_file, - edit in src/ts.rs at line 30
meta_from_file, - replacement in src/ts.rs at line 32
use crate::error::{Error,};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
// -- "ts_spec.keytree" ---------------------------------------------------------------------------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
/// 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/// ```/// 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
pub struct TSSpec(pub Vec<TSPageSpec>);pub struct TSData(pub HashMap<PageKey, String>); - replacement in src/ts.rs at line 75
impl TSSpec {impl TSData { - replacement in src/ts.rs at line 77
pub (crate) fn new() -> TSSpec {TSSpec(Vec::new())/// 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)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()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
} - replacement in src/ts.rs at line 100
/// ts_spec:/// page:/// data_type: u/// country: Australia/// graphic:/// series:/// id: AUSURANAA/// id: AUSURAQS/// id: AUSURHARMADSMEI/// id: AUSURHARMMDSMEIpub fn into_json(&self,data_spec: &DataSpec,root_path: &str) -> Result<TSJson, Error>{let mut ts_json = TSJson::new();/// Converts specification data into `TSData`.pub struct Json(Vec<PageJson>); - edit in src/ts.rs at line 103
impl Json { - replacement in src/ts.rs at line 105
for page_spec in &self.0 {let key = page_spec.key();pub (crate) fn into_data(&self) -> Result<TSData, Error> { - replacement in src/ts.rs at line 107
let mut value: Vec<GraphicJson> = Vec::new();let mut ts_data = TSData::new(); - edit in src/ts.rs at line 109
for page_json in &self.0 { - replacement in src/ts.rs at line 111
for graphic in &page_spec.graphics {let json = graphic.into_json(data_spec, root_path)?;value.push(json);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
ts_json.insert(&key, value);ts_data.insert(&key, value); - replacement in src/ts.rs at line 128
Ok(ts_json)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());#[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
kt - edit in src/ts.rs at line 156
} - 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))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 {/// 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,pub height: Option<f32>, - replacement in src/ts.rs at line 168
pub graphics: Vec<TSGraphicSpec>,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,impl GraphicJson {pub (crate) fn new() -> Self {GraphicJson {height: None,series: Vec::new(), - replacement in src/ts.rs at line 179
pub (crate) fn push(&mut self, ts_graphic_spec: TSGraphicSpec) {self.graphics.push(ts_graphic_spec)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
} - 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,// === 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
// 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
} - replacement in src/ts.rs at line 259
impl IntoKeyTree for TSPageSpec {fn keytree(&self) -> KeyTreeString {/// 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
let mut kt = KeyTreeString::new();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());}ktpub (crate) fn push(&mut self, page_spec: PageSpec) {self.0.push(page_spec) - replacement in src/ts.rs at line 289
impl<'a> TryInto<TSPageSpec> for KeyTreeRef<'a> {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")?,})fn try_into(self) -> Result<Spec, keytree::Error> {Ok(Spec(self.vec_at("ts_spec::page")?)) - replacement in src/ts.rs at line 297
/// Component of `TSSpec`.// 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
/// 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/// 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>,pub struct PageSpec {country: Country,data_type: DataType,index: usize,graphics: Vec<GraphicSpec>, - edit in src/ts.rs at line 321
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(),}}impl PageSpec { - replacement in src/ts.rs at line 324
pub (crate) fn push(&mut self, series: TSSeriesSpec) {self.series.push(series)///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>{} - replacement in src/ts.rs at line 335
let mut series_json = SeriesJson::new();for (series_id, _) in &data_spec.reverse {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);}fn try_into(self) -> Result<PageSpec, keytree::Error> { - replacement in src/ts.rs at line 340
GraphicJson {height: self.height,series: series_json,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
impl IntoKeyTree for TSGraphicSpec {fn keytree(&self) -> KeyTreeString {let mut kt = KeyTreeString::new();/// 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());impl GraphicSpec {pub (crate) fn new() -> Self {GraphicSpec {height: None,seriess: Vec::new(), - replacement in src/ts.rs at line 371
kt}pub (crate) fn push(&mut self, series_spec: self::SeriesSpec) {self.seriess.push(series_spec) - replacement in src/ts.rs at line 378
impl<'a> TryInto<TSGraphicSpec> for KeyTreeRef<'a> {impl<'a> TryInto<GraphicSpec> for KeyTreeRef<'a> { - replacement in src/ts.rs at line 381
fn try_into(self) -> Result<TSGraphicSpec, Self::Error> {fn try_into(self) -> Result<GraphicSpec, keytree::Error> { - replacement in src/ts.rs at line 383
TSGraphicSpec {height: self.opt_value("graphic::height")?,series: self.vec_at("graphic::series")?,GraphicSpec{height: self.opt_value("graphic::height")?,seriess: self.vec_at("graphic::series")?, - replacement in src/ts.rs at line 391
/// Component of `TSGraphicSpec`./// ```text// 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
/// data_type: u/// series_id: AUSURHARMADSMEI/// data_type: u/// series_id: AUSURAMS - replacement in src/ts.rs at line 399
#[derive(Debug)]pub struct TSSeriesSpec {///pub struct SeriesSpec { - replacement in src/ts.rs at line 404
impl TSSeriesSpec {/// Return a new `TSSeries`.impl SeriesSpec {/// - replacement in src/ts.rs at line 407
TSSeriesSpec {SeriesSpec { - replacement in src/ts.rs at line 414
impl<'a> TryInto<TSSeriesSpec> for KeyTreeRef<'a> {impl<'a> TryInto<SeriesSpec> for KeyTreeRef<'a> { - replacement in src/ts.rs at line 417
fn try_into(self) -> Result<TSSeriesSpec, Self::Error> {fn try_into(self) -> Result<SeriesSpec, keytree::Error> { - replacement in src/ts.rs at line 419
TSSeriesSpec {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
// --- 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
#![allow(unused_imports)]use std::time::SystemTime;use time::{Duration,OffsetDateTime,}; - replacement in src/main.rs at line 23
let data_spec = DataSpec::from_file("source_data.keytree").unwrap();let ts_spec = TSSpec::from_file("ts_spec.keytree");// 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);}// 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 2let data_spec = DataSpec::from_file("source_data.keytree").unwrap();// data_spec.update_write(&root_dir).unwrap(); - edit in src/main.rs at line 48
// Step 3 - edit in src/main.rs at line 50[3.10088]
// println!("{}", data_spec.generic_ts_spec().keytree());// (paste this)// Step 4let 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
//! to resume.//! 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
//! let ts_json = ts_spec.into_json(&data_spec, "/full/path/to/data");//! let ts_json = ts_spec.into_json(&data_spec, "/full/path/to/data").unwrap(); - edit in src/lib.rs at line 136
use std::file; - edit in src/lib.rs at line 139
use std::line;use std::path::Path; - edit in src/lib.rs at line 144
use walkdir::WalkDir; - edit in src/lib.rs at line 157
DatePoint,DateRange, - replacement in src/lib.rs at line 167
TSGraphicSpec,TSPageSpec,TSSeriesSpec,TSSpec,PageSpec,Spec, - edit in src/lib.rs at line 170
/// 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
let year = s[..4].parse().map_err(|_| parse_date("failed"))?;let month = s[5..7].parse().map_err(|_| parse_date("failed"))?;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
_ => Err(parse_datatype(s)),_ => Err(parse_datatype(file!(), line!(), s)), - replacement in src/lib.rs at line 285
pub fn title(series_id: &SeriesId) -> String {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
let seriess = match Fred::series(&series_id.to_string()) {let seriess = match Fred::series(&sid.to_string()) { - replacement in src/lib.rs at line 290
Err(err) => {println!("{}", err);panic!();},Err(err) => { return Err(fred_error(file!(), line!(), &err.to_string())) }, - replacement in src/lib.rs at line 295
sOk(s) - replacement in src/lib.rs at line 331
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 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())) },let key = match self.reverse.get(&series_id) {Some(key) => key,None => { return None }, - replacement in src/lib.rs at line 337
Ok(series_specs.iter().any(|series| &series.series_id == series_id))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
/// Build a generic `TSSpec` from `Self`.pub fn generic_ts_spec(&self) -> TSSpec {/// Build a generic `Spec` from `Self`.pub fn generic_ts_spec(&self) -> ts::Spec { - replacement in src/lib.rs at line 399
let mut ts_spec = TSSpec::new();let mut ts_spec = ts::Spec::new(); - replacement in src/lib.rs at line 403
let mut ts_graphic_spec = TSGraphicSpec::new();let mut ts_graphic_spec = ts::GraphicSpec::new(); - replacement in src/lib.rs at line 406
let ts_series_spec = TSSeriesSpec::new(let ts_series_spec = ts::SeriesSpec::new( - replacement in src/lib.rs at line 414
let ts_page_spec = TSPageSpec::new(page_key, vec!(ts_graphic_spec));let ts_page_spec = ts::PageSpec::new(*country,*data_type,0,vec!(ts_graphic_spec),); - replacement in src/lib.rs at line 440
Err(err) => { return Err(failed_to_read_file(&err.to_string())) },Err(err) => { return Err(failed_to_read_file(file!(),line!(),&err.to_string()))}, - replacement in src/lib.rs at line 449
kt.to_ref().try_into().map_err(|err: keytree::error::Error| keytree_error(&err.to_string()))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
pub fn write(&self, root_path: &str) {pub fn write(&self, root_path: &str) -> Result<(), Error> { - replacement in src/lib.rs at line 465
series_spec.write_data(root_path);series_spec.write_meta(root_path);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
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
Ok(()) - replacement in src/lib.rs at line 531
pub fn resume_write(&self, series_id: &str, root_path: &str) {pub fn resume_write(&self, series_id: &str, root_path: &str) -> Result<(), Error> { - replacement in src/lib.rs at line 533
for ((data_type, country), series_specs) in selffor (_, series_specs) in self - replacement in src/lib.rs at line 536
.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,.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
series_spec.write_data(root_path);series_spec.write_meta(root_path);series_spec.write_data(root_path)?;series_spec.write_meta(root_path)?; - edit in src/lib.rs at line 548
Ok(()) - edit in src/lib.rs at line 551
- replacement in src/lib.rs at line 575
#[derive(Clone)]#[derive(Clone, Debug)] - edit in src/lib.rs at line 589
/// 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
None => { return Err(series_id_not_in_dataspec(&series_id.to_string())) },None => { return Err(series_id_not_in_dataspec(file!(),line!(),&series_id.to_string()))}, - replacement in src/lib.rs at line 643
/// Return the meta data for a `SeriesSpec`.pub fn meta(&self, root_path: &str) -> SeriesMetaData {/// 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
let path = &format!("{}/{}/{}/{}.meta",root_path,self.data_type,self.country.as_path(),self.series_id,);// 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
let meta_str = fs::read_to_string(path).unwrap();let kt = KeyTree::parse(&meta_str).unwrap();kt.to_ref().try_into().unwrap()}// Want power to drop_first - replacement in src/lib.rs at line 658
/// Return the time-series data for `series_id`.pub fn time_series_data(&self, root_path: &str) -> Result<RegularTimeSeries<1>, Error> {let mut v = Vec::new(); - replacement in src/lib.rs at line 660
let path = &format!("{}/{}/{}/{}.csv",root_path,self.data_type,self.country.as_path(),self.series_id,);// Drop the first n itemslet 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
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())),}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
Err(err) => Err(from_time_series(&err.to_string())),};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
eprintln!("{}", err);std::process::exit(1); - edit in src/lib.rs at line 728
/// 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
let rts = self.into_time_series()?; - replacement in src/lib.rs at line 733
/// Fetches data as specified in `checked_data.keytree` and saves to disk.pub fn write_data(&self, root_path: &str) {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
// 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 line = format!("{}, {}\n",date_str,date_point.value(0),);csv.push_str(&line); - replacement in src/lib.rs at line 763
fs::create_dir_all(&dir_path).unwrap();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
println!("Writing {}", filename);fs::write(filename, &data).unwrap();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
/// Fetches data as specified in `checked_data.keytree` and saves meta_data to disk.pub fn write_meta(&self, root_path: &str) {/// 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
Err(err) => {println!("{}", err);panic! ();},Err(err) => { return Err(fred_error(file!(),line!(),&err.to_string()))}, - edit in src/lib.rs at line 829
Ok(()) - replacement in src/lib.rs at line 947
// 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"