rust_filesearch/output/
csvw.rs1use 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 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 }
86}