use qubit_value::{Value, ValueConstructor};
use crate::{
Condition, FilterMatchOptions, MetadataFilter, MetadataResult, MetadataSchema,
MissingKeyPolicy, NumberComparisonPolicy, metadata_filter::FilterExpr,
};
#[derive(Debug, Clone, PartialEq, Default)]
pub struct MetadataFilterBuilder {
pub(crate) expr: Option<FilterExpr>,
pub(crate) options: FilterMatchOptions,
}
impl MetadataFilterBuilder {
#[inline]
#[must_use]
pub fn build(self) -> MetadataFilter {
MetadataFilter::new(self.expr, self.options)
}
#[inline]
pub fn build_checked(self, schema: &MetadataSchema) -> MetadataResult<MetadataFilter> {
let filter = self.build();
schema.validate_filter(&filter)?;
Ok(filter)
}
#[inline]
#[must_use]
pub fn with_options(mut self, options: FilterMatchOptions) -> Self {
self.options = options;
self
}
#[inline]
#[must_use]
pub fn missing_key_policy(mut self, missing_key_policy: MissingKeyPolicy) -> Self {
self.options.missing_key_policy = missing_key_policy;
self
}
#[inline]
#[must_use]
pub fn number_comparison_policy(
mut self,
number_comparison_policy: NumberComparisonPolicy,
) -> Self {
self.options.number_comparison_policy = number_comparison_policy;
self
}
#[inline]
#[must_use]
pub fn eq<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_eq(key, value)
}
#[inline]
#[must_use]
pub fn ne<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_ne(key, value)
}
#[inline]
#[must_use]
pub fn lt<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_lt(key, value)
}
#[inline]
#[must_use]
pub fn le<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_le(key, value)
}
#[inline]
#[must_use]
pub fn gt<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_gt(key, value)
}
#[inline]
#[must_use]
pub fn ge<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_ge(key, value)
}
#[inline]
#[must_use]
pub fn in_set<I, T>(self, key: &str, values: I) -> Self
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
self.and_in_set(key, values)
}
#[inline]
#[must_use]
pub fn not_in_set<I, T>(self, key: &str, values: I) -> Self
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
self.and_not_in_set(key, values)
}
#[inline]
#[must_use]
pub fn exists(self, key: &str) -> Self {
self.and_exists(key)
}
#[inline]
#[must_use]
pub fn not_exists(self, key: &str) -> Self {
self.and_not_exists(key)
}
#[inline]
#[must_use]
pub fn and_eq<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_condition(Condition::Equal {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn and_ne<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_condition(Condition::NotEqual {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn and_lt<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_condition(Condition::Less {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn and_le<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_condition(Condition::LessEqual {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn and_gt<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_condition(Condition::Greater {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn and_ge<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.and_condition(Condition::GreaterEqual {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn and_in_set<I, T>(self, key: &str, values: I) -> Self
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
self.and_condition(Condition::In {
key: key.to_string(),
values: Self::collect_values(values),
})
}
#[inline]
#[must_use]
pub fn and_not_in_set<I, T>(self, key: &str, values: I) -> Self
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
self.and_condition(Condition::NotIn {
key: key.to_string(),
values: Self::collect_values(values),
})
}
#[inline]
#[must_use]
pub fn and_exists(self, key: &str) -> Self {
self.and_condition(Condition::Exists {
key: key.to_string(),
})
}
#[inline]
#[must_use]
pub fn and_not_exists(self, key: &str) -> Self {
self.and_condition(Condition::NotExists {
key: key.to_string(),
})
}
#[inline]
#[must_use]
pub fn or_eq<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.or_condition(Condition::Equal {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn or_ne<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.or_condition(Condition::NotEqual {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn or_lt<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.or_condition(Condition::Less {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn or_le<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.or_condition(Condition::LessEqual {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn or_gt<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.or_condition(Condition::Greater {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn or_ge<T>(self, key: &str, value: T) -> Self
where
Value: ValueConstructor<T>,
{
self.or_condition(Condition::GreaterEqual {
key: key.to_string(),
value: to_value(value),
})
}
#[inline]
#[must_use]
pub fn or_in_set<I, T>(self, key: &str, values: I) -> Self
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
self.or_condition(Condition::In {
key: key.to_string(),
values: Self::collect_values(values),
})
}
#[inline]
#[must_use]
pub fn or_not_in_set<I, T>(self, key: &str, values: I) -> Self
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
self.or_condition(Condition::NotIn {
key: key.to_string(),
values: Self::collect_values(values),
})
}
#[inline]
#[must_use]
pub fn or_exists(self, key: &str) -> Self {
self.or_condition(Condition::Exists {
key: key.to_string(),
})
}
#[inline]
#[must_use]
pub fn or_not_exists(self, key: &str) -> Self {
self.or_condition(Condition::NotExists {
key: key.to_string(),
})
}
#[inline]
#[must_use]
pub fn and<F>(self, build: F) -> Self
where
F: FnOnce(Self) -> Self,
{
let group = build(Self::default()).expr;
self.and_expr(group)
}
#[inline]
#[must_use]
pub fn or<F>(self, build: F) -> Self
where
F: FnOnce(Self) -> Self,
{
let group = build(Self::default()).expr;
self.or_expr(group)
}
#[inline]
#[must_use]
pub fn and_not<F>(self, build: F) -> Self
where
F: FnOnce(Self) -> Self,
{
let group = build(Self::default()).expr;
self.and_expr(Self::negate_expr(group))
}
#[inline]
#[must_use]
pub fn or_not<F>(self, build: F) -> Self
where
F: FnOnce(Self) -> Self,
{
let group = build(Self::default()).expr;
self.or_expr(Self::negate_expr(group))
}
#[allow(clippy::should_implement_trait)]
#[inline]
#[must_use]
pub fn not(mut self) -> Self {
self.expr = Self::negate_expr(self.expr);
self
}
#[inline]
fn collect_values<I, T>(values: I) -> Vec<Value>
where
I: IntoIterator<Item = T>,
Value: ValueConstructor<T>,
{
values.into_iter().map(to_value).collect()
}
#[inline]
fn and_expr(mut self, expr: Option<FilterExpr>) -> Self {
self.expr = match (self.expr, expr) {
(None, rhs) => rhs,
(lhs, None) => lhs,
(Some(lhs), Some(rhs)) => Some(FilterExpr::and(lhs, rhs)),
};
self
}
#[inline]
fn or_expr(mut self, expr: Option<FilterExpr>) -> Self {
self.expr = match (self.expr, expr) {
(None, rhs) => rhs,
(lhs, None) => lhs,
(Some(lhs), Some(rhs)) => Some(FilterExpr::or(lhs, rhs)),
};
self
}
#[inline]
fn and_condition(self, condition: Condition) -> Self {
self.and_expr(Some(FilterExpr::Condition(condition)))
}
#[inline]
fn or_condition(self, condition: Condition) -> Self {
self.or_expr(Some(FilterExpr::Condition(condition)))
}
#[inline]
pub(crate) fn negate_expr(expr: Option<FilterExpr>) -> Option<FilterExpr> {
match expr {
None => Some(FilterExpr::False),
Some(FilterExpr::False) => None,
Some(FilterExpr::Not(inner)) => Some(*inner),
Some(other) => Some(FilterExpr::Not(Box::new(other))),
}
}
}
#[inline]
fn to_value<T>(value: T) -> Value
where
Value: ValueConstructor<T>,
{
<Value as ValueConstructor<T>>::from_type(value)
}