1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
3#[serde(rename_all = "lowercase")]
4pub enum QualityDimension {
5 Completeness,
6 Consistency,
7 Uniqueness,
8 Accuracy,
9 Timeliness,
10 Validity,
11 Precision,
12}
13
14impl QualityDimension {
15 pub fn all() -> Vec<Self> {
17 vec![
18 Self::Completeness,
19 Self::Consistency,
20 Self::Uniqueness,
21 Self::Accuracy,
22 Self::Timeliness,
23 Self::Validity,
24 Self::Precision,
25 ]
26 }
27}
28
29impl std::str::FromStr for QualityDimension {
30 type Err = String;
31
32 fn from_str(s: &str) -> Result<Self, Self::Err> {
33 match s.to_lowercase().as_str() {
34 "completeness" => Ok(Self::Completeness),
35 "consistency" => Ok(Self::Consistency),
36 "uniqueness" => Ok(Self::Uniqueness),
37 "accuracy" => Ok(Self::Accuracy),
38 "timeliness" => Ok(Self::Timeliness),
39 "validity" => Ok(Self::Validity),
40 "precision" => Ok(Self::Precision),
41 _ => Err(format!("Unknown quality dimension: {s}")),
42 }
43 }
44}
45
46impl std::fmt::Display for QualityDimension {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 match self {
49 Self::Completeness => write!(f, "completeness"),
50 Self::Consistency => write!(f, "consistency"),
51 Self::Uniqueness => write!(f, "uniqueness"),
52 Self::Accuracy => write!(f, "accuracy"),
53 Self::Timeliness => write!(f, "timeliness"),
54 Self::Validity => write!(f, "validity"),
55 Self::Precision => write!(f, "precision"),
56 }
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
62#[serde(rename_all = "lowercase")]
63pub enum MetricPack {
64 Schema,
66 Statistics,
68 Patterns,
70 Quality,
72}
73
74impl MetricPack {
75 pub fn all() -> Vec<Self> {
77 vec![
78 Self::Schema,
79 Self::Statistics,
80 Self::Patterns,
81 Self::Quality,
82 ]
83 }
84
85 pub fn include_statistics(packs: Option<&[Self]>) -> bool {
87 match packs {
88 None => true,
89 Some(p) => p.contains(&Self::Statistics),
90 }
91 }
92
93 pub fn include_patterns(packs: Option<&[Self]>) -> bool {
95 match packs {
96 None => true,
97 Some(p) => p.contains(&Self::Patterns),
98 }
99 }
100
101 pub fn include_quality(packs: Option<&[Self]>) -> bool {
103 match packs {
104 None => true,
105 Some(p) => p.contains(&Self::Quality),
106 }
107 }
108
109 pub fn resolve_with_dimensions(
122 packs: Option<&[Self]>,
123 dimensions: Option<&[QualityDimension]>,
124 ) -> Option<Vec<Self>> {
125 if !dimensions.is_some_and(<[QualityDimension]>::is_empty) {
126 return packs.map(<[Self]>::to_vec);
127 }
128 let selected = packs.map_or_else(Self::all, <[Self]>::to_vec);
131 Some(
132 selected
133 .into_iter()
134 .filter(|pack| *pack != Self::Quality)
135 .collect(),
136 )
137 }
138}
139
140impl std::str::FromStr for MetricPack {
141 type Err = String;
142
143 fn from_str(s: &str) -> Result<Self, Self::Err> {
144 match s.to_lowercase().as_str() {
145 "schema" => Ok(Self::Schema),
146 "statistics" => Ok(Self::Statistics),
147 "patterns" => Ok(Self::Patterns),
148 "quality" => Ok(Self::Quality),
149 _ => Err(format!(
150 "Unknown metric pack: {s}. Valid packs: schema, statistics, patterns, quality"
151 )),
152 }
153 }
154}
155
156impl std::fmt::Display for MetricPack {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 Self::Schema => write!(f, "schema"),
160 Self::Statistics => write!(f, "statistics"),
161 Self::Patterns => write!(f, "patterns"),
162 Self::Quality => write!(f, "quality"),
163 }
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_metric_pack_include_helpers_none_means_all() {
173 assert!(MetricPack::include_statistics(None));
174 assert!(MetricPack::include_patterns(None));
175 assert!(MetricPack::include_quality(None));
176 }
177
178 #[test]
179 fn test_resolve_with_dimensions_empty_selection_drops_quality() {
180 let resolved = MetricPack::resolve_with_dimensions(None, Some(&[])).unwrap();
184 assert!(!resolved.contains(&MetricPack::Quality));
185 assert!(!MetricPack::include_quality(Some(&resolved)));
186 assert!(resolved.contains(&MetricPack::Schema));
188 assert!(resolved.contains(&MetricPack::Statistics));
189 assert!(resolved.contains(&MetricPack::Patterns));
190 }
191
192 #[test]
193 fn test_resolve_with_dimensions_empty_selection_keeps_explicit_packs() {
194 let packs = vec![MetricPack::Schema, MetricPack::Quality];
195 let resolved = MetricPack::resolve_with_dimensions(Some(&packs), Some(&[])).unwrap();
196 assert_eq!(resolved, vec![MetricPack::Schema]);
197 }
198
199 #[test]
200 fn test_resolve_with_dimensions_non_empty_selection_is_untouched() {
201 let dims = vec![QualityDimension::Completeness];
203 assert_eq!(MetricPack::resolve_with_dimensions(None, Some(&dims)), None);
204 assert!(MetricPack::include_quality(None));
205
206 let packs = vec![MetricPack::Quality];
207 let resolved = MetricPack::resolve_with_dimensions(Some(&packs), Some(&dims)).unwrap();
208 assert!(MetricPack::include_quality(Some(&resolved)));
209 }
210
211 #[test]
212 fn test_resolve_with_dimensions_absent_selection_is_untouched() {
213 assert_eq!(MetricPack::resolve_with_dimensions(None, None), None);
215 let packs = vec![MetricPack::Quality];
216 assert_eq!(
217 MetricPack::resolve_with_dimensions(Some(&packs), None),
218 Some(packs)
219 );
220 }
221
222 #[test]
223 fn test_metric_pack_include_helpers_selective() {
224 let packs = vec![MetricPack::Schema, MetricPack::Quality];
225 assert!(!MetricPack::include_statistics(Some(&packs)));
226 assert!(!MetricPack::include_patterns(Some(&packs)));
227 assert!(MetricPack::include_quality(Some(&packs)));
228 }
229
230 #[test]
231 fn test_metric_pack_from_str() {
232 assert_eq!(
233 "statistics".parse::<MetricPack>().unwrap(),
234 MetricPack::Statistics
235 );
236 assert_eq!(
237 "QUALITY".parse::<MetricPack>().unwrap(),
238 MetricPack::Quality
239 );
240 assert!("invalid".parse::<MetricPack>().is_err());
241 }
242}