kql_panopticon/execution/processing/
output.rs1use crate::execution::result::ResultHandle;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
10pub struct ProcessingStepOutput {
11 handle: ResultHandle,
13
14 duration: Duration,
16}
17
18impl ProcessingStepOutput {
19 pub fn new(handle: ResultHandle, duration: Duration) -> Self {
21 Self { handle, duration }
22 }
23
24 pub fn empty(step_name: &str, duration: Duration) -> Self {
26 Self {
27 handle: ResultHandle::empty(step_name),
28 duration,
29 }
30 }
31
32 pub fn handle(&self) -> &ResultHandle {
34 &self.handle
35 }
36
37 pub fn into_handle(self) -> ResultHandle {
39 self.handle
40 }
41
42 pub fn duration(&self) -> Duration {
44 self.duration
45 }
46
47 pub fn duration_ms(&self) -> u64 {
49 self.duration.as_millis() as u64
50 }
51
52 pub fn is_empty(&self) -> bool {
54 self.handle.row_count().unwrap_or(0) == 0
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::execution::result::ResultWriter;
62 use std::path::PathBuf;
63
64 fn temp_path(name: &str) -> PathBuf {
65 std::env::temp_dir()
66 .join("kql-panopticon-test")
67 .join("processing_output")
68 .join(name)
69 }
70
71 fn cleanup(path: &std::path::Path) {
72 let _ = std::fs::remove_file(path);
73 }
74
75 #[test]
76 fn test_processing_output() {
77 let path = temp_path("test_output.jsonl");
78 cleanup(&path);
79
80 let mut writer = ResultWriter::new(&path, "test_step").unwrap();
82 writer
83 .write_row(&serde_json::json!({"score": 75, "level": "HIGH"}))
84 .unwrap();
85 let handle = writer.finish().unwrap();
86
87 let output = ProcessingStepOutput::new(handle, Duration::from_millis(100));
88
89 assert!(!output.is_empty());
90 assert_eq!(output.duration_ms(), 100);
91 assert_eq!(output.handle().row_count().unwrap(), 1);
92
93 cleanup(&path);
94 }
95
96 #[test]
97 fn test_empty_output() {
98 let output = ProcessingStepOutput::empty("skipped_step", Duration::from_millis(50));
99 assert!(output.is_empty());
100 assert_eq!(output.duration_ms(), 50);
101 }
102}