summaryrefslogtreecommitdiff
path: root/src/template.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/template.rs')
-rw-r--r--src/template.rs99
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(&params[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)]