-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RUST-735 Remove Document as default generic type on Collection and Cursor #323
Changes from all commits
9700c84
7e49bd8
546ef0f
861fb50
af9f755
7196276
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,7 +39,7 @@ use crate::{ | |
/// ```rust | ||
/// | ||
/// # #[cfg(not(feature = "sync"))] | ||
/// # use mongodb::{Client, error::Result}; | ||
/// # use mongodb::{bson::Document, Client, error::Result}; | ||
/// # #[cfg(feature = "async-std-runtime")] | ||
/// # use async_std::task; | ||
/// # #[cfg(feature = "tokio-runtime")] | ||
|
@@ -55,7 +55,7 @@ use crate::{ | |
/// let db_ref = db.clone(); | ||
/// | ||
/// task::spawn(async move { | ||
/// let collection = db_ref.collection(&format!("coll{}", i)); | ||
/// let collection = db_ref.collection::<Document>(&format!("coll{}", i)); | ||
/// | ||
/// // Do something with the collection | ||
/// }); | ||
|
@@ -129,45 +129,26 @@ impl Database { | |
self.inner.write_concern.as_ref() | ||
} | ||
|
||
/// Gets a handle to a collection specified by `name` of the database. The `Collection` options | ||
/// (e.g. read preference and write concern) will default to those of the `Database`. | ||
/// | ||
/// This method does not send or receive anything across the wire to the database, so it can be | ||
/// used repeatedly without incurring any costs from I/O. | ||
pub fn collection(&self, name: &str) -> Collection { | ||
Collection::new(self.clone(), name, None) | ||
} | ||
|
||
/// Gets a handle to a collection with type `T` specified by `name` of the database. The | ||
/// `Collection` options (e.g. read preference and write concern) will default to those of the | ||
/// `Database`. | ||
/// | ||
/// This method does not send or receive anything across the wire to the database, so it can be | ||
/// used repeatedly without incurring any costs from I/O. | ||
pub fn collection_with_type<T>(&self, name: &str) -> Collection<T> | ||
pub fn collection<T>(&self, name: &str) -> Collection<T> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know we discussed the possibility of introducing a e.g. let collection: Collection<Document> = db.collection("foo"); // explicit type way
let collection = db.collection::<Document>("foo"); // turbofish
let collection = db.collection_with_document("foo"); // helper To me, the helper didn't really make it any easier to type nor did it actually make it clearer what was happening, so it seemed fine to me to just not have it. Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from my outsider perspective it doesn't seem to make a significant difference, but I'd defer to you two on whether There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine by me. The explicit type/turbofish ways both make it clearer that the value returned is generic over |
||
where | ||
T: Serialize + DeserializeOwned + Unpin + Debug, | ||
{ | ||
Collection::new(self.clone(), name, None) | ||
} | ||
|
||
/// Gets a handle to a collection specified by `name` in the cluster the `Client` is connected | ||
/// to. Operations done with this `Collection` will use the options specified by `options` by | ||
/// default and will otherwise default to those of the `Database`. | ||
/// | ||
/// This method does not send or receive anything across the wire to the database, so it can be | ||
/// used repeatedly without incurring any costs from I/O. | ||
pub fn collection_with_options(&self, name: &str, options: CollectionOptions) -> Collection { | ||
Collection::new(self.clone(), name, Some(options)) | ||
} | ||
|
||
/// Gets a handle to a collection with type `T` specified by `name` in the cluster the `Client` | ||
/// is connected to. Operations done with this `Collection` will use the options specified by | ||
/// `options` by default and will otherwise default to those of the `Database`. | ||
/// | ||
/// This method does not send or receive anything across the wire to the database, so it can be | ||
/// used repeatedly without incurring any costs from I/O. | ||
pub fn collection_with_type_and_options<T>( | ||
pub fn collection_with_options<T>( | ||
&self, | ||
name: &str, | ||
options: CollectionOptions, | ||
|
@@ -213,7 +194,7 @@ impl Database { | |
&self, | ||
filter: impl Into<Option<Document>>, | ||
options: impl Into<Option<ListCollectionsOptions>>, | ||
) -> Result<Cursor> { | ||
) -> Result<Cursor<Document>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Swift, we have this return a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sgtm (though that's probably not surprising since I already agreed to it once...) if so, would be nice to use a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call, I filed RUST-740 to cover the both of them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not super familiar with the swift library, would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, exactly. |
||
let list_collections = ListCollections::new( | ||
self.name().to_string(), | ||
filter.into(), | ||
|
@@ -234,7 +215,7 @@ impl Database { | |
filter: impl Into<Option<Document>>, | ||
options: impl Into<Option<ListCollectionsOptions>>, | ||
session: &mut ClientSession, | ||
) -> Result<SessionCursor> { | ||
) -> Result<SessionCursor<Document>> { | ||
let list_collections = ListCollections::new( | ||
self.name().to_string(), | ||
filter.into(), | ||
|
@@ -392,7 +373,7 @@ impl Database { | |
&self, | ||
pipeline: impl IntoIterator<Item = Document>, | ||
options: impl Into<Option<AggregateOptions>>, | ||
) -> Result<Cursor> { | ||
) -> Result<Cursor<Document>> { | ||
let mut options = options.into(); | ||
resolve_options!( | ||
self, | ||
|
@@ -417,7 +398,7 @@ impl Database { | |
pipeline: impl IntoIterator<Item = Document>, | ||
options: impl Into<Option<AggregateOptions>>, | ||
session: &mut ClientSession, | ||
) -> Result<SessionCursor> { | ||
) -> Result<SessionCursor<Document>> { | ||
let mut options = options.into(); | ||
resolve_options!( | ||
self, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,7 +74,7 @@ use crate::{ | |
/// ``` | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct Collection<T = Document> | ||
pub struct Collection<T> | ||
where | ||
T: Serialize + DeserializeOwned + Unpin + Debug + Send + Sync, | ||
{ | ||
|
@@ -153,7 +153,7 @@ where | |
&self, | ||
pipeline: impl IntoIterator<Item = Document>, | ||
options: impl Into<Option<AggregateOptions>>, | ||
) -> Result<Cursor> { | ||
) -> Result<Cursor<Document>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could consider returning a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. per slack conversation: seems we're all on the same page the as for whether to require a type be specified in this method (which I was not thinking about the option of in the slack discussion), or just having a separate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, my original inclination was to just leave this as However This got me trying it out and I noticed an interesting / frustrating technical challenge to doing it the e.g. fn foo<T>(bar: impl ToString) { ... }
foo::<usize>("blah"); // compile error! yields the following compiler error:
So you'd have to do it the explicit type parameter way: let x: Cursor<Document> = coll.aggregate(vec![], None).await? Which could be pretty frustrating. This will make it tough to implement the one that takes in a generic argument, since we use impl Trait in all our CRUD methods for our options types (e.g. to be able to say let cursor = coll.aggregate(vec![ ... ], None).await?.with_type::<MyDeserializeType>(); This is pretty ugly admittedly, but I think it's preferable to breaking consistency with how options are provided to the other CRUD methods or requiring users to use explicit type annotations instead of turbofish. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree changing the way we pass options either here or everywhere doesn't seem like a great path forward. is turbofish common/used rather than type annotations that people would be running into this a lot? adding the method to cursor seems reasonable though it does look clunky.... it also seems consistent with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah none of these options is very ideal to me; In any case since we're opting to go the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think even with the builder pattern for options/sessions we'd still have the same issue unfortunately, since we use Also, to clarify, I don't think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah right, I forgot we use |
||
let pipeline: Vec<Document> = pipeline.into_iter().collect(); | ||
RUNTIME | ||
.block_on(self.async_collection.aggregate(pipeline, options.into())) | ||
|
@@ -169,7 +169,7 @@ where | |
pipeline: impl IntoIterator<Item = Document>, | ||
options: impl Into<Option<AggregateOptions>>, | ||
session: &mut ClientSession, | ||
) -> Result<SessionCursor> { | ||
) -> Result<SessionCursor<Document>> { | ||
let pipeline: Vec<Document> = pipeline.into_iter().collect(); | ||
RUNTIME | ||
.block_on(self.async_collection.aggregate_with_session( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is honestly not really relevant to the PR, but I'm just curious for my own knowledge and future reference for Swift- aren't some cursors not actually tied to particular collections e.g. one resulting from db-level aggregate? how does this work in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not actually sure either. From testing it out, the namespace appears to be
"blah.$cmd.aggregate"
:We should probably add some test coverage of this case to ensure it's working properly. Assuming that's a valid namespace to send a
killCursors
to, it seems like it should be okay though.