use serde::{
Deserialize,
Serialize,
};
use crate::{
Condition,
Metadata,
};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum MetadataFilter {
Condition(Condition),
And(Vec<MetadataFilter>),
Or(Vec<MetadataFilter>),
Not(Box<MetadataFilter>),
}
impl MetadataFilter {
pub fn equal<T: Serialize>(key: impl Into<String>, value: T) -> Self {
Self::Condition(Condition::Equal {
key: key.into(),
value: serde_json::to_value(value)
.expect("MetadataFilter::equal: value must be serializable"),
})
}
pub fn not_equal<T: Serialize>(key: impl Into<String>, value: T) -> Self {
Self::Condition(Condition::NotEqual {
key: key.into(),
value: serde_json::to_value(value)
.expect("MetadataFilter::not_equal: value must be serializable"),
})
}
pub fn greater<T: Serialize>(key: impl Into<String>, value: T) -> Self {
Self::Condition(Condition::Greater {
key: key.into(),
value: serde_json::to_value(value)
.expect("MetadataFilter::greater: value must be serializable"),
})
}
pub fn greater_equal<T: Serialize>(key: impl Into<String>, value: T) -> Self {
Self::Condition(Condition::GreaterEqual {
key: key.into(),
value: serde_json::to_value(value)
.expect("MetadataFilter::greater_equal: value must be serializable"),
})
}
pub fn less<T: Serialize>(key: impl Into<String>, value: T) -> Self {
Self::Condition(Condition::Less {
key: key.into(),
value: serde_json::to_value(value)
.expect("MetadataFilter::less: value must be serializable"),
})
}
pub fn less_equal<T: Serialize>(key: impl Into<String>, value: T) -> Self {
Self::Condition(Condition::LessEqual {
key: key.into(),
value: serde_json::to_value(value)
.expect("MetadataFilter::less_equal: value must be serializable"),
})
}
pub fn exists(key: impl Into<String>) -> Self {
Self::Condition(Condition::Exists { key: key.into() })
}
pub fn not_exists(key: impl Into<String>) -> Self {
Self::Condition(Condition::NotExists { key: key.into() })
}
pub fn in_values<T, I>(key: impl Into<String>, values: I) -> Self
where
T: Serialize,
I: IntoIterator<Item = T>,
{
let values = values
.into_iter()
.map(|v| {
serde_json::to_value(v)
.expect("MetadataFilter::in_values: each value must be serializable")
})
.collect();
Self::Condition(Condition::In {
key: key.into(),
values,
})
}
pub fn not_in_values<T, I>(key: impl Into<String>, values: I) -> Self
where
T: Serialize,
I: IntoIterator<Item = T>,
{
let values = values
.into_iter()
.map(|v| {
serde_json::to_value(v)
.expect("MetadataFilter::not_in_values: each value must be serializable")
})
.collect();
Self::Condition(Condition::NotIn {
key: key.into(),
values,
})
}
#[must_use]
pub fn and(self, other: MetadataFilter) -> Self {
match self {
MetadataFilter::And(mut children) => {
children.push(other);
MetadataFilter::And(children)
}
_ => MetadataFilter::And(vec![self, other]),
}
}
#[must_use]
pub fn or(self, other: MetadataFilter) -> Self {
match self {
MetadataFilter::Or(mut children) => {
children.push(other);
MetadataFilter::Or(children)
}
_ => MetadataFilter::Or(vec![self, other]),
}
}
#[allow(clippy::should_implement_trait)]
#[must_use]
pub fn not(self) -> Self {
!self
}
pub fn matches(&self, meta: &Metadata) -> bool {
match self {
MetadataFilter::Condition(cond) => cond.matches(meta),
MetadataFilter::And(children) => children.iter().all(|f| f.matches(meta)),
MetadataFilter::Or(children) => children.iter().any(|f| f.matches(meta)),
MetadataFilter::Not(inner) => !inner.matches(meta),
}
}
}
impl std::ops::Not for MetadataFilter {
type Output = MetadataFilter;
fn not(self) -> Self::Output {
MetadataFilter::Not(Box::new(self))
}
}