use std::fmt::Debug;
use serde::Deserialize;
use bson::{ Bson, Document };
use mongodb::common::WriteConcern;
use mongodb::coll::options::{
FindOptions,
CountOptions,
DistinctOptions,
AggregateOptions,
FindOneAndUpdateOptions,
};
use crate::{
doc::Doc,
error::Result,
};
pub trait Count<T: Doc>: Debug {
fn filter(&self) -> Document {
Default::default()
}
fn options(&self) -> CountOptions {
T::count_options()
}
}
pub trait Distinct<T: Doc>: Debug {
type Output: for<'a> Deserialize<'a>;
const FIELD: &'static str;
fn filter(&self) -> Document {
Default::default()
}
fn transform(raw: Bson) -> Result<Bson> {
Ok(raw)
}
fn options(&self) -> DistinctOptions {
T::distinct_options()
}
}
pub trait Pipeline<T: Doc>: Debug {
type Output: for<'a> Deserialize<'a>;
fn stages(&self) -> Vec<Document>;
fn transform(raw: Document) -> Result<Bson> {
Ok(raw.into())
}
fn options(&self) -> AggregateOptions {
T::aggregate_options()
}
}
pub trait Query<T: Doc>: Debug {
type Output: for<'a> Deserialize<'a>;
fn filter(&self) -> Document {
Default::default()
}
fn transform(raw: Document) -> Result<Bson> {
Ok(raw.into())
}
fn options(&self) -> FindOptions {
T::query_options()
}
}
pub trait Update<T: Doc>: Debug {
fn filter(&self) -> Document;
fn update(&self) -> Document;
fn options(&self) -> WriteConcern {
T::update_options()
}
}
pub trait Upsert<T: Doc>: Debug {
fn filter(&self) -> Document;
fn upsert(&self) -> Document;
fn options(&self) -> WriteConcern {
T::upsert_options()
}
}
pub trait Delete<T: Doc>: Debug {
fn filter(&self) -> Document;
fn options(&self) -> WriteConcern {
T::delete_options()
}
}
pub trait FindAndUpdate<T: Doc>: Debug {
type Output: for<'a> Deserialize<'a>;
fn filter(&self) -> Document;
fn update(&self) -> Document;
fn transform(raw: Document) -> Result<Bson> {
Ok(raw.into())
}
fn options(&self) -> FindOneAndUpdateOptions {
T::find_and_update_options()
}
}
impl<T: Doc> Count<T> for Document {
fn filter(&self) -> Document {
self.clone()
}
}
impl<T: Doc> Query<T> for Document {
type Output = T;
fn filter(&self) -> Document {
self.clone()
}
}
impl<T: Doc> Delete<T> for Document {
fn filter(&self) -> Document {
self.clone()
}
}
impl<T: Doc, Q: Count<T>> Count<T> for &Q {
fn filter(&self) -> Document {
(**self).filter()
}
fn options(&self) -> CountOptions {
(**self).options()
}
}
impl<T: Doc, Q: Distinct<T>> Distinct<T> for &Q {
type Output = Q::Output;
const FIELD: &'static str = Q::FIELD;
fn filter(&self) -> Document {
(**self).filter()
}
fn transform(bson: Bson) -> Result<Bson> {
Q::transform(bson)
}
fn options(&self) -> DistinctOptions {
(**self).options()
}
}
impl<T: Doc, P: Pipeline<T>> Pipeline<T> for &P {
type Output = P::Output;
fn stages(&self) -> Vec<Document> {
(**self).stages()
}
fn transform(doc: Document) -> Result<Bson> {
P::transform(doc)
}
fn options(&self) -> AggregateOptions {
(**self).options()
}
}
impl<T: Doc, Q: Query<T>> Query<T> for &Q {
type Output = Q::Output;
fn filter(&self) -> Document {
(**self).filter()
}
fn transform(doc: Document) -> Result<Bson> {
Q::transform(doc)
}
fn options(&self) -> FindOptions {
(**self).options()
}
}
impl<T: Doc, U: Update<T>> Update<T> for &U {
fn filter(&self) -> Document {
(**self).filter()
}
fn update(&self) -> Document {
(**self).update()
}
fn options(&self) -> WriteConcern {
(**self).options()
}
}
impl<T: Doc, U: Upsert<T>> Upsert<T> for &U {
fn filter(&self) -> Document {
(**self).filter()
}
fn upsert(&self) -> Document {
(**self).upsert()
}
fn options(&self) -> WriteConcern {
(**self).options()
}
}
impl<T: Doc, Q: Delete<T>> Delete<T> for &Q {
fn filter(&self) -> Document {
(**self).filter()
}
fn options(&self) -> WriteConcern {
(**self).options()
}
}
impl<T: Doc, U: FindAndUpdate<T>> FindAndUpdate<T> for &U {
type Output = U::Output;
fn filter(&self) -> Document {
(**self).filter()
}
fn update(&self) -> Document {
(**self).update()
}
fn transform(raw: Document) -> Result<Bson> {
U::transform(raw)
}
fn options(&self) -> FindOneAndUpdateOptions {
(**self).options()
}
}