cipherstash_config/
operator.rs

1use std::{fmt::Debug, str::FromStr};
2
3use thiserror::Error;
4
5#[derive(Debug, Clone, Error)]
6#[error("Invalid operator `{0}`")]
7pub struct InvalidOperatorError(String);
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[non_exhaustive]
11pub enum Operator {
12    Lt,
13    Lte,
14    Eq,
15    Gt,
16    Gte,
17    Like,
18    ILike,
19    STEVecOperator(STEVecOperator),
20
21    #[deprecated(note = "Use Result and InvalidOperatorError instead", since = "0.2.4")]
22    Unsupported,
23}
24
25/// These are all binary operators (*probably* PG specific).
26#[non_exhaustive]
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum STEVecOperator {
29    LeftContainsRight, // @>
30    RightContainsLeft, // <@
31    Selector,          // ->
32}
33
34impl Operator {
35    pub fn as_str(&self) -> &'static str {
36        match self {
37            Self::Lt => "<",
38            Self::Lte => "<=",
39            Self::Eq => "=",
40            Self::Gt => ">",
41            Self::Gte => ">=",
42            Self::Like => "~~",   //Note: This is PostgreSQL specific syntax.
43            Self::ILike => "~~*", //Note: This PostgreSQL specific syntax.
44            Self::STEVecOperator(op) => op.as_str(),
45            // TODO: Probably better to use an Error and handle errors in callers
46            _ => "unsupported",
47        }
48    }
49}
50
51impl STEVecOperator {
52    pub fn as_str(&self) -> &'static str {
53        match self {
54            STEVecOperator::LeftContainsRight => "@>",
55            STEVecOperator::RightContainsLeft => "<@",
56            STEVecOperator::Selector => "->",
57            // TODO: implement support for the following (which will require creating a custom PG type called ste_vec with operators defined on it)
58            // The above two operators happen to "just work" because cs_ste_vec_v1 is an array and they are defined for arrays and JSON in PG.
59            // In the meantime the lack of the following operators can be worked around by converting to `@>` and multiple expressions with logical AND/OR.
60            // STEVecOperator::LeftIsTopLevelKey => "?",
61            // STEVecOperator::AnyOfLeftIsTopLevelKey => "?|",
62            // STEVecOperator::AllOfLeftIsTopLevelKey => "?&",
63        }
64    }
65}
66
67impl FromStr for Operator {
68    type Err = InvalidOperatorError;
69
70    fn from_str(op: &str) -> Result<Self, Self::Err> {
71        match op {
72            "<" => Ok(Self::Lt),
73            "<=" => Ok(Self::Lte),
74            "=" => Ok(Self::Eq),
75            ">" => Ok(Self::Gt),
76            ">=" => Ok(Self::Gte),
77            "~~" => Ok(Self::Like),
78            "~~*" => Ok(Self::ILike),
79            "@>" => Ok(Self::STEVecOperator(STEVecOperator::LeftContainsRight)),
80            "<@" => Ok(Self::STEVecOperator(STEVecOperator::RightContainsLeft)),
81            "->" => Ok(Self::STEVecOperator(STEVecOperator::Selector)),
82            invalid => Err(InvalidOperatorError(invalid.to_string())),
83        }
84    }
85}
86
87impl From<&str> for Operator {
88    fn from(value: &str) -> Self {
89        match value {
90            "<" => Self::Lt,
91            "<=" => Self::Lte,
92            "=" => Self::Eq,
93            ">" => Self::Gt,
94            ">=" => Self::Gte,
95            "~~" => Self::Like,
96            "~~*" => Self::ILike,
97            "@>" => Self::STEVecOperator(STEVecOperator::LeftContainsRight),
98            "<@" => Self::STEVecOperator(STEVecOperator::RightContainsLeft),
99            #[allow(deprecated)]
100            _ => Self::Unsupported,
101        }
102    }
103}
104
105impl From<String> for Operator {
106    fn from(value: String) -> Self {
107        value.as_str().into()
108    }
109}
110
111impl From<Vec<String>> for Operator {
112    fn from(value: Vec<String>) -> Self {
113        if value.len() == 1 {
114            value[0].to_string().into()
115        } else {
116            #[allow(deprecated)]
117            Self::Unsupported
118        }
119    }
120}
121
122impl std::fmt::Display for Operator {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        let text = match self {
125            Self::Lt => "<",
126            Self::Lte => "<=",
127            Self::Eq => "==",
128            Self::Gt => ">",
129            Self::Gte => ">=",
130            Self::Like => "LIKE",
131            Self::ILike => "ILIKE",
132            Self::STEVecOperator(op) => op.as_str(),
133            #[allow(deprecated)]
134            Self::Unsupported => "Unsupported",
135        };
136
137        write!(f, "{text}")
138    }
139}