use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum JmapFilter<C> {
Operator(JmapFilterOperator<C>),
Condition(C),
}
impl<C> From<C> for JmapFilter<C> {
fn from(condition: C) -> Self {
JmapFilter::Condition(condition)
}
}
impl<C> JmapFilter<C> {
pub fn and(conditions: Vec<JmapFilter<C>>) -> Self {
JmapFilter::Operator(JmapFilterOperator {
operator: JmapFilterOperatorKind::And,
conditions,
})
}
pub fn or(conditions: Vec<JmapFilter<C>>) -> Self {
JmapFilter::Operator(JmapFilterOperator {
operator: JmapFilterOperatorKind::Or,
conditions,
})
}
pub fn not(conditions: Vec<JmapFilter<C>>) -> Self {
JmapFilter::Operator(JmapFilterOperator {
operator: JmapFilterOperatorKind::Not,
conditions,
})
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JmapFilterOperator<C> {
pub operator: JmapFilterOperatorKind,
pub conditions: Vec<JmapFilter<C>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum JmapFilterOperatorKind {
And,
Or,
Not,
}
#[cfg(test)]
mod tests {
use alloc::{string::String, vec};
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::rfc8620::filter::*;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct Cond {
from: Option<String>,
}
#[test]
fn condition_serializes_flat() {
let f: JmapFilter<Cond> = JmapFilter::Condition(Cond {
from: Some("alice".into()),
});
assert_eq!(
serde_json::to_value(&f).unwrap(),
json!({ "from": "alice" })
);
}
#[test]
fn and_serializes_with_operator_key() {
let f: JmapFilter<Cond> = JmapFilter::and(vec![
JmapFilter::Condition(Cond {
from: Some("a".into()),
}),
JmapFilter::Condition(Cond {
from: Some("b".into()),
}),
]);
assert_eq!(
serde_json::to_value(&f).unwrap(),
json!({
"operator": "AND",
"conditions": [
{ "from": "a" },
{ "from": "b" },
],
}),
);
}
#[test]
fn not_wraps_a_single_subfilter() {
let f: JmapFilter<Cond> = JmapFilter::not(vec![JmapFilter::Condition(Cond {
from: Some("a".into()),
})]);
assert_eq!(
serde_json::to_value(&f).unwrap(),
json!({
"operator": "NOT",
"conditions": [{ "from": "a" }],
}),
);
}
#[test]
fn deserialize_discriminates_on_operator_key() {
let v = json!({ "from": "alice" });
let f: JmapFilter<Cond> = serde_json::from_value(v).unwrap();
assert!(matches!(f, JmapFilter::Condition(Cond { from: Some(_) })));
let v = json!({
"operator": "OR",
"conditions": [{ "from": "a" }, { "from": "b" }],
});
let f: JmapFilter<Cond> = serde_json::from_value(v).unwrap();
assert!(matches!(
f,
JmapFilter::Operator(JmapFilterOperator {
operator: JmapFilterOperatorKind::Or,
..
})
));
}
}