evidentsource_core/domain/
selectors.rs1use super::error::IdentifierError;
7use super::identifiers::{EventSubject, EventType, StreamName};
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub enum EventAttribute {
12 Stream(StreamName),
14 Subject(Option<EventSubject>),
16 EventType(EventType),
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub enum EventAttributePrefix {
23 Stream(StreamName),
25 Subject(EventSubject),
27 EventType(EventType),
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Hash)]
36pub enum EventSelector {
37 Equals(EventAttribute),
39
40 StartsWith(EventAttributePrefix),
42
43 And {
45 left: Box<EventSelector>,
46 right: Box<EventSelector>,
47 },
48
49 Or {
51 left: Box<EventSelector>,
52 right: Box<EventSelector>,
53 },
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
61pub enum FlatSelectorNode {
62 Equals(EventAttribute),
64 StartsWith(EventAttributePrefix),
66 And(u32, u32),
68 Or(u32, u32),
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
85pub enum QueryDirection {
86 #[default]
88 Forward,
89 Reverse,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
114pub struct QueryOptions {
115 direction: QueryDirection,
117 limit: Option<u64>,
119}
120
121impl QueryOptions {
122 pub fn new() -> Self {
124 Self::default()
125 }
126
127 pub fn direction(mut self, direction: QueryDirection) -> Self {
129 self.direction = direction;
130 self
131 }
132
133 pub fn forward(mut self) -> Self {
135 self.direction = QueryDirection::Forward;
136 self
137 }
138
139 pub fn reverse(mut self) -> Self {
141 self.direction = QueryDirection::Reverse;
142 self
143 }
144
145 pub fn limit(mut self, limit: u64) -> Self {
147 self.limit = Some(limit);
148 self
149 }
150
151 pub fn get_direction(&self) -> QueryDirection {
153 self.direction
154 }
155
156 pub fn get_limit(&self) -> Option<u64> {
158 self.limit
159 }
160}
161
162impl EventSelector {
163 pub fn stream_equals(stream: impl AsRef<str>) -> Result<Self, IdentifierError> {
165 let s = StreamName::new(stream.as_ref())?;
166 Ok(EventSelector::Equals(EventAttribute::Stream(s)))
167 }
168
169 pub fn subject_equals(subject: impl AsRef<str>) -> Result<Self, IdentifierError> {
171 let s = EventSubject::new(subject.as_ref())?;
172 Ok(EventSelector::Equals(EventAttribute::Subject(Some(s))))
173 }
174
175 pub fn no_subject() -> Self {
177 EventSelector::Equals(EventAttribute::Subject(None))
178 }
179
180 pub fn event_type_equals(event_type: impl AsRef<str>) -> Result<Self, IdentifierError> {
182 let et = EventType::new(event_type.as_ref())?;
183 Ok(EventSelector::Equals(EventAttribute::EventType(et)))
184 }
185
186 pub fn stream_starts_with(prefix: impl AsRef<str>) -> Result<Self, IdentifierError> {
188 let s = StreamName::new(prefix.as_ref())?;
189 Ok(EventSelector::StartsWith(EventAttributePrefix::Stream(s)))
190 }
191
192 pub fn subject_starts_with(prefix: impl AsRef<str>) -> Result<Self, IdentifierError> {
194 let s = EventSubject::new(prefix.as_ref())?;
195 Ok(EventSelector::StartsWith(EventAttributePrefix::Subject(s)))
196 }
197
198 pub fn event_type_starts_with(prefix: impl AsRef<str>) -> Result<Self, IdentifierError> {
200 let et = EventType::new(prefix.as_ref())?;
201 Ok(EventSelector::StartsWith(EventAttributePrefix::EventType(
202 et,
203 )))
204 }
205
206 pub fn and(self, other: EventSelector) -> Self {
208 EventSelector::And {
209 left: Box::new(self),
210 right: Box::new(other),
211 }
212 }
213
214 pub fn or(self, other: EventSelector) -> Self {
216 EventSelector::Or {
217 left: Box::new(self),
218 right: Box::new(other),
219 }
220 }
221
222 pub fn matches_prospective(&self, event: &super::ProspectiveEvent) -> bool {
226 match self {
227 EventSelector::Equals(attr) => match attr {
228 EventAttribute::Stream(expected) => event.stream() == expected.as_str(),
229 EventAttribute::Subject(expected) => match (event.subject(), expected) {
230 (Some(actual), Some(exp)) => actual == exp.as_str(),
231 (None, None) => true,
232 _ => false,
233 },
234 EventAttribute::EventType(expected) => event.event_type() == expected.as_str(),
235 },
236 EventSelector::StartsWith(prefix) => match prefix {
237 EventAttributePrefix::Stream(p) => event.stream().starts_with(p.as_str()),
238 EventAttributePrefix::Subject(p) => event
239 .subject()
240 .map(|s| s.starts_with(p.as_str()))
241 .unwrap_or(false),
242 EventAttributePrefix::EventType(p) => event.event_type().starts_with(p.as_str()),
243 },
244 EventSelector::And { left, right } => {
245 left.matches_prospective(event) && right.matches_prospective(event)
246 }
247 EventSelector::Or { left, right } => {
248 left.matches_prospective(event) || right.matches_prospective(event)
249 }
250 }
251 }
252
253 pub fn matches(&self, event: &super::Event) -> bool {
257 match self {
258 EventSelector::Equals(attr) => match attr {
259 EventAttribute::Stream(expected) => {
260 event
262 .stream()
263 .map(|s| s == expected.as_str())
264 .unwrap_or(false)
265 }
266 EventAttribute::Subject(expected) => match (event.subject(), expected) {
267 (Some(actual), Some(exp)) => actual == exp.as_str(),
268 (None, None) => true,
269 _ => false,
270 },
271 EventAttribute::EventType(expected) => event.event_type() == expected.as_str(),
272 },
273 EventSelector::StartsWith(prefix) => match prefix {
274 EventAttributePrefix::Stream(p) => event
275 .stream()
276 .map(|s| s.starts_with(p.as_str()))
277 .unwrap_or(false),
278 EventAttributePrefix::Subject(p) => event
279 .subject()
280 .map(|s| s.starts_with(p.as_str()))
281 .unwrap_or(false),
282 EventAttributePrefix::EventType(p) => event.event_type().starts_with(p.as_str()),
283 },
284 EventSelector::And { left, right } => left.matches(event) && right.matches(event),
285 EventSelector::Or { left, right } => left.matches(event) || right.matches(event),
286 }
287 }
288
289 pub fn flatten(&self) -> Vec<FlatSelectorNode> {
295 let mut nodes = Vec::new();
296 self.flatten_into(&mut nodes);
297 nodes
298 }
299
300 fn flatten_into(&self, nodes: &mut Vec<FlatSelectorNode>) -> u32 {
301 match self {
302 EventSelector::Equals(attr) => {
303 let idx = nodes.len() as u32;
304 nodes.push(FlatSelectorNode::Equals(attr.clone()));
305 idx
306 }
307 EventSelector::StartsWith(prefix) => {
308 let idx = nodes.len() as u32;
309 nodes.push(FlatSelectorNode::StartsWith(prefix.clone()));
310 idx
311 }
312 EventSelector::And { left, right } => {
313 let left_idx = left.flatten_into(nodes);
314 let right_idx = right.flatten_into(nodes);
315 let idx = nodes.len() as u32;
316 nodes.push(FlatSelectorNode::And(left_idx, right_idx));
317 idx
318 }
319 EventSelector::Or { left, right } => {
320 let left_idx = left.flatten_into(nodes);
321 let right_idx = right.flatten_into(nodes);
322 let idx = nodes.len() as u32;
323 nodes.push(FlatSelectorNode::Or(left_idx, right_idx));
324 idx
325 }
326 }
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_simple_selector() {
336 let selector = EventSelector::stream_equals("my-stream").unwrap();
337
338 assert!(matches!(
339 selector,
340 EventSelector::Equals(EventAttribute::Stream(s)) if s.as_str() == "my-stream"
341 ));
342 }
343
344 #[test]
345 fn test_and_selector() {
346 let selector = EventSelector::stream_equals("my-stream")
347 .unwrap()
348 .and(EventSelector::event_type_equals("my.event").unwrap());
349
350 assert!(matches!(selector, EventSelector::And { .. }));
351 }
352
353 #[test]
354 fn test_or_selector() {
355 let selector = EventSelector::event_type_equals("type1")
356 .unwrap()
357 .or(EventSelector::event_type_equals("type2").unwrap());
358
359 assert!(matches!(selector, EventSelector::Or { .. }));
360 }
361
362 #[test]
363 fn test_no_subject() {
364 let selector = EventSelector::no_subject();
365 assert!(matches!(
366 selector,
367 EventSelector::Equals(EventAttribute::Subject(None))
368 ));
369 }
370
371 #[test]
372 fn test_flatten_simple() {
373 let selector = EventSelector::event_type_equals("my.event").unwrap();
374 let nodes = selector.flatten();
375
376 assert_eq!(nodes.len(), 1);
377 assert!(matches!(
378 nodes[0],
379 FlatSelectorNode::Equals(EventAttribute::EventType(_))
380 ));
381 }
382
383 #[test]
384 fn test_flatten_and() {
385 let selector = EventSelector::subject_equals("sub-123")
386 .unwrap()
387 .and(EventSelector::event_type_equals("my.event").unwrap());
388
389 let nodes = selector.flatten();
390
391 assert_eq!(nodes.len(), 3);
392 assert!(matches!(
394 nodes[0],
395 FlatSelectorNode::Equals(EventAttribute::Subject(_))
396 ));
397 assert!(matches!(
398 nodes[1],
399 FlatSelectorNode::Equals(EventAttribute::EventType(_))
400 ));
401 assert!(matches!(nodes[2], FlatSelectorNode::And(0, 1)));
403 }
404
405 #[test]
406 fn test_flatten_complex() {
407 let selector = EventSelector::subject_equals("sub")
409 .unwrap()
410 .and(EventSelector::event_type_equals("type1").unwrap())
411 .or(EventSelector::event_type_equals("type2").unwrap());
412
413 let nodes = selector.flatten();
414
415 assert_eq!(nodes.len(), 5);
416 assert!(matches!(nodes[4], FlatSelectorNode::Or(2, 3)));
418 }
419
420 #[test]
421 fn test_query_direction_default() {
422 let dir = QueryDirection::default();
423 assert_eq!(dir, QueryDirection::Forward);
424 }
425
426 #[test]
427 fn test_query_options_default() {
428 let opts = QueryOptions::default();
429 assert_eq!(opts.get_direction(), QueryDirection::Forward);
430 assert_eq!(opts.get_limit(), None);
431 }
432
433 #[test]
434 fn test_query_options_builder() {
435 let opts = QueryOptions::new()
436 .direction(QueryDirection::Reverse)
437 .limit(100);
438
439 assert_eq!(opts.get_direction(), QueryDirection::Reverse);
440 assert_eq!(opts.get_limit(), Some(100));
441 }
442
443 #[test]
444 fn test_query_options_convenience_methods() {
445 let opts = QueryOptions::new().reverse().limit(50);
446 assert_eq!(opts.get_direction(), QueryDirection::Reverse);
447 assert_eq!(opts.get_limit(), Some(50));
448
449 let opts = QueryOptions::new().forward();
450 assert_eq!(opts.get_direction(), QueryDirection::Forward);
451 }
452}