use crate::error::Error;
use mongodb::{
bson::{from_document, Document},
options::*,
ClientSession, Collection, Cursor, SessionCursor,
};
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
pub struct AggregateCursor<D>
where
D: Serialize + for<'a> Deserialize<'a> + Send + Sync,
{
cursor: Option<Cursor<Document>>,
session_cursor: Option<SessionCursor<Document>>,
_phantom: PhantomData<D>,
}
impl<D> AggregateCursor<D>
where
D: Serialize + for<'a> Deserialize<'a> + Send + Sync,
{
pub async fn from(
collection: &Collection<D>,
pipeline: Vec<Document>,
options: Option<AggregateOptions>,
session: Option<&mut ClientSession>,
) -> Result<Self, Error> {
let (cursor, session_cursor) = if let Some(session) = session {
(
None,
Some(
collection
.aggregate(pipeline)
.with_options(options)
.session(session)
.await
.map_err(Error::Mongo)?,
),
)
} else {
(
Some(
collection
.aggregate(pipeline)
.with_options(options)
.await
.map_err(Error::Mongo)?,
),
None,
)
};
Ok(Self {
cursor,
session_cursor,
_phantom: PhantomData,
})
}
pub async fn next(&mut self) -> Result<Option<D>, Error> {
if let Some(cursor) = &mut self.cursor {
if cursor.advance().await.map_err(Error::Mongo)? {
let generic_document = cursor.deserialize_current().map_err(Error::Mongo)?;
let document: D = from_document(generic_document).map_err(Error::Bson)?;
return Ok(Some(document));
} else {
return Ok(None);
}
}
Err(Error::internal(
"Cannot call `next` on `AggregateCursor`\
when using a `ClientSession`. Please use `next_with_session`",
))
}
pub async fn next_with_session(
&mut self,
session: &mut ClientSession,
) -> Result<Option<D>, Error> {
if let Some(session_cursor) = &mut self.session_cursor {
if session_cursor
.advance(session)
.await
.map_err(Error::Mongo)?
{
let generic_document =
session_cursor.deserialize_current().map_err(Error::Mongo)?;
let document: D = from_document(generic_document).map_err(Error::Bson)?;
return Ok(Some(document));
} else {
return Ok(None);
}
}
Err(Error::internal(
"Cannot call `next_with_session` on `AggregateCursor`\
without using a `ClientSession`. Please use `next`",
))
}
pub async fn next_generic(&mut self) -> Result<Option<Document>, Error> {
if let Some(cursor) = &mut self.cursor {
if cursor.advance().await.map_err(Error::Mongo)? {
let generic_document = cursor.deserialize_current().map_err(Error::Mongo)?;
return Ok(Some(generic_document));
} else {
return Ok(None);
}
}
Err(Error::internal(
"Cannot call `next_generic` on `AggregateCursor`\
when using a `ClientSession`. Please use `next_generic_with_session`",
))
}
pub async fn next_generic_with_session(
&mut self,
session: &mut ClientSession,
) -> Result<Option<Document>, Error> {
if let Some(session_cursor) = &mut self.session_cursor {
if session_cursor
.advance(session)
.await
.map_err(Error::Mongo)?
{
let generic_document =
session_cursor.deserialize_current().map_err(Error::Mongo)?;
return Ok(Some(generic_document));
} else {
return Ok(None);
}
}
Err(Error::internal(
"Cannot call `next_generic_with_session` on `AggregateCursor`\
without using a `ClientSession`. Please use `next_generic`",
))
}
pub async fn all(mut self) -> Result<Vec<D>, Error> {
if self.cursor.is_none() {
return Err(Error::internal(
"Cannot call `all` on `AggregateCursor`\
when using a `ClientSession`. Please use `all_with_session`",
));
}
let mut documents = vec![];
while let Some(document) = self.next().await? {
documents.push(document);
}
Ok(documents)
}
pub async fn all_with_session(mut self, session: &mut ClientSession) -> Result<Vec<D>, Error> {
if self.session_cursor.is_none() {
return Err(Error::internal(
"Cannot call `all_with_session` on `AggregateCursor`\
without using a `ClientSession`. Please use `all`",
));
}
let mut documents = vec![];
while let Some(document) = self.next_with_session(session).await? {
documents.push(document);
}
Ok(documents)
}
pub async fn all_generic(mut self) -> Result<Vec<Document>, Error> {
if self.cursor.is_none() {
return Err(Error::internal(
"Cannot call `all_generic` on `AggregateCursor`\
when using a `ClientSession`. Please use `all_generic_with_session`",
));
}
let mut documents = vec![];
while let Some(document) = self.next_generic().await? {
documents.push(document);
}
Ok(documents)
}
pub async fn all_generic_with_session(
mut self,
session: &mut ClientSession,
) -> Result<Vec<Document>, Error> {
if self.session_cursor.is_none() {
return Err(Error::internal(
"Cannot call `all_generic_with_session` on `AggregateCursor`\
without using a `ClientSession`. Please use `all_generic`",
));
}
let mut documents = vec![];
while let Some(document) = self.next_generic_with_session(session).await? {
documents.push(document);
}
Ok(documents)
}
}