1use chrono::{DateTime, Utc};
8use ocel::Ocel;
9use serde::Serialize;
10
11use crate::trace;
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
15#[serde(rename_all = "camelCase")]
16pub struct CaseSummary {
17 pub object_id: String,
18 pub activities: Vec<String>,
20 pub events: usize,
22 pub start: DateTime<Utc>,
23 pub end: DateTime<Utc>,
24 pub lead_secs: i64,
25}
26
27#[must_use]
30pub fn cases(log: &Ocel, object_type: &str) -> Vec<CaseSummary> {
31 let traces = trace::build(log, object_type);
32 let mut out: Vec<CaseSummary> = traces
33 .steps
34 .iter()
35 .enumerate()
36 .filter_map(|(slot, steps)| {
37 let (&(_, start), &(_, end)) = (steps.first()?, steps.last()?);
38 Some(CaseSummary {
39 object_id: traces.object_ids[slot].to_owned(),
40 activities: steps
41 .iter()
42 .map(|&(a, _)| traces.activity_names[a as usize].to_owned())
43 .collect(),
44 events: steps.len(),
45 start,
46 end,
47 lead_secs: (end - start).num_seconds(),
48 })
49 })
50 .collect();
51 out.sort_unstable_by(|a, b| {
52 a.start
53 .cmp(&b.start)
54 .then_with(|| a.object_id.cmp(&b.object_id))
55 });
56 out
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use crate::test_util::log_from_sequences;
63
64 #[test]
65 fn digests_only_objects_with_events() {
66 let log = log_from_sequences(&[&["a", "b", "c"], &["a"]]);
67 let all = cases(&log, "case");
68 assert_eq!(all.len(), 2);
69 assert_eq!(all[0].object_id, "o0");
70 assert_eq!(all[0].activities, ["a", "b", "c"]);
71 assert_eq!(all[0].events, 3);
72 assert_eq!(all[0].lead_secs, 120);
73 assert_eq!(all[1].lead_secs, 0);
74 }
75
76 #[test]
77 fn empty_type_is_empty() {
78 let log = log_from_sequences(&[]);
79 assert!(cases(&log, "case").is_empty());
80 }
81}