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
use std::path::PathBuf;
use std::result;
use std::io;

use regex::Regex;

use crate::Row;

/// An error found somewhere in the transformation chain.
#[derive(Debug, Clone)]
pub enum Error {
    // TODO derive partialeq, eq and hash. This will
    // allow for errors to be grouped and streamed in groups
    /// An error ocurred in the underlaying csv library, likely a permissions
    /// issue.
    Csv(String),

    /// The headers of two of the input csv files do not match each other.
    InconsistentHeaders,

    /// A stream was found that has a row with different number of fields than
    /// the rest.
    InconsistentSizeOfRows(PathBuf),

    /// You tried to add a column to the stream but that name was alredy in
    /// use.
    DuplicatedColumn(String),

    /// You tried to use a column as source for something but that column does
    /// not exist.
    ColumnNotFound(String),

    /// An error ocurred trying to convert a value from string to a different
    /// data type.
    ValueError {
        data: String,
        to_type: String,
    },

    /// String didn't match regular expression. Likely in the .add() method.
    ReNoMatch(Regex, String),

    /// Template string for defining a new column had an invalid format.
    InvalidFormat(String),

    IOError(String),
}

pub type Result<T> = result::Result<T, Error>;

/// The type that actually flows through the row stream. Either a row or an
/// error.
pub type RowResult = result::Result<Row, Error>;

impl From<csv::Error> for Error {
    fn from(error: csv::Error) -> Error {
        Error::Csv(format!("{:?}", error))
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error::IOError(format!("{:?}", error))
    }
}

impl std::error::Error for Error { }

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error::Csv(e) => write!(f, "Error in underlaying csv library: {}", e),
            Error::InconsistentSizeOfRows(path) => write!(f, "inconsistent size of rows for path {:?}", path),
            Error::InconsistentHeaders => write!(f, "inconsistent headers among input files"),
            Error::DuplicatedColumn(name) => write!(f, "Column {} already exists and cannot be added again", name),
            Error::ColumnNotFound(name) => write!(f, "Requested unexistent column '{}'", name),
            Error::ValueError { data, to_type } => write!(f, "Could not convert value '{}' to type {}", data, to_type),
            Error::ReNoMatch(re, string) => write!(f, "String '{}' doesn't match regular expression {}", string, re),
            Error::InvalidFormat(format) => write!(f, "Template string '{}' is not valid", format),
            Error::IOError(msg) => write!(f, "IOError: {}", msg),
        }
    }
}