Skip to main content

superposition_types/
contextual.rs

1use std::collections::HashMap;
2
3use serde_json::{Map, Value};
4
5use crate::config::Condition;
6use crate::{logic, DimensionInfo};
7
8pub trait Contextual: Clone {
9    fn get_condition(&self) -> Condition;
10
11    fn filter_by_eval(
12        contexts: Vec<Self>,
13        dimension_data: &Map<String, Value>,
14    ) -> Vec<Self> {
15        contexts
16            .into_iter()
17            .filter(|context| {
18                crate::partial_apply(&context.get_condition().into(), dimension_data)
19            })
20            .collect()
21    }
22
23    fn filter_exact_match(
24        contexts: Vec<Self>,
25        dimension_data: &Map<String, Value>,
26    ) -> Vec<Self> {
27        contexts
28            .into_iter()
29            .filter(|context| {
30                let condition = context.get_condition().into();
31                logic::apply(&condition, dimension_data)
32                    && condition.len() == dimension_data.len()
33            })
34            .collect()
35    }
36
37    fn filter_by_dimension(
38        contexts: Vec<Self>,
39        dimension_keys: &[String],
40        request_keys_len: usize,
41        dimensions_info: &HashMap<String, DimensionInfo>,
42    ) -> Vec<Self> {
43        contexts
44            .into_iter()
45            .filter(|context| {
46                let variables: Map<String, Value> = context.get_condition().into();
47                dimension_keys.iter().all(|dimension| {
48                    variables.contains_key(dimension)
49                        || dimensions_info
50                            .get(dimension)
51                            .map(|info| {
52                                info.dependency_graph
53                                    .keys()
54                                    .any(|k| variables.contains_key(k))
55                            })
56                            .unwrap_or_default()
57                }) && request_keys_len <= variables.len()
58            })
59            .collect()
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use crate::config::tests::map::{
66        get_dimension_filtered_contexts1, get_dimension_filtered_contexts2,
67        with_dimensions::{
68            get_config, get_dimension_filtered_config1, get_dimension_filtered_config2,
69        },
70    };
71    use crate::config::tests::{
72        get_dimension_data1, get_dimension_data2, get_dimension_data3,
73        get_dimension_filtered_config3_with_dimension,
74    };
75
76    use super::Contextual;
77
78    #[test]
79    fn filter_by_eval() {
80        let config = get_config();
81
82        assert_eq!(
83            Contextual::filter_by_eval(config.contexts.clone(), &get_dimension_data1()),
84            get_dimension_filtered_config1().contexts
85        );
86
87        assert_eq!(
88            Contextual::filter_by_eval(config.contexts.clone(), &get_dimension_data2()),
89            get_dimension_filtered_config2().contexts
90        );
91
92        assert_eq!(
93            Contextual::filter_by_eval(config.contexts, &get_dimension_data3()),
94            get_dimension_filtered_config3_with_dimension().contexts
95        );
96    }
97
98    #[test]
99    fn filter_by_dimension() {
100        let config = get_config();
101
102        assert_eq!(
103            Contextual::filter_by_dimension(
104                config.contexts.clone(),
105                &get_dimension_data1().keys().cloned().collect::<Vec<_>>(),
106                get_dimension_data1().len(),
107                &config.dimensions
108            ),
109            get_dimension_filtered_contexts1()
110        );
111
112        assert_eq!(
113            Contextual::filter_by_dimension(
114                config.contexts.clone(),
115                &get_dimension_data2().keys().cloned().collect::<Vec<_>>(),
116                get_dimension_data2().len(),
117                &config.dimensions
118            ),
119            get_dimension_filtered_contexts2()
120        );
121
122        assert_eq!(
123            Contextual::filter_by_dimension(
124                config.contexts,
125                &get_dimension_data3().keys().cloned().collect::<Vec<_>>(),
126                get_dimension_data3().len(),
127                &config.dimensions
128            ),
129            Vec::new()
130        );
131    }
132}