use std::marker::PhantomData;
use bson::Document;
use mongodb::options::{Collation, Hint, UpdateOptions, WriteConcern};
use crate::collection::Collection;
use crate::filter::{AsFilter, Filter};
use crate::r#async::Client;
use crate::update::{AsUpdate, Updates};
#[derive(Clone)]
pub struct Update<C: Collection> {
filter: Option<Document>,
many: bool,
options: UpdateOptions,
query_type: std::marker::PhantomData<C>,
}
impl<C: Collection> Default for Update<C> {
fn default() -> Self {
Self::new()
}
}
impl<C: Collection> Update<C> {
pub fn new() -> Self {
Self {
filter: None,
many: true,
options: UpdateOptions::default(),
query_type: PhantomData,
}
}
pub fn array_filters(mut self, filters: Vec<Document>) -> Self {
self.options.array_filters = Some(filters);
self
}
pub fn bypass_document_validation(mut self, enable: bool) -> Self {
self.options.bypass_document_validation = Some(enable);
self
}
pub fn collation(mut self, collation: Collation) -> Self {
self.options.collation = Some(collation);
self
}
pub fn filter<F>(mut self, filter: F) -> crate::Result<Self>
where
C: AsFilter<F>,
F: Filter,
{
self.filter = Some(filter.into_document()?);
Ok(self)
}
pub fn hint(mut self, value: Hint) -> Self {
self.options.hint = Some(value);
self
}
pub fn many(mut self, enable: bool) -> Self {
self.many = enable;
self
}
pub fn upsert(mut self, enable: bool) -> Self {
self.options.upsert = Some(enable);
self
}
pub fn write_concern(mut self, concern: WriteConcern) -> Self {
self.options.write_concern = Some(concern);
self
}
pub async fn query<U>(self, client: &Client, updates: Updates<U>) -> crate::Result<i64>
where
C: AsUpdate<U>,
U: crate::update::Update,
{
let filter = match self.filter {
Some(f) => f,
None => bson::Document::new(),
};
let result = if self.many {
client
.database()
.collection::<Document>(C::COLLECTION)
.update_many(filter, updates.into_document()?, self.options)
.await
} else {
client
.database()
.collection::<Document>(C::COLLECTION)
.update_one(filter, updates.into_document()?, self.options)
.await
}
.map_err(crate::error::mongodb)?;
Ok(result.matched_count as i64)
}
#[cfg(feature = "blocking")]
pub fn blocking<U>(
self,
client: &crate::blocking::Client,
updates: Updates<U>,
) -> crate::Result<u64>
where
C: AsUpdate<U>,
U: crate::update::Update,
{
let filter = match self.filter {
Some(f) => f,
None => bson::Document::new(),
};
let resp = client.execute(crate::blocking::Request::Update(
self.many,
C::COLLECTION,
filter,
updates.into_document()?,
self.options,
))?;
if let crate::blocking::Response::Update(r) = resp {
return Ok(r.matched_count);
}
Err(crate::error::runtime(
"incorrect response from blocking client",
))
}
}