csv_sanity/
transformer.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
//! Traits and types that define transformations on CSV record fields.

use std::result;
use std::error;
use std::fmt::{
    self,
    Formatter,
    Display,
};

/// `Result` for the transformation of a CSV record's field, either an `Option<String>` if
/// successfully transformed or a `TransformError` if unsuccessful.
pub type TransformResult = result::Result<Option<String>, TransformError>;

/// Helper trait with a few useful utility methods for constructing `TransformResult`.
pub trait TransformResultHelper
{
    /// Construct a `TransformResult` that represents a successful transformation of a CSV record's
    /// field with a non-empty value.
    fn present(value: &str) -> TransformResult {
        Ok(Some(value.to_string()))
    }

    /// Construct a `TransformResult` that represents a successful tranformation of a CSV record's
    /// field with an empty value.
    fn excluded() -> TransformResult {
        Ok(None)
    }

    /// Construct a `TransformResult` that represents a failed transformation of a CSV record's
    /// field with a descritive error reason.
    ///
    /// An error reason should be a short, single sentence without punctuation or capitization,
    /// e.g. "not a valid email address" instead of "The email address was invalid.".
    ///
    /// ```
    /// use csv_sanity::transformer::{
    ///     TransformResult,
    ///     TransformError,
    ///     TransformResultHelper,
    /// };
    ///
    /// let result = TransformResult::error("jak,.@hot mail.com", "Email", 0, "not a valid email address");
    /// assert_eq!(result, Err(TransformError {
    ///     field_value: "jak,.@hot mail.com".to_string(),
    ///     field_name: "Email".to_string(),
    ///     record_n: 0,
    ///     reason: "not a valid email address".to_string(),
    /// }));
    /// ```
    fn error(field_value: &str, field_name: &str, record_n: usize, reason: &str) -> TransformResult {
        Err(
            TransformError {
                field_value: field_value.to_string(),
                field_name: field_name.to_string(),
                record_n: record_n,
                reason: reason.to_string(),
            }
        )
    }
}

impl TransformResultHelper for TransformResult {}

pub trait Transformer
{
    fn transform(&self, field_value: &str, field_name: &str, record_n: usize) -> TransformResult;
}

#[derive(RustcEncodable, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, Debug)]
pub struct TransformError
{
    pub record_n: usize,
    pub field_name: String,
    pub field_value: String,
    pub reason: String,
}

impl Display for TransformError
{
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        write!(formatter, "failed to transform field: {}", self.reason)
    }
}

impl error::Error for TransformError
{
    fn description(&self) -> &str {
        &self.reason
    }
}