1use std::ops::{Deref, DerefMut};
16use std::str::FromStr;
17
18use snafu::OptionExt;
19
20use crate::error::{EmptyInputFieldSnafu, Error, MissingInputFieldSnafu, Result};
21
22#[derive(Debug, Default, Clone)]
24pub struct Field {
25 input_field: String,
26 target_field: Option<String>,
27}
28
29impl FromStr for Field {
30 type Err = Error;
31
32 fn from_str(s: &str) -> Result<Self> {
33 let mut parts = s.split(',');
34 let input_field = parts
35 .next()
36 .context(MissingInputFieldSnafu)?
37 .trim()
38 .to_string();
39 let target_field = parts.next().map(|x| x.trim().to_string());
40
41 if input_field.is_empty() {
42 return EmptyInputFieldSnafu.fail();
43 }
44
45 Ok(Field {
46 input_field,
47 target_field,
48 })
49 }
50}
51
52impl Field {
53 pub(crate) fn new(input_field: impl Into<String>, target_field: Option<String>) -> Self {
55 Field {
56 input_field: input_field.into(),
57 target_field,
58 }
59 }
60
61 pub(crate) fn input_field(&self) -> &str {
63 &self.input_field
64 }
65
66 pub(crate) fn target_field(&self) -> Option<&str> {
68 self.target_field.as_deref()
69 }
70
71 pub(crate) fn target_or_input_field(&self) -> &str {
73 self.target_field.as_deref().unwrap_or(&self.input_field)
74 }
75
76 pub(crate) fn set_target_field(&mut self, target_field: Option<String>) {
77 self.target_field = target_field;
78 }
79}
80
81#[derive(Debug, Default, Clone)]
83pub struct Fields(Vec<Field>);
84
85impl Fields {
86 pub(crate) fn new(fields: Vec<Field>) -> Self {
87 Fields(fields)
88 }
89
90 pub(crate) fn one(field: Field) -> Self {
91 Fields(vec![field])
92 }
93}
94
95impl Deref for Fields {
96 type Target = Vec<Field>;
97
98 fn deref(&self) -> &Self::Target {
99 &self.0
100 }
101}
102
103impl DerefMut for Fields {
104 fn deref_mut(&mut self) -> &mut Self::Target {
105 &mut self.0
106 }
107}
108
109impl IntoIterator for Fields {
110 type Item = Field;
111 type IntoIter = std::vec::IntoIter<Field>;
112
113 fn into_iter(self) -> Self::IntoIter {
114 self.0.into_iter()
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use crate::etl::field::Field;
121
122 #[test]
123 fn test_parse_field() {
124 let field: Result<Field, _> = " ".parse();
125 assert!(field.is_err());
126
127 let field: Result<Field, _> = ",".parse();
128 assert!(field.is_err());
129
130 let field: Result<Field, _> = ",field".parse();
131 assert!(field.is_err());
132
133 let cases = [
134 ("field, target_field", "field", Some("target_field")),
136 ("field", "field", None),
137 ];
138
139 for (s, field, target_field) in cases.into_iter() {
140 let f: Field = s.parse().unwrap();
141 assert_eq!(f.input_field(), field, "{s}");
142 assert_eq!(f.target_field(), target_field, "{s}");
143 }
144 }
145}