Finished into_json() functionality.
[?]
Jun 24, 2021, 7:55 AM
2SABVMY3A2RZDF3KJXZSMJ2UQ4Q5EW422G4DVBJRKK26S2ESGVQACDependencies
- [2]
U4VCAFXQAdded data_type to TSSpec key. - [3]
JTX5OHWHAdded USA CPI. - [4]
LVMGQJGHFinished framework for checking series specifications with data. - [5]
77SIQZ3ESeparating out spec generation. - [6]
CUADTSHQSave csv data as multiple files. - [7]
AT753JPOSelected US unemployment series. - [8]
GQVS55HIFinished generate_ts_spec() function. - [9]
5POF332LWorking on fn cpi_included(). - [*]
4MG5JFXTFirst record.
Change contents
- edit in src/serve_ts.rs at line 1[3.7119]→[3.7120:7194](∅→∅),[3.7194]→[2.0:142](∅→∅),[2.142]→[3.7347:7507](∅→∅),[3.7347]→[3.7347:7507](∅→∅),[3.7507]→[2.143:204](∅→∅),[2.204]→[3.7572:7581](∅→∅),[3.7572]→[3.7572:7581](∅→∅)
//! Deserialize data to be served as JSON to build time-series plots.//!//! The `TSSpec::TSPageSpec::TSGraphicSpec` group of data-structures mirrors//! `ts_spec.keytree`. Its main function is TSSpec::new(PageJson//!//! The `PageJson::GraphicJson::SeriesJson` group of datastructures is convertible into Json and//! served to the client. Its main function is//!//! ```//! PageJson::new(ts_spec: TSSpec, checked_spec: Checked...)//! ``` - replacement in src/serve_ts.rs at line 2
use std::convert::{TryFrom, TryInto};use std::env;use std::convert::{Into,TryInto,}; - edit in src/serve_ts.rs at line 12
use keytree::Error; - edit in src/serve_ts.rs at line 18
TimeSeries, - edit in src/serve_ts.rs at line 21
use crate::error::{Error,}; - replacement in src/serve_ts.rs at line 25
CheckedDataSpec,IndexedCheckedDataSpec, - replacement in src/serve_ts.rs at line 31
/// The specification for HTML pages that present a series of time-series plots. The keytree/// specification looks like/// Top-level time-series specification data-structure.////// It can be serialized into something like, - replacement in src/serve_ts.rs at line 50
pub fn new() -> TSSpec {pub (crate) fn new() -> TSSpec { - replacement in src/serve_ts.rs at line 54
pub fn push(&mut self, item: TSPageSpec) {pub (crate) fn push(&mut self, item: TSPageSpec) { - replacement in src/serve_ts.rs at line 58
pub fn from_file(path: &str) -> Self {pub (crate) fn from_file(path: &str) -> Self { - edit in src/serve_ts.rs at line 62
}/// ts_spec:/// page:/// data_type: u/// country: Australia/// graphic:/// series:/// id: AUSURANAA/// id: AUSURAQS/// id: AUSURHARMADSMEI/// id: AUSURHARMMDSMEIpub fn into_json(&self,data_spec: &IndexedCheckedDataSpec,root_path: &str) -> Result<TSJson, Error>{let mut ts_json = TSJson::new();for page_spec in &self.0 {let key = page_spec.key();let mut value: Vec<GraphicJson> = Vec::new();for graphic in &page_spec.graphics {let json = graphic.into_json(data_spec, root_path)?;value.push(json);};ts_json.insert(&key, value);}Ok(ts_json) - edit in src/serve_ts.rs at line 94
// // 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)// } - replacement in src/serve_ts.rs at line 142
type Error = Error;type Error = keytree::Error; - replacement in src/serve_ts.rs at line 144
fn try_into(self) -> Result<TSSpec, Error> {fn try_into(self) -> Result<TSSpec, Self::Error> { - edit in src/serve_ts.rs at line 151
/// - edit in src/serve_ts.rs at line 165
/// - edit in src/serve_ts.rs at line 167
/// - edit in src/serve_ts.rs at line 169
/// - replacement in src/serve_ts.rs at line 174
pub fn new(key: PageKey, graphics: Vec<TSGraphicSpec>) -> Self {pub (crate) fn new(key: PageKey, graphics: Vec<TSGraphicSpec>) -> Self { - replacement in src/serve_ts.rs at line 177
country: key.country,data_type: key.data_type,graphics: graphics,country: key.country,data_type: key.data_type,graphics: graphics, - replacement in src/serve_ts.rs at line 183
pub fn key(&self) -> PageKey {pub (crate) fn key(&self) -> PageKey { - replacement in src/serve_ts.rs at line 185
country: self.country,data_type: self.data_type,country: self.country,data_type: self.data_type, - replacement in src/serve_ts.rs at line 207
type Error = Error;type Error = keytree::Error; - replacement in src/serve_ts.rs at line 209
fn try_into(self) -> Result<TSPageSpec, Error> {fn try_into(self) -> Result<TSPageSpec, Self::Error> { - replacement in src/serve_ts.rs at line 225
/// Specifies the data files required for a graphic in the '/source' route./// Component of `TSSpec`./// - edit in src/serve_ts.rs at line 228
/// Heigh in pixels of the graphic. - replacement in src/serve_ts.rs at line 231
// e.g. AUSURHARMADSMEI, .../// e.g. [ AUSURHARMADSMEI, ... ] - replacement in src/serve_ts.rs at line 237
pub fn new() -> Self {pub (crate) fn new() -> Self { - replacement in src/serve_ts.rs at line 245
pub fn push(&mut self, id: &str) {pub (crate) fn push(&mut self, id: &str) { - edit in src/serve_ts.rs at line 247
}pub (crate) fn into_json(&self,data_spec: &IndexedCheckedDataSpec,root_path: &str) -> Result<GraphicJson, Error>{let mut series_json = SeriesJson::new();for series_id in &self.series_ids {let ts = data_spec.time_series_data(series_id.clone(), root_path)?;let meta = data_spec.meta(series_id.to_string(), root_path);series_json.push(ts, meta);}Ok(GraphicJson {height: self.height,series: series_json,}) - replacement in src/serve_ts.rs at line 292
type Error = Error;type Error = keytree::Error; - replacement in src/serve_ts.rs at line 294
fn try_into(self) -> Result<TSGraphicSpec, Error> {fn try_into(self) -> Result<TSGraphicSpec, Self::Error> { - replacement in src/serve_ts.rs at line 308
pub struct PageJson(HashMap<PageKey, Vec<GraphicJson>>);impl PageJson {// Build from a `TSSpec`.pub fn new(page_spec: TSSpec, data_root: &str) -> Self {pub struct TSJson(HashMap<PageKey, Vec<GraphicJson>>); - replacement in src/serve_ts.rs at line 310[2.2823]→[2.2823:2883](∅→∅),[2.2883]→[3.11376:11377](∅→∅),[3.11376]→[3.11376:11377](∅→∅),[3.11377]→[2.2884:2902](∅→∅)
let ts_spec = TSSpec::from_file("ts_spec.keytree");impl TSJson { - edit in src/serve_ts.rs at line 312
pub (crate) fn new() -> TSJson {TSJson(HashMap::new())} - replacement in src/serve_ts.rs at line 316
PageJson(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, value); },} - edit in src/serve_ts.rs at line 330
/// - edit in src/serve_ts.rs at line 332
/// - replacement in src/serve_ts.rs at line 338
pub struct SeriesJson {data: Vec<(RegularTimeSeries<1>, SeriesMetaData)>,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));} - replacement in src/serve_ts.rs at line 353
#[derive(Clone, Copy, Eq, Hash, PartialEq)]#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - edit in src/serve_ts.rs at line 355
/// - edit in src/serve_ts.rs at line 357
/// - replacement in src/serve_ts.rs at line 362
type Error = Error;type Error = keytree::Error; - replacement in src/serve_ts.rs at line 364
fn try_into(self) -> Result<PageKey, Error> {let data_type_str: String = self.at("key::data_type")?;fn try_into(self) -> Result<PageKey, Self::Error> {let data_type_str: String = self.at("key::data_type").map_err(|err| err.into())?; - replacement in src/serve_ts.rs at line 371
let country_str: String = self.at("key::country")?;let country_str: String = self.at("key::country").map_err(|err| err.into())?; - edit in src/lib.rs at line 1[11.16][3.10187]
#![deny(missing_docs)] - edit in src/lib.rs at line 38
//! ```//! The specification will look something like, - edit in src/lib.rs at line 41
//! seriess://! series://! data_type: u//! country: Australia//! id: AUSURAMS//! series://! data_type: u//! country: Australia//! id: AUSURANAA//! series://! data_type: u//! country: Australia//! id: AUSURAQS//! series://! data_type: u//! country: Australia//! id: AUSURHARMADSMEI//! series://! data_type: u//! country: Australia//! id: AUSURHARMMDSMEI//! ```//! ### Step 2. Check and Save Data - replacement in src/lib.rs at line 65
//! ### Step 3. Save Data//!//! 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//! ``` - replacement in src/lib.rs at line 89
//! ### Step 4*. Bootstrap TSPageSpec.//! ### Step 3*. Bootstrap TSPageSpec. - replacement in src/lib.rs at line 91
//! ### Step 4. Serve Time-series//! To generate a generic time-series specification,//! ```//! checked_data_spec//! .from_file("data_spec.keytree")//! .bootstrap_ts_spec;//! ```//! The specification will look something like//! ```//! page://! country://! name: Australia//! graphic://! series://! id: AUSURANAA//! id: AUSURAQS//! id: AUSURHARMADSMEI//! id: AUSURHARMMDSMEI//! ```//! Once it has been generated with the full set of data, we want to be able to edit it manually.//!//! ### Step 3. Serve Time-series//!//! The structure of JSON which is served to the client is determined by `Serialize`-able data//! structures. The top structure is `TSJson`. The `ts_spec.keytree` file specifies the graphics on//! each page, and what data each graphic uses. The `ts_spec.keytree` file is deserialized into//! `TSSpec`. - edit in src/lib.rs at line 118
//! The procedure is generally to read in the specification in `ts_spec.keytree`, and to read in the//! `data_spec.keytree` which specifies data available, and also acts as a gate-keeper for that//! data.//! ```//! // Read in the data specification.//! let data_spec = CheckedData::from_file("data_spec.keytree").indexed();//!//! // Read in the time-series specification.//! let ts_spec = TSSpec::from_file("ts_spec.keytree");//!//! // Load all data to memory. The server uses `ts_json` as a data-store to respond to data//! // requests.//! let ts_json = ts_spec.into_json(data_spec);//! ```//! Then `TSSpec` uses `IndexedCheckedDataSpec` as an argument to be converted into `TSJson`.//!//! - edit in src/lib.rs at line 142
/// - edit in src/lib.rs at line 144
/// - edit in src/lib.rs at line 147
///pub mod error;/// - edit in src/lib.rs at line 153
- replacement in src/lib.rs at line 163
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize)]#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize)] - edit in src/lib.rs at line 176
/// Parse a string into a `DataType` or return `None` on failure. - edit in src/lib.rs at line 220
pub fn usa_cpi() -> String {Fred::tags_series("cpi;usa;nation").unwrap().to_string()} - edit in src/check_data.rs at line 4
use std::path::PathBuf; - replacement in src/check_data.rs at line 5
use time::PrimitiveDateTime;use time::OffsetDateTime; - edit in src/check_data.rs at line 13
use keytree::Error; - edit in src/check_data.rs at line 16
};use time_series::{RegularTimeSeries,TimeSeries, - replacement in src/check_data.rs at line 23
use crate::build_spec::DataSpec;use crate::build_spec::{DataSpec,};use crate::error::{Error,ErrorKind,}; - edit in src/check_data.rs at line 38
/// Check for errors that might have occurred somewhere along the toolchain. - edit in src/check_data.rs at line 68
}}// 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<String, usize>,}impl IndexedCheckedDataSpec {/// Return the time-series data for `series_id`.pub fn time_series_data(&self,series_id: String,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);panic!();},};let checked_series = self.data.series_from_index(*i);if checked_series.error != "ok" {return Err(Error::new(ErrorKind::SpecErrorStatus(series_id, checked_series.error.clone())))};let path = &format!("{}/{}/{}/{}.csv",root_path,checked_series.data_type,checked_series.country,series_id,);Ok(TimeSeries::<1>::from_csv(&path).try_into().map_err(|err| Error::new(ErrorKind::NotRegular(checked_series.id.clone())))?)}/// Return the meta-data for `series_id`.pub fn meta(&self, series_id: String, 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!("{}/{}/{}/{}.csv",root_path,checked_series.data_type,checked_series.country,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 157
fn series_from_index(&self, i: usize) -> &CheckedSourceSeries {&self.0[i]} - edit in src/check_data.rs at line 183
}/// Wrap CheckedDataSpec with an index into its inner `Vec`.pub fn into_indexed(self) -> IndexedCheckedDataSpec {let mut h: HashMap<String, usize> = HashMap::new();for (i, series) in self.0.iter().enumerate() {h.insert(series.id.clone(), i);}IndexedCheckedDataSpec {data: self,index: h} - replacement in src/check_data.rs at line 239
type Error = Error;type Error = keytree::Error; - replacement in src/check_data.rs at line 241
fn try_into(self) -> Result<CheckedDataSpec, Error> {fn try_into(self) -> Result<CheckedDataSpec, Self::Error> { - replacement in src/check_data.rs at line 243
CheckedDataSpec(self.vec("seriess:series")?)CheckedDataSpec(self.vec("seriess::series")?) - edit in src/check_data.rs at line 262
/// - edit in src/check_data.rs at line 265
/// - edit in src/check_data.rs at line 268
/// - edit in src/check_data.rs at line 271
/// Used to track problems and to check that data is consistent before serving to client. - replacement in src/check_data.rs at line 274
pub time_stamp: Option<time::PrimitiveDateTime>,///pub time_stamp: Option<time::OffsetDateTime>, - edit in src/check_data.rs at line 281
/// Return a key. - replacement in src/check_data.rs at line 324
self.time_stamp = Some(PrimitiveDateTime::now());self.time_stamp = Some(OffsetDateTime::now_utc()); - replacement in src/check_data.rs at line 404
Some(PrimitiveDateTime::parse(date_str, "%Y %T").unwrap())Some(OffsetDateTime::parse(date_str, "%Y %T").unwrap()) - edit in src/check_data.rs at line 448
impl SeriesMetaData {///pub fn from_file(data_type: DataType,country: Country,series_id: String,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())}} - replacement in src/check_data.rs at line 474
type Error = Error;type Error = keytree::Error; - replacement in src/check_data.rs at line 476
fn try_into(self) -> Result<SeriesMetaData, Error> {fn try_into(self) -> Result<SeriesMetaData, Self::Error> { - edit in src/build_spec.rs at line 1052
/// - edit in src/build_spec.rs at line 1054
/// - edit in src/build_spec.rs at line 1057
/// - edit in src/build_spec.rs at line 1060
///