dctap/
tap_reader_builder.rs

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
127
128
129
130
use crate::{tap_error::Result, tap_headers::TapHeaders};
use crate::{ReaderRange, TapConfig, TapError, TapReader, TapReaderState};
use calamine::{open_workbook, Reader as XlsxReader, Xlsx};
use csv::ReaderBuilder;
use std::fs::File;
// use indexmap::IndexSet;
use std::io::{self, BufReader};
use std::path::Path;

#[derive(Default)]
pub struct TapReaderBuilder {
    _reader_builder: ReaderBuilder,
}

impl TapReaderBuilder {
    pub fn new() -> TapReaderBuilder {
        TapReaderBuilder::default()
    }
    /*
        // Most of these options are copied from CSV Rust
        pub fn _flexible(mut self, yes: bool) -> Self {
            self.reader_builder.flexible(yes);
            self
        }

        pub fn _trim(&mut self, trim: Trim) -> &mut TapReaderBuilder {
            self.reader_builder.trim(trim);
            self
        }

        pub fn _terminator(&mut self, term: Terminator) -> &mut TapReaderBuilder {
            self.reader_builder.terminator(term);
            self
        }

        pub fn _quote(&mut self, quote: u8) -> &mut TapReaderBuilder {
            self.reader_builder.quote(quote);
            self
        }

        pub fn _delimiter(&mut self, delimiter: u8) -> &mut TapReaderBuilder {
            self.reader_builder.delimiter(delimiter);
            self
        }
    */
    /// Build a TapReader from a path and a `TapConfig`
    ///
    /// # Example
    /// ```no_run
    /// use dctap::TapReaderBuilder;
    /// use dctap::TapConfig;
    /// use std::error::Error;
    ///
    /// # fn main() { example().unwrap(); }
    /// fn example() -> Result<(), Box<dyn Error>> {
    ///     let mut tap = TapReaderBuilder::from_path("foo.csv", &TapConfig::default())?;
    ///     for result in tap.shapes() {
    ///         let shape = result?;
    ///         println!("{:?}", shape);
    ///     }
    ///     Ok(())
    /// }
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P, config: &TapConfig) -> Result<TapReader<File>> {
        let mut reader = ReaderBuilder::new()
            .delimiter(config.delimiter())
            .quote(config.quote())
            .flexible(config.flexible())
            .from_path(path)?;
        let rcd_headers = reader.headers()?;
        let headers = TapHeaders::from_record(rcd_headers)?;
        let state = TapReaderState::new().with_headers(headers);
        Ok(TapReader::new_csv_reader(reader, state, config))
    }

    pub fn from_reader<R: io::Read>(rdr: R, config: &TapConfig) -> Result<TapReader<R>> {
        let mut reader = ReaderBuilder::new()
            .delimiter(config.delimiter())
            .quote(config.quote())
            .flexible(config.flexible())
            .from_reader(rdr);
        let rcd_headers = reader.headers()?;
        let headers = TapHeaders::from_record(rcd_headers)?;
        let state = TapReaderState::new().with_headers(headers);
        Ok(TapReader::new_csv_reader(reader, state, config))
    }

    pub fn from_excel<R: io::Read, P: AsRef<Path>>(
        path: P,
        sheet_name: Option<&str>,
        config: &TapConfig,
    ) -> Result<TapReader<R>> {
        let path_name = path.as_ref().to_string_lossy().to_string();
        let mut excel: Xlsx<_> = match open_workbook(path) {
            Ok(xls) => Ok::<calamine::Xlsx<BufReader<File>>, TapError>(xls),
            Err(e) => Err(TapError::OpeningWorkbook {
                path: path_name.clone(),
                error: e,
            }),
        }?;
        let range = match sheet_name {
            None => match excel.worksheet_range_at(0) {
                Some(range) => range.map_err(|e| TapError::Sheet0Error {
                    path: path_name.clone(),
                    error: e,
                }),
                None => Err(TapError::Sheet0NotFound {
                    path: path_name.clone(),
                }),
            },
            Some(name) => excel
                .worksheet_range(name)
                .map_err(|e| TapError::SheetNameError {
                    path: path_name.clone(),
                    sheet_name: name.to_string(),
                    error: e,
                }),
        }?;
        let mut reader_range: ReaderRange<R> = ReaderRange::new(range);
        if let Some(rcd) = reader_range.next_record() {
            let headers = TapHeaders::from_record(&rcd)?;
            let state = TapReaderState::new().with_headers(headers);
            Ok(TapReader::new_range_reader(reader_range, state, config))
        } else {
            Err(TapError::NoHeadersExcel {
                path: path_name.clone(),
            })
        }
    }
}