dctap/
tap_config.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::{collections::HashMap, path::Path};

use serde_derive::{Deserialize, Serialize};

use crate::{PlaceholderResolver, TapError};

#[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Default)]
pub struct DCTapConfig {
    pub dctap: Option<TapConfig>,
}

impl DCTapConfig {
    /// Obtain a DCTapConfig from a path file in YAML
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<DCTapConfig, TapError> {
        let path_name = path.as_ref().display().to_string();
        let f = std::fs::File::open(path).map_err(|e| TapError::TapConfigFromPathError {
            path: path_name.clone(),
            error: e,
        })?;
        let config: DCTapConfig =
            serde_yml::from_reader(f).map_err(|e| TapError::TapConfigYamlError {
                path: path_name.clone(),
                error: e,
            })?;
        Ok(config)
    }
}

/// Represents configuration file structure of DCTAP files
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Default)]
pub struct TapConfig {
    /// Character that is used to separate columns in CSV
    delimiter: Option<char>,

    /// The quote character to use when parsing CSV.
    /// The default is `"`.
    /// It can be used to indicate single quotes instead of double quotes.
    quote: Option<char>,

    /// Whether the number of fields in records is allowed to change or not.
    ///
    /// When disabled, parsing CSV data will return an
    /// error if a record is found with a number of fields different from the
    /// number of fields in a previous record.
    ///
    /// When enabled, this error checking is turned off. It is enabled by default.
    flexible: Option<bool>,

    /// Character that is used to separate values in a picklist cell. The default value is `|`
    picklist_delimiter: Option<char>,

    /// Table that can be used to generate values for some keys.
    /// When the processor finds a cell with some of those keys,
    /// it generates a value according to the placeholder resolver indicated.
    /// At this moment, `rudof` supports the placeholder resolver `!Stem`
    /// which means that it will replace the key by the corresponding stem value.
    ///
    /// For example, if the property placeholder has the entry `x` with the
    /// placeholder resolver of type `!Stem` and the value `stem: "Pending"`,
    /// when a cell contains `x:User`, the generated value will be: `pending:User`.
    ///
    /// <div class="warning">This field is experimental and the syntax may change</div>
    ///
    property_placeholders: HashMap<String, PlaceholderResolver>,

    /// Indicates how to generate a value for a row whose property ID is empty.
    ///
    /// When the processor find
    ///
    /// <div class="warning">This field is experimental and the syntax may change</div>
    ///
    empty_property_placeholder: Option<PlaceholderResolver>,
}

impl TapConfig {
    pub fn picklist_delimiter(&self) -> &char {
        match &self.picklist_delimiter {
            None => &'|',
            Some(c) => c,
        }
    }

    pub fn delimiter(&self) -> u8 {
        match self.delimiter {
            None => b',',
            Some(c) => c as u8,
        }
    }

    pub fn quote(&self) -> u8 {
        match self.quote {
            None => b'"',
            Some(c) => c as u8,
        }
    }

    pub fn flexible(&self) -> bool {
        self.flexible.unwrap_or(true)
    }

    pub fn with_property_placeholders(
        mut self,
        property_place_holders: HashMap<String, PlaceholderResolver>,
    ) -> Self {
        self.property_placeholders = property_place_holders;
        self
    }

    pub fn with_picklist_delimiter(mut self, c: char) -> Self {
        self.picklist_delimiter = Some(c);
        self
    }

    pub fn with_empty_property_placeholder(mut self, placeholder: PlaceholderResolver) -> Self {
        self.empty_property_placeholder = Some(placeholder);
        self
    }

    pub fn get_property_placeholder(&self, str: &str) -> Option<PlaceholderResolver> {
        if str.is_empty() {
            self.empty_property_placeholder.clone()
        } else {
            self.property_placeholders.get(str).cloned()
        }
    }

    pub fn empty_property_placeholder(&self) -> Option<PlaceholderResolver> {
        self.empty_property_placeholder.clone()
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    // use tracing::debug;
    // use tracing_test::traced_test;

    use crate::PlaceholderResolver;

    use super::TapConfig;

    // #[traced_test]
    #[test]
    fn test_config() {
        let key = "nalt";
        let resolver = PlaceholderResolver::stem("pending");
        let mut ph = HashMap::new();
        ph.insert(key.to_string(), resolver.clone());
        let config = TapConfig::default()
            .with_property_placeholders(ph)
            .with_empty_property_placeholder(resolver.clone());
        // let yaml = serde_yml::to_string(&config).unwrap();
        // debug!("YAML\n{yaml}");
        assert_eq!(
            config.get_property_placeholder("nalt"),
            Some(resolver.clone())
        );
        assert_eq!(config.get_property_placeholder(""), Some(resolver.clone()))
    }
}