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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use super::{models::Metric, setup_db, Result};
use diesel::prelude::*;
use std::path::Path;
use std::time::Duration;
const SESSION_TIME_GAP_THRESHOLD: Duration = Duration::from_secs(30);
#[derive(Debug)]
pub struct DerivMetric {
pub timestamp: f64,
pub key: String,
pub value: f64,
}
pub struct Session {
pub start_time: f64,
pub end_time: f64,
pub duration: Duration,
}
impl Session {
pub fn new(start_time: f64, end_time: f64) -> Self {
Session {
start_time,
end_time,
duration: Duration::from_secs_f64(end_time - start_time),
}
}
}
pub struct MetricsDb {
db: SqliteConnection,
sessions: Vec<Session>,
}
impl MetricsDb {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
let db = setup_db(path)?;
let sessions = Self::process_sessions(&db)?;
Ok(MetricsDb { db, sessions })
}
pub fn sessions(&self) -> &[Session] {
&self.sessions
}
fn process_sessions(db: &SqliteConnection) -> Result<Vec<Session>> {
use crate::schema::metrics::dsl::*;
let timestamps = metrics
.select(timestamp)
.order(timestamp.asc())
.load::<f64>(db)?;
let mut sessions: Vec<Session> = Vec::new();
let mut current_start = timestamps[0];
for pair in timestamps.windows(2) {
if pair[1] - pair[0] > SESSION_TIME_GAP_THRESHOLD.as_secs_f64() {
sessions.push(Session::new(current_start, pair[0]));
current_start = pair[1];
}
}
if let Some(last) = timestamps.last() {
if current_start < *last {
sessions.push(Session::new(current_start, *last));
}
}
Ok(sessions)
}
pub fn available_keys(&self) -> Result<Vec<String>> {
use crate::schema::metrics::dsl::*;
let r = metrics.select(key).distinct().load::<String>(&self.db)?;
Ok(r)
}
pub fn metrics_for_key(
&self,
key_name: &str,
session: Option<&Session>,
) -> Result<Vec<Metric>> {
use crate::schema::metrics::dsl::*;
let query = metrics.order(timestamp.asc()).filter(key.eq(key_name));
let r = match session {
Some(session) => query
.filter(timestamp.ge(session.start_time))
.filter(timestamp.le(session.end_time))
.load::<Metric>(&self.db)?,
None => query.load::<Metric>(&self.db)?,
};
Ok(r)
}
pub fn deriv_metrics_for_key(
&self,
key_name: &str,
session: Option<&Session>,
) -> Result<Vec<DerivMetric>> {
let m = self.metrics_for_key(key_name, session)?;
let new_values: Vec<_> = m
.windows(2)
.map(|v| {
let new_value =
(v[1].value - v[0].value) as f64 / (v[1].timestamp - v[0].timestamp);
DerivMetric {
timestamp: v[1].timestamp,
key: format!("{}.deriv", key_name),
value: new_value,
}
})
.collect();
Ok(new_values)
}
}