use bson::{Bson, doc};
use vantage_expressions::Expressive;
use crate::condition::MongoCondition;
use crate::types::{AnyMongoType, MongoType};
fn field_name<T>(expr: &(impl Expressive<T> + ?Sized)) -> String {
expr.expr().template.clone()
}
fn to_bson_val(value: impl Into<AnyMongoType>) -> Bson {
let any: AnyMongoType = value.into();
any.to_bson()
}
fn negate(cond: MongoCondition) -> MongoCondition {
match cond {
MongoCondition::Doc(doc) => {
let mut negated = bson::Document::new();
for (key, val) in doc {
match val {
Bson::Document(inner) => {
negated.insert(key, doc! { "$not": inner });
}
other => {
negated.insert(key, doc! { "$not": { "$eq": other } });
}
}
}
MongoCondition::Doc(negated)
}
MongoCondition::And(conditions) => {
MongoCondition::And(conditions.into_iter().map(negate).collect())
}
other => other,
}
}
pub trait MongoOperation<T>: Expressive<T> {
fn eq(&self, value: impl Into<AnyMongoType>) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$eq": to_bson_val(value) } })
}
fn ne(&self, value: impl Into<AnyMongoType>) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$ne": to_bson_val(value) } })
}
fn gt(&self, value: impl Into<AnyMongoType>) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$gt": to_bson_val(value) } })
}
fn gte(&self, value: impl Into<AnyMongoType>) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$gte": to_bson_val(value) } })
}
fn lt(&self, value: impl Into<AnyMongoType>) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$lt": to_bson_val(value) } })
}
fn lte(&self, value: impl Into<AnyMongoType>) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$lte": to_bson_val(value) } })
}
fn in_<I, V>(&self, values: I) -> MongoCondition
where
Self: Sized,
I: IntoIterator<Item = V>,
V: Into<AnyMongoType>,
{
let arr: Vec<Bson> = values.into_iter().map(to_bson_val).collect();
MongoCondition::Doc(doc! { field_name(self): { "$in": arr } })
}
fn is_null(&self) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): Bson::Null })
}
fn is_not_null(&self) -> MongoCondition
where
Self: Sized,
{
MongoCondition::Doc(doc! { field_name(self): { "$ne": Bson::Null } })
}
}
impl<T, S: Expressive<T>> MongoOperation<T> for S {}
impl Expressive<AnyMongoType> for MongoCondition {
fn expr(&self) -> vantage_expressions::Expression<AnyMongoType> {
vantage_expressions::Expression::new(format!("{:?}", self), vec![])
}
}
impl MongoCondition {
pub fn eq_bool(&self, value: bool) -> MongoCondition {
if value {
self.clone()
} else {
negate(self.clone())
}
}
pub fn ne_bool(&self, value: bool) -> MongoCondition {
if value {
negate(self.clone())
} else {
self.clone()
}
}
}