1use crate::error::EventsRoutingError;
6use crate::walk_state::WalkStateUnit;
7use cm_rust::DictionaryValue;
8use cm_types::Name;
9use maplit::btreemap;
10use moniker::ExtendedMoniker;
11use std::collections::BTreeMap;
12
13#[derive(Debug, Clone)]
14pub struct EventSubscription<NameType = Name>
15where
16 NameType: Clone,
17{
18 pub event_name: NameType,
19}
20
21impl<T: Clone> EventSubscription<T> {
22 pub fn new(event_name: T) -> Self {
23 Self { event_name }
24 }
25}
26
27type OptionFilterMap = Option<BTreeMap<String, DictionaryValue>>;
28
29#[derive(Debug, Clone, Eq, PartialEq)]
30pub struct EventFilter {
31 moniker: ExtendedMoniker,
32 filter: Option<BTreeMap<String, DictionaryValue>>,
33 is_debug: bool,
34}
35
36impl EventFilter {
37 pub fn new(
38 moniker: impl Into<ExtendedMoniker>,
39 filter: Option<BTreeMap<String, DictionaryValue>>,
40 ) -> Self {
41 Self { moniker: moniker.into(), filter, is_debug: false }
42 }
43
44 pub fn debug(moniker: ExtendedMoniker) -> Self {
45 Self { moniker, filter: None, is_debug: true }
46 }
47
48 pub fn has_fields(&self, fields: &OptionFilterMap) -> bool {
51 if self.is_debug {
52 return true;
53 }
54 Self::validate_subset(&self.moniker, &fields, &self.filter).is_ok()
55 }
56
57 pub fn contains(&self, key: impl Into<String>, values: Vec<String>) -> bool {
58 self.has_fields(&Some(btreemap! {key.into() => DictionaryValue::StrVec(values)}))
59 }
60
61 fn validate_subset(
62 moniker: &ExtendedMoniker,
63 self_filter: &OptionFilterMap,
64 next_filter: &OptionFilterMap,
65 ) -> Result<(), EventsRoutingError> {
66 match (self_filter, next_filter) {
67 (None, None) => {}
68 (None, Some(_)) => {}
69 (Some(filter), Some(next_filter)) => {
70 for (key, value) in filter {
71 if !(next_filter.contains_key(key)
72 && is_subset(value, next_filter.get(key).as_ref().unwrap()))
73 {
74 return Err(EventsRoutingError::InvalidFilter { moniker: moniker.clone() });
75 }
76 }
77 }
78 (Some(_), None) => {
79 return Err(EventsRoutingError::InvalidFilter { moniker: moniker.clone() });
80 }
81 }
82 Ok(())
83 }
84}
85
86impl WalkStateUnit for EventFilter {
87 type Error = EventsRoutingError;
88
89 fn validate_next(&self, next_state: &EventFilter) -> Result<(), Self::Error> {
97 Self::validate_subset(&self.moniker, &self.filter, &next_state.filter)
98 }
99
100 fn finalize_error(&self) -> Self::Error {
101 EventsRoutingError::MissingFilter { moniker: self.moniker.clone() }
102 }
103}
104
105fn is_subset(prev_value: &DictionaryValue, next_value: &DictionaryValue) -> bool {
106 match (prev_value, next_value) {
107 (DictionaryValue::Str(field), DictionaryValue::Str(next_field)) => field == next_field,
108 (DictionaryValue::StrVec(fields), DictionaryValue::StrVec(next_fields)) => {
109 fields.iter().all(|field| next_fields.contains(field))
110 }
111 (DictionaryValue::Str(field), DictionaryValue::StrVec(next_fields)) => {
112 next_fields.contains(field)
113 }
114 (DictionaryValue::StrVec(fields), DictionaryValue::Str(next_field)) => {
115 if fields.is_empty() {
116 return true;
117 }
118 if fields.len() > 1 {
119 return false;
120 }
121 fields.contains(next_field)
122 }
123 _ => false,
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use assert_matches::assert_matches;
132 use maplit::btreemap;
133 use moniker::Moniker;
134
135 #[test]
136 fn test_filter_walk_state() {
137 let none_filter = EventFilter::new(Moniker::root(), None);
138 let empty_filter = EventFilter::new(Moniker::root(), Some(btreemap! {}));
139 let single_field_filter = EventFilter::new(
140 Moniker::root(),
141 Some(btreemap! {
142 "field".to_string() => DictionaryValue::Str("/foo".to_string()),
143 }),
144 );
145 let single_field_filter_2 = EventFilter::new(
146 Moniker::root(),
147 Some(btreemap! {
148 "field".to_string() => DictionaryValue::Str("/bar".to_string()),
149 }),
150 );
151 let multi_field_filter = EventFilter::new(
152 Moniker::root(),
153 Some(btreemap! {
154 "field".to_string() => DictionaryValue::StrVec(vec![
155 "/bar".to_string(), "/baz".to_string()])
156 }),
157 );
158 let multi_field_filter_2 = EventFilter::new(
159 Moniker::root(),
160 Some(btreemap! {
161 "field".to_string() => DictionaryValue::StrVec(vec![
162 "/bar".to_string(), "/baz".to_string(), "/foo".to_string()])
163 }),
164 );
165 let multi_field_single = EventFilter::new(
166 Moniker::root(),
167 Some(btreemap! {
168 "field".to_string() => DictionaryValue::StrVec(vec!["/foo".to_string()])
169 }),
170 );
171 let multi_field_empty = EventFilter::new(
172 Moniker::root(),
173 Some(btreemap! {
174 "field".to_string() => DictionaryValue::StrVec(vec![])
175 }),
176 );
177
178 assert_matches!(none_filter.validate_next(&none_filter), Ok(()));
179
180 assert_matches!(
181 single_field_filter.validate_next(&none_filter),
182 Err(EventsRoutingError::InvalidFilter { .. })
183 );
184 assert_matches!(
185 single_field_filter.validate_next(&empty_filter),
186 Err(EventsRoutingError::InvalidFilter { .. })
187 );
188 assert_matches!(single_field_filter.validate_next(&single_field_filter), Ok(()));
189 assert_matches!(
190 single_field_filter.validate_next(&single_field_filter_2),
191 Err(EventsRoutingError::InvalidFilter { .. })
192 );
193 assert_matches!(
194 single_field_filter.validate_next(&multi_field_filter),
195 Err(EventsRoutingError::InvalidFilter { .. })
196 );
197 assert_matches!(single_field_filter.validate_next(&multi_field_filter_2), Ok(()));
198
199 assert_matches!(
200 multi_field_filter.validate_next(&none_filter),
201 Err(EventsRoutingError::InvalidFilter { .. })
202 );
203 assert_matches!(
204 multi_field_filter_2.validate_next(&multi_field_filter),
205 Err(EventsRoutingError::InvalidFilter { .. })
206 );
207 assert_matches!(
208 multi_field_filter.validate_next(&single_field_filter),
209 Err(EventsRoutingError::InvalidFilter { .. })
210 );
211 assert_matches!(
212 multi_field_filter.validate_next(&single_field_filter_2),
213 Err(EventsRoutingError::InvalidFilter { .. })
214 );
215 assert_matches!(multi_field_filter.validate_next(&multi_field_filter), Ok(()));
216 assert_matches!(multi_field_filter.validate_next(&multi_field_filter_2), Ok(()));
217 assert_matches!(
218 multi_field_filter.validate_next(&empty_filter),
219 Err(EventsRoutingError::InvalidFilter { .. })
220 );
221
222 assert_matches!(
223 empty_filter.validate_next(&none_filter),
224 Err(EventsRoutingError::InvalidFilter { .. })
225 );
226 assert_matches!(empty_filter.validate_next(&empty_filter), Ok(()));
227 assert_matches!(empty_filter.validate_next(&single_field_filter), Ok(()));
228 assert_matches!(empty_filter.validate_next(&multi_field_filter), Ok(()));
229
230 assert_matches!(multi_field_single.validate_next(&single_field_filter), Ok(()));
231 assert_matches!(multi_field_empty.validate_next(&single_field_filter), Ok(()));
232 }
233
234 #[test]
235 fn contains_filter() {
236 let filter = EventFilter::new(
237 Moniker::root(),
238 Some(btreemap! {
239 "field".to_string() => DictionaryValue::StrVec(vec!["/foo".to_string(), "/bar".to_string()]),
240 }),
241 );
242
243 assert!(filter.contains("field", vec!["/foo".to_string()]));
244 assert!(filter.contains("field", vec!["/foo".to_string(), "/bar".to_string()]));
245 assert!(!filter.contains("field2", vec!["/foo".to_string()]));
246 assert!(!filter
247 .contains("field2", vec!["/foo".to_string(), "/bar".to_string(), "/baz".to_string()]));
248 assert!(!filter.contains("field2", vec!["/baz".to_string()]));
249 }
250}