Skip to content

Commit 7d92fdb

Browse files
feat: undo the serde only approach
On reflection it makes more sense to keep with the original approach at the cost of one additional layer of type conversion. I think for the serde approach to make sense then we would have to go all in with it, not do half and half.
1 parent d4d1f96 commit 7d92fdb

File tree

18 files changed

+274
-100
lines changed

18 files changed

+274
-100
lines changed

mongod-derive/src/lib.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
//! ```
2121
//! # mod wrap {
2222
//! # use mongod_derive::Mongo;
23-
//! use serde::{Deserialize, Serialize};
24-
//! #[derive(Mongo, Deserialize, Serialize)]
23+
//! # #[derive(mongod_derive::Bson)]
24+
//! #[derive(Mongo)]
2525
//! #[mongo(collection = "users", field, filter, update)]
2626
//! pub struct User {
2727
//! name: String,
@@ -143,9 +143,8 @@ pub fn derive_bson(input: TokenStream) -> TokenStream {
143143
/// ```
144144
/// # mod wrap {
145145
/// # use mongod_derive::Mongo;
146-
/// use serde::{Deserialize, Serialize};
147-
///
148-
/// #[derive(Mongo, Deserialize, Serialize)]
146+
/// # #[derive(mongod_derive::Bson)]
147+
/// #[derive(Mongo)]
149148
/// #[mongo(collection = "users")]
150149
/// pub struct User {
151150
/// name: String,
@@ -229,9 +228,8 @@ pub fn derive_bson(input: TokenStream) -> TokenStream {
229228
/// ```
230229
/// # mod wrap {
231230
/// # use mongod_derive::Mongo;
232-
/// use serde::{Deserialize, Serialize};
233-
///
234-
/// #[derive(Mongo, Deserialize, Serialize)]
231+
/// # #[derive(mongod_derive::Bson)]
232+
/// #[derive(Mongo)]
235233
/// #[mongo(collection = "users")]
236234
/// pub struct User {
237235
/// name: String,
@@ -248,9 +246,8 @@ pub fn derive_bson(input: TokenStream) -> TokenStream {
248246
/// ```
249247
/// # mod wrap {
250248
/// # use mongod_derive::Mongo;
251-
/// use serde::{Deserialize, Serialize};
252-
///
253-
/// #[derive(Mongo, Deserialize, Serialize)]
249+
/// # #[derive(mongod_derive::Bson)]
250+
/// #[derive(Mongo)]
254251
/// #[mongo(collection = "users")]
255252
/// pub struct User {
256253
/// name: String,

mongod-derive/src/mongo.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,40 @@ fn impl_struct(
5858
attrs: &attr::Container,
5959
) -> proc_macro2::TokenStream {
6060
let collection = if let Some(col) = &attrs.collection {
61+
let from = if attrs.bson == attr::BsonMode::Serde {
62+
quote! {
63+
_mongo::bson::from_document(document).map_err(_mongo::Error::invalid_document)
64+
}
65+
} else {
66+
quote! {
67+
Self::try_from(_mongo::bson::Bson::Document(document)).map_err(_mongo::Error::invalid_document)
68+
}
69+
};
70+
let into = if attrs.bson == attr::BsonMode::Serde {
71+
quote! {
72+
let b = _mongo::bson::to_bson(&self).map_err(_mongo::Error::invalid_document)?;
73+
}
74+
} else {
75+
quote! {
76+
let b = _mongo::bson::Bson::try_from(self).map_err(_mongo::Error::invalid_document)?;
77+
}
78+
};
6179
quote! {
6280
#[automatically_derived]
6381
impl _mongo::Collection for #name {
6482
const COLLECTION: &'static str = #col;
83+
84+
fn from_document(document: _mongo::bson::Document) -> Result<Self, _mongo::Error> {
85+
#from
86+
}
87+
88+
fn into_document(self) -> Result<_mongo::bson::Document, _mongo::Error> {
89+
#into
90+
match b {
91+
_mongo::bson::Bson::Document(doc) => Ok(doc),
92+
_ => Err(_mongo::Error::invalid_document("not a bson document")),
93+
}
94+
}
6595
}
6696
}
6797
} else {

mongod/src/async/client.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ impl Client {
533533
/// # Errors
534534
///
535535
/// This method fails if the mongodb encountered an error.
536-
pub async fn find<C, F>(&self, filter: Option<F>) -> crate::Result<mongodb::Cursor<C>>
536+
pub async fn find<C, F>(&self, filter: Option<F>) -> crate::Result<mongodb::Cursor<Document>>
537537
where
538538
C: AsFilter<F> + Collection,
539539
F: Filter,
@@ -563,6 +563,7 @@ impl Client {
563563
let mut cursor = find.filter(filter)?.query(&self).await?;
564564
if let Some(res) = cursor.next().await {
565565
let doc = res.map_err(crate::error::mongodb)?;
566+
let doc = C::from_document(doc)?;
566567
return Ok(Some(doc));
567568
}
568569
Ok(None)

mongod/src/async/cursor.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use std::marker::PhantomData;
2+
use std::pin::Pin;
3+
use std::task::{Context, Poll};
4+
5+
use bson::Document;
6+
use futures::Stream;
7+
use mongodb::Cursor;
8+
9+
use crate::collection::Collection;
10+
11+
/// A typed blocking cursor.
12+
///
13+
/// This wraps the blocking `Cursor` so that is can be automatically return typed documents.
14+
pub struct TypedCursor<T>
15+
where
16+
T: Collection,
17+
{
18+
cursor: Cursor<Document>,
19+
document_type: PhantomData<T>,
20+
}
21+
22+
impl<T> From<Cursor<Document>> for TypedCursor<T>
23+
where
24+
T: Collection,
25+
{
26+
fn from(cursor: Cursor<Document>) -> Self {
27+
TypedCursor {
28+
cursor: cursor,
29+
document_type: PhantomData,
30+
}
31+
}
32+
}
33+
34+
impl<T> Stream for TypedCursor<T>
35+
where
36+
T: Collection,
37+
{
38+
type Item = crate::Result<T>;
39+
40+
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
41+
let next = Pin::new(&mut self.cursor).poll_next(cx);
42+
match next {
43+
Poll::Ready(opt) => Poll::Ready(opt.map(|result| {
44+
result
45+
.map_err(crate::error::mongodb)
46+
.and_then(|doc| T::from_document(doc))
47+
})),
48+
Poll::Pending => Poll::Pending,
49+
}
50+
}
51+
}
52+
53+
impl<T> Unpin for TypedCursor<T> where T: Collection {}

mongod/src/async/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
pub use self::client::{Client, ClientBuilder};
2+
pub use self::cursor::TypedCursor;
23

34
pub mod client;
5+
mod cursor;

mongod/src/blocking/client.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use mongodb::options::{
1010
};
1111
use mongodb::results::{DeleteResult, InsertManyResult, UpdateResult};
1212

13-
use super::cursor::{Cursor, CursorInt};
13+
use super::cursor::Cursor;
1414
use crate::collection::Collection;
1515
use crate::filter::{AsFilter, Filter};
1616
use crate::query;
@@ -167,7 +167,7 @@ pub(crate) enum Request {
167167
}
168168
pub(crate) enum Response {
169169
Delete(DeleteResult),
170-
Find(CursorInt),
170+
Find(Cursor),
171171
Insert(InsertManyResult),
172172
Replace(UpdateResult),
173173
Update(UpdateResult),
@@ -255,7 +255,7 @@ impl Client {
255255
/// # Errors
256256
///
257257
/// This method fails if the mongodb encountered an error.
258-
pub fn find<C, F>(&self, filter: Option<F>) -> crate::Result<Cursor<C>>
258+
pub fn find<C, F>(&self, filter: Option<F>) -> crate::Result<Cursor>
259259
where
260260
C: AsFilter<F> + Collection,
261261
F: Filter,
@@ -285,6 +285,7 @@ impl Client {
285285
let mut cursor = find.filter(filter)?.blocking(&self)?;
286286
if let Some(res) = cursor.next() {
287287
let document = res.map_err(crate::error::mongodb)?;
288+
let document = C::from_document(document)?;
288289
return Ok(Some(document));
289290
}
290291
Ok(None)
@@ -488,7 +489,7 @@ impl ClientInner {
488489
.map_err(crate::error::mongodb),
489490
Request::Find(collection, filter, options) => {
490491
match database.collection(collection).find(filter, options).await {
491-
Ok(c) => Ok(Response::Find(CursorInt::new(c))),
492+
Ok(c) => Ok(Response::Find(Cursor::new(c))),
492493
Err(e) => Err(crate::error::mongodb(e)),
493494
}
494495
}

mongod/src/blocking/cursor.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use std::marker::{PhantomData, Unpin};
1+
use std::marker::PhantomData;
22

33
use bson::Document;
44
use futures::stream::StreamExt;
5-
use serde::de::DeserializeOwned;
5+
6+
use crate::collection::Collection;
67

78
#[derive(Debug)]
89
enum Request {
@@ -12,12 +13,16 @@ enum Response {
1213
Next(Option<crate::Result<Document>>),
1314
}
1415

15-
pub(crate) struct CursorInt {
16+
/// A blocking version of the [`mongodb::Cursor`](https://docs.rs/mongodb/1.1.1/mongodb/struct.Cursor.html).
17+
///
18+
/// This wraps the async `Cursor` so that is can be called in a synchronous fashion, please see the
19+
/// asynchronous description for more information about the cursor.
20+
pub struct Cursor {
1621
tx: tokio::sync::mpsc::UnboundedSender<(Request, std::sync::mpsc::Sender<Response>)>,
1722
}
1823

19-
impl CursorInt {
20-
pub fn new(cursor: mongodb::Cursor<Document>) -> Self {
24+
impl Cursor {
25+
pub(crate) fn new(cursor: mongodb::Cursor<Document>) -> Self {
2126
let (tx, mut rx) =
2227
tokio::sync::mpsc::unbounded_channel::<(Request, std::sync::mpsc::Sender<Response>)>();
2328
let f = async move {
@@ -37,34 +42,50 @@ impl CursorInt {
3742
tokio::spawn(f);
3843
Self { tx }
3944
}
45+
}
4046

41-
pub fn to_cursor<T>(self) -> Cursor<T>
42-
where
43-
T: DeserializeOwned + Unpin + Send + Sync,
44-
{
45-
Cursor {
46-
document_type: PhantomData,
47-
tx: self.tx,
48-
}
47+
impl Iterator for Cursor {
48+
type Item = crate::Result<Document>;
49+
fn next(&mut self) -> Option<Self::Item> {
50+
let (tx, rx) = std::sync::mpsc::channel();
51+
self.tx
52+
.send((Request::Next, tx))
53+
.expect("core thread panicked");
54+
let res = rx
55+
.recv()
56+
.expect("could not get response from mongo runtime");
57+
let Response::Next(c) = res;
58+
c
4959
}
5060
}
5161

52-
/// A blocking version of the [`mongodb::Cursor`](https://docs.rs/mongodb/1.1.1/mongodb/struct.Cursor.html).
62+
/// A typed blocking cursor.
5363
///
54-
/// This wraps the async `Cursor` so that is can be called in a synchronous fashion, please see the
55-
/// asynchronous description for more information about the cursor.
56-
pub struct Cursor<T>
64+
/// This wraps the blocking `Cursor` so that is can be automatically return typed documents.
65+
pub struct TypedCursor<T>
5766
where
58-
T: DeserializeOwned + Unpin + Send + Sync,
67+
T: Collection,
5968
{
6069
document_type: PhantomData<T>,
6170

6271
tx: tokio::sync::mpsc::UnboundedSender<(Request, std::sync::mpsc::Sender<Response>)>,
6372
}
6473

65-
impl<T> Iterator for Cursor<T>
74+
impl<T> From<Cursor> for TypedCursor<T>
75+
where
76+
T: Collection,
77+
{
78+
fn from(cursor: Cursor) -> Self {
79+
TypedCursor {
80+
document_type: PhantomData,
81+
tx: cursor.tx,
82+
}
83+
}
84+
}
85+
86+
impl<T> Iterator for TypedCursor<T>
6687
where
67-
T: DeserializeOwned + Unpin + Send + Sync,
88+
T: Collection,
6889
{
6990
type Item = crate::Result<T>;
7091
fn next(&mut self) -> Option<Self::Item> {
@@ -77,7 +98,7 @@ where
7798
.expect("could not get response from mongo runtime");
7899
let Response::Next(c) = res;
79100
let resp = match c {
80-
Some(Ok(b)) => Some(bson::from_document::<T>(b).map_err(crate::error::mongodb)),
101+
Some(Ok(b)) => Some(T::from_document(b)),
81102
Some(Err(e)) => Some(Err(crate::error::mongodb(e))),
82103
None => None,
83104
};

mongod/src/blocking/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
//! example to fetch users from a collection.
1414
//!
1515
//! ```no_run
16-
//! # use mongod_derive::Mongo;
17-
//! # use serde::{Deserialize, Serialize};
18-
//! # #[derive(Debug, Mongo, Deserialize, Serialize)]
16+
//! # use mongod_derive::{Bson, Mongo};
17+
//! # #[derive(Debug, Bson, Mongo)]
1918
//! # #[mongo(collection="users", field, filter, update)]
2019
//! # pub struct User {
2120
//! # name: String,

0 commit comments

Comments
 (0)