1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use chrono::{DateTime, Timelike, Utc};
use chrono::serde::ts_seconds;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Visit {
#[serde(rename = "action_name", serialize_with = "serialize_scene_path", deserialize_with = "deserialize_action_name")]
pub scene_path: Vec<String>,
pub campaign_id: String,
pub times: u32,
#[serde(rename = "period_start", with = "ts_seconds")]
pub first: DateTime<Utc>,
#[serde(rename = "period_end", with = "ts_seconds")]
pub last: DateTime<Utc>,
}
fn serialize_scene_path<S>(scene_path: &Vec<String>, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
serializer.serialize_str(scene_path.join("/").as_str())
}
fn deserialize_action_name<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error> where D: Deserializer<'de> {
let action_name = String::deserialize(deserializer)?;
Ok(action_name.split('/').map(|item| item.to_owned()).collect())
}
impl Visit {
pub fn new(scene_path: Vec<String>, campaign_id: String) -> Visit {
let now = Utc::now().with_nanosecond(0).unwrap();
Visit { scene_path, campaign_id, times: 1, first: now.clone(), last: now }
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::TimeZone;
#[test]
fn new_visit() {
let visit = Visit {
scene_path: vec!["foo".to_string(), "bar".to_string()],
campaign_id: "test".to_string(),
times: 100,
first: Utc.timestamp(0, 0),
last: Utc.timestamp(0, 0) };
let json = serde_json::to_string(&visit).unwrap();
assert_eq!(json,
"{\"action_name\":\"foo/bar\",\"campaign_id\":\"test\",\"times\":100,\"period_start\":0,\"period_end\":0}");
let visit2: Visit = serde_json::from_str(json.as_str()).unwrap();
assert_eq!(visit2, visit);
}
#[test]
fn new_visit_with_defaults() {
let visit = Visit::new(
vec!["foo".to_string(), "bar".to_string()],
"test".to_string());
let json = serde_json::to_string(&visit).unwrap();
let now = Utc::now().timestamp();
assert_eq!(json,
format!("{{\"action_name\":\"foo/bar\",\"campaign_id\":\"test\",\"times\":1,\"period_start\":{now},\"period_end\":{now}}}", now=now));
let visit2: Visit = serde_json::from_str(json.as_str()).unwrap();
assert_eq!(visit2, visit);
}
}