Skip to main content

sofie_values/
filter.rs

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    /// As a list's query names it: `total.gte=100`; equality is the bare field.
20    #[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];
49/// Codes, flags and sensitive values, whose parts must not be probed.
50pub 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::LocalDateTime, crate::TimeOfDay);
78#[cfg(feature = "time")]
79filters!(EXACT => crate::TimeZone, crate::Weekday);
80#[cfg(feature = "phone")]
81filters!(EXACT => crate::PhoneNumber);
82#[cfg(feature = "person")]
83filters!(EXACT => crate::PersonName);
84#[cfg(feature = "geo")]
85filters!(EXACT => crate::Coordinate);
86#[cfg(feature = "percentage")]
87filters!(ORDERED => crate::Percentage);
88#[cfg(feature = "web")]
89filters!(EXACT => crate::Slug, crate::Url, crate::Locale);
90
91#[cfg(feature = "measure")]
92impl<U: crate::Unit> Filter for crate::Measurement<U> {
93    const OPERATORS: &'static [Operator] = ORDERED;
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn a_value_offers_the_operators_of_its_kind() {
102        assert_eq!(Money::OPERATORS, ORDERED);
103        assert_eq!(<Option<Money>>::OPERATORS, ORDERED);
104        assert_eq!(String::OPERATORS, TEXT);
105        assert!(!Email::OPERATORS.contains(&Operator::Contains));
106    }
107}