1use sofie_core::Instant;
2
3use crate::{Currency, Email, Money};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum Operator {
7 Equals,
8 NotEquals,
9 GreaterThan,
10 LessThan,
11 AtLeast,
12 AtMost,
13 Between,
14 Contains,
15 IsEmpty,
16}
17
18impl Operator {
19 #[must_use]
21 pub fn named(name: &str) -> Option<Self> {
22 Some(match name {
23 "ne" => Self::NotEquals,
24 "gt" => Self::GreaterThan,
25 "lt" => Self::LessThan,
26 "gte" => Self::AtLeast,
27 "lte" => Self::AtMost,
28 "between" => Self::Between,
29 "contains" => Self::Contains,
30 "empty" => Self::IsEmpty,
31 _ => return None,
32 })
33 }
34}
35
36pub trait Filter {
37 const OPERATORS: &'static [Operator];
38}
39
40pub const ORDERED: &[Operator] = &[
41 Operator::Equals,
42 Operator::GreaterThan,
43 Operator::LessThan,
44 Operator::AtLeast,
45 Operator::AtMost,
46 Operator::Between,
47];
48pub const TEXT: &[Operator] = &[Operator::Equals, Operator::NotEquals, Operator::Contains];
49pub const EXACT: &[Operator] = &[Operator::Equals, Operator::NotEquals];
51
52macro_rules! filters {
53 ($operators:expr => $($value:ty),+) => {$(
54 impl Filter for $value {
55 const OPERATORS: &'static [Operator] = $operators;
56 }
57 )+};
58}
59
60filters!(ORDERED => i16, i32, i64, u16, u32, Money, Instant);
61filters!(TEXT => String);
62filters!(EXACT => bool, Currency, Email);
63
64impl<V: crate::SurfacesFromInner<Inner: Filter>> Filter for V {
65 const OPERATORS: &'static [Operator] = if <V as crate::SurfacesFromInner>::SENSITIVE {
66 EXACT
67 } else {
68 V::Inner::OPERATORS
69 };
70}
71
72impl<T: Filter> Filter for Option<T> {
73 const OPERATORS: &'static [Operator] = T::OPERATORS;
74}
75
76#[cfg(feature = "time")]
77filters!(ORDERED => crate::Date, crate::TimeOfDay);
78#[cfg(feature = "time")]
80filters!(EXACT => crate::LocalDateTime, crate::TimeZone, crate::Weekday);
81#[cfg(feature = "phone")]
82filters!(EXACT => crate::PhoneNumber);
83#[cfg(feature = "person")]
84filters!(EXACT => crate::PersonName);
85#[cfg(feature = "geo")]
86filters!(EXACT => crate::Coordinate);
87#[cfg(feature = "percentage")]
88filters!(ORDERED => crate::Percentage);
89#[cfg(feature = "web")]
90filters!(EXACT => crate::Slug, crate::Url, crate::Locale);
91
92#[cfg(feature = "measure")]
93impl<U: crate::Unit> Filter for crate::Measurement<U> {
94 const OPERATORS: &'static [Operator] = EXACT;
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn a_value_offers_the_operators_of_its_kind() {
103 assert_eq!(Money::OPERATORS, ORDERED);
104 assert_eq!(<Option<Money>>::OPERATORS, ORDERED);
105 assert_eq!(String::OPERATORS, TEXT);
106 assert!(!Email::OPERATORS.contains(&Operator::Contains));
107 }
108
109 #[cfg(feature = "time")]
110 #[test]
111 fn a_wall_clock_in_its_own_zone_filters_only_exactly() {
112 assert_eq!(crate::LocalDateTime::OPERATORS, EXACT);
113 }
114}