diff options
Diffstat (limited to 'src/template.rs')
-rw-r--r-- | src/template.rs | 99 |
1 files changed, 72 insertions, 27 deletions
diff --git a/src/template.rs b/src/template.rs index d469394..2810600 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,8 +1,10 @@ use crate::error::Error; +use crate::models; use serde::Deserialize; use serde::Serialize; use serde_json::to_value; use serde_json::Value as Json; +use chrono::DateTime; pub fn running_template() -> TemplateSpec { TemplateSpec::Table(vec![ @@ -10,7 +12,7 @@ pub fn running_template() -> TemplateSpec { display_name: "Date".to_string(), field: FieldSpec::App( Function::DisplayUnit(Unit::Timestamp, "date".to_string()), - vec![FieldSpec::Field("start_time".to_string())], + vec![FieldSpec::Field("start_timestamp".to_string())], ), }, Column { @@ -92,28 +94,51 @@ mod function { .map_err(|_| Error::TemplateError("convert to f64".to_string(), d.clone())) } - fn format_pace(d: &Json) -> Result<Json, Error> { - let pace = really_f64(d)?; - let seconds_per_mile = (pace * METERS_PER_MILE).round() as i64; + fn format_duration(d: &Json, _opts: &str) -> Result<Json, Error> { + let seconds = really_f64(d)? as i64; let mut hours = "".to_string(); - if seconds_per_mile > 3600 { - hours = format!("{}", seconds_per_mile / 3600); + if seconds > 3600 { + hours = format!("{}:", seconds / 3600); } Ok(json!(format!( "{}{:02}:{:02}", hours, - seconds_per_mile / 60, - seconds_per_mile % 60 + (seconds % 3600) / 60, + seconds % 60 ))) } + fn format_pace(d: &Json) -> Result<Json, Error> { + let pace = really_f64(d)?; + format_duration(&json!(pace * METERS_PER_MILE), "") + } + fn format_distance(d: &Json, opts: &str) -> Result<Json, Error> { Ok(json!(match opts { "miles" => format!("{:.1}", really_f64(d)? / METERS_PER_MILE), - _ => format!("{} m", really_f64(d)?) + _ => format!("{} m", really_f64(d)?), })) } + fn format_timestamp(d: &Json, opts: &str) -> Result<Json, Error> { + fn format_timestamp(t: DateTime<chrono::Utc>, opts: &str) -> Result<Json, Error> { + let s = match opts { + "date" => t.format("%Y/%m/%d"), + _ => t.format("%c"), + }; + Ok(json!(format!("{}", s))) + } + + let t = d.as_str(); + match t { + None => Ok(json!(())), + Some(t) => { + format_timestamp(DateTime::parse_from_rfc3339(t)?.with_timezone(&chrono::Utc), opts) + } + } + + } + fn display_unit(u: Unit, opts: &str, params: &Vec<FieldSpec>, d: &Json) -> Result<Json, Error> { if params.len() != 1 { Err(Error::TemplateError( @@ -123,9 +148,9 @@ mod function { } let d = eval(¶ms[0], &d)?; Ok(match u { - Unit::Timestamp => json!(format!("as_timestamp({:?})", d)), + Unit::Timestamp => format_timestamp(&d, &opts)?, Unit::Meters => format_distance(&d, &opts)?, - Unit::Seconds => json!(format!("as_duration({:?})", d)), + Unit::Seconds => format_duration(&d, &opts)?, Unit::Speed => json!(format!("as_speed({:?})", d)), Unit::Pace => format_pace(&d)?, }) @@ -173,7 +198,7 @@ mod function { #[test] fn eval_fn1() { - let d = json!({"x": 0.260976}); + let d = json!({"x": 2}); let app1 = |f| { println!("{:?}", f); @@ -184,9 +209,13 @@ mod function { .unwrap() }; assert_eq!( - json!("07:00"), + json!("53:00"), app1(Function::DisplayUnit(Unit::Pace, "".to_string())) ); + assert_eq!( + json!("00:02"), + app1(Function::DisplayUnit(Unit::Seconds, "".to_string())) + ); } #[test] @@ -198,10 +227,16 @@ mod function { assert_eq!( eval( - &FieldSpec::App(Function::Div, - vec!(FieldSpec::Field("time".to_string()), - FieldSpec::Field("distance".to_string()))), - &d).unwrap(), + &FieldSpec::App( + Function::Div, + vec!( + FieldSpec::Field("time".to_string()), + FieldSpec::Field("distance".to_string()) + ) + ), + &d + ) + .unwrap(), json!((time as f64) / distance) ) } @@ -218,24 +253,34 @@ mod table { } pub fn apply(columns: &Vec<Column>, d: &Json) -> Result<DisplayTable, Error> { - let rows = d.as_array() + let rows = d + .as_array() .ok_or_else(|| Error::TemplateError("expected array".to_string(), d.clone()))?; Ok(DisplayTable { headings: columns.iter().map(|c| c.display_name.clone()).collect(), - rows: rows.iter().map(|d| { - columns.iter().map(|c| { - function::eval(&c.field, d) - }).collect::<Result<Vec<_>, _>>() - }).collect::<Result<Vec<_>, _>>()?, + rows: rows + .iter() + .map(|d| { + columns + .iter() + .map(|c| function::eval(&c.field, d)) + .collect::<Result<Vec<_>, _>>() + }) + .collect::<Result<Vec<_>, _>>()?, }) } } -pub fn apply(t: &TemplateSpec, d: &Json) -> Result<Json, Error> { - Ok(match t { - &TemplateSpec::Table(ref c) => to_value(table::apply(c, d)?)?, - }) +impl TemplateSpec { + pub fn apply(self: &TemplateSpec, entries: Vec<models::Entry>) -> Result<Json, Error> { + info!("Applying template\n {:#?}", self); + info!("Sample entry\n {:#?}", entries.first()); + let d = Json::Array(entries.into_iter().map(|e| e.payload).collect()); + Ok(match self { + &TemplateSpec::Table(ref c) => to_value(table::apply(c, &d)?)?, + }) + } } #[cfg(test)] |