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(
68 Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
69)]
70#[serde(rename_all = "snake_case")]
71pub enum RangeRuleCount {
72 ViolatingValues,
75}
76
77#[derive(
85 Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
86)]
87#[serde(rename_all = "snake_case")]
88pub enum KeyUniquenessUnits {
89 NonNullValues,
91}
92
93#[derive(
101 Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
102)]
103#[serde(rename_all = "snake_case")]
104pub enum OutlierUnits {
105 TestedValues,
108}
109
110#[derive(
118 Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
119)]
120#[serde(rename_all = "snake_case")]
121pub enum KeyColumnSource {
122 Declared,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
129#[serde(rename_all = "lowercase")]
130pub enum MetricPack {
131 Schema,
133 Statistics,
135 Patterns,
137 Quality,
139}
140
141impl MetricPack {
142 pub fn all() -> Vec<Self> {
144 vec![
145 Self::Schema,
146 Self::Statistics,
147 Self::Patterns,
148 Self::Quality,
149 ]
150 }
151
152 pub fn include_statistics(packs: Option<&[Self]>) -> bool {
154 match packs {
155 None => true,
156 Some(p) => p.contains(&Self::Statistics),
157 }
158 }
159
160 pub fn include_patterns(packs: Option<&[Self]>) -> bool {
162 match packs {
163 None => true,
164 Some(p) => p.contains(&Self::Patterns),
165 }
166 }
167
168 pub fn include_quality(packs: Option<&[Self]>) -> bool {
170 match packs {
171 None => true,
172 Some(p) => p.contains(&Self::Quality),
173 }
174 }
175
176 pub fn resolve_with_dimensions(
189 packs: Option<&[Self]>,
190 dimensions: Option<&[QualityDimension]>,
191 ) -> Option<Vec<Self>> {
192 if !dimensions.is_some_and(<[QualityDimension]>::is_empty) {
193 return packs.map(<[Self]>::to_vec);
194 }
195 let selected = packs.map_or_else(Self::all, <[Self]>::to_vec);
198 Some(
199 selected
200 .into_iter()
201 .filter(|pack| *pack != Self::Quality)
202 .collect(),
203 )
204 }
205}
206
207impl std::str::FromStr for MetricPack {
208 type Err = String;
209
210 fn from_str(s: &str) -> Result<Self, Self::Err> {
211 match s.to_lowercase().as_str() {
212 "schema" => Ok(Self::Schema),
213 "statistics" => Ok(Self::Statistics),
214 "patterns" => Ok(Self::Patterns),
215 "quality" => Ok(Self::Quality),
216 _ => Err(format!(
217 "Unknown metric pack: {s}. Valid packs: schema, statistics, patterns, quality"
218 )),
219 }
220 }
221}
222
223impl std::fmt::Display for MetricPack {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 match self {
226 Self::Schema => write!(f, "schema"),
227 Self::Statistics => write!(f, "statistics"),
228 Self::Patterns => write!(f, "patterns"),
229 Self::Quality => write!(f, "quality"),
230 }
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237
238 #[test]
239 fn test_metric_pack_include_helpers_none_means_all() {
240 assert!(MetricPack::include_statistics(None));
241 assert!(MetricPack::include_patterns(None));
242 assert!(MetricPack::include_quality(None));
243 }
244
245 #[test]
246 fn test_resolve_with_dimensions_empty_selection_drops_quality() {
247 let resolved = MetricPack::resolve_with_dimensions(None, Some(&[])).unwrap();
251 assert!(!resolved.contains(&MetricPack::Quality));
252 assert!(!MetricPack::include_quality(Some(&resolved)));
253 assert!(resolved.contains(&MetricPack::Schema));
255 assert!(resolved.contains(&MetricPack::Statistics));
256 assert!(resolved.contains(&MetricPack::Patterns));
257 }
258
259 #[test]
260 fn test_resolve_with_dimensions_empty_selection_keeps_explicit_packs() {
261 let packs = vec![MetricPack::Schema, MetricPack::Quality];
262 let resolved = MetricPack::resolve_with_dimensions(Some(&packs), Some(&[])).unwrap();
263 assert_eq!(resolved, vec![MetricPack::Schema]);
264 }
265
266 #[test]
267 fn test_resolve_with_dimensions_non_empty_selection_is_untouched() {
268 let dims = vec![QualityDimension::Completeness];
270 assert_eq!(MetricPack::resolve_with_dimensions(None, Some(&dims)), None);
271 assert!(MetricPack::include_quality(None));
272
273 let packs = vec![MetricPack::Quality];
274 let resolved = MetricPack::resolve_with_dimensions(Some(&packs), Some(&dims)).unwrap();
275 assert!(MetricPack::include_quality(Some(&resolved)));
276 }
277
278 #[test]
279 fn test_resolve_with_dimensions_absent_selection_is_untouched() {
280 assert_eq!(MetricPack::resolve_with_dimensions(None, None), None);
282 let packs = vec![MetricPack::Quality];
283 assert_eq!(
284 MetricPack::resolve_with_dimensions(Some(&packs), None),
285 Some(packs)
286 );
287 }
288
289 #[test]
290 fn test_metric_pack_include_helpers_selective() {
291 let packs = vec![MetricPack::Schema, MetricPack::Quality];
292 assert!(!MetricPack::include_statistics(Some(&packs)));
293 assert!(!MetricPack::include_patterns(Some(&packs)));
294 assert!(MetricPack::include_quality(Some(&packs)));
295 }
296
297 #[test]
298 fn test_metric_pack_from_str() {
299 assert_eq!(
300 "statistics".parse::<MetricPack>().unwrap(),
301 MetricPack::Statistics
302 );
303 assert_eq!(
304 "QUALITY".parse::<MetricPack>().unwrap(),
305 MetricPack::Quality
306 );
307 assert!("invalid".parse::<MetricPack>().is_err());
308 }
309}