rust_filesearch/output/
csvw.rs

1use crate::errors::Result;
2use crate::models::{Column, Entry};
3use crate::output::format::OutputSink;
4use csv::Writer;
5use std::io::Write;
6
7pub struct CsvFormatter {
8    writer: Writer<Box<dyn Write>>,
9    columns: Vec<Column>,
10}
11
12impl CsvFormatter {
13    pub fn new(output: Box<dyn Write>, columns: Vec<Column>) -> Result<Self> {
14        let mut writer = Writer::from_writer(output);
15
16        // Write header
17        let headers: Vec<String> = columns
18            .iter()
19            .map(|c| format!("{:?}", c).to_lowercase())
20            .collect();
21        writer.write_record(&headers)?;
22
23        Ok(Self { writer, columns })
24    }
25}
26
27impl OutputSink for CsvFormatter {
28    fn write(&mut self, entry: &Entry) -> Result<()> {
29        let values: Vec<String> = self
30            .columns
31            .iter()
32            .map(|column| match column {
33                Column::Path => entry.path.display().to_string(),
34                Column::Name => entry.name.clone(),
35                Column::Size => entry.size.to_string(),
36                Column::Mtime => entry.mtime.to_rfc3339(),
37                Column::Kind => format!("{:?}", entry.kind).to_lowercase(),
38                Column::Perms => entry.perms.clone().unwrap_or_default(),
39                Column::Owner => entry.owner.clone().unwrap_or_default(),
40            })
41            .collect();
42
43        self.writer.write_record(&values)?;
44        Ok(())
45    }
46
47    fn finish(&mut self) -> Result<()> {
48        self.writer.flush()?;
49        Ok(())
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56    use crate::models::EntryKind;
57    use std::path::PathBuf;
58
59    fn make_test_entry(name: &str) -> Entry {
60        use chrono::Utc;
61
62        Entry {
63            path: PathBuf::from(name),
64            name: name.to_string(),
65            size: 1024,
66            kind: EntryKind::File,
67            mtime: Utc::now(),
68            perms: Some("rw-r--r--".to_string()),
69            owner: Some("1000".to_string()),
70            depth: 0,
71        }
72    }
73
74    #[test]
75    fn test_csv_formatter() {
76        let output = Vec::new();
77        let mut formatter =
78            CsvFormatter::new(Box::new(output), vec![Column::Name, Column::Size]).unwrap();
79
80        formatter.write(&make_test_entry("test.txt")).unwrap();
81        formatter.finish().unwrap();
82
83        // Can't easily extract output from boxed writer in this test
84        // In real usage, output goes to stdout which is fine
85    }
86}