Skip to main content

tvdata_rs/scanner/
validation.rs

1use crate::scanner::query::ScanQuery;
2use crate::scanner::{Column, Market};
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct PartiallySupportedColumn {
6    pub column: Column,
7    pub supported_markets: Vec<Market>,
8    pub unsupported_markets: Vec<Market>,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct ScanValidationReport {
13    pub route_segment: String,
14    pub requested_markets: Vec<Market>,
15    pub supported_columns: Vec<Column>,
16    pub partially_supported_columns: Vec<PartiallySupportedColumn>,
17    pub unsupported_columns: Vec<Column>,
18}
19
20impl ScanValidationReport {
21    pub fn is_strictly_supported(&self) -> bool {
22        self.partially_supported_columns.is_empty() && self.unsupported_columns.is_empty()
23    }
24
25    pub fn is_leniently_supported(&self) -> bool {
26        self.unsupported_columns.is_empty()
27    }
28
29    pub fn strict_violation_column_names(&self) -> Vec<&str> {
30        self.partially_supported_columns
31            .iter()
32            .map(|entry| entry.column.as_str())
33            .chain(self.unsupported_columns.iter().map(Column::as_str))
34            .collect()
35    }
36
37    pub fn filtered_query(&self, query: &ScanQuery) -> ScanQuery {
38        let mut filtered = query.clone();
39        filtered.columns = self.supported_columns.clone();
40        filtered
41    }
42
43    pub fn filtered_column_names(&self) -> Vec<&str> {
44        self.supported_columns.iter().map(Column::as_str).collect()
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn report_distinguishes_strict_and_lenient_support() {
54        let report = ScanValidationReport {
55            route_segment: "global/scan".to_owned(),
56            requested_markets: vec![
57                Market::from_static("america"),
58                Market::from_static("crypto"),
59            ],
60            supported_columns: vec![Column::from_static("close")],
61            partially_supported_columns: vec![PartiallySupportedColumn {
62                column: Column::from_static("market_cap_basic"),
63                supported_markets: vec![Market::from_static("america")],
64                unsupported_markets: vec![Market::from_static("crypto")],
65            }],
66            unsupported_columns: vec![Column::from_static("imaginary_field")],
67        };
68
69        assert!(!report.is_strictly_supported());
70        assert!(!report.is_leniently_supported());
71        assert_eq!(
72            report.strict_violation_column_names(),
73            vec!["market_cap_basic", "imaginary_field"]
74        );
75        let filtered =
76            report.filtered_query(&ScanQuery::new().markets(["america", "crypto"]).select([
77                Column::from_static("close"),
78                Column::from_static("market_cap_basic"),
79            ]));
80        assert_eq!(filtered.columns, vec![Column::from_static("close")]);
81    }
82}