superposition_types/
contextual.rs1use 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}