diff --git a/Cargo.toml b/Cargo.toml index 2d538a846..87eeccdb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ in-use-encryption-unstable = ["mongocrypt", "rayon", "num_cpus"] tracing-unstable = ["tracing", "log"] [dependencies] +action_macro = { path = "action_macro" } async-trait = "0.1.42" base64 = "0.13.0" bitflags = "1.1.0" diff --git a/action_macro/.gitignore b/action_macro/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/action_macro/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/action_macro/Cargo.toml b/action_macro/Cargo.toml new file mode 100644 index 000000000..8320208ca --- /dev/null +++ b/action_macro/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "action_macro" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +proc-macro2 = "1.0.78" +quote = "1.0.35" +syn = { version = "2.0.52", features = ["full", "parsing", "proc-macro"] } + +[lib] +proc-macro = true diff --git a/action_macro/src/lib.rs b/action_macro/src/lib.rs new file mode 100644 index 000000000..b3c2b4a7e --- /dev/null +++ b/action_macro/src/lib.rs @@ -0,0 +1,220 @@ +extern crate proc_macro; + +use quote::quote; +use syn::{ + braced, + parenthesized, + parse::{Parse, ParseStream}, + parse_macro_input, + parse_quote, + parse_quote_spanned, + spanned::Spanned, + Block, + Error, + Generics, + Ident, + Lifetime, + Token, + Type, +}; + +/// Generates: +/// * an `IntoFuture` executing the given method body +/// * an opaque wrapper type for the future in case we want to do something more fancy than +/// BoxFuture. +/// * a `run` method for sync execution, optionally with a wrapper function +#[proc_macro] +pub fn action_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ActionImpl { + generics, + lifetime, + action, + future_name, + exec_self_mut, + exec_output, + exec_body, + sync_wrap, + } = parse_macro_input!(input as ActionImpl); + + let mut unbounded_generics = generics.clone(); + for lt in unbounded_generics.lifetimes_mut() { + lt.bounds.clear(); + } + for ty in unbounded_generics.type_params_mut() { + ty.bounds.clear(); + } + + let SyncWrap { + sync_arg_mut, + sync_arg, + sync_output, + sync_body, + } = sync_wrap.unwrap_or_else(|| { + parse_quote! { fn sync_wrap(out) -> #exec_output { out } } + }); + + quote! { + impl #generics crate::action::private::Sealed for #action { } + + impl #generics crate::action::Action for #action { } + + impl #generics std::future::IntoFuture for #action { + type Output = #exec_output; + type IntoFuture = #future_name #unbounded_generics; + + fn into_future(#exec_self_mut self) -> Self::IntoFuture { + #future_name (Box::pin(async move { + #exec_body + })) + } + } + + pub struct #future_name #generics (crate::BoxFuture<#lifetime, #exec_output>); + + impl #generics std::future::Future for #future_name #unbounded_generics { + type Output = #exec_output; + + fn poll(mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll { + self.0.as_mut().poll(cx) + } + } + + #[cfg(feature = "sync")] + impl #generics #action { + /// Synchronously execute this action. + pub fn run(self) -> #sync_output { + let #sync_arg_mut #sync_arg = crate::sync::TOKIO_RUNTIME.block_on(std::future::IntoFuture::into_future(self)); + #sync_body + } + } + }.into() +} + +// impl Action for ActionType { +// type Future = FutureName; +// async fn execute([mut] self) -> OutType { } +// [SyncWrap] +// } +struct ActionImpl { + generics: Generics, + lifetime: Lifetime, + action: Type, + future_name: Ident, + exec_self_mut: Option, + exec_output: Type, + exec_body: Block, + sync_wrap: Option, +} + +impl Parse for ActionImpl { + fn parse(input: ParseStream) -> syn::Result { + // impl Action for ActionType + input.parse::()?; + let generics: Generics = input.parse()?; + let mut lifetime = None; + for lt in generics.lifetimes() { + if lifetime.is_some() { + return Err(input.error("only one lifetime argument permitted")); + } + lifetime = Some(lt); + } + let lifetime = match lifetime { + Some(lt) => lt.lifetime.clone(), + None => parse_quote_spanned! { generics.span() => 'static }, + }; + parse_name(input, "Action")?; + input.parse::()?; + let action = input.parse()?; + + let impl_body; + braced!(impl_body in input); + + // type Future = FutureName; + impl_body.parse::()?; + parse_name(&impl_body, "Future")?; + impl_body.parse::()?; + let future_name = impl_body.parse()?; + impl_body.parse::()?; + + // async fn execute([mut] self) -> OutType { } + impl_body.parse::()?; + impl_body.parse::()?; + parse_name(&impl_body, "execute")?; + let exec_args; + parenthesized!(exec_args in impl_body); + let exec_self_mut = exec_args.parse()?; + exec_args.parse::()?; + if !exec_args.is_empty() { + return Err(exec_args.error("unexpected token")); + } + impl_body.parse::]>()?; + let exec_output = impl_body.parse()?; + let exec_body = impl_body.parse()?; + + // Optional SyncWrap. + let sync_wrap = if impl_body.peek(Token![fn]) { + Some(impl_body.parse()?) + } else { + None + }; + + if !impl_body.is_empty() { + return Err(exec_args.error("unexpected token")); + } + + Ok(ActionImpl { + generics, + lifetime, + action, + future_name, + exec_self_mut, + exec_output, + exec_body, + sync_wrap, + }) + } +} + +// fn sync_wrap([mut] out) -> OutType { } +struct SyncWrap { + sync_arg_mut: Option, + sync_arg: Ident, + sync_output: Type, + sync_body: Block, +} + +impl Parse for SyncWrap { + fn parse(input: ParseStream) -> syn::Result { + input.parse::()?; + parse_name(input, "sync_wrap")?; + let args_input; + parenthesized!(args_input in input); + let sync_arg_mut = args_input.parse()?; + let sync_arg = args_input.parse()?; + if !args_input.is_empty() { + return Err(args_input.error("unexpected token")); + } + input.parse::]>()?; + let sync_output = input.parse()?; + let sync_body = input.parse()?; + + Ok(SyncWrap { + sync_arg_mut, + sync_arg, + sync_output, + sync_body, + }) + } +} + +/// Parse an identifier with a specific expected value. +fn parse_name(input: ParseStream, name: &str) -> syn::Result<()> { + let ident = input.parse::()?; + if ident.to_string() != name { + return Err(Error::new( + ident.span(), + format!("expected '{}', got '{}'", name, ident), + )); + } + Ok(()) +} diff --git a/manual/src/README.md b/manual/src/README.md index 2e8cbfa02..b4def29c7 100644 --- a/manual/src/README.md +++ b/manual/src/README.md @@ -23,7 +23,7 @@ e.g. # let client = Client::with_uri_str("mongodb://example.com").await?; let collection = client.database("foo").collection("bar"); let handle = tokio::task::spawn(async move { - collection.insert_one(doc! { "x": 1 }, None).await + collection.insert_one(doc! { "x": 1 }).await }); tokio::time::timeout(Duration::from_secs(5), handle).await???; diff --git a/manual/src/encryption.md b/manual/src/encryption.md index 4c9e4e1f8..0fbfd9a79 100644 --- a/manual/src/encryption.md +++ b/manual/src/encryption.md @@ -187,16 +187,16 @@ async fn main() -> Result<()> { // Clear old data. coll.drop().await?; - coll.insert_one(doc! { "encryptedField": "123456789" }, None) + coll.insert_one(doc! { "encryptedField": "123456789" }) .await?; - println!("Decrypted document: {:?}", coll.find_one(None, None).await?); + println!("Decrypted document: {:?}", coll.find_one(doc! {}).await?); let unencrypted_coll = Client::with_uri_str(URI) .await? .database(&encrypted_namespace.db) .collection::(&encrypted_namespace.coll); println!( "Encrypted document: {:?}", - unencrypted_coll.find_one(None, None).await? + unencrypted_coll.find_one(doc! {}).await? ); Ok(()) @@ -294,19 +294,19 @@ async fn main() -> Result<()> { .validator(doc! { "$jsonSchema": schema }) .await?; - coll.insert_one(doc! { "encryptedField": "123456789" }, None) + coll.insert_one(doc! { "encryptedField": "123456789" }) .await?; - println!("Decrypted document: {:?}", coll.find_one(None, None).await?); + println!("Decrypted document: {:?}", coll.find_one(doc! {}).await?); let unencrypted_coll = Client::with_uri_str(URI) .await? .database(&encrypted_namespace.db) .collection::(&encrypted_namespace.coll); println!( "Encrypted document: {:?}", - unencrypted_coll.find_one(None, None).await? + unencrypted_coll.find_one(doc! {}).await? ); // This would return a Write error with the message "Document failed validation". - // unencrypted_coll.insert_one(doc! { "encryptedField": "123456789" }, None) + // unencrypted_coll.insert_one(doc! { "encryptedField": "123456789" }) // .await?; Ok(()) @@ -407,11 +407,10 @@ async fn main() -> Result<()> { db.create_collection("encryptedCollection").await?; coll.insert_one( doc! { "_id": 1, "firstName": "Jane", "lastName": "Doe" }, - None, ) .await?; let docs: Vec<_> = coll - .find(doc! {"firstName": "Jane"}, None) + .find(doc! {"firstName": "Jane"}) .await? .try_collect() .await?; @@ -540,7 +539,6 @@ async fn main() -> Result<()> { "encryptedIndexed": insert_payload_indexed, "encryptedUnindexed": insert_payload_unindexed, }, - None, ) .await?; @@ -556,7 +554,7 @@ async fn main() -> Result<()> { // Find the document we inserted using the encrypted payload. // The returned document is automatically decrypted. let doc = coll - .find_one(doc! { "encryptedIndexed": find_payload }, None) + .find_one(doc! { "encryptedIndexed": find_payload }) .await?; println!("Returned document: {:?}", doc); @@ -634,9 +632,9 @@ async fn main() -> Result<()> { Algorithm::AeadAes256CbcHmacSha512Deterministic, ) .await?; - coll.insert_one(doc! { "encryptedField": encrypted_field }, None) + coll.insert_one(doc! { "encryptedField": encrypted_field }) .await?; - let mut doc = coll.find_one(None, None).await?.unwrap(); + let mut doc = coll.find_one(doc! {}).await?.unwrap(); println!("Encrypted document: {:?}", doc); // Explicitly decrypt the field: @@ -735,10 +733,10 @@ async fn main() -> Result<()> { Algorithm::AeadAes256CbcHmacSha512Deterministic, ) .await?; - coll.insert_one(doc! { "encryptedField": encrypted_field }, None) + coll.insert_one(doc! { "encryptedField": encrypted_field }) .await?; // Automatically decrypts any encrypted fields. - let doc = coll.find_one(None, None).await?.unwrap(); + let doc = coll.find_one(doc! {}).await?.unwrap(); println!("Decrypted document: {:?}", doc); let unencrypted_coll = Client::with_uri_str(URI) .await? @@ -746,7 +744,7 @@ async fn main() -> Result<()> { .collection::("coll"); println!( "Encrypted document: {:?}", - unencrypted_coll.find_one(None, None).await? + unencrypted_coll.find_one(doc! {}).await? ); Ok(()) diff --git a/manual/src/reading.md b/manual/src/reading.md index cf064d821..b54ba6b4c 100644 --- a/manual/src/reading.md +++ b/manual/src/reading.md @@ -58,7 +58,7 @@ let coll = client.database("items").collection::("in_stock"); for i in 0..5 { // Perform operations that work with directly our model. - coll.insert_one(Item { id: i }, None).await; + coll.insert_one(Item { id: i }).await; } # # Ok(()) @@ -89,9 +89,10 @@ use futures::stream::TryStreamExt; use mongodb::{bson::doc, options::FindOptions}; // Query the books in the collection with a filter and an option. -let filter = doc! { "author": "George Orwell" }; -let find_options = FindOptions::builder().sort(doc! { "title": 1 }).build(); -let mut cursor = typed_collection.find(filter, find_options).await?; +let mut cursor = typed_collection + .find(doc! { "author": "George Orwell" }) + .sort(doc! { "title": 1 }) + .await?; // Iterate over the results of the cursor. while let Some(book) = cursor.try_next().await? { diff --git a/manual/src/tracing.md b/manual/src/tracing.md index f981edef6..2e6ca01cd 100644 --- a/manual/src/tracing.md +++ b/manual/src/tracing.md @@ -62,7 +62,7 @@ async fn main() -> Result<()> { // Insert a document. let coll = client.database("test").collection("test_coll"); - coll.insert_one(doc! { "x" : 1 }, None).await?; + coll.insert_one(doc! { "x" : 1 }).await?; Ok(()) } @@ -114,7 +114,7 @@ async fn main() -> Result<()> { // Insert a document. let coll = client.database("test").collection("test_coll"); - coll.insert_one(doc! { "x" : 1 }, None).await?; + coll.insert_one(doc! { "x" : 1 }).await?; Ok(()) } diff --git a/src/action.rs b/src/action.rs index 81fa9866e..c30074125 100644 --- a/src/action.rs +++ b/src/action.rs @@ -10,17 +10,22 @@ mod delete; mod distinct; mod drop; mod drop_index; +mod find; +mod find_and_modify; +mod insert_many; +mod insert_one; mod list_collections; mod list_databases; mod list_indexes; mod perf; +mod replace_one; mod run_command; mod session; mod shutdown; mod update; mod watch; -use std::{marker::PhantomData, ops::Deref}; +use std::{future::IntoFuture, marker::PhantomData, ops::Deref}; pub use aggregate::Aggregate; use bson::Document; @@ -31,10 +36,15 @@ pub use delete::Delete; pub use distinct::Distinct; pub use drop::{DropCollection, DropDatabase}; pub use drop_index::DropIndex; +pub use find::{Find, FindOne}; +pub use find_and_modify::{FindOneAndDelete, FindOneAndReplace, FindOneAndUpdate}; +pub use insert_many::InsertMany; +pub use insert_one::InsertOne; pub use list_collections::ListCollections; pub use list_databases::ListDatabases; pub use list_indexes::ListIndexes; pub use perf::WarmConnectionPool; +pub use replace_one::ReplaceOne; pub use run_command::{RunCommand, RunCursorCommand}; pub use session::StartSession; pub use shutdown::Shutdown; @@ -57,6 +67,7 @@ pub struct Single; pub struct Multiple; macro_rules! option_setters { + // Include options aggregate accessors. ( $opt_field:ident: $opt_field_ty:ty; $( @@ -70,10 +81,25 @@ macro_rules! option_setters { /// Set all options. Note that this will replace all previous values set. pub fn with_options(mut self, value: impl Into>) -> Self { - self.options = value.into(); + self.$opt_field = value.into(); self } + crate::action::option_setters!($opt_field_ty; + $( + $(#[$($attrss)*])* + $opt_name: $opt_ty, + )* + ); + }; + // Just generate field setters. + ( + $opt_field_ty:ty; + $( + $(#[$($attrss:tt)*])* + $opt_name:ident: $opt_ty:ty, + )* + ) => { $( #[doc = concat!("Set the [`", stringify!($opt_field_ty), "::", stringify!($opt_name), "`] option.")] $(#[$($attrss)*])* @@ -86,12 +112,13 @@ macro_rules! option_setters { } use option_setters; +pub(crate) mod private { + pub trait Sealed {} +} + /// A pending action to execute on the server. The action can be configured via chained methods and /// executed via `await` (or `run` if using the sync client). -pub trait Action { - /// The type of the value produced by execution. - type Output; - +pub trait Action: private::Sealed + IntoFuture { /// If the value is `Some`, call the provided function on `self`. Convenient for chained /// updates with values that need to be set conditionally. For example: /// ```rust @@ -116,83 +143,7 @@ pub trait Action { } } -/// Generates: -/// * an `IntoFuture` executing the given method body -/// * an opaque wrapper type for the future in case we want to do something more fancy than -/// BoxFuture. -/// * a `run` method for sync execution, optionally with a wrapper function -macro_rules! action_impl { - // Generate with no sync type conversion - ( - impl$(<$lt:lifetime $(, $($at:ident),+)?>)? Action for $action:ty { - type Future = $f_ty:ident; - async fn execute($($args:ident)+) -> $out:ty $code:block - } - ) => { - crate::action::action_impl! { - impl$(<$lt $(, $($at),+)?>)? Action for $action { - type Future = $f_ty; - async fn execute($($args)+) -> $out $code - fn sync_wrap(out) -> $out { out } - } - } - }; - // Generate with a sync type conversion - ( - impl$(<$lt:lifetime $(, $($at:ident),+)?>)? Action for $action:ty { - type Future = $f_ty:ident; - async fn execute($($args:ident)+) -> $out:ty $code:block - fn sync_wrap($($wrap_args:ident)+) -> $sync_out:ty $wrap_code:block - } - ) => { - impl$(<$lt $(, $($at),+)?>)? std::future::IntoFuture for $action { - type Output = $out; - type IntoFuture = $f_ty$(<$lt>)?; - - fn into_future($($args)+) -> Self::IntoFuture { - $f_ty(Box::pin(async move { - $code - })) - } - } - - impl$(<$lt $(, $($at),+)?>)? crate::action::Action for $action { - type Output = $out; - } - - crate::action::action_impl_future_wrapper!($($lt)?, $f_ty, $out); - - impl$(<$lt>)? std::future::Future for $f_ty$(<$lt>)? { - type Output = $out; - - fn poll(mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll { - self.0.as_mut().poll(cx) - } - } - - #[cfg(feature = "sync")] - impl$(<$lt $(, $($at),+)?>)? $action { - /// Synchronously execute this action. - pub fn run(self) -> $sync_out { - let $($wrap_args)+ = crate::sync::TOKIO_RUNTIME.block_on(std::future::IntoFuture::into_future(self)); - return $wrap_code - } - } - } -} -pub(crate) use action_impl; - -macro_rules! action_impl_future_wrapper { - (, $f_ty:ident, $out:ty) => { - /// Opaque future type for action execution. - pub struct $f_ty(crate::BoxFuture<'static, $out>); - }; - ($lt:lifetime, $f_ty:ident, $out:ty) => { - /// Opaque future type for action execution. - pub struct $f_ty<$lt>(crate::BoxFuture<$lt, $out>); - }; -} -pub(crate) use action_impl_future_wrapper; +pub(crate) use action_macro::action_impl; use crate::Collection; diff --git a/src/action/aggregate.rs b/src/action/aggregate.rs index b4272f4f7..108a68d12 100644 --- a/src/action/aggregate.rs +++ b/src/action/aggregate.rs @@ -116,7 +116,7 @@ impl<'a, Session> Aggregate<'a, Session> { } impl<'a> Aggregate<'a, ImplicitSession> { - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session( self, value: impl Into<&'a mut ClientSession>, diff --git a/src/action/count.rs b/src/action/count.rs index 533dfefc2..6e2ad40da 100644 --- a/src/action/count.rs +++ b/src/action/count.rs @@ -129,7 +129,7 @@ impl<'a> CountDocuments<'a> { comment: bson::Bson, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/create_collection.rs b/src/action/create_collection.rs index 3d8827be4..f68cf334b 100644 --- a/src/action/create_collection.rs +++ b/src/action/create_collection.rs @@ -66,7 +66,7 @@ impl<'a> CreateCollection<'a> { encrypted_fields: Document, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/create_index.rs b/src/action/create_index.rs index 83b06cc11..ba9a39b64 100644 --- a/src/action/create_index.rs +++ b/src/action/create_index.rs @@ -91,7 +91,7 @@ impl<'a, M> CreateIndex<'a, M> { comment: Bson, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/delete.rs b/src/action/delete.rs index 97067deb1..200e642a9 100644 --- a/src/action/delete.rs +++ b/src/action/delete.rs @@ -94,7 +94,7 @@ impl<'a> Delete<'a> { comment: Bson, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/distinct.rs b/src/action/distinct.rs index bc1280342..939feca33 100644 --- a/src/action/distinct.rs +++ b/src/action/distinct.rs @@ -65,7 +65,7 @@ impl<'a> Distinct<'a> { comment: Bson, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/drop_index.rs b/src/action/drop_index.rs index 6ed3c0642..725cf9193 100644 --- a/src/action/drop_index.rs +++ b/src/action/drop_index.rs @@ -78,7 +78,7 @@ impl<'a> DropIndex<'a> { comment: Bson, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/find.rs b/src/action/find.rs new file mode 100644 index 000000000..628b43609 --- /dev/null +++ b/src/action/find.rs @@ -0,0 +1,214 @@ +use std::time::Duration; + +use bson::{Bson, Document}; +use serde::de::DeserializeOwned; + +use crate::{ + coll::options::{CursorType, FindOneOptions, FindOptions, Hint}, + collation::Collation, + error::Result, + operation::Find as Op, + options::ReadConcern, + selection_criteria::SelectionCriteria, + ClientSession, + Collection, + Cursor, + SessionCursor, +}; + +use super::{action_impl, option_setters, ExplicitSession, ImplicitSession}; + +impl Collection { + /// Finds the documents in the collection matching `filter`. + /// + /// `await` will return `Result>` (or `Result>` if a session is + /// provided). + pub fn find(&self, filter: Document) -> Find<'_, T> { + Find { + coll: self, + filter, + options: None, + session: ImplicitSession, + } + } +} + +impl Collection { + /// Finds a single document in the collection matching `filter`. + /// + /// `await` will return `Result>`. + pub fn find_one(&self, filter: Document) -> FindOne<'_, T> { + FindOne { + coll: self, + filter, + options: None, + session: None, + } + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Finds the documents in the collection matching `filter`. + /// + /// [`run`](Find::run) will return `Result>` (or `Result>` if a + /// session is provided). + pub fn find(&self, filter: Document) -> Find<'_, T> { + self.async_collection.find(filter) + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Finds a single document in the collection matching `filter`. + /// + /// [`run`](Find::run) will return `Result>`. + pub fn find_one(&self, filter: Document) -> FindOne<'_, T> { + self.async_collection.find_one(filter) + } +} + +/// Finds the documents in a collection matching a filter. Construct with [`Collection::find`]. +#[must_use] +pub struct Find<'a, T: Send + Sync, Session = ImplicitSession> { + coll: &'a Collection, + filter: Document, + options: Option, + session: Session, +} + +impl<'a, T: Send + Sync, Session> Find<'a, T, Session> { + option_setters!(options: FindOptions; + allow_disk_use: bool, + allow_partial_results: bool, + batch_size: u32, + comment: String, + comment_bson: Bson, + cursor_type: CursorType, + hint: Hint, + limit: i64, + max: Document, + max_await_time: Duration, + max_scan: u64, + max_time: Duration, + min: Document, + no_cursor_timeout: bool, + projection: Document, + read_concern: ReadConcern, + return_key: bool, + selection_criteria: SelectionCriteria, + show_record_id: bool, + skip: u64, + sort: Document, + collation: Collation, + let_vars: Document, + ); + + /// Use the provided session when running the operation. + pub fn session<'s>( + self, + value: impl Into<&'s mut ClientSession>, + ) -> Find<'a, T, ExplicitSession<'s>> { + Find { + coll: self.coll, + filter: self.filter, + options: self.options, + session: ExplicitSession(value.into()), + } + } +} + +action_impl! { + impl<'a, T: Send + Sync> Action for Find<'a, T, ImplicitSession> { + type Future = FindFuture; + + async fn execute(mut self) -> Result> { + resolve_options!(self.coll, self.options, [read_concern, selection_criteria]); + + let find = Op::new(self.coll.namespace(), self.filter, self.options); + self.coll.client().execute_cursor_operation(find).await + } + + fn sync_wrap(out) -> Result> { + out.map(crate::sync::Cursor::new) + } + } +} + +action_impl! { + impl<'a, T: Send + Sync> Action for Find<'a, T, ExplicitSession<'a>> { + type Future = FindSessionFuture; + + async fn execute(mut self) -> Result> { + resolve_read_concern_with_session!(self.coll, self.options, Some(&mut *self.session.0))?; + resolve_selection_criteria_with_session!(self.coll, self.options, Some(&mut *self.session.0))?; + + let find = Op::new(self.coll.namespace(), self.filter, self.options); + self.coll.client().execute_session_cursor_operation(find, self.session.0).await + } + + fn sync_wrap(out) -> Result> { + out.map(crate::sync::SessionCursor::new) + } + } +} + +/// Finds a single document in a collection matching a filter. Construct with +/// [`Collection::find_one`]. +#[must_use] +pub struct FindOne<'a, T: Send + Sync> { + coll: &'a Collection, + filter: Document, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a, T: Send + Sync> FindOne<'a, T> { + option_setters! { options: FindOneOptions; + allow_partial_results: bool, + collation: Collation, + comment: String, + comment_bson: Bson, + hint: Hint, + max: Document, + max_scan: u64, + max_time: Duration, + min: Document, + projection: Document, + read_concern: ReadConcern, + return_key: bool, + selection_criteria: SelectionCriteria, + show_record_id: bool, + skip: u64, + sort: Document, + let_vars: Document, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a, T: DeserializeOwned + Send + Sync> Action for FindOne<'a, T> + { + type Future = FindOneFuture; + + async fn execute(self) -> Result> { + use futures_util::stream::StreamExt; + let mut options: FindOptions = self.options.unwrap_or_default().into(); + options.limit = Some(-1); + let find = self.coll.find(self.filter).with_options(options); + if let Some(session) = self.session { + let mut cursor = find.session(&mut *session).await?; + let mut stream = cursor.stream(session); + stream.next().await.transpose() + } else { + let mut cursor = find.await?; + cursor.next().await.transpose() + } + } + } +} diff --git a/src/action/find_and_modify.rs b/src/action/find_and_modify.rs new file mode 100644 index 000000000..1429985e8 --- /dev/null +++ b/src/action/find_and_modify.rs @@ -0,0 +1,307 @@ +use std::{borrow::Borrow, time::Duration}; + +use bson::{Bson, Document, RawDocumentBuf}; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::{ + coll::options::{ + FindOneAndDeleteOptions, + FindOneAndReplaceOptions, + FindOneAndUpdateOptions, + Hint, + ReturnDocument, + UpdateModifications, + }, + collation::Collation, + error::Result, + operation::{ + find_and_modify::options::{FindAndModifyOptions, Modification}, + FindAndModify as Op, + UpdateOrReplace, + }, + options::WriteConcern, + serde_util, + ClientSession, + Collection, +}; + +use super::{action_impl, option_setters}; + +impl Collection { + async fn find_and_modify<'a>( + &self, + filter: Document, + modification: Modification, + mut options: Option, + session: Option<&'a mut ClientSession>, + ) -> Result> { + resolve_write_concern_with_session!(self, options, session.as_ref())?; + + let op = Op::::with_modification(self.namespace(), filter, modification, options)?; + self.client().execute_operation(op, session).await + } + + /// Atomically finds up to one document in the collection matching `filter` and deletes it. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// `await` will return `Result>`. + pub fn find_one_and_delete(&self, filter: Document) -> FindOneAndDelete<'_, T> { + FindOneAndDelete { + coll: self, + filter, + options: None, + session: None, + } + } + + /// Atomically finds up to one document in the collection matching `filter` and updates it. + /// Both `Document` and `Vec` implement `Into`, so either can be + /// passed in place of constructing the enum case. Note: pipeline updates are only supported + /// in MongoDB 4.2+. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// `await` will return `Result>`. + pub fn find_one_and_update( + &self, + filter: Document, + update: impl Into, + ) -> FindOneAndUpdate<'_, T> { + FindOneAndUpdate { + coll: self, + filter, + update: update.into(), + options: None, + session: None, + } + } +} + +impl Collection { + /// Atomically finds up to one document in the collection matching `filter` and replaces it with + /// `replacement`. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + pub fn find_one_and_replace( + &self, + filter: Document, + replacement: impl Borrow, + ) -> FindOneAndReplace<'_, T> { + FindOneAndReplace { + coll: self, + filter, + replacement: serde_util::to_raw_document_buf_with_options( + replacement.borrow(), + self.human_readable_serialization(), + ), + options: None, + session: None, + } + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Atomically finds up to one document in the collection matching `filter` and deletes it. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// [`run`](FindOneAndDelete::run) will return `Result>`. + pub fn find_one_and_delete(&self, filter: Document) -> FindOneAndDelete<'_, T> { + self.async_collection.find_one_and_delete(filter) + } + + /// Atomically finds up to one document in the collection matching `filter` and updates it. + /// Both `Document` and `Vec` implement `Into`, so either can be + /// passed in place of constructing the enum case. Note: pipeline updates are only supported + /// in MongoDB 4.2+. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// [`run`](FindOneAndDelete::run) will return `Result>`. + pub fn find_one_and_update( + &self, + filter: Document, + update: impl Into, + ) -> FindOneAndUpdate<'_, T> { + self.async_collection.find_one_and_update(filter, update) + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Atomically finds up to one document in the collection matching `filter` and replaces it with + /// `replacement`. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// [`run`](FindOneAndReplace::run) will return `Result>`. + pub fn find_one_and_replace( + &self, + filter: Document, + replacement: impl Borrow, + ) -> FindOneAndReplace<'_, T> { + self.async_collection + .find_one_and_replace(filter, replacement) + } +} + +/// Atomically finds up to one document in the collection matching a filter and deletes it. +/// Construct with [`Collection::find_one_and_delete`]. +#[must_use] +pub struct FindOneAndDelete<'a, T: Send + Sync> { + coll: &'a Collection, + filter: Document, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a, T: Send + Sync> FindOneAndDelete<'a, T> { + option_setters! { options: FindOneAndDeleteOptions; + max_time: Duration, + projection: Document, + sort: Document, + write_concern: WriteConcern, + collation: Collation, + hint: Hint, + let_vars: Document, + comment: Bson, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a, T: DeserializeOwned + Send + Sync> Action for FindOneAndDelete<'a, T> { + type Future = FindOneAndDeleteFuture; + + async fn execute(self) -> Result> { + self.coll.find_and_modify( + self.filter, + Modification::Delete, + self.options.map(FindAndModifyOptions::from), + self.session, + ).await + } + } +} + +/// Atomically finds up to one document in the collection matching a filter and updates it. +/// Construct with [`Collection::find_one_and_update`]. +#[must_use] +pub struct FindOneAndUpdate<'a, T: Send + Sync> { + coll: &'a Collection, + filter: Document, + update: UpdateModifications, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a, T: Send + Sync> FindOneAndUpdate<'a, T> { + option_setters! { options: FindOneAndUpdateOptions; + array_filters: Vec, + bypass_document_validation: bool, + max_time: Duration, + projection: Document, + return_document: ReturnDocument, + sort: Document, + upsert: bool, + write_concern: WriteConcern, + collation: Collation, + hint: Hint, + let_vars: Document, + comment: Bson, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a, T: DeserializeOwned + Send + Sync> Action for FindOneAndUpdate<'a, T> { + type Future = FindOneAndUpdateFuture; + + async fn execute(self) -> Result> { + self.coll.find_and_modify( + self.filter, + Modification::Update(self.update.into()), + self.options.map(FindAndModifyOptions::from), + self.session, + ).await + } + } +} + +/// Atomically finds up to one document in the collection matching a filter and replaces it. +/// Construct with [`Collection::find_one_and_replace`]. +#[must_use] +pub struct FindOneAndReplace<'a, T: Send + Sync> { + coll: &'a Collection, + filter: Document, + replacement: Result, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a, T: Send + Sync> FindOneAndReplace<'a, T> { + option_setters! { options: FindOneAndReplaceOptions; + bypass_document_validation: bool, + max_time: Duration, + projection: Document, + return_document: ReturnDocument, + sort: Document, + upsert: bool, + write_concern: WriteConcern, + collation: Collation, + hint: Hint, + let_vars: Document, + comment: Bson, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a, T: DeserializeOwned + Send + Sync> Action for FindOneAndReplace<'a, T> { + type Future = FindOneAndReplaceFuture; + + async fn execute(self) -> Result> { + self.coll.find_and_modify( + self.filter, + Modification::Update(UpdateOrReplace::Replacement(self.replacement?)), + self.options.map(FindAndModifyOptions::from), + self.session, + ).await + } + } +} diff --git a/src/action/insert_many.rs b/src/action/insert_many.rs new file mode 100644 index 000000000..4bd5f5447 --- /dev/null +++ b/src/action/insert_many.rs @@ -0,0 +1,198 @@ +use std::{borrow::Borrow, collections::HashSet, ops::Deref}; + +use bson::{Bson, RawDocumentBuf}; +use serde::Serialize; + +use crate::{ + coll::options::InsertManyOptions, + error::{BulkWriteError, BulkWriteFailure, Error, ErrorKind, Result}, + operation::Insert as Op, + options::WriteConcern, + results::InsertManyResult, + serde_util, + ClientSession, + Collection, +}; + +use super::{action_impl, option_setters, CollRef}; + +impl Collection { + /// Inserts the data in `docs` into the collection. + /// + /// Note that this method accepts both owned and borrowed values, so the input documents + /// do not need to be cloned in order to be passed in. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// `await` will return `Result`. + pub fn insert_many(&self, docs: impl IntoIterator>) -> InsertMany { + let human_readable = self.human_readable_serialization(); + InsertMany { + coll: CollRef::new(self), + docs: docs + .into_iter() + .map(|v| serde_util::to_raw_document_buf_with_options(v.borrow(), human_readable)) + .collect(), + options: None, + session: None, + } + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Inserts the data in `docs` into the collection. + /// + /// Note that this method accepts both owned and borrowed values, so the input documents + /// do not need to be cloned in order to be passed in. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// [`run`](InsertMany::run) will return `Result`. + pub fn insert_many(&self, docs: impl IntoIterator>) -> InsertMany { + self.async_collection.insert_many(docs) + } +} + +/// Inserts documents into a collection. Construct with [`Collection::insert_many`]. +#[must_use] +pub struct InsertMany<'a> { + coll: CollRef<'a>, + docs: Result>, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a> InsertMany<'a> { + option_setters! { options: InsertManyOptions; + bypass_document_validation: bool, + ordered: bool, + write_concern: WriteConcern, + comment: Bson, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a> Action for InsertMany<'a> { + type Future = InsertManyFuture; + + async fn execute(mut self) -> Result { + resolve_write_concern_with_session!(self.coll, self.options, self.session.as_ref())?; + + let ds = self.docs?; + if ds.is_empty() { + return Err(ErrorKind::InvalidArgument { + message: "No documents provided to insert_many".to_string(), + } + .into()); + } + let ordered = self.options.as_ref().and_then(|o| o.ordered).unwrap_or(true); + #[cfg(feature = "in-use-encryption-unstable")] + let encrypted = self.coll.client().auto_encryption_opts().await.is_some(); + #[cfg(not(feature = "in-use-encryption-unstable"))] + let encrypted = false; + + let mut cumulative_failure: Option = None; + let mut error_labels: HashSet = Default::default(); + let mut cumulative_result: Option = None; + + let mut n_attempted = 0; + + while n_attempted < ds.len() { + let docs: Vec<_> = ds.iter().skip(n_attempted).map(Deref::deref).collect(); + let insert = Op::new( + self.coll.namespace(), + docs, + self.options.clone(), + encrypted, + ); + + match self + .coll + .client() + .execute_operation(insert, self.session.as_deref_mut()) + .await + { + Ok(result) => { + let current_batch_size = result.inserted_ids.len(); + + let cumulative_result = + cumulative_result.get_or_insert_with(InsertManyResult::new); + for (index, id) in result.inserted_ids { + cumulative_result + .inserted_ids + .insert(index + n_attempted, id); + } + + n_attempted += current_batch_size; + } + Err(e) => { + let labels = e.labels().clone(); + match *e.kind { + ErrorKind::BulkWrite(bw) => { + // for ordered inserts this size will be incorrect, but knowing the + // batch size isn't needed for ordered + // failures since we return immediately from + // them anyways. + let current_batch_size = bw.inserted_ids.len() + + bw.write_errors.as_ref().map(|we| we.len()).unwrap_or(0); + + let failure_ref = + cumulative_failure.get_or_insert_with(BulkWriteFailure::new); + if let Some(write_errors) = bw.write_errors { + for err in write_errors { + let index = n_attempted + err.index; + + failure_ref + .write_errors + .get_or_insert_with(Default::default) + .push(BulkWriteError { index, ..err }); + } + } + + if let Some(wc_error) = bw.write_concern_error { + failure_ref.write_concern_error = Some(wc_error); + } + + error_labels.extend(labels); + + if ordered { + // this will always be true since we invoked get_or_insert_with + // above. + if let Some(failure) = cumulative_failure { + return Err(Error::new( + ErrorKind::BulkWrite(failure), + Some(error_labels), + )); + } + } + n_attempted += current_batch_size; + } + _ => return Err(e), + } + } + } + } + + match cumulative_failure { + Some(failure) => Err(Error::new( + ErrorKind::BulkWrite(failure), + Some(error_labels), + )), + None => Ok(cumulative_result.unwrap_or_else(InsertManyResult::new)), + } + } + } +} diff --git a/src/action/insert_one.rs b/src/action/insert_one.rs new file mode 100644 index 000000000..0f4296241 --- /dev/null +++ b/src/action/insert_one.rs @@ -0,0 +1,112 @@ +use std::{borrow::Borrow, ops::Deref}; + +use bson::{Bson, RawDocumentBuf}; +use serde::Serialize; + +use crate::{ + coll::options::{InsertManyOptions, InsertOneOptions}, + error::{convert_bulk_errors, Result}, + operation::Insert as Op, + options::WriteConcern, + results::InsertOneResult, + serde_util, + ClientSession, + Collection, +}; + +use super::{action_impl, option_setters, CollRef}; + +impl Collection { + /// Inserts `doc` into the collection. + /// + /// Note that either an owned or borrowed value can be inserted here, so the input document + /// does not need to be cloned to be passed in. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// `await` will return `Result`. + pub fn insert_one(&self, doc: impl Borrow) -> InsertOne { + InsertOne { + coll: CollRef::new(self), + doc: serde_util::to_raw_document_buf_with_options( + doc.borrow(), + self.human_readable_serialization(), + ), + options: None, + session: None, + } + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Inserts `doc` into the collection. + /// + /// Note that either an owned or borrowed value can be inserted here, so the input document + /// does not need to be cloned to be passed in. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// [`run`](InsertOne::run) will return `Result`. + pub fn insert_one(&self, doc: impl Borrow) -> InsertOne { + self.async_collection.insert_one(doc) + } +} + +/// Inserts a document into a collection. Construct with ['Collection::insert_one`]. +#[must_use] +pub struct InsertOne<'a> { + coll: CollRef<'a>, + doc: Result, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a> InsertOne<'a> { + option_setters! { options: InsertOneOptions; + bypass_document_validation: bool, + write_concern: WriteConcern, + comment: Bson, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a> Action for InsertOne<'a> { + type Future = InsertOneFuture; + + async fn execute(mut self) -> Result { + resolve_write_concern_with_session!(self.coll, self.options, self.session.as_ref())?; + + #[cfg(feature = "in-use-encryption-unstable")] + let encrypted = self.coll.client().auto_encryption_opts().await.is_some(); + #[cfg(not(feature = "in-use-encryption-unstable"))] + let encrypted = false; + + let doc = self.doc?; + + let insert = Op::new( + self.coll.namespace(), + vec![doc.deref()], + self.options.map(InsertManyOptions::from_insert_one_options), + encrypted, + ); + self.coll.client() + .execute_operation(insert, self.session) + .await + .map(InsertOneResult::from_insert_many_result) + .map_err(convert_bulk_errors) + } + } +} diff --git a/src/action/list_collections.rs b/src/action/list_collections.rs index 15dcb2ed0..b81a103e9 100644 --- a/src/action/list_collections.rs +++ b/src/action/list_collections.rs @@ -87,7 +87,7 @@ impl<'a, M, S> ListCollections<'a, M, S> { } impl<'a, M> ListCollections<'a, M, ImplicitSession> { - /// Runs the query using the provided session. + /// Use the provided session when running the operation. pub fn session<'s>( self, value: impl Into<&'s mut ClientSession>, diff --git a/src/action/list_databases.rs b/src/action/list_databases.rs index f4c7c28d7..08b9eb73f 100644 --- a/src/action/list_databases.rs +++ b/src/action/list_databases.rs @@ -75,7 +75,7 @@ impl<'a, M> ListDatabases<'a, M> { comment: Bson, ); - /// Runs the query using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self diff --git a/src/action/list_indexes.rs b/src/action/list_indexes.rs index ac05c5566..0e2e23bd9 100644 --- a/src/action/list_indexes.rs +++ b/src/action/list_indexes.rs @@ -94,7 +94,7 @@ impl<'a, Mode, Session> ListIndexes<'a, Mode, Session> { } impl<'a, Mode> ListIndexes<'a, Mode, ImplicitSession> { - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session( self, value: impl Into<&'a mut ClientSession>, diff --git a/src/action/replace_one.rs b/src/action/replace_one.rs new file mode 100644 index 000000000..50cd190e4 --- /dev/null +++ b/src/action/replace_one.rs @@ -0,0 +1,103 @@ +use std::borrow::Borrow; + +use bson::{Bson, Document, RawDocumentBuf}; +use serde::Serialize; + +use crate::{ + coll::options::{Hint, ReplaceOptions, UpdateOptions}, + collation::Collation, + error::Result, + operation::Update as Op, + options::WriteConcern, + results::UpdateResult, + serde_util, + ClientSession, + Collection, +}; + +use super::{action_impl, option_setters, CollRef}; + +impl Collection { + /// Replaces up to one document matching `query` in the collection with `replacement`. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// `await` will return `Result`. + pub fn replace_one(&self, query: Document, replacement: impl Borrow) -> ReplaceOne { + ReplaceOne { + coll: CollRef::new(self), + query, + replacement: serde_util::to_raw_document_buf_with_options( + replacement.borrow(), + self.human_readable_serialization(), + ), + options: None, + session: None, + } + } +} + +#[cfg(feature = "sync")] +impl crate::sync::Collection { + /// Replaces up to one document matching `query` in the collection with `replacement`. + /// + /// This operation will retry once upon failure if the connection and encountered error support + /// retryability. See the documentation + /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on + /// retryable writes. + /// + /// [`run`](ReplaceOne::run) will return `Result`. + pub fn replace_one(&self, query: Document, replacement: impl Borrow) -> ReplaceOne { + self.async_collection.replace_one(query, replacement) + } +} + +/// Replace up to one document matching a query. Construct with [`Collection::replace_one`]. +#[must_use] +pub struct ReplaceOne<'a> { + coll: CollRef<'a>, + query: Document, + replacement: Result, + options: Option, + session: Option<&'a mut ClientSession>, +} + +impl<'a> ReplaceOne<'a> { + option_setters! { options: ReplaceOptions; + bypass_document_validation: bool, + upsert: bool, + collation: Collation, + hint: Hint, + write_concern: WriteConcern, + let_vars: Document, + comment: Bson, + } + + /// Use the provided session when running the operation. + pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { + self.session = Some(value.into()); + self + } +} + +action_impl! { + impl<'a> Action for ReplaceOne<'a> { + type Future = ReplaceOneFuture; + + async fn execute(mut self) -> Result { + resolve_write_concern_with_session!(self.coll, self.options, self.session.as_ref())?; + + let update = Op::with_replace_raw( + self.coll.namespace(), + self.query, + self.replacement?, + false, + self.options.map(UpdateOptions::from_replace_options), + )?; + self.coll.client().execute_operation(update, self.session).await + } + } +} diff --git a/src/action/update.rs b/src/action/update.rs index 231b8d1d4..ca877f9fa 100644 --- a/src/action/update.rs +++ b/src/action/update.rs @@ -120,7 +120,7 @@ impl<'a> Update<'a> { comment: Bson, ); - /// Runs the operation using the provided session. + /// Use the provided session when running the operation. pub fn session(mut self, value: impl Into<&'a mut ClientSession>) -> Self { self.session = Some(value.into()); self @@ -143,7 +143,6 @@ action_impl! { self.update, self.multi, self.options, - self.coll.human_readable_serialization(), ); self.coll.client().execute_operation(op, self.session).await } diff --git a/src/change_stream.rs b/src/change_stream.rs index 428158ba6..86c2bb0b7 100644 --- a/src/change_stream.rs +++ b/src/change_stream.rs @@ -57,7 +57,7 @@ use crate::{ /// let mut change_stream = coll.watch().await?; /// let coll_ref = coll.clone(); /// task::spawn(async move { -/// coll_ref.insert_one(doc! { "x": 1 }, None).await; +/// coll_ref.insert_one(doc! { "x": 1 }).await; /// }); /// while let Some(event) = change_stream.next().await.transpose()? { /// println!("operation performed: {:?}, document: {:?}", event.operation_type, event.full_document); diff --git a/src/change_stream/session.rs b/src/change_stream/session.rs index e292b44af..0af9e2fa4 100644 --- a/src/change_stream/session.rs +++ b/src/change_stream/session.rs @@ -85,7 +85,7 @@ where /// let mut cs = coll.watch().session(&mut session).await?; /// while let Some(event) = cs.next(&mut session).await? { /// let id = bson::to_bson(&event.id)?; - /// other_coll.insert_one_with_session(doc! { "id": id }, None, &mut session).await?; + /// other_coll.insert_one(doc! { "id": id }).session(&mut session).await?; /// } /// # Ok::<(), mongodb::error::Error>(()) /// # }; diff --git a/src/client/csfle/client_encryption.rs b/src/client/csfle/client_encryption.rs index 5b6c0c045..aee2f4438 100644 --- a/src/client/csfle/client_encryption.rs +++ b/src/client/csfle/client_encryption.rs @@ -99,13 +99,13 @@ impl ClientEncryption { /// Finds a single key document with the given UUID (BSON binary subtype 0x04). /// Returns the result of the internal find() operation on the key vault collection. pub async fn get_key(&self, id: &Binary) -> Result> { - self.key_vault.find_one(doc! { "_id": id }, None).await + self.key_vault.find_one(doc! { "_id": id }).await } /// Finds all documents in the key vault collection. /// Returns the result of the internal find() operation on the key vault collection. pub async fn get_keys(&self) -> Result> { - self.key_vault.find(doc! {}, None).await + self.key_vault.find(doc! {}).await } /// Adds a keyAltName to the keyAltNames array of the key document in the key vault collection @@ -120,7 +120,6 @@ impl ClientEncryption { .find_one_and_update( doc! { "_id": id }, doc! { "$addToSet": { "keyAltNames": key_alt_name } }, - None, ) .await } @@ -150,7 +149,7 @@ impl ClientEncryption { } }; self.key_vault - .find_one_and_update(doc! { "_id": id }, vec![update], None) + .find_one_and_update(doc! { "_id": id }, vec![update]) .await } @@ -160,7 +159,7 @@ impl ClientEncryption { key_alt_name: impl AsRef, ) -> Result> { self.key_vault - .find_one(doc! { "keyAltNames": key_alt_name.as_ref() }, None) + .find_one(doc! { "keyAltNames": key_alt_name.as_ref() }) .await } diff --git a/src/client/csfle/client_encryption/create_data_key.rs b/src/client/csfle/client_encryption/create_data_key.rs index b4307bee2..358e1826e 100644 --- a/src/client/csfle/client_encryption/create_data_key.rs +++ b/src/client/csfle/client_encryption/create_data_key.rs @@ -24,7 +24,7 @@ action_impl! { } let ctx = self.client_enc.create_data_key_ctx(provider, self.master_key, self.options)?; let data_key = self.client_enc.exec.run_ctx(ctx, None).await?; - self.client_enc.key_vault.insert_one(&data_key, None).await?; + self.client_enc.key_vault.insert_one(&data_key).await?; let bin_ref = data_key .get_binary("_id") .map_err(|e| Error::internal(format!("invalid data key id: {}", e)))?; diff --git a/src/client/csfle/state_machine.rs b/src/client/csfle/state_machine.rs index 13f75cbd9..bc7aa5f05 100644 --- a/src/client/csfle/state_machine.rs +++ b/src/client/csfle/state_machine.rs @@ -15,7 +15,6 @@ use tokio::{ use crate::{ client::{options::ServerAddress, WeakClient}, - coll::options::FindOptions, error::{Error, Result}, operation::{run_command::RunCommand, RawOutput}, options::ReadConcern, @@ -164,12 +163,8 @@ impl CryptExecutor { .database(&kv_ns.db) .collection::(&kv_ns.coll); let mut cursor = kv_coll - .find( - filter, - FindOptions::builder() - .read_concern(ReadConcern::majority()) - .build(), - ) + .find(filter) + .read_concern(ReadConcern::majority()) .await?; while cursor.advance().await? { ctx.mongo_feed(cursor.current())?; diff --git a/src/client/session.rs b/src/client/session.rs index c96c834b8..3c9f43d01 100644 --- a/src/client/session.rs +++ b/src/client/session.rs @@ -81,7 +81,7 @@ pub(crate) static SESSIONS_UNSUPPORTED_COMMANDS: Lazy> = L /// # } /// /// async fn execute_transaction(coll: &Collection, session: &mut ClientSession) -> Result<()> { -/// coll.insert_one_with_session(doc! { "x": 1 }, None, session).await?; +/// coll.insert_one(doc! { "x": 1 }).session(&mut *session).await?; /// coll.delete_one(doc! { "y": 2 }).session(&mut *session).await?; /// // An "UnknownTransactionCommitResult" label indicates that it is unknown whether the /// // commit has satisfied the write concern associated with the transaction. If an error @@ -355,7 +355,7 @@ impl ClientSession { /// # let coll = client.database("foo").collection::("bar"); /// # let mut session = client.start_session().await?; /// session.start_transaction(None).await?; - /// let result = coll.insert_one_with_session(doc! { "x": 1 }, None, &mut session).await?; + /// let result = coll.insert_one(doc! { "x": 1 }).session(&mut session).await?; /// session.commit_transaction().await?; /// # Ok(()) /// # } @@ -456,7 +456,7 @@ impl ClientSession { /// # let coll = client.database("foo").collection::("bar"); /// # let mut session = client.start_session().await?; /// session.start_transaction(None).await?; - /// let result = coll.insert_one_with_session(doc! { "x": 1 }, None, &mut session).await?; + /// let result = coll.insert_one(doc! { "x": 1 }).session(&mut session).await?; /// session.commit_transaction().await?; /// # Ok(()) /// # } @@ -524,8 +524,8 @@ impl ClientSession { /// # } /// /// async fn execute_transaction(coll: &Collection, session: &mut ClientSession) -> Result<()> { - /// coll.insert_one_with_session(doc! { "x": 1 }, None, session).await?; - /// coll.delete_one(doc! { "y": 2 }).session(session).await?; + /// coll.insert_one(doc! { "x": 1 }).session(&mut *session).await?; + /// coll.delete_one(doc! { "y": 2 }).session(&mut *session).await?; /// Ok(()) /// } /// ``` @@ -605,7 +605,7 @@ impl ClientSession { /// session.with_transaction( /// (&coll, &my_data), /// |session, (coll, my_data)| async move { - /// coll.insert_one_with_session(doc! { "data": *my_data }, None, session).await + /// coll.insert_one(doc! { "data": *my_data }).session(session).await /// }.boxed(), /// None, /// ).await?; @@ -613,7 +613,7 @@ impl ClientSession { /// session.with_transaction( /// (), /// |session, _| async move { - /// coll.insert_one_with_session(doc! { "data": my_data }, None, session).await + /// coll.insert_one(doc! { "data": my_data }).session(session).await /// }.boxed(), /// None, /// ).await?; diff --git a/src/client/session/test.rs b/src/client/session/test.rs index 62fa47ad1..1649e0de5 100644 --- a/src/client/session/test.rs +++ b/src/client/session/test.rs @@ -7,10 +7,10 @@ use futures::stream::StreamExt; use crate::{ bson::{doc, Bson}, - coll::options::{CountOptions, InsertManyOptions}, + coll::options::CountOptions, error::Result, event::sdam::SdamEvent, - options::{Acknowledgment, FindOptions, ReadConcern, ReadPreference, WriteConcern}, + options::{FindOptions, ReadConcern, ReadPreference, WriteConcern}, sdam::ServerInfo, selection_criteria::SelectionCriteria, test::{get_client_options, log_uncaptured, Event, EventClient, EventHandler, TestClient}, @@ -58,16 +58,12 @@ macro_rules! for_each_op { // collection operations $test_func( "insert", - collection_op!($test_name, coll, coll.insert_one(doc! { "x": 1 }, None)), + collection_op!($test_name, coll, coll.insert_one(doc! { "x": 1 })), ) .await; $test_func( "insert", - collection_op!( - $test_name, - coll, - coll.insert_many(vec![doc! { "x": 1 }], None) - ), + collection_op!($test_name, coll, coll.insert_many(vec![doc! { "x": 1 }])), ) .await; $test_func( @@ -75,7 +71,7 @@ macro_rules! for_each_op { collection_op!( $test_name, coll, - coll.replace_one(doc! { "x": 1 }, doc! { "x": 2 }, None) + coll.replace_one(doc! { "x": 1 }, doc! { "x": 2 }) ), ) .await; @@ -109,11 +105,7 @@ macro_rules! for_each_op { .await; $test_func( "findAndModify", - collection_op!( - $test_name, - coll, - coll.find_one_and_delete(doc! { "x": 1 }, None) - ), + collection_op!($test_name, coll, coll.find_one_and_delete(doc! { "x": 1 })), ) .await; $test_func( @@ -121,7 +113,7 @@ macro_rules! for_each_op { collection_op!( $test_name, coll, - coll.find_one_and_update(doc! {}, doc! { "$inc": { "x": 1 } }, None) + coll.find_one_and_update(doc! {}, doc! { "$inc": { "x": 1 } }) ), ) .await; @@ -130,7 +122,7 @@ macro_rules! for_each_op { collection_op!( $test_name, coll, - coll.find_one_and_replace(doc! {}, doc! {"x": 1}, None) + coll.find_one_and_replace(doc! {}, doc! {"x": 1}) ), ) .await; @@ -145,12 +137,12 @@ macro_rules! for_each_op { .await; $test_func( "find", - collection_op!($test_name, coll, coll.find(doc! { "x": 1 }, None)), + collection_op!($test_name, coll, coll.find(doc! { "x": 1 })), ) .await; $test_func( "find", - collection_op!($test_name, coll, coll.find_one(doc! { "x": 1 }, None)), + collection_op!($test_name, coll, coll.find_one(doc! { "x": 1 })), ) .await; $test_func( @@ -362,7 +354,7 @@ async fn cluster_time_in_commands() { client .database(function_name!()) .collection::(function_name!()) - .find(doc! {}, None) + .find(doc! {}) .await }) .await; @@ -371,7 +363,7 @@ async fn cluster_time_in_commands() { client .database(function_name!()) .collection::(function_name!()) - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await }) .await; @@ -416,7 +408,7 @@ async fn implicit_session_returned_after_immediate_exhaust() { let coll = client .init_db_and_coll(function_name!(), function_name!()) .await; - coll.insert_many(vec![doc! {}, doc! {}], None) + coll.insert_many(vec![doc! {}, doc! {}]) .await .expect("insert should succeed"); @@ -424,7 +416,7 @@ async fn implicit_session_returned_after_immediate_exhaust() { tokio::time::sleep(Duration::from_millis(250)).await; client.clear_session_pool().await; - let mut cursor = coll.find(doc! {}, None).await.expect("find should succeed"); + let mut cursor = coll.find(doc! {}).await.expect("find should succeed"); assert!(matches!(cursor.next().await, Some(Ok(_)))); let (find_started, _) = client.get_successful_command_execution("find"); @@ -457,7 +449,7 @@ async fn implicit_session_returned_after_exhaust_by_get_more() { .init_db_and_coll(function_name!(), function_name!()) .await; for _ in 0..5 { - coll.insert_one(doc! {}, None) + coll.insert_one(doc! {}) .await .expect("insert should succeed"); } @@ -466,9 +458,9 @@ async fn implicit_session_returned_after_exhaust_by_get_more() { tokio::time::sleep(Duration::from_millis(250)).await; client.clear_session_pool().await; - let options = FindOptions::builder().batch_size(3).build(); let mut cursor = coll - .find(doc! {}, options) + .find(doc! {}) + .batch_size(3) .await .expect("find should succeed"); @@ -509,10 +501,10 @@ async fn find_and_getmore_share_session() { .init_db_and_coll(function_name!(), function_name!()) .await; - let options = InsertManyOptions::builder() - .write_concern(WriteConcern::builder().w(Acknowledgment::Majority).build()) - .build(); - coll.insert_many(vec![doc! {}; 3], options).await.unwrap(); + coll.insert_many(vec![doc! {}; 3]) + .write_concern(WriteConcern::majority()) + .await + .unwrap(); let read_preferences: Vec = vec![ ReadPreference::Primary, @@ -545,7 +537,8 @@ async fn find_and_getmore_share_session() { let mut cursor; loop { cursor = coll - .find(doc! {}, options.clone()) + .find(doc! {}) + .with_options(options.clone()) .await .expect("find should succeed"); if cursor.has_next() { diff --git a/src/client/session/test/causal_consistency.rs b/src/client/session/test/causal_consistency.rs index 2b51f12f6..12caec724 100644 --- a/src/client/session/test/causal_consistency.rs +++ b/src/client/session/test/causal_consistency.rs @@ -45,21 +45,20 @@ fn all_session_ops() -> impl Iterator { let mut ops = vec![]; ops.push(op!("insert", false, |coll, session| { - coll.insert_one_with_session(doc! { "x": 1 }, None, session) + coll.insert_one(doc! { "x": 1 }).session(session) })); ops.push(op!("insert", false, |coll, session| { - coll.insert_many_with_session(vec![doc! { "x": 1 }], None, session) + coll.insert_many(vec![doc! { "x": 1 }]).session(session) })); ops.push(op!("find", true, |coll, session| coll - .find_one_with_session(doc! { "x": 1 }, None, session))); + .find_one(doc! { "x": 1 }) + .session(session))); - ops.push(op!("find", true, |coll, session| coll.find_with_session( - doc! { "x": 1 }, - None, - session - ))); + ops.push(op!("find", true, |coll, session| coll + .find(doc! { "x": 1 }) + .session(session))); ops.push(op!("update", false, |coll, s| coll .update_one(doc! { "x": 1 }, doc! { "$inc": { "x": 1 } },) @@ -70,12 +69,8 @@ fn all_session_ops() -> impl Iterator { .session(s))); ops.push(op!("update", false, |coll, s| coll - .replace_one_with_session( - doc! { "x": 1 }, - doc! { "x": 2 }, - None, - s, - ))); + .replace_one(doc! { "x": 1 }, doc! { "x": 2 },) + .session(s))); ops.push(op!("delete", false, |coll, s| coll .delete_one(doc! { "x": 1 }) @@ -86,23 +81,16 @@ fn all_session_ops() -> impl Iterator { .session(s))); ops.push(op!("findAndModify", false, |coll, s| coll - .find_one_and_update_with_session( - doc! { "x": 1 }, - doc! { "$inc": { "x": 1 } }, - None, - s, - ))); + .find_one_and_update(doc! { "x": 1 }, doc! { "$inc": { "x": 1 } },) + .session(s))); ops.push(op!("findAndModify", false, |coll, s| coll - .find_one_and_replace_with_session( - doc! { "x": 1 }, - doc! { "x": 1 }, - None, - s, - ))); + .find_one_and_replace(doc! { "x": 1 }, doc! { "x": 1 },) + .session(s))); ops.push(op!("findAndModify", false, |coll, s| coll - .find_one_and_delete_with_session(doc! { "x": 1 }, None, s,))); + .find_one_and_delete(doc! { "x": 1 }) + .session(s))); ops.push(op!("aggregate", true, |coll, s| coll .count_documents(doc! { "x": 1 }) @@ -242,9 +230,7 @@ async fn read_includes_after_cluster_time() { for op in all_session_ops().filter(|o| o.is_read) { let command_name = op.name; let mut session = client.start_session().await.unwrap(); - coll.find_one_with_session(None, None, &mut session) - .await - .unwrap(); + coll.find_one(doc! {}).session(&mut session).await.unwrap(); let op_time = session.operation_time().unwrap(); op.execute(coll.clone(), &mut session).await.unwrap(); @@ -290,9 +276,7 @@ async fn find_after_write_includes_after_cluster_time() { .unwrap(); op.execute(coll.clone(), &mut session).await.unwrap(); let op_time = session.operation_time().unwrap(); - coll.find_one_with_session(None, None, &mut session) - .await - .unwrap(); + coll.find_one(doc! {}).session(&mut session).await.unwrap(); let command_started = client.get_command_started_events(&["find"]).pop().unwrap(); assert_eq!( @@ -404,9 +388,7 @@ async fn omit_default_read_concern_level() { .causal_consistency(true) .await .unwrap(); - coll.find_one_with_session(None, None, &mut session) - .await - .unwrap(); + coll.find_one(doc! {}).session(&mut session).await.unwrap(); let op_time = session.operation_time().unwrap(); op.execute(coll.clone(), &mut session).await.unwrap(); @@ -451,9 +433,7 @@ async fn test_causal_consistency_read_concern_merge() { for op in all_session_ops().filter(|o| o.is_read) { let command_name = op.name; - coll.find_one_with_session(None, None, &mut session) - .await - .unwrap(); + coll.find_one(doc! {}).session(&mut session).await.unwrap(); let op_time = session.operation_time().unwrap(); op.execute(coll.clone(), &mut session).await.unwrap(); @@ -484,7 +464,7 @@ async fn omit_cluster_time_standalone() { .database("causal_consistency_11") .collection::("causal_consistency_11"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); let (started, _) = client.get_successful_command_execution("find"); started.command.get_document("$clusterTime").unwrap_err(); @@ -503,7 +483,7 @@ async fn cluster_time_sent_in_commands() { .database("causal_consistency_12") .collection::("causal_consistency_12"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); let (started, _) = client.get_successful_command_execution("find"); started.command.get_document("$clusterTime").unwrap(); diff --git a/src/coll.rs b/src/coll.rs index 634ffa5c9..005d3d088 100644 --- a/src/coll.rs +++ b/src/coll.rs @@ -1,31 +1,20 @@ mod action; pub mod options; -use std::{borrow::Borrow, collections::HashSet, fmt, fmt::Debug, str::FromStr, sync::Arc}; - -use futures_util::stream::StreamExt; -use serde::{ - de::{DeserializeOwned, Error as DeError}, - Deserialize, - Deserializer, - Serialize, -}; +use std::{fmt, fmt::Debug, str::FromStr, sync::Arc}; + +use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize}; use self::options::*; use crate::{ - bson::{doc, Document}, + bson::doc, client::options::ServerAddress, cmap::conn::PinnedConnectionHandle, concern::{ReadConcern, WriteConcern}, - error::{convert_bulk_errors, BulkWriteError, BulkWriteFailure, Error, ErrorKind, Result}, - operation::{Find, FindAndModify, Insert, Update}, - results::{InsertManyResult, InsertOneResult, UpdateResult}, + error::{Error, Result}, selection_criteria::SelectionCriteria, Client, - ClientSession, - Cursor, Database, - SessionCursor, }; /// `Collection` is the client-side abstraction of a MongoDB Collection. It can be used to @@ -74,7 +63,7 @@ use crate::{ /// // Spawn several tasks that operate on the same collection concurrently. /// tokio::task::spawn(async move { /// // Perform operations with `coll_ref` that work with directly our model. -/// coll_ref.insert_one(Item { id: i }, None).await; +/// coll_ref.insert_one(Item { id: i }).await; /// }); /// } /// # @@ -225,529 +214,11 @@ where Ok(()) } - /// Finds the documents in the collection matching `filter`. - pub async fn find( - &self, - filter: impl Into>, - options: impl Into>, - ) -> Result> { - let mut options = options.into(); - resolve_options!(self, options, [read_concern, selection_criteria]); - - let find = Find::new(self.namespace(), filter.into(), options); - let client = self.client(); - - client.execute_cursor_operation(find).await - } - - /// Finds the documents in the collection matching `filter` using the provided `ClientSession`. - pub async fn find_with_session( - &self, - filter: impl Into>, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - let mut options = options.into(); - resolve_read_concern_with_session!(self, options, Some(&mut *session))?; - resolve_selection_criteria_with_session!(self, options, Some(&mut *session))?; - - let find = Find::new(self.namespace(), filter.into(), options); - let client = self.client(); - - client.execute_session_cursor_operation(find, session).await - } - pub(crate) fn human_readable_serialization(&self) -> bool { self.inner.human_readable_serialization } } -impl Collection -where - T: DeserializeOwned + Unpin + Send + Sync, -{ - /// Finds a single document in the collection matching `filter`. - pub async fn find_one( - &self, - filter: impl Into>, - options: impl Into>, - ) -> Result> { - let mut options = options.into(); - resolve_options!(self, options, [read_concern, selection_criteria]); - - let options: FindOptions = options.map(Into::into).unwrap_or_else(Default::default); - let mut cursor = self.find(filter, Some(options)).await?; - cursor.next().await.transpose() - } - - /// Finds a single document in the collection matching `filter` using the provided - /// `ClientSession`. - pub async fn find_one_with_session( - &self, - filter: impl Into>, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - let mut options = options.into(); - resolve_read_concern_with_session!(self, options, Some(&mut *session))?; - resolve_selection_criteria_with_session!(self, options, Some(&mut *session))?; - - let options: FindOptions = options.map(Into::into).unwrap_or_else(Default::default); - let mut cursor = self - .find_with_session(filter, Some(options), session) - .await?; - let mut cursor = cursor.stream(session); - cursor.next().await.transpose() - } -} - -impl Collection -where - T: DeserializeOwned + Send + Sync, -{ - async fn find_one_and_delete_common( - &self, - filter: Document, - options: impl Into>, - session: impl Into>, - ) -> Result> { - let session = session.into(); - - let mut options = options.into(); - resolve_write_concern_with_session!(self, options, session.as_ref())?; - - let op = FindAndModify::with_delete(self.namespace(), filter, options); - self.client().execute_operation(op, session).await - } - - /// Atomically finds up to one document in the collection matching `filter` and deletes it. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn find_one_and_delete( - &self, - filter: Document, - options: impl Into>, - ) -> Result> { - self.find_one_and_delete_common(filter, options, None).await - } - - /// Atomically finds up to one document in the collection matching `filter` and deletes it using - /// the provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn find_one_and_delete_with_session( - &self, - filter: Document, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - self.find_one_and_delete_common(filter, options, session) - .await - } - - async fn find_one_and_update_common( - &self, - filter: Document, - update: impl Into, - options: impl Into>, - session: impl Into>, - ) -> Result> { - let update = update.into(); - - let session = session.into(); - - let mut options = options.into(); - resolve_write_concern_with_session!(self, options, session.as_ref())?; - - let op = FindAndModify::with_update(self.namespace(), filter, update, options)?; - self.client().execute_operation(op, session).await - } - - /// Atomically finds up to one document in the collection matching `filter` and updates it. - /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn find_one_and_update( - &self, - filter: Document, - update: impl Into, - options: impl Into>, - ) -> Result> { - self.find_one_and_update_common(filter, update, options, None) - .await - } - - /// Atomically finds up to one document in the collection matching `filter` and updates it using - /// the provided `ClientSession`. Both `Document` and `Vec` implement - /// `Into`, so either can be passed in place of constructing the enum - /// case. Note: pipeline updates are only supported in MongoDB 4.2+. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn find_one_and_update_with_session( - &self, - filter: Document, - update: impl Into, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - self.find_one_and_update_common(filter, update, options, session) - .await - } -} - -impl Collection -where - T: Serialize + DeserializeOwned + Send + Sync, -{ - async fn find_one_and_replace_common( - &self, - filter: Document, - replacement: impl Borrow, - options: impl Into>, - session: impl Into>, - ) -> Result> { - let mut options = options.into(); - let session = session.into(); - resolve_write_concern_with_session!(self, options, session.as_ref())?; - - let op = FindAndModify::with_replace( - self.namespace(), - filter, - replacement.borrow(), - options, - self.inner.human_readable_serialization, - )?; - self.client().execute_operation(op, session).await - } - - /// Atomically finds up to one document in the collection matching `filter` and replaces it with - /// `replacement`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn find_one_and_replace( - &self, - filter: Document, - replacement: impl Borrow, - options: impl Into>, - ) -> Result> { - self.find_one_and_replace_common(filter, replacement, options, None) - .await - } - - /// Atomically finds up to one document in the collection matching `filter` and replaces it with - /// `replacement` using the provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn find_one_and_replace_with_session( - &self, - filter: Document, - replacement: impl Borrow, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - self.find_one_and_replace_common(filter, replacement, options, session) - .await - } -} - -impl Collection -where - T: Serialize + Send + Sync, -{ - #[allow(clippy::needless_option_as_deref)] - async fn insert_many_common( - &self, - docs: impl IntoIterator>, - options: impl Into>, - mut session: Option<&mut ClientSession>, - ) -> Result { - let ds: Vec<_> = docs.into_iter().collect(); - let mut options = options.into(); - resolve_write_concern_with_session!(self, options, session.as_ref())?; - - if ds.is_empty() { - return Err(ErrorKind::InvalidArgument { - message: "No documents provided to insert_many".to_string(), - } - .into()); - } - - let ordered = options.as_ref().and_then(|o| o.ordered).unwrap_or(true); - #[cfg(feature = "in-use-encryption-unstable")] - let encrypted = self.client().auto_encryption_opts().await.is_some(); - #[cfg(not(feature = "in-use-encryption-unstable"))] - let encrypted = false; - - let mut cumulative_failure: Option = None; - let mut error_labels: HashSet = Default::default(); - let mut cumulative_result: Option = None; - - let mut n_attempted = 0; - - while n_attempted < ds.len() { - let docs: Vec<&T> = ds.iter().skip(n_attempted).map(Borrow::borrow).collect(); - let insert = Insert::new( - self.namespace(), - docs, - options.clone(), - encrypted, - self.inner.human_readable_serialization, - ); - - match self - .client() - .execute_operation(insert, session.as_deref_mut()) - .await - { - Ok(result) => { - let current_batch_size = result.inserted_ids.len(); - - let cumulative_result = - cumulative_result.get_or_insert_with(InsertManyResult::new); - for (index, id) in result.inserted_ids { - cumulative_result - .inserted_ids - .insert(index + n_attempted, id); - } - - n_attempted += current_batch_size; - } - Err(e) => { - let labels = e.labels().clone(); - match *e.kind { - ErrorKind::BulkWrite(bw) => { - // for ordered inserts this size will be incorrect, but knowing the - // batch size isn't needed for ordered - // failures since we return immediately from - // them anyways. - let current_batch_size = bw.inserted_ids.len() - + bw.write_errors.as_ref().map(|we| we.len()).unwrap_or(0); - - let failure_ref = - cumulative_failure.get_or_insert_with(BulkWriteFailure::new); - if let Some(write_errors) = bw.write_errors { - for err in write_errors { - let index = n_attempted + err.index; - - failure_ref - .write_errors - .get_or_insert_with(Default::default) - .push(BulkWriteError { index, ..err }); - } - } - - if let Some(wc_error) = bw.write_concern_error { - failure_ref.write_concern_error = Some(wc_error); - } - - error_labels.extend(labels); - - if ordered { - // this will always be true since we invoked get_or_insert_with - // above. - if let Some(failure) = cumulative_failure { - return Err(Error::new( - ErrorKind::BulkWrite(failure), - Some(error_labels), - )); - } - } - n_attempted += current_batch_size; - } - _ => return Err(e), - } - } - } - } - - match cumulative_failure { - Some(failure) => Err(Error::new( - ErrorKind::BulkWrite(failure), - Some(error_labels), - )), - None => Ok(cumulative_result.unwrap_or_else(InsertManyResult::new)), - } - } - - /// Inserts the data in `docs` into the collection. - /// - /// Note that this method accepts both owned and borrowed values, so the input documents - /// do not need to be cloned in order to be passed in. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn insert_many( - &self, - docs: impl IntoIterator>, - options: impl Into>, - ) -> Result { - self.insert_many_common(docs, options, None).await - } - - /// Inserts the data in `docs` into the collection using the provided `ClientSession`. - /// - /// Note that this method accepts both owned and borrowed values, so the input documents - /// do not need to be cloned in order to be passed in. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn insert_many_with_session( - &self, - docs: impl IntoIterator>, - options: impl Into>, - session: &mut ClientSession, - ) -> Result { - self.insert_many_common(docs, options, Some(session)).await - } - - async fn insert_one_common( - &self, - doc: &T, - options: impl Into>, - session: impl Into>, - ) -> Result { - let session = session.into(); - - let mut options = options.into(); - resolve_write_concern_with_session!(self, options, session.as_ref())?; - - #[cfg(feature = "in-use-encryption-unstable")] - let encrypted = self.client().auto_encryption_opts().await.is_some(); - #[cfg(not(feature = "in-use-encryption-unstable"))] - let encrypted = false; - - let insert = Insert::new( - self.namespace(), - vec![doc], - options.map(InsertManyOptions::from_insert_one_options), - encrypted, - self.inner.human_readable_serialization, - ); - self.client() - .execute_operation(insert, session) - .await - .map(InsertOneResult::from_insert_many_result) - .map_err(convert_bulk_errors) - } - - /// Inserts `doc` into the collection. - /// - /// Note that either an owned or borrowed value can be inserted here, so the input document - /// does not need to be cloned to be passed in. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn insert_one( - &self, - doc: impl Borrow, - options: impl Into>, - ) -> Result { - self.insert_one_common(doc.borrow(), options, None).await - } - - /// Inserts `doc` into the collection using the provided `ClientSession`. - /// - /// Note that either an owned or borrowed value can be inserted here, so the input document - /// does not need to be cloned to be passed in. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn insert_one_with_session( - &self, - doc: impl Borrow, - options: impl Into>, - session: &mut ClientSession, - ) -> Result { - self.insert_one_common(doc.borrow(), options, session).await - } - - async fn replace_one_common( - &self, - query: Document, - replacement: impl Borrow, - options: impl Into>, - session: impl Into>, - ) -> Result { - let mut options = options.into(); - - let session = session.into(); - - resolve_write_concern_with_session!(self, options, session.as_ref())?; - - let update = Update::with_replace( - self.namespace(), - query, - replacement.borrow(), - false, - options.map(UpdateOptions::from_replace_options), - self.inner.human_readable_serialization, - ); - self.client().execute_operation(update, session).await - } - - /// Replaces up to one document matching `query` in the collection with `replacement`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn replace_one( - &self, - query: Document, - replacement: impl Borrow, - options: impl Into>, - ) -> Result { - self.replace_one_common(query, replacement, options, None) - .await - } - - /// Replaces up to one document matching `query` in the collection with `replacement` using the - /// provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub async fn replace_one_with_session( - &self, - query: Document, - replacement: impl Borrow, - options: impl Into>, - session: &mut ClientSession, - ) -> Result { - self.replace_one_common(query, replacement, options, session) - .await - } -} - /// A struct modeling the canonical name for a collection in MongoDB. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Namespace { diff --git a/src/coll/options.rs b/src/coll/options.rs index 9ec535dda..1f10bd7af 100644 --- a/src/coll/options.rs +++ b/src/coll/options.rs @@ -61,6 +61,15 @@ pub enum ReturnDocument { Before, } +impl ReturnDocument { + pub(crate) fn as_bool(&self) -> bool { + match self { + ReturnDocument::After => true, + ReturnDocument::Before => false, + } + } +} + impl<'de> Deserialize<'de> for ReturnDocument { fn deserialize>(deserializer: D) -> std::result::Result { let s = String::deserialize(deserializer)?; diff --git a/src/concern/test.rs b/src/concern/test.rs index bbad87f9e..d14a7bb1a 100644 --- a/src/concern/test.rs +++ b/src/concern/test.rs @@ -3,19 +3,7 @@ use std::time::Duration; use crate::{ bson::{doc, Bson, Document}, error::ErrorKind, - options::{ - Acknowledgment, - FindOneAndDeleteOptions, - FindOneAndReplaceOptions, - FindOneAndUpdateOptions, - FindOneOptions, - InsertManyOptions, - InsertOneOptions, - ReadConcern, - ReplaceOptions, - TransactionOptions, - WriteConcern, - }, + options::{Acknowledgment, ReadConcern, TransactionOptions, WriteConcern}, test::{EventClient, TestClient}, Collection, }; @@ -112,9 +100,9 @@ async fn inconsistent_write_concern_rejected() { journal: true.into(), w_timeout: None, }; - let options = InsertOneOptions::builder().write_concern(wc).build(); let error = coll - .insert_one(doc! {}, options) + .insert_one(doc! {}) + .write_concern(wc) .await .expect_err("insert should fail"); assert!(matches!(*error.kind, ErrorKind::InvalidArgument { .. })); @@ -131,9 +119,9 @@ async fn unacknowledged_write_concern_rejected() { journal: false.into(), w_timeout: None, }; - let options = InsertOneOptions::builder().write_concern(wc).build(); let error = coll - .insert_one(doc! {}, options) + .insert_one(doc! {}) + .write_concern(wc) .await .expect_err("insert should fail"); assert!(matches!(*error.kind, ErrorKind::InvalidArgument { .. })); @@ -158,17 +146,15 @@ async fn snapshot_read_concern() { .read_concern(ReadConcern::snapshot()) .build(); session.start_transaction(options).await.unwrap(); - let result = coll.find_one_with_session(None, None, &mut session).await; + let result = coll.find_one(doc! {}).session(&mut session).await; assert!(result.is_ok()); assert_event_contains_read_concern(&client).await; } if client.server_version_lt(4, 9) { - let options = FindOneOptions::builder() - .read_concern(ReadConcern::snapshot()) - .build(); let error = coll - .find_one(None, options) + .find_one(doc! {}) + .read_concern(ReadConcern::snapshot()) .await .expect_err("non-transaction find one with snapshot read concern should fail"); // ensure that an error from the server is returned @@ -201,32 +187,24 @@ async fn command_contains_write_concern_insert_one() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_one( - doc! { "foo": "bar" }, - InsertOneOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(true) - .build(), - ) - .build(), - ) - .await - .unwrap(); - coll.insert_one( - doc! { "foo": "bar" }, - InsertOneOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(false) - .build(), - ) - .build(), - ) - .await - .unwrap(); + coll.insert_one(doc! { "foo": "bar" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(true) + .build(), + ) + .await + .unwrap(); + coll.insert_one(doc! { "foo": "bar" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(false) + .build(), + ) + .await + .unwrap(); assert_eq!( command_write_concerns(&client, "insert"), @@ -250,32 +228,24 @@ async fn command_contains_write_concern_insert_many() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many( - &[doc! { "foo": "bar" }], - InsertManyOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(true) - .build(), - ) - .build(), - ) - .await - .unwrap(); - coll.insert_many( - &[doc! { "foo": "bar" }], - InsertManyOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(false) - .build(), - ) - .build(), - ) - .await - .unwrap(); + coll.insert_many(&[doc! { "foo": "bar" }]) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(true) + .build(), + ) + .await + .unwrap(); + coll.insert_many(&[doc! { "foo": "bar" }]) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(false) + .build(), + ) + .await + .unwrap(); assert_eq!( command_write_concerns(&client, "insert"), @@ -299,7 +269,7 @@ async fn command_contains_write_concern_update_one() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_one(doc! { "foo": "bar" }, None).await.unwrap(); + coll.insert_one(doc! { "foo": "bar" }).await.unwrap(); coll.update_one(doc! { "foo": "bar" }, doc! { "$set": { "foo": "baz" } }) .write_concern( WriteConcern::builder() @@ -341,7 +311,7 @@ async fn command_contains_write_concern_update_many() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) .await .unwrap(); coll.update_many(doc! { "foo": "bar" }, doc! { "$set": { "foo": "baz" } }) @@ -385,35 +355,25 @@ async fn command_contains_write_concern_replace_one() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_one(doc! { "foo": "bar" }, None).await.unwrap(); - coll.replace_one( - doc! { "foo": "bar" }, - doc! { "baz": "fun" }, - ReplaceOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(true) - .build(), - ) - .build(), - ) - .await - .unwrap(); - coll.replace_one( - doc! { "foo": "bar" }, - doc! { "baz": "fun" }, - ReplaceOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(false) - .build(), - ) - .build(), - ) - .await - .unwrap(); + coll.insert_one(doc! { "foo": "bar" }).await.unwrap(); + coll.replace_one(doc! { "foo": "bar" }, doc! { "baz": "fun" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(true) + .build(), + ) + .await + .unwrap(); + coll.replace_one(doc! { "foo": "bar" }, doc! { "baz": "fun" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(false) + .build(), + ) + .await + .unwrap(); assert_eq!( command_write_concerns(&client, "update"), @@ -437,7 +397,7 @@ async fn command_contains_write_concern_delete_one() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) .await .unwrap(); coll.delete_one(doc! { "foo": "bar" }) @@ -481,7 +441,7 @@ async fn command_contains_write_concern_delete_many() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) .await .unwrap(); coll.delete_many(doc! { "foo": "bar" }) @@ -493,7 +453,7 @@ async fn command_contains_write_concern_delete_many() { ) .await .unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) .await .unwrap(); coll.delete_many(doc! { "foo": "bar" }) @@ -528,35 +488,27 @@ async fn command_contains_write_concern_find_one_and_delete() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) - .await - .unwrap(); - coll.find_one_and_delete( - doc! { "foo": "bar" }, - FindOneAndDeleteOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(true) - .build(), - ) - .build(), - ) - .await - .unwrap(); - coll.find_one_and_delete( - doc! { "foo": "bar" }, - FindOneAndDeleteOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(false) - .build(), - ) - .build(), - ) - .await - .unwrap(); + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) + .await + .unwrap(); + coll.find_one_and_delete(doc! { "foo": "bar" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(true) + .build(), + ) + .await + .unwrap(); + coll.find_one_and_delete(doc! { "foo": "bar" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(false) + .build(), + ) + .await + .unwrap(); assert_eq!( command_write_concerns(&client, "findAndModify"), @@ -580,37 +532,27 @@ async fn command_contains_write_concern_find_one_and_replace() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) - .await - .unwrap(); - coll.find_one_and_replace( - doc! { "foo": "bar" }, - doc! { "baz": "fun" }, - FindOneAndReplaceOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(true) - .build(), - ) - .build(), - ) - .await - .unwrap(); - coll.find_one_and_replace( - doc! { "foo": "bar" }, - doc! { "baz": "fun" }, - FindOneAndReplaceOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(false) - .build(), - ) - .build(), - ) - .await - .unwrap(); + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) + .await + .unwrap(); + coll.find_one_and_replace(doc! { "foo": "bar" }, doc! { "baz": "fun" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(true) + .build(), + ) + .await + .unwrap(); + coll.find_one_and_replace(doc! { "foo": "bar" }, doc! { "baz": "fun" }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(false) + .build(), + ) + .await + .unwrap(); assert_eq!( command_write_concerns(&client, "findAndModify"), @@ -634,37 +576,27 @@ async fn command_contains_write_concern_find_one_and_update() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }], None) - .await - .unwrap(); - coll.find_one_and_update( - doc! { "foo": "bar" }, - doc! { "$set": { "foo": "fun" } }, - FindOneAndUpdateOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(true) - .build(), - ) - .build(), - ) - .await - .unwrap(); - coll.find_one_and_update( - doc! { "foo": "bar" }, - doc! { "$set": { "foo": "fun" } }, - FindOneAndUpdateOptions::builder() - .write_concern( - WriteConcern::builder() - .w(Acknowledgment::Nodes(1)) - .journal(false) - .build(), - ) - .build(), - ) - .await - .unwrap(); + coll.insert_many(&[doc! { "foo": "bar" }, doc! { "foo": "bar" }]) + .await + .unwrap(); + coll.find_one_and_update(doc! { "foo": "bar" }, doc! { "$set": { "foo": "fun" } }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(true) + .build(), + ) + .await + .unwrap(); + coll.find_one_and_update(doc! { "foo": "bar" }, doc! { "$set": { "foo": "fun" } }) + .write_concern( + WriteConcern::builder() + .w(Acknowledgment::Nodes(1)) + .journal(false) + .build(), + ) + .await + .unwrap(); assert_eq!( command_write_concerns(&client, "findAndModify"), @@ -688,7 +620,7 @@ async fn command_contains_write_concern_aggregate() { let coll: Collection = client.database("test").collection(function_name!()); coll.drop().await.unwrap(); - coll.insert_one(doc! { "foo": "bar" }, None).await.unwrap(); + coll.insert_one(doc! { "foo": "bar" }).await.unwrap(); coll.aggregate(vec![ doc! { "$match": { "foo": "bar" } }, doc! { "$addFields": { "foo": "baz" } }, @@ -739,7 +671,7 @@ async fn command_contains_write_concern_drop() { coll.drop().await.unwrap(); client.clear_cached_events(); - coll.insert_one(doc! { "foo": "bar" }, None).await.unwrap(); + coll.insert_one(doc! { "foo": "bar" }).await.unwrap(); coll.drop() .write_concern( WriteConcern::builder() @@ -749,7 +681,7 @@ async fn command_contains_write_concern_drop() { ) .await .unwrap(); - coll.insert_one(doc! { "foo": "bar" }, None).await.unwrap(); + coll.insert_one(doc! { "foo": "bar" }).await.unwrap(); coll.drop() .write_concern( WriteConcern::builder() diff --git a/src/cursor.rs b/src/cursor.rs index 8dae51d2d..d22474441 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -67,7 +67,7 @@ pub(crate) use common::{ /// used in conjunction with the `?` operator. /// /// ```rust -/// # use mongodb::{bson::Document, Client, error::Result}; +/// # use mongodb::{bson::{Document, doc}, Client, error::Result}; /// # /// # async fn do_stuff() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://example.com").await?; @@ -75,7 +75,7 @@ pub(crate) use common::{ /// # /// use futures::stream::{StreamExt, TryStreamExt}; /// -/// let mut cursor = coll.find(None, None).await?; +/// let mut cursor = coll.find(doc! {}).await?; /// // regular Stream uses next() and iterates over Option> /// while let Some(doc) = cursor.next().await { /// println!("{}", doc?) @@ -83,7 +83,7 @@ pub(crate) use common::{ /// // regular Stream uses collect() and collects into a Vec> /// let v: Vec> = cursor.collect().await; /// -/// let mut cursor = coll.find(None, None).await?; +/// let mut cursor = coll.find(doc! {}).await?; /// // TryStream uses try_next() and iterates over Result> /// while let Some(doc) = cursor.try_next().await? { /// println!("{}", doc) @@ -190,11 +190,11 @@ impl Cursor { /// calling [`Cursor::advance`] first or after [`Cursor::advance`] returns an error / false. /// /// ``` - /// # use mongodb::{Client, bson::Document, error::Result}; + /// # use mongodb::{Client, bson::{Document, doc}, error::Result}; /// # async fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017").await?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find(None, None).await?; + /// let mut cursor = coll.find(doc! {}).await?; /// while cursor.advance().await? { /// println!("{:?}", cursor.current()); /// } @@ -223,11 +223,11 @@ impl Cursor { /// or without calling [`Cursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{Client, bson::Document, error::Result}; + /// # use mongodb::{Client, bson::{Document, doc}, error::Result}; /// # async fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017").await?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find(None, None).await?; + /// let mut cursor = coll.find(doc! {}).await?; /// while cursor.advance().await? { /// println!("{:?}", cursor.current()); /// } @@ -246,7 +246,7 @@ impl Cursor { /// true or without calling [`Cursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{Client, error::Result}; + /// # use mongodb::{Client, error::Result, bson::doc}; /// # async fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017").await?; /// # let db = client.database("foo"); @@ -259,7 +259,7 @@ impl Cursor { /// } /// /// let coll = db.collection::("cat"); - /// let mut cursor = coll.find(None, None).await?; + /// let mut cursor = coll.find(doc! {}).await?; /// while cursor.advance().await? { /// println!("{:?}", cursor.deserialize_current()?); /// } diff --git a/src/cursor/session.rs b/src/cursor/session.rs index 39faa7a3f..6f460ac63 100644 --- a/src/cursor/session.rs +++ b/src/cursor/session.rs @@ -40,7 +40,7 @@ use crate::{ /// [`SessionCursor::stream`]: /// /// ```rust -/// # use mongodb::{bson::Document, Client, error::Result, ClientSession, SessionCursor}; +/// # use mongodb::{bson::{Document, doc}, Client, error::Result, ClientSession, SessionCursor}; /// # /// # async fn do_stuff() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://example.com").await?; @@ -48,7 +48,7 @@ use crate::{ /// # let coll = client.database("foo").collection::("bar"); /// # /// // iterate using next() -/// let mut cursor = coll.find_with_session(None, None, &mut session).await?; +/// let mut cursor = coll.find(doc! {}).session(&mut session).await?; /// while let Some(doc) = cursor.next(&mut session).await.transpose()? { /// println!("{}", doc) /// } @@ -56,7 +56,7 @@ use crate::{ /// // iterate using `Stream`: /// use futures::stream::TryStreamExt; /// -/// let mut cursor = coll.find_with_session(None, None, &mut session).await?; +/// let mut cursor = coll.find(doc! {}).session(&mut session).await?; /// let results: Vec<_> = cursor.stream(&mut session).try_collect().await?; /// # /// # Ok(()) @@ -129,23 +129,23 @@ where /// use futures::stream::TryStreamExt; /// /// // iterate over the results - /// let mut cursor = coll.find_with_session(doc! { "x": 1 }, None, &mut session).await?; + /// let mut cursor = coll.find(doc! { "x": 1 }).session(&mut session).await?; /// while let Some(doc) = cursor.stream(&mut session).try_next().await? { /// println!("{}", doc); /// } /// /// // collect the results - /// let mut cursor1 = coll.find_with_session(doc! { "x": 1 }, None, &mut session).await?; + /// let mut cursor1 = coll.find(doc! { "x": 1 }).session(&mut session).await?; /// let v: Vec = cursor1.stream(&mut session).try_collect().await?; /// /// // use session between iterations - /// let mut cursor2 = coll.find_with_session(doc! { "x": 1 }, None, &mut session).await?; + /// let mut cursor2 = coll.find(doc! { "x": 1 }).session(&mut session).await?; /// loop { /// let doc = match cursor2.stream(&mut session).try_next().await? { /// Some(d) => d, /// None => break, /// }; - /// other_coll.insert_one_with_session(doc, None, &mut session).await?; + /// other_coll.insert_one(doc).session(&mut session).await?; /// } /// # Ok::<(), mongodb::error::Error>(()) /// # }; @@ -173,9 +173,9 @@ where /// # let coll = client.database("foo").collection::("bar"); /// # let other_coll = coll.clone(); /// # let mut session = client.start_session().await?; - /// let mut cursor = coll.find_with_session(doc! { "x": 1 }, None, &mut session).await?; + /// let mut cursor = coll.find(doc! { "x": 1 }).session(&mut session).await?; /// while let Some(doc) = cursor.next(&mut session).await.transpose()? { - /// other_coll.insert_one_with_session(doc, None, &mut session).await?; + /// other_coll.insert_one(doc).session(&mut session).await?; /// } /// # Ok::<(), mongodb::error::Error>(()) /// # }; @@ -223,12 +223,12 @@ impl SessionCursor { /// [`SessionCursor::advance`] returns an error / false. /// /// ``` - /// # use mongodb::{Client, bson::Document, error::Result}; + /// # use mongodb::{Client, bson::{doc, Document}, error::Result}; /// # async fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017").await?; /// # let mut session = client.start_session().await?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find_with_session(None, None, &mut session).await?; + /// let mut cursor = coll.find(doc! {}).session(&mut session).await?; /// while cursor.advance(&mut session).await? { /// println!("{:?}", cursor.current()); /// } @@ -256,12 +256,12 @@ impl SessionCursor { /// true or without calling [`SessionCursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{Client, bson::Document, error::Result}; + /// # use mongodb::{Client, bson::{Document, doc}, error::Result}; /// # async fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017").await?; /// # let mut session = client.start_session().await?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find_with_session(None, None, &mut session).await?; + /// let mut cursor = coll.find(doc! {}).session(&mut session).await?; /// while cursor.advance(&mut session).await? { /// println!("{:?}", cursor.current()); /// } @@ -281,7 +281,7 @@ impl SessionCursor { /// true or without calling [`SessionCursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{Client, error::Result}; + /// # use mongodb::{Client, error::Result, bson::doc}; /// # async fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017").await?; /// # let mut session = client.start_session().await?; @@ -295,7 +295,7 @@ impl SessionCursor { /// } /// /// let coll = db.collection::("cat"); - /// let mut cursor = coll.find_with_session(None, None, &mut session).await?; + /// let mut cursor = coll.find(doc! {}).session(&mut session).await?; /// while cursor.advance(&mut session).await? { /// println!("{:?}", cursor.deserialize_current()?); /// } diff --git a/src/gridfs.rs b/src/gridfs.rs index 9c45d886f..34ecce928 100644 --- a/src/gridfs.rs +++ b/src/gridfs.rs @@ -234,7 +234,7 @@ impl GridFsBucket { options: impl Into>, ) -> Result> { let find_options = options.into().map(FindOptions::from); - self.files().find(filter, find_options).await + self.files().find(filter).with_options(find_options).await } /// Finds and returns a single [`FilesCollectionDocument`] within this bucket that matches the @@ -245,7 +245,10 @@ impl GridFsBucket { options: impl Into>, ) -> Result> { let find_options = options.into().map(FindOneOptions::from); - self.files().find_one(filter, find_options).await + self.files() + .find_one(filter) + .with_options(find_options) + .await } /// Renames the file with the given 'id' to the provided `new_filename`. This method returns an diff --git a/src/gridfs/download.rs b/src/gridfs/download.rs index ef23228f6..2cbfd2c2a 100644 --- a/src/gridfs/download.rs +++ b/src/gridfs/download.rs @@ -14,7 +14,6 @@ use super::{options::GridFsDownloadByNameOptions, Chunk, FilesCollectionDocument use crate::{ bson::{doc, Bson}, error::{ErrorKind, GridFsErrorKind, GridFsFileIdentifier, Result}, - options::{FindOneOptions, FindOptions}, Collection, Cursor, }; @@ -42,21 +41,19 @@ impl GridFsBucket { } else { (-1, -revision - 1) }; - let options = FindOneOptions::builder() - .sort(doc! { "uploadDate": sort }) - .skip(skip as u64) - .build(); match self .files() - .find_one(doc! { "filename": filename }, options) + .find_one(doc! { "filename": filename }) + .sort(doc! { "uploadDate": sort }) + .skip(skip as u64) .await? { Some(fcd) => Ok(fcd), None => { if self .files() - .find_one(doc! { "filename": filename }, None) + .find_one(doc! { "filename": filename }) .await? .is_some() { @@ -161,10 +158,10 @@ impl GridFsBucket { return Ok(()); } - let options = FindOptions::builder().sort(doc! { "n": 1 }).build(); let mut cursor = self .chunks() - .find(doc! { "files_id": &file.id }, options) + .find(doc! { "files_id": &file.id }) + .sort(doc! { "n": 1 }) .await?; let mut n = 0; @@ -272,8 +269,10 @@ impl GridFsDownloadStream { let initial_state = if file.length == 0 { State::Done } else { - let options = FindOptions::builder().sort(doc! { "n": 1 }).build(); - let cursor = chunks.find(doc! { "files_id": &file.id }, options).await?; + let cursor = chunks + .find(doc! { "files_id": &file.id }) + .sort(doc! { "n": 1 }) + .await?; State::Idle(Some(Idle { buffer: Vec::new(), cursor: Box::new(cursor), diff --git a/src/gridfs/upload.rs b/src/gridfs/upload.rs index 8cceaec8c..2b978f671 100644 --- a/src/gridfs/upload.rs +++ b/src/gridfs/upload.rs @@ -19,7 +19,7 @@ use crate::{ client::AsyncDropToken, error::{Error, ErrorKind, GridFsErrorKind, Result}, index::IndexModel, - options::{FindOneOptions, ReadPreference, SelectionCriteria}, + options::{ReadPreference, SelectionCriteria}, Collection, }; @@ -132,7 +132,7 @@ impl GridFsBucket { bytes: &buf[..bytes_read], }, }; - self.chunks().insert_one(chunk, None).await?; + self.chunks().insert_one(chunk).await?; length += bytes_read as u64; n += 1; @@ -146,21 +146,19 @@ impl GridFsBucket { filename: Some(filename.as_ref().to_string()), metadata: options.and_then(|opts| opts.metadata), }; - self.files().insert_one(file, None).await?; + self.files().insert_one(file).await?; Ok(()) } async fn create_indexes(&self) -> Result<()> { if !self.inner.created_indexes.load(Ordering::SeqCst) { - let find_options = FindOneOptions::builder() - .selection_criteria(SelectionCriteria::ReadPreference(ReadPreference::Primary)) - .projection(doc! { "_id": 1 }) - .build(); if self .files() .clone_with_type::() - .find_one(None, find_options) + .find_one(doc! {}) + .selection_criteria(SelectionCriteria::ReadPreference(ReadPreference::Primary)) + .projection(doc! { "_id": 1 }) .await? .is_none() { @@ -532,7 +530,7 @@ async fn write_bytes( chunks.push(chunk); } - match bucket.chunks().insert_many(chunks, None).await { + match bucket.chunks().insert_many(chunks).await { Ok(_) => { buffer.drain(..(n * chunk_size_bytes).get()?); Ok((n.try_into()?, buffer)) @@ -559,9 +557,9 @@ async fn close(bucket: GridFsBucket, buffer: Vec, file: FilesCollectionDocum bytes: &buffer[..], }, }; - bucket.chunks().insert_one(final_chunk, None).await?; + bucket.chunks().insert_one(final_chunk).await?; } - bucket.files().insert_one(&file, None).await?; + bucket.files().insert_one(&file).await?; Ok(()) } .await; diff --git a/src/lib.rs b/src/lib.rs index cad30f697..123c45cf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,7 @@ //! ]; //! //! // Insert some documents into the "mydb.books" collection. -//! collection.insert_many(docs, None).await?; +//! collection.insert_many(docs).await?; //! # Ok(()) } //! ``` //! @@ -137,7 +137,7 @@ //! ]; //! //! // Insert the books into "mydb.books" collection, no manual conversion to BSON necessary. -//! typed_collection.insert_many(books, None).await?; +//! typed_collection.insert_many(books).await?; //! # Ok(()) } //! ``` //! @@ -166,8 +166,10 @@ //! //! // Query the books in the collection with a filter and an option. //! let filter = doc! { "author": "George Orwell" }; -//! let find_options = FindOptions::builder().sort(doc! { "title": 1 }).build(); -//! let mut cursor = typed_collection.find(filter, find_options).await?; +//! let mut cursor = typed_collection +//! .find(filter) +//! .sort(doc! { "title": 1 }) +//! .await?; //! //! // Iterate over the results of the cursor. //! while let Some(book) = cursor.try_next().await? { @@ -218,9 +220,9 @@ //! ]; //! //! // Insert some books into the "mydb.books" collection. -//! collection.insert_many(docs, None)?; +//! collection.insert_many(docs).run()?; //! -//! let cursor = collection.find(doc! { "author": "George Orwell" }, None)?; +//! let cursor = collection.find(doc! { "author": "George Orwell" }).run()?; //! for result in cursor { //! println!("title: {}", result?.title); //! } @@ -256,7 +258,7 @@ //! # let client = Client::with_uri_str("mongodb://example.com").await?; //! let collection = client.database("foo").collection("bar"); //! let handle = tokio::task::spawn(async move { -//! collection.insert_one(doc! { "x": 1 }, None).await +//! collection.insert_one(doc! { "x": 1 }).await //! }); //! //! tokio::time::timeout(Duration::from_secs(5), handle).await???; diff --git a/src/operation.rs b/src/operation.rs index 829958345..3cf389bf4 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -11,7 +11,7 @@ pub(crate) mod drop_collection; pub(crate) mod drop_database; mod drop_indexes; mod find; -mod find_and_modify; +pub(crate) mod find_and_modify; mod get_more; mod insert; pub(crate) mod list_collections; diff --git a/src/operation/find.rs b/src/operation/find.rs index 947fc23cc..fb0434461 100644 --- a/src/operation/find.rs +++ b/src/operation/find.rs @@ -1,6 +1,3 @@ -#[cfg(test)] -mod test; - use crate::{ bson::{doc, Document}, cmap::{Command, RawCommandResponse, StreamDescription}, @@ -20,28 +17,12 @@ use crate::{ #[derive(Debug)] pub(crate) struct Find { ns: Namespace, - filter: Option, + filter: Document, options: Option>, } impl Find { - #[cfg(test)] - fn empty() -> Self { - Self::new( - Namespace { - db: String::new(), - coll: String::new(), - }, - None, - None, - ) - } - - pub(crate) fn new( - ns: Namespace, - filter: Option, - mut options: Option, - ) -> Self { + pub(crate) fn new(ns: Namespace, filter: Document, mut options: Option) -> Self { if let Some(ref mut options) = options { if let Some(ref comment) = options.comment { if options.comment_bson.is_none() { @@ -99,9 +80,7 @@ impl OperationWithDefaults for Find { append_options(&mut body, self.options.as_ref())?; - if let Some(ref filter) = self.filter { - body.insert("filter", filter.clone()); - } + body.insert("filter", self.filter.clone()); Ok(Command::new_read( Self::NAME.to_string(), diff --git a/src/operation/find/test.rs b/src/operation/find/test.rs deleted file mode 100644 index 57bb6dd28..000000000 --- a/src/operation/find/test.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::time::Duration; - -use crate::{ - bson::doc, - operation::{ - test::{self, handle_response_test}, - Find, - }, - options::{CursorType, FindOptions}, - Namespace, -}; - -#[test] -fn op_selection_criteria() { - test::op_selection_criteria(|selection_criteria| { - let options = FindOptions { - selection_criteria, - ..Default::default() - }; - Find::new(Namespace::empty(), None, Some(options)) - }); -} - -fn verify_max_await_time(max_await_time: Option, cursor_type: Option) { - let ns = Namespace::empty(); - let find = Find::new( - ns, - None, - Some(FindOptions { - cursor_type, - max_await_time, - ..Default::default() - }), - ); - - let spec = handle_response_test( - &find, - doc! { - "cursor": { - "id": 123, - "ns": "a.b", - "firstBatch": [], - }, - "ok": 1 - }, - ) - .unwrap(); - assert_eq!(spec.max_time(), max_await_time); -} - -#[test] -fn handle_max_await_time() { - verify_max_await_time(None, None); - verify_max_await_time(Some(Duration::from_millis(5)), None); - verify_max_await_time( - Some(Duration::from_millis(5)), - Some(CursorType::NonTailable), - ); - verify_max_await_time(Some(Duration::from_millis(5)), Some(CursorType::Tailable)); - verify_max_await_time( - Some(Duration::from_millis(5)), - Some(CursorType::TailableAwait), - ); -} - -#[test] -fn handle_invalid_response() { - let find = Find::empty(); - - let garbled = doc! { "asdfasf": "ASdfasdf" }; - handle_response_test(&find, garbled).unwrap_err(); - - let missing_cursor_field = doc! { - "cursor": { - "ns": "test.test", - "firstBatch": [], - } - }; - handle_response_test(&find, missing_cursor_field).unwrap_err(); -} diff --git a/src/operation/find_and_modify.rs b/src/operation/find_and_modify.rs index 04e6a538d..45c029e0b 100644 --- a/src/operation/find_and_modify.rs +++ b/src/operation/find_and_modify.rs @@ -1,24 +1,16 @@ -mod options; +pub(crate) mod options; -use std::fmt::Debug; +use std::{fmt::Debug, marker::PhantomData}; use bson::{from_slice, RawBson}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize}; use self::options::FindAndModifyOptions; use crate::{ bson::{doc, rawdoc, Document, RawDocumentBuf}, bson_util, cmap::{Command, RawCommandResponse, StreamDescription}, - coll::{ - options::{ - FindOneAndDeleteOptions, - FindOneAndReplaceOptions, - FindOneAndUpdateOptions, - UpdateModifications, - }, - Namespace, - }, + coll::{options::UpdateModifications, Namespace}, error::{ErrorKind, Result}, operation::{ append_options_to_raw_document, @@ -30,71 +22,40 @@ use crate::{ options::WriteConcern, }; -pub(crate) struct FindAndModify<'a, R, T: DeserializeOwned> { +use super::UpdateOrReplace; + +pub(crate) struct FindAndModify { ns: Namespace, query: Document, - modification: Modification<'a, R>, - human_readable_serialization: Option, + modification: Modification, options: Option, - _phantom: std::marker::PhantomData, + _phantom: PhantomData T>, } -impl FindAndModify<'_, (), T> { - pub fn with_delete( +impl FindAndModify { + pub(crate) fn with_modification( ns: Namespace, query: Document, - options: Option, - ) -> Self { - FindAndModify { - ns, - query, - modification: Modification::Delete, - human_readable_serialization: None, - options: options.map(Into::into), - _phantom: Default::default(), - } - } - - pub fn with_update( - ns: Namespace, - query: Document, - update: UpdateModifications, - options: Option, + modification: Modification, + options: Option, ) -> Result { - if let UpdateModifications::Document(ref d) = update { + if let Modification::Update(UpdateOrReplace::UpdateModifications( + UpdateModifications::Document(d), + )) = &modification + { bson_util::update_document_check(d)?; }; - Ok(FindAndModify { + Ok(Self { ns, query, - modification: Modification::Update(update.into()), - human_readable_serialization: None, - options: options.map(Into::into), - _phantom: Default::default(), + modification, + options, + _phantom: PhantomData, }) } } -impl<'a, R: Serialize, T: DeserializeOwned> FindAndModify<'a, R, T> { - pub fn with_replace( - ns: Namespace, - query: Document, - replacement: &'a R, - options: Option, - human_readable_serialization: bool, - ) -> Result { - Ok(FindAndModify { - ns, - query, - modification: Modification::Update(replacement.into()), - human_readable_serialization: Some(human_readable_serialization), - options: options.map(Into::into), - _phantom: Default::default(), - }) - } -} - -impl<'a, R: Serialize, T: DeserializeOwned> OperationWithDefaults for FindAndModify<'a, R, T> { +impl OperationWithDefaults for FindAndModify { type O = Option; type Command = RawDocumentBuf; const NAME: &'static str = "findAndModify"; @@ -116,15 +77,12 @@ impl<'a, R: Serialize, T: DeserializeOwned> OperationWithDefaults for FindAndMod "query": RawDocumentBuf::from_document(&self.query)?, }; - let (key, modification) = match &self.modification { - Modification::Delete => ("remove", true.into()), - Modification::Update(update_or_replace) => ( - "update", - update_or_replace - .to_raw_bson(self.human_readable_serialization.unwrap_or_default())?, - ), - }; - body.append(key, modification); + match &self.modification { + Modification::Delete => body.append("remove", true), + Modification::Update(update_or_replace) => { + update_or_replace.append_to_rawdoc(&mut body, "update")? + } + } if let Some(ref mut options) = self.options { remove_empty_write_concern!(Some(options)); diff --git a/src/operation/find_and_modify/options.rs b/src/operation/find_and_modify/options.rs index fcdb90af0..5147c3ba5 100644 --- a/src/operation/find_and_modify/options.rs +++ b/src/operation/find_and_modify/options.rs @@ -19,16 +19,16 @@ use crate::{ }; #[derive(Clone, Debug)] -pub(super) enum Modification<'a, T> { +pub(crate) enum Modification { Delete, - Update(UpdateOrReplace<'a, T>), + Update(UpdateOrReplace), } #[serde_with::skip_serializing_none] -#[derive(Clone, Debug, TypedBuilder, Serialize)] +#[derive(Clone, Debug, TypedBuilder, Serialize, Default)] #[builder(field_defaults(setter(into)))] #[serde(rename_all = "camelCase")] -pub(super) struct FindAndModifyOptions { +pub(crate) struct FindAndModifyOptions { #[builder(default)] pub(crate) sort: Option, @@ -130,11 +130,5 @@ impl From for FindAndModifyOptions { } fn return_document_to_bool(return_document: Option) -> Option { - if let Some(return_document) = return_document { - return match return_document { - ReturnDocument::After => Some(true), - ReturnDocument::Before => Some(false), - }; - } - None + return_document.as_ref().map(ReturnDocument::as_bool) } diff --git a/src/operation/insert.rs b/src/operation/insert.rs index 8ace66155..e2b7ca282 100644 --- a/src/operation/insert.rs +++ b/src/operation/insert.rs @@ -1,10 +1,6 @@ -#[cfg(test)] -mod test; - use std::{collections::HashMap, convert::TryInto}; -use bson::{oid::ObjectId, Bson, RawArrayBuf, RawDocumentBuf}; -use serde::Serialize; +use bson::{oid::ObjectId, Bson, RawArrayBuf, RawDocument, RawDocumentBuf}; use crate::{ bson::rawdoc, @@ -15,29 +11,26 @@ use crate::{ operation::{OperationWithDefaults, Retryability, WriteResponseBody}, options::{InsertManyOptions, WriteConcern}, results::InsertManyResult, - serde_util, Namespace, }; use super::{COMMAND_OVERHEAD_SIZE, MAX_ENCRYPTED_WRITE_SIZE}; #[derive(Debug)] -pub(crate) struct Insert<'a, T> { +pub(crate) struct Insert<'a> { ns: Namespace, - documents: Vec<&'a T>, + documents: Vec<&'a RawDocument>, inserted_ids: Vec, options: InsertManyOptions, encrypted: bool, - human_readable_serialization: bool, } -impl<'a, T> Insert<'a, T> { +impl<'a> Insert<'a> { pub(crate) fn new( ns: Namespace, - documents: Vec<&'a T>, + documents: Vec<&'a RawDocument>, options: Option, encrypted: bool, - human_readable_serialization: bool, ) -> Self { let mut options = options.unwrap_or_default(); if options.ordered.is_none() { @@ -50,12 +43,11 @@ impl<'a, T> Insert<'a, T> { documents, inserted_ids: vec![], encrypted, - human_readable_serialization, } } } -impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { +impl<'a> OperationWithDefaults for Insert<'a> { type O = InsertManyResult; type Command = RawDocumentBuf; @@ -69,14 +61,13 @@ impl<'a, T: Serialize> OperationWithDefaults for Insert<'a, T> { let max_doc_sequence_size = Checked::::try_from(description.max_message_size_bytes)? - COMMAND_OVERHEAD_SIZE; - for (i, d) in self + for (i, &d) in self .documents .iter() .take(Checked::new(description.max_write_batch_size).try_into()?) .enumerate() { - let mut doc = - serde_util::to_raw_document_buf_with_options(d, self.human_readable_serialization)?; + let mut doc = d.to_owned(); let id = match doc.get("_id")? { Some(b) => b.try_into()?, None => { diff --git a/src/operation/insert/test.rs b/src/operation/insert/test.rs deleted file mode 100644 index c8385338f..000000000 --- a/src/operation/insert/test.rs +++ /dev/null @@ -1,153 +0,0 @@ -use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; - -use crate::{ - bson::{doc, Document}, - cmap::StreamDescription, - concern::WriteConcern, - error::{BulkWriteError, ErrorKind, WriteConcernError}, - operation::{test::handle_response_test, Insert, Operation}, - options::InsertManyOptions, - Namespace, -}; - -struct TestFixtures { - op: Insert<'static, Document>, - documents: Vec, -} - -/// Get an Insert operation and the documents/options used to construct it. -fn fixtures(opts: Option) -> TestFixtures { - static DOCUMENTS: Lazy> = Lazy::new(|| { - vec![ - Document::new(), - doc! {"_id": 1234, "a": 1}, - doc! {"a": 123, "b": "hello world" }, - ] - }); - - let options = opts.unwrap_or(InsertManyOptions { - ordered: Some(true), - write_concern: Some(WriteConcern::builder().journal(true).build()), - ..Default::default() - }); - - let op = Insert::new( - Namespace { - db: "test_db".to_string(), - coll: "test_coll".to_string(), - }, - DOCUMENTS.iter().collect(), - Some(options.clone()), - false, - false, - ); - - TestFixtures { - op, - documents: DOCUMENTS.clone(), - } -} - -#[derive(Debug, Serialize, Deserialize)] -struct Documents { - documents: Vec, -} - -#[test] -fn handle_success() { - let mut fixtures = fixtures(None); - - // populate _id for documents that don't provide it - fixtures - .op - .build(&StreamDescription::new_testing()) - .unwrap(); - let response = handle_response_test(&fixtures.op, doc! { "ok": 1.0, "n": 3 }).unwrap(); - let inserted_ids = response.inserted_ids; - assert_eq!(inserted_ids.len(), 3); - assert_eq!( - inserted_ids.get(&1).unwrap(), - fixtures.documents[1].get("_id").unwrap() - ); -} - -#[test] -fn handle_invalid_response() { - let fixtures = fixtures(None); - handle_response_test(&fixtures.op, doc! { "ok": 1.0, "asdfadsf": 123123 }).unwrap_err(); -} - -#[test] -fn handle_write_failure() { - let mut fixtures = fixtures(None); - - // generate _id for operations missing it. - let _ = fixtures - .op - .build(&StreamDescription::new_testing()) - .unwrap(); - - let write_error_response = doc! { - "ok": 1.0, - "n": 1, - "writeErrors": [ - { - "index": 1, - "code": 11000, - "errmsg": "duplicate key", - "errInfo": { - "test key": "test value", - } - } - ], - "writeConcernError": { - "code": 123, - "codeName": "woohoo", - "errmsg": "error message", - "errInfo": { - "writeConcern": { - "w": 2, - "wtimeout": 0, - "provenance": "clientSupplied" - } - } - } - }; - - let write_error_response = - handle_response_test(&fixtures.op, write_error_response).unwrap_err(); - match *write_error_response.kind { - ErrorKind::BulkWrite(bwe) => { - let write_errors = bwe.write_errors.expect("write errors should be present"); - assert_eq!(write_errors.len(), 1); - let expected_err = BulkWriteError { - index: 1, - code: 11000, - code_name: None, - message: "duplicate key".to_string(), - details: Some(doc! { "test key": "test value" }), - }; - assert_eq!(write_errors.first().unwrap(), &expected_err); - - let write_concern_error = bwe - .write_concern_error - .expect("write concern error should be present"); - let expected_wc_err = WriteConcernError { - code: 123, - code_name: "woohoo".to_string(), - message: "error message".to_string(), - details: Some(doc! { "writeConcern": { - "w": 2, - "wtimeout": 0, - "provenance": "clientSupplied" - } }), - labels: vec![], - }; - assert_eq!(write_concern_error, expected_wc_err); - - assert_eq!(bwe.inserted_ids.len(), 1); - } - e => panic!("expected bulk write error, got {:?}", e), - }; -} diff --git a/src/operation/update.rs b/src/operation/update.rs index 3d5d34fa0..a09609c73 100644 --- a/src/operation/update.rs +++ b/src/operation/update.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod test; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use crate::{ bson::{doc, rawdoc, Document, RawArrayBuf, RawBson, RawDocumentBuf}, @@ -11,58 +11,54 @@ use crate::{ operation::{OperationWithDefaults, Retryability, WriteResponseBody}, options::{UpdateModifications, UpdateOptions, WriteConcern}, results::UpdateResult, - serde_util::to_raw_document_buf_with_options, Namespace, }; #[derive(Clone, Debug)] -pub(crate) enum UpdateOrReplace<'a, T = ()> { +pub(crate) enum UpdateOrReplace { UpdateModifications(UpdateModifications), - Replacement(&'a T), + Replacement(RawDocumentBuf), } -impl<'a, T: Serialize> UpdateOrReplace<'a, T> { - pub(crate) fn to_raw_bson(&self, human_readable_serialization: bool) -> Result { +impl UpdateOrReplace { + pub(crate) fn append_to_rawdoc(&self, doc: &mut RawDocumentBuf, key: &str) -> Result<()> { match self { Self::UpdateModifications(update_modifications) => match update_modifications { UpdateModifications::Document(document) => { - Ok(RawDocumentBuf::from_document(document)?.into()) + let raw = RawDocumentBuf::from_document(document)?; + doc.append(key, raw); + } + UpdateModifications::Pipeline(pipeline) => { + let raw = bson_util::to_raw_bson_array(pipeline)?; + doc.append(key, raw); } - UpdateModifications::Pipeline(pipeline) => bson_util::to_raw_bson_array(pipeline), }, - Self::Replacement(replacement) => { - let replacement_doc = - to_raw_document_buf_with_options(replacement, human_readable_serialization)?; - bson_util::replacement_raw_document_check(&replacement_doc)?; - Ok(replacement_doc.into()) + Self::Replacement(replacement_doc) => { + bson_util::replacement_raw_document_check(replacement_doc)?; + doc.append_ref(key, replacement_doc); } } + + Ok(()) } } -impl From for UpdateOrReplace<'_> { +impl From for UpdateOrReplace { fn from(update_modifications: UpdateModifications) -> Self { Self::UpdateModifications(update_modifications) } } -impl<'a, T: Serialize> From<&'a T> for UpdateOrReplace<'a, T> { - fn from(t: &'a T) -> Self { - Self::Replacement(t) - } -} - #[derive(Debug)] -pub(crate) struct Update<'a, T = ()> { +pub(crate) struct Update { ns: Namespace, filter: Document, - update: UpdateOrReplace<'a, T>, + update: UpdateOrReplace, multi: Option, options: Option, - human_readable_serialization: bool, } -impl Update<'_> { +impl Update { #[cfg(test)] fn empty() -> Self { Self::with_update( @@ -71,7 +67,6 @@ impl Update<'_> { UpdateModifications::Document(doc! {}), false, None, - false, ) } @@ -81,7 +76,6 @@ impl Update<'_> { update: UpdateModifications, multi: bool, options: Option, - human_readable_serialization: bool, ) -> Self { Self { ns, @@ -89,32 +83,27 @@ impl Update<'_> { update: update.into(), multi: multi.then_some(true), options, - human_readable_serialization, } } -} -impl<'a, T: Serialize> Update<'a, T> { - pub(crate) fn with_replace( + pub(crate) fn with_replace_raw( ns: Namespace, filter: Document, - update: &'a T, + update: RawDocumentBuf, multi: bool, options: Option, - human_readable_serialization: bool, - ) -> Self { - Self { + ) -> Result { + Ok(Self { ns, filter, - update: update.into(), + update: UpdateOrReplace::Replacement(update), multi: multi.then_some(true), options, - human_readable_serialization, - } + }) } } -impl<'a, T: Serialize> OperationWithDefaults for Update<'a, T> { +impl OperationWithDefaults for Update { type O = UpdateResult; type Command = RawDocumentBuf; @@ -127,8 +116,8 @@ impl<'a, T: Serialize> OperationWithDefaults for Update<'a, T> { let mut update = rawdoc! { "q": RawDocumentBuf::from_document(&self.filter)?, - "u": self.update.to_raw_bson(self.human_readable_serialization)?, }; + self.update.append_to_rawdoc(&mut update, "u")?; if let Some(ref options) = self.options { if let Some(upsert) = options.upsert { diff --git a/src/sdam/description/topology/server_selection/test/in_window.rs b/src/sdam/description/topology/server_selection/test/in_window.rs index b62d604cb..1e81cefa5 100644 --- a/src/sdam/description/topology/server_selection/test/in_window.rs +++ b/src/sdam/description/topology/server_selection/test/in_window.rs @@ -7,7 +7,6 @@ use serde::Deserialize; use crate::{ cmap::DEFAULT_MAX_POOL_SIZE, - coll::options::FindOptions, error::Result, event::cmap::CmapEvent, options::ServerAddress, @@ -156,7 +155,7 @@ async fn load_balancing_test() { setup_client .database("load_balancing_test") .collection("load_balancing_test") - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await .unwrap(); @@ -178,7 +177,7 @@ async fn load_balancing_test() { .collection::("load_balancing_test"); handles.push(runtime::spawn(async move { for _ in 0..iterations { - collection.find_one(None, None).await?; + collection.find_one(doc! {}).await?; } Ok(()) })) @@ -231,13 +230,11 @@ async fn load_balancing_test() { let client = client.clone(); let selector = selector.clone(); runtime::spawn(async move { - let options = FindOptions::builder() - .selection_criteria(SelectionCriteria::Predicate(selector)) - .build(); client .database("load_balancing_test") .collection::("load_balancing_test") - .find(doc! { "$where": "sleep(500) && true" }, options) + .find(doc! { "$where": "sleep(500) && true" }) + .selection_criteria(SelectionCriteria::Predicate(selector)) .await .unwrap(); }); diff --git a/src/sdam/description/topology/test/sdam.rs b/src/sdam/description/topology/test/sdam.rs index cd45346b7..58750785f 100644 --- a/src/sdam/description/topology/test/sdam.rs +++ b/src/sdam/description/topology/test/sdam.rs @@ -603,7 +603,7 @@ async fn topology_closed_event_last() { client .database(function_name!()) .collection(function_name!()) - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); drop(client); @@ -722,7 +722,7 @@ async fn direct_connection() { direct_false_client .database(function_name!()) .collection(function_name!()) - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await .expect("write should succeed with directConnection=false on secondary"); @@ -733,7 +733,7 @@ async fn direct_connection() { let error = direct_true_client .database(function_name!()) .collection(function_name!()) - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await .expect_err("write should fail with directConnection=true on secondary"); assert!(error.is_notwritableprimary()); @@ -743,7 +743,7 @@ async fn direct_connection() { client .database(function_name!()) .collection(function_name!()) - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await .expect("write should succeed with directConnection unspecified"); } diff --git a/src/sync/change_stream.rs b/src/sync/change_stream.rs index cac5f42ce..516900c5d 100644 --- a/src/sync/change_stream.rs +++ b/src/sync/change_stream.rs @@ -36,7 +36,7 @@ use super::ClientSession; /// # let client = Client::with_uri_str("mongodb://example.com")?; /// # let coll = client.database("foo").collection("bar"); /// let mut change_stream = coll.watch().run()?; -/// coll.insert_one(doc! { "x": 1 }, None)?; +/// coll.insert_one(doc! { "x": 1 }).run()?; /// for event in change_stream { /// let event = event?; /// println!("operation performed: {:?}, document: {:?}", event.operation_type, event.full_document); @@ -192,7 +192,7 @@ where /// let mut cs = coll.watch().session(&mut session).run()?; /// while let Some(event) = cs.next(&mut session)? { /// let id = bson::to_bson(&event.id)?; - /// other_coll.insert_one_with_session(doc! { "id": id }, None, &mut session)?; + /// other_coll.insert_one(doc! { "id": id }).session(&mut session).run()?; /// } /// # Ok::<(), mongodb::error::Error>(()) /// # }; diff --git a/src/sync/client/session.rs b/src/sync/client/session.rs index 8272f5fef..b8c305bc7 100644 --- a/src/sync/client/session.rs +++ b/src/sync/client/session.rs @@ -67,7 +67,7 @@ impl ClientSession { /// # let coll = client.database("foo").collection::("bar"); /// # let mut session = client.start_session().run()?; /// session.start_transaction(None)?; - /// let result = coll.insert_one_with_session(doc! { "x": 1 }, None, &mut session)?; + /// let result = coll.insert_one(doc! { "x": 1 }).session(&mut session).run()?; /// session.commit_transaction()?; /// # Ok(()) /// # } @@ -89,7 +89,7 @@ impl ClientSession { /// # let coll = client.database("foo").collection::("bar"); /// # let mut session = client.start_session().run()?; /// session.start_transaction(None)?; - /// let result = coll.insert_one_with_session(doc! { "x": 1 }, None, &mut session)?; + /// let result = coll.insert_one(doc! { "x": 1 }).session(&mut session).run()?; /// session.commit_transaction()?; /// # Ok(()) /// # } @@ -122,8 +122,8 @@ impl ClientSession { /// # } /// /// fn execute_transaction(coll: Collection, session: &mut ClientSession) -> Result<()> { - /// coll.insert_one_with_session(doc! { "x": 1 }, None, session)?; - /// coll.delete_one(doc! { "y": 2 }).session(session).run()?; + /// coll.insert_one(doc! { "x": 1 }).session(&mut *session).run()?; + /// coll.delete_one(doc! { "y": 2 }).session(&mut *session).run()?; /// Ok(()) /// } /// ``` diff --git a/src/sync/coll.rs b/src/sync/coll.rs index 6ca866f3f..74c7bcc7c 100644 --- a/src/sync/coll.rs +++ b/src/sync/coll.rs @@ -1,26 +1,5 @@ -use std::{borrow::Borrow, fmt::Debug}; - -use serde::{de::DeserializeOwned, Serialize}; - -use super::{ClientSession, Cursor, SessionCursor}; use crate::{ - bson::Document, - error::Result, - options::{ - FindOneAndDeleteOptions, - FindOneAndReplaceOptions, - FindOneAndUpdateOptions, - FindOneOptions, - FindOptions, - InsertManyOptions, - InsertOneOptions, - ReadConcern, - ReplaceOptions, - SelectionCriteria, - UpdateModifications, - WriteConcern, - }, - results::{InsertManyResult, InsertOneResult, UpdateResult}, + options::{ReadConcern, SelectionCriteria, WriteConcern}, Collection as AsyncCollection, Namespace, }; @@ -50,7 +29,7 @@ use crate::{ /// /// std::thread::spawn(move || { /// // Perform operations with `coll_ref`. For example: -/// coll_ref.insert_one(doc! { "x": i }, None); +/// coll_ref.insert_one(doc! { "x": i }); /// }); /// } /// # @@ -111,315 +90,4 @@ where pub fn write_concern(&self) -> Option<&WriteConcern> { self.async_collection.write_concern() } - - /// Finds the documents in the collection matching `filter`. - pub fn find( - &self, - filter: impl Into>, - options: impl Into>, - ) -> Result> { - crate::sync::TOKIO_RUNTIME - .block_on(self.async_collection.find(filter.into(), options.into())) - .map(Cursor::new) - } - - /// Finds the documents in the collection matching `filter` using the provided `ClientSession`. - pub fn find_with_session( - &self, - filter: impl Into>, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - crate::sync::TOKIO_RUNTIME - .block_on(self.async_collection.find_with_session( - filter.into(), - options.into(), - &mut session.async_client_session, - )) - .map(SessionCursor::new) - } -} - -impl Collection -where - T: DeserializeOwned + Unpin + Send + Sync, -{ - /// Finds a single document in the collection matching `filter`. - pub fn find_one( - &self, - filter: impl Into>, - options: impl Into>, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on( - self.async_collection - .find_one(filter.into(), options.into()), - ) - } - - /// Finds a single document in the collection matching `filter` using the provided - /// `ClientSession`. - pub fn find_one_with_session( - &self, - filter: impl Into>, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.find_one_with_session( - filter.into(), - options.into(), - &mut session.async_client_session, - )) - } -} - -impl Collection -where - T: DeserializeOwned + Send + Sync, -{ - /// Atomically finds up to one document in the collection matching `filter` and deletes it. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn find_one_and_delete( - &self, - filter: Document, - options: impl Into>, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on( - self.async_collection - .find_one_and_delete(filter, options.into()), - ) - } - - /// Atomically finds up to one document in the collection matching `filter` and deletes it using - /// the provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn find_one_and_delete_with_session( - &self, - filter: Document, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.find_one_and_delete_with_session( - filter, - options.into(), - &mut session.async_client_session, - )) - } - - /// Atomically finds up to one document in the collection matching `filter` and updates it. - /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn find_one_and_update( - &self, - filter: Document, - update: impl Into, - options: impl Into>, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.find_one_and_update( - filter, - update.into(), - options.into(), - )) - } - - /// Atomically finds up to one document in the collection matching `filter` and updates it using - /// the provided `ClientSession`. Both `Document` and `Vec` implement - /// `Into`, so either can be passed in place of constructing the enum - /// case. Note: pipeline updates are only supported in MongoDB 4.2+. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn find_one_and_update_with_session( - &self, - filter: Document, - update: impl Into, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.find_one_and_update_with_session( - filter, - update.into(), - options.into(), - &mut session.async_client_session, - )) - } -} - -impl Collection -where - T: Serialize + DeserializeOwned + Send + Sync, -{ - /// Atomically finds up to one document in the collection matching `filter` and replaces it with - /// `replacement`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn find_one_and_replace( - &self, - filter: Document, - replacement: T, - options: impl Into>, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.find_one_and_replace( - filter, - replacement, - options.into(), - )) - } - - /// Atomically finds up to one document in the collection matching `filter` and replaces it with - /// `replacement` using the provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn find_one_and_replace_with_session( - &self, - filter: Document, - replacement: T, - options: impl Into>, - session: &mut ClientSession, - ) -> Result> { - crate::sync::TOKIO_RUNTIME.block_on( - self.async_collection.find_one_and_replace_with_session( - filter, - replacement, - options.into(), - &mut session.async_client_session, - ), - ) - } -} - -impl Collection -where - T: Serialize + Send + Sync, -{ - /// Inserts the documents in `docs` into the collection. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn insert_many( - &self, - docs: impl IntoIterator>, - options: impl Into>, - ) -> Result { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.insert_many(docs, options.into())) - } - - /// Inserts the documents in `docs` into the collection using the provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn insert_many_with_session( - &self, - docs: impl IntoIterator>, - options: impl Into>, - session: &mut ClientSession, - ) -> Result { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.insert_many_with_session( - docs, - options.into(), - &mut session.async_client_session, - )) - } - - /// Inserts `doc` into the collection. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn insert_one( - &self, - doc: impl Borrow, - options: impl Into>, - ) -> Result { - crate::sync::TOKIO_RUNTIME.block_on( - self.async_collection - .insert_one(doc.borrow(), options.into()), - ) - } - - /// Inserts `doc` into the collection using the provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn insert_one_with_session( - &self, - doc: impl Borrow, - options: impl Into>, - session: &mut ClientSession, - ) -> Result { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.insert_one_with_session( - doc.borrow(), - options.into(), - &mut session.async_client_session, - )) - } - - /// Replaces up to one document matching `query` in the collection with `replacement`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn replace_one( - &self, - query: Document, - replacement: impl Borrow, - options: impl Into>, - ) -> Result { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.replace_one( - query, - replacement.borrow(), - options.into(), - )) - } - - /// Replaces up to one document matching `query` in the collection with `replacement` using the - /// provided `ClientSession`. - /// - /// This operation will retry once upon failure if the connection and encountered error support - /// retryability. See the documentation - /// [here](https://www.mongodb.com/docs/manual/core/retryable-writes/) for more information on - /// retryable writes. - pub fn replace_one_with_session( - &self, - query: Document, - replacement: impl Borrow, - options: impl Into>, - session: &mut ClientSession, - ) -> Result { - crate::sync::TOKIO_RUNTIME.block_on(self.async_collection.replace_one_with_session( - query, - replacement.borrow(), - options.into(), - &mut session.async_client_session, - )) - } } diff --git a/src/sync/cursor.rs b/src/sync/cursor.rs index 779848117..5c1d7724a 100644 --- a/src/sync/cursor.rs +++ b/src/sync/cursor.rs @@ -31,12 +31,12 @@ use crate::{ /// documents it yields using a for loop: /// /// ```rust -/// # use mongodb::{bson::Document, sync::Client, error::Result}; +/// # use mongodb::{bson::{doc, Document}, sync::Client, error::Result}; /// # /// # fn do_stuff() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://example.com")?; /// # let coll = client.database("foo").collection::("bar"); -/// # let mut cursor = coll.find(None, None)?; +/// # let mut cursor = coll.find(doc! {}).run()?; /// # /// for doc in cursor { /// println!("{}", doc?) @@ -60,7 +60,7 @@ use crate::{ /// # fn do_stuff() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://example.com")?; /// # let coll = client.database("foo").collection("bar"); -/// # let cursor = coll.find(Some(doc! { "x": 1 }), None)?; +/// # let cursor = coll.find(doc! { "x": 1 }).run()?; /// # /// let results: Vec> = cursor.collect(); /// # Ok(()) @@ -92,11 +92,11 @@ impl Cursor { /// calling [`Cursor::advance`] first or after [`Cursor::advance`] returns an error / false. /// /// ``` - /// # use mongodb::{sync::Client, bson::Document, error::Result}; + /// # use mongodb::{sync::Client, bson::{Document, doc}, error::Result}; /// # fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017")?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find(None, None)?; + /// let mut cursor = coll.find(doc! {}).run()?; /// while cursor.advance()? { /// println!("{:?}", cursor.deserialize_current()?); /// } @@ -115,11 +115,11 @@ impl Cursor { /// or without calling [`Cursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{sync::Client, bson::Document, error::Result}; + /// # use mongodb::{sync::Client, bson::{doc, Document}, error::Result}; /// # fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017")?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find(None, None)?; + /// let mut cursor = coll.find(doc! {}).run()?; /// while cursor.advance()? { /// println!("{:?}", cursor.current()); /// } @@ -138,7 +138,7 @@ impl Cursor { /// true or without calling [`Cursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{sync::Client, error::Result}; + /// # use mongodb::{sync::Client, error::Result, bson::doc}; /// # fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017")?; /// # let db = client.database("foo"); @@ -151,7 +151,7 @@ impl Cursor { /// } /// /// let coll = db.collection::("cat"); - /// let mut cursor = coll.find(None, None)?; + /// let mut cursor = coll.find(doc! {}).run()?; /// while cursor.advance()? { /// println!("{:?}", cursor.deserialize_current()?); /// } @@ -181,13 +181,13 @@ where /// one. To iterate, retrieve a [`SessionCursorIter]` using [`SessionCursor::iter`]: /// /// ```rust -/// # use mongodb::{bson::Document, sync::Client, error::Result}; +/// # use mongodb::{bson::{doc, Document}, sync::Client, error::Result}; /// # /// # fn do_stuff() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://example.com")?; /// # let mut session = client.start_session().run()?; /// # let coll = client.database("foo").collection::("bar"); -/// # let mut cursor = coll.find_with_session(None, None, &mut session)?; +/// # let mut cursor = coll.find(doc! {}).session(&mut session).run()?; /// # /// for doc in cursor.iter(&mut session) { /// println!("{}", doc?) @@ -220,12 +220,12 @@ impl SessionCursor { /// calling [`Cursor::advance`] first or after [`Cursor::advance`] returns an error / false. /// /// ``` - /// # use mongodb::{sync::Client, bson::Document, error::Result}; + /// # use mongodb::{sync::Client, bson::{doc, Document}, error::Result}; /// # fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017")?; /// # let mut session = client.start_session().run()?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find_with_session(None, None, &mut session)?; + /// let mut cursor = coll.find(doc! {}).session(&mut session).run()?; /// while cursor.advance(&mut session)? { /// println!("{:?}", cursor.deserialize_current()?); /// } @@ -245,12 +245,12 @@ impl SessionCursor { /// or without calling [`Cursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{sync::Client, bson::Document, error::Result}; + /// # use mongodb::{sync::Client, bson::{doc, Document}, error::Result}; /// # fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017")?; /// # let mut session = client.start_session().run()?; /// # let coll = client.database("stuff").collection::("stuff"); - /// let mut cursor = coll.find_with_session(None, None, &mut session)?; + /// let mut cursor = coll.find(doc! {}).session(&mut session).run()?; /// while cursor.advance(&mut session)? { /// println!("{:?}", cursor.current()); /// } @@ -269,7 +269,7 @@ impl SessionCursor { /// true or without calling [`Cursor::advance`] at all may result in a panic. /// /// ``` - /// # use mongodb::{sync::Client, error::Result}; + /// # use mongodb::{sync::Client, error::Result, bson::doc}; /// # fn foo() -> Result<()> { /// # let client = Client::with_uri_str("mongodb://localhost:27017")?; /// # let mut session = client.start_session().run()?; @@ -283,7 +283,7 @@ impl SessionCursor { /// } /// /// let coll = db.collection::("cat"); - /// let mut cursor = coll.find_with_session(None, None, &mut session)?; + /// let mut cursor = coll.find(doc! {}).session(&mut session).run()?; /// while cursor.advance(&mut session)? { /// println!("{:?}", cursor.deserialize_current()?); /// } @@ -327,9 +327,9 @@ where /// # let coll = client.database("foo").collection::("bar"); /// # let other_coll = coll.clone(); /// # let mut session = client.start_session().run()?; - /// let mut cursor = coll.find_with_session(doc! { "x": 1 }, None, &mut session)?; + /// let mut cursor = coll.find(doc! { "x": 1 }).session(&mut session).run()?; /// while let Some(doc) = cursor.next(&mut session).transpose()? { - /// other_coll.insert_one_with_session(doc, None, &mut session)?; + /// other_coll.insert_one(doc).session(&mut session).run()?; /// } /// # Ok::<(), mongodb::error::Error>(()) /// # } diff --git a/src/sync/test.rs b/src/sync/test.rs index 129345592..8df3df920 100644 --- a/src/sync/test.rs +++ b/src/sync/test.rs @@ -69,7 +69,8 @@ fn client() { client .database(function_name!()) .collection(function_name!()) - .insert_one(Document::new(), None) + .insert_one(Document::new()) + .run() .expect("insert should succeed"); let db_names = client @@ -116,7 +117,8 @@ fn database() { let coll = init_db_and_coll(&client, function_name!(), function_name!()); - coll.insert_one(doc! { "x": 1 }, None) + coll.insert_one(doc! { "x": 1 }) + .run() .expect("insert should succeed"); let coll_names = db @@ -159,12 +161,14 @@ fn collection() { let client = Client::with_options(options).expect("client creation should succeed"); let coll = init_db_and_coll(&client, function_name!(), function_name!()); - coll.insert_one(doc! { "x": 1 }, None) + coll.insert_one(doc! { "x": 1 }) + .run() .expect("insert should succeed"); - let find_options = FindOptions::builder().projection(doc! { "_id": 0 }).build(); let cursor = coll - .find(doc! { "x": 1 }, find_options) + .find(doc! { "x": 1 }) + .projection(doc! { "_id": 0 }) + .run() .expect("find should succeed"); let results = cursor .collect::>>() @@ -221,7 +225,7 @@ fn typed_collection() { str: "hello".into(), }; - assert!(coll.insert_one(my_type, None).is_ok()); + assert!(coll.insert_one(my_type).run().is_ok()); } #[test] @@ -275,7 +279,7 @@ fn transactions() { .expect("start transaction should succeed"); run_transaction_with_retry(&mut session, |s| { - coll.insert_one_with_session(doc! { "x": 1 }, None, s)?; + coll.insert_one(doc! { "x": 1 }).session(s).run()?; Ok(()) }) .unwrap(); @@ -299,7 +303,7 @@ fn transactions() { .start_transaction(None) .expect("start transaction should succeed"); run_transaction_with_retry(&mut session, |s| { - coll.insert_one_with_session(doc! { "x": 1 }, None, s)?; + coll.insert_one(doc! { "x": 1 }).session(s).run()?; Ok(()) }) .unwrap(); @@ -324,7 +328,7 @@ fn collection_generic_bounds() { let coll: Collection = client .database(function_name!()) .collection(function_name!()); - let _result: Result> = coll.find_one(None, None); + let _result: Result> = coll.find_one(doc! {}).run(); #[derive(Serialize)] struct Bar; @@ -333,7 +337,7 @@ fn collection_generic_bounds() { let coll: Collection = client .database(function_name!()) .collection(function_name!()); - let _result = coll.insert_one(Bar {}, None); + let _result = coll.insert_one(Bar {}); } #[test] @@ -377,13 +381,17 @@ fn borrowed_deserialization() { Doc { id: 5, foo: "1" }, ]; - coll.insert_many(&docs, None).unwrap(); + coll.insert_many(&docs).run().unwrap(); let options = FindOptions::builder() .batch_size(2) .sort(doc! { "_id": 1 }) .build(); - let mut cursor = coll.find(None, options.clone()).unwrap(); + let mut cursor = coll + .find(doc! {}) + .with_options(options.clone()) + .run() + .unwrap(); let mut i = 0; while cursor.advance().unwrap() { @@ -393,7 +401,12 @@ fn borrowed_deserialization() { } let mut session = client.start_session().run().unwrap(); - let mut cursor = coll.find_with_session(None, options, &mut session).unwrap(); + let mut cursor = coll + .find(doc! {}) + .with_options(options) + .session(&mut session) + .run() + .unwrap(); let mut i = 0; while cursor.advance(&mut session).unwrap() { @@ -414,13 +427,14 @@ fn mixed_sync_and_async() -> Result<()> { sync_db.drop().run()?; sync_db .collection::(COLL_NAME) - .insert_one(doc! { "a": 1 }, None)?; + .insert_one(doc! { "a": 1 }) + .run()?; let mut found = crate::sync::TOKIO_RUNTIME .block_on(async { async_client .database(DB_NAME) .collection::(COLL_NAME) - .find_one(doc! {}, None) + .find_one(doc! {}) .await })? .unwrap(); diff --git a/src/test/atlas_connectivity.rs b/src/test/atlas_connectivity.rs index 01cbca813..6da943ffa 100644 --- a/src/test/atlas_connectivity.rs +++ b/src/test/atlas_connectivity.rs @@ -34,7 +34,7 @@ async fn run_test(uri_env_var: &str, resolver_config: Option) { .expect("hello should succeed"); let coll = db.collection::("test"); - coll.find_one(None, None) + coll.find_one(doc! {}) .await .expect("findOne should succeed"); } diff --git a/src/test/auth_aws.rs b/src/test/auth_aws.rs index 5363718a8..0bd75b82e 100644 --- a/src/test/auth_aws.rs +++ b/src/test/auth_aws.rs @@ -1,5 +1,7 @@ use std::env::{remove_var, set_var, var}; +use bson::doc; + use crate::{bson::Document, client::auth::aws::test_utils::*, test::DEFAULT_URI, Client}; use super::TestClient; @@ -9,7 +11,7 @@ async fn auth_aws() { let client = TestClient::new().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); } // The TestClient performs operations upon creation that trigger authentication, so the credential @@ -29,7 +31,7 @@ async fn credential_caching() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert!(cached_credential().await.is_some()); let now = bson::DateTime::now(); @@ -37,7 +39,7 @@ async fn credential_caching() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert!(cached_credential().await.is_some()); assert!(cached_expiration().await > now); @@ -45,7 +47,7 @@ async fn credential_caching() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - match coll.find_one(None, None).await { + match coll.find_one(doc! {}).await { Ok(_) => panic!( "find one should have failed with authentication error due to poisoned cached \ credential" @@ -54,7 +56,7 @@ async fn credential_caching() { } assert!(cached_credential().await.is_none()); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert!(cached_credential().await.is_some()); } @@ -69,7 +71,7 @@ async fn credential_caching_environment_vars() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert!(cached_credential().await.is_some()); set_var("AWS_ACCESS_KEY_ID", cached_access_key_id().await); @@ -81,7 +83,7 @@ async fn credential_caching_environment_vars() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert!(cached_credential().await.is_none()); set_var("AWS_ACCESS_KEY_ID", "bad"); @@ -90,7 +92,7 @@ async fn credential_caching_environment_vars() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - match coll.find_one(None, None).await { + match coll.find_one(doc! {}).await { Ok(_) => panic!( "find one should have failed with authentication error due to poisoned environment \ variables" @@ -105,7 +107,7 @@ async fn credential_caching_environment_vars() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert!(cached_credential().await.is_some()); set_var("AWS_ACCESS_KEY_ID", "bad"); @@ -114,7 +116,7 @@ async fn credential_caching_environment_vars() { let client = get_client().await; let coll = client.database("aws").collection::("somecoll"); - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); remove_var("AWS_ACCESS_KEY_ID"); remove_var("AWS_SECRET_ACCESS_KEY"); diff --git a/src/test/change_stream.rs b/src/test/change_stream.rs index 53b2f4c5e..05f409114 100644 --- a/src/test/change_stream.rs +++ b/src/test/change_stream.rs @@ -73,7 +73,7 @@ async fn tracks_resume_token() -> Result<()> { tokens.push(token.parsed()?); } for _ in 0..3 { - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; stream.next().await.transpose()?; tokens.push(stream.resume_token().unwrap().parsed()?); } @@ -140,7 +140,7 @@ async fn errors_on_missing_token() -> Result<()> { .watch() .pipeline(vec![doc! { "$project": { "_id": 0 } }]) .await?; - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; assert!(stream.next().await.transpose().is_err()); Ok(()) @@ -155,7 +155,7 @@ async fn resumes_on_error() -> Result<()> { None => return Ok(()), }; - coll.insert_one(doc! { "_id": 1 }, None).await?; + coll.insert_one(doc! { "_id": 1 }).await?; assert!(matches!(stream.next().await.transpose()?, Some(ChangeStreamEvent { operation_type: OperationType::Insert, @@ -172,7 +172,7 @@ async fn resumes_on_error() -> Result<()> { .enable(&client, None) .await?; - coll.insert_one(doc! { "_id": 2 }, None).await?; + coll.insert_one(doc! { "_id": 2 }).await?; assert!(matches!(stream.next().await.transpose()?, Some(ChangeStreamEvent { operation_type: OperationType::Insert, @@ -227,7 +227,7 @@ async fn empty_batch_not_closed() -> Result<()> { assert!(stream.next_if_any().await?.is_none()); - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; stream.next().await.transpose()?; let events = client.get_command_events(&["aggregate", "getMore"]); @@ -256,7 +256,7 @@ async fn resume_kill_cursor_error_suppressed() -> Result<()> { None => return Ok(()), }; - coll.insert_one(doc! { "_id": 1 }, None).await?; + coll.insert_one(doc! { "_id": 1 }).await?; assert!(matches!(stream.next().await.transpose()?, Some(ChangeStreamEvent { operation_type: OperationType::Insert, @@ -273,7 +273,7 @@ async fn resume_kill_cursor_error_suppressed() -> Result<()> { .enable(&client, None) .await?; - coll.insert_one(doc! { "_id": 2 }, None).await?; + coll.insert_one(doc! { "_id": 2 }).await?; assert!(matches!(stream.next().await.transpose()?, Some(ChangeStreamEvent { operation_type: OperationType::Insert, @@ -318,7 +318,7 @@ async fn resume_start_at_operation_time() -> Result<()> { .enable(&client, None) .await?; - coll.insert_one(doc! { "_id": 2 }, None).await?; + coll.insert_one(doc! { "_id": 2 }).await?; stream.next().await.transpose()?; let events = client.get_command_events(&["aggregate"]); @@ -399,7 +399,7 @@ async fn batch_end_resume_token_legacy() -> Result<()> { assert_eq!(stream.resume_token(), None); // Case: end of batch - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; let expected_id = stream.next_if_any().await?.unwrap().id; assert_eq!(stream.next_if_any().await?, None); assert_eq!(stream.resume_token().as_ref(), Some(&expected_id)); @@ -430,7 +430,7 @@ async fn batch_mid_resume_token() -> Result<()> { } // If we're out of events, make some more. None => { - coll.insert_many((0..3).map(|_| doc! {}), None).await?; + coll.insert_many((0..3).map(|_| doc! {})).await?; } }; @@ -470,13 +470,13 @@ async fn aggregate_batch() -> Result<()> { } // Synthesize a resume token for the new stream to start at. - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; stream.next().await; let token = stream.resume_token().unwrap(); // Populate the initial batch of the new stream. - coll.insert_one(doc! {}, None).await?; - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; + coll.insert_one(doc! {}).await?; // Case: `start_after` is given let stream = coll.watch().start_after(token.clone()).await?; @@ -510,14 +510,14 @@ async fn resume_uses_start_after() -> Result<()> { return Ok(()); } - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; stream.next().await.transpose()?; let token = stream.resume_token().unwrap(); let mut stream = coll.watch().start_after(token.clone()).await?; // Create an event, and synthesize a resumable error when calling `getMore` for that event. - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; let _guard = FailPoint::fail_command( &["getMore"], FailPointMode::Times(1), @@ -566,18 +566,18 @@ async fn resume_uses_resume_after() -> Result<()> { return Ok(()); } - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; stream.next().await.transpose()?; let token = stream.resume_token().unwrap(); let mut stream = coll.watch().start_after(token.clone()).await?; // Create an event and read it. - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; stream.next().await.transpose()?; // Create an event, and synthesize a resumable error when calling `getMore` for that event. - coll.insert_one(doc! {}, None).await?; + coll.insert_one(doc! {}).await?; let _guard = FailPoint::fail_command( &["getMore"], FailPointMode::Times(1), @@ -658,7 +658,7 @@ async fn split_large_event() -> Result<()> { .await?; let coll = db.collection::("split_large_event"); - coll.insert_one(doc! { "value": "q".repeat(10 * 1024 * 1024) }, None) + coll.insert_one(doc! { "value": "q".repeat(10 * 1024 * 1024) }) .await?; let stream = coll .watch() diff --git a/src/test/client.rs b/src/test/client.rs index 4ffb1e54a..369160f23 100644 --- a/src/test/client.rs +++ b/src/test/client.rs @@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize}; use crate::{ bson::{doc, Bson}, - coll::options::FindOptions, error::{CommandError, Error, ErrorKind}, event::{cmap::CmapEvent, sdam::SdamEvent}, hello::LEGACY_HELLO_COMMAND_NAME, @@ -97,7 +96,7 @@ async fn connection_drop_during_read() { let db = client.database("test"); db.collection(function_name!()) - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); @@ -179,7 +178,7 @@ async fn list_databases() { let db = client.database(name); db.collection("foo") - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); } @@ -224,7 +223,7 @@ async fn list_database_names() { let db = client.database(name); db.collection("foo") - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); } @@ -604,7 +603,7 @@ async fn x509_auth() { client .database(function_name!()) .collection::(function_name!()) - .find_one(None, None) + .find_one(doc! {}) .await .unwrap(); } @@ -633,7 +632,7 @@ async fn plain_auth() { let client = Client::with_options(options).unwrap(); let coll = client.database("ldap").collection("test"); - let doc = coll.find_one(None, None).await.unwrap().unwrap(); + let doc = coll.find_one(doc! {}).await.unwrap().unwrap(); #[derive(Debug, Deserialize, PartialEq)] struct TestDocument { @@ -683,7 +682,7 @@ async fn retry_commit_txn_check_out() { setup_client .database("retry_commit_txn_check_out") .collection("retry_commit_txn_check_out") - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await .unwrap(); @@ -702,7 +701,8 @@ async fn retry_commit_txn_check_out() { client .database("retry_commit_txn_check_out") .collection("retry_commit_txn_check_out") - .insert_one_with_session(doc! {}, None, &mut session) + .insert_one(doc! {}) + .session(&mut session) .await .unwrap(); @@ -811,15 +811,12 @@ async fn manual_shutdown_with_resources() { let db = client.database("shutdown_test"); db.drop().await.unwrap(); let coll = db.collection::("test"); - coll.insert_many([doc! {}, doc! {}], None).await.unwrap(); + coll.insert_many([doc! {}, doc! {}]).await.unwrap(); let bucket = db.gridfs_bucket(None); // Scope to force drop of resources { // Exhausted cursors don't need cleanup, so make sure there's more than one batch to fetch - let _cursor = coll - .find(None, FindOptions::builder().batch_size(1).build()) - .await - .unwrap(); + let _cursor = coll.find(doc! {}).batch_size(1).await.unwrap(); // Similarly, sessions need an in-progress transaction to have cleanup. let mut session = client.start_session().await.unwrap(); if session.start_transaction(None).await.is_err() { @@ -828,7 +825,8 @@ async fn manual_shutdown_with_resources() { return; } if coll - .insert_one_with_session(doc! {}, None, &mut session) + .insert_one(doc! {}) + .session(&mut session) .await .is_err() { @@ -874,20 +872,18 @@ async fn manual_shutdown_immediate_with_resources() { let db = client.database("shutdown_test"); db.drop().await.unwrap(); let coll = db.collection::("test"); - coll.insert_many([doc! {}, doc! {}], None).await.unwrap(); + coll.insert_many([doc! {}, doc! {}]).await.unwrap(); let bucket = db.gridfs_bucket(None); // Resources are scoped to past the `shutdown_immediate`. // Exhausted cursors don't need cleanup, so make sure there's more than one batch to fetch - let _cursor = coll - .find(None, FindOptions::builder().batch_size(1).build()) - .await - .unwrap(); + let _cursor = coll.find(doc! {}).batch_size(1).await.unwrap(); // Similarly, sessions need an in-progress transaction to have cleanup. let mut session = client.start_session().await.unwrap(); session.start_transaction(None).await.unwrap(); - coll.insert_one_with_session(doc! {}, None, &mut session) + coll.insert_one(doc! {}) + .session(&mut session) .await .unwrap(); let _stream = bucket.open_upload_stream("test", None); @@ -921,17 +917,13 @@ async fn find_one_and_delete_serde_consistency() { problematic: vec![0, 1, 2, 3, 4, 5, 6, 7], }; - coll.insert_one(&doc, None).await.unwrap(); - let rec: Foo = coll.find_one(doc! {}, None).await.unwrap().unwrap(); + coll.insert_one(&doc).await.unwrap(); + let rec: Foo = coll.find_one(doc! {}).await.unwrap().unwrap(); assert_eq!(doc.problematic, rec.problematic); - let rec: Foo = coll - .find_one_and_delete(doc! {}, None) - .await - .unwrap() - .unwrap(); + let rec: Foo = coll.find_one_and_delete(doc! {}).await.unwrap().unwrap(); assert_eq!(doc.problematic, rec.problematic); - let nothing = coll.find_one_and_delete(doc! {}, None).await.unwrap(); + let nothing = coll.find_one_and_delete(doc! {}).await.unwrap(); assert!(nothing.is_none()); } diff --git a/src/test/coll.rs b/src/test/coll.rs index 9aeb871af..a12bbf030 100644 --- a/src/test/coll.rs +++ b/src/test/coll.rs @@ -21,11 +21,9 @@ use crate::{ DeleteOptions, DropCollectionOptions, FindOneAndDeleteOptions, - FindOneOptions, FindOptions, Hint, IndexOptions, - InsertManyOptions, ReadConcern, ReadPreference, SelectionCriteria, @@ -76,7 +74,7 @@ async fn insert_err_details() { .await .unwrap(); - let wc_error_result = coll.insert_one(doc! { "test": 1 }, None).await; + let wc_error_result = coll.insert_one(doc! { "test": 1 }).await; match *wc_error_result.unwrap_err().kind { ErrorKind::Write(WriteFailure::WriteConcernError(ref wc_error)) => { match &wc_error.details { @@ -106,11 +104,11 @@ async fn count() { assert_eq!(coll.estimated_document_count().await.unwrap(), 0); - let _ = coll.insert_one(doc! { "x": 1 }, None).await.unwrap(); + let _ = coll.insert_one(doc! { "x": 1 }).await.unwrap(); assert_eq!(coll.estimated_document_count().await.unwrap(), 1); let result = coll - .insert_many((1..4).map(|i| doc! { "x": i }).collect::>(), None) + .insert_many((1..4).map(|i| doc! { "x": i }).collect::>()) .await .unwrap(); assert_eq!(result.inserted_ids.len(), 3); @@ -126,12 +124,12 @@ async fn find() { .await; let result = coll - .insert_many((0i32..5).map(|i| doc! { "x": i }).collect::>(), None) + .insert_many((0i32..5).map(|i| doc! { "x": i }).collect::>()) .await .unwrap(); assert_eq!(result.inserted_ids.len(), 5); - let mut cursor = coll.find(None, None).await.unwrap().enumerate(); + let mut cursor = coll.find(doc! {}).await.unwrap().enumerate(); while let Some((i, result)) = cursor.next().await { let doc = result.unwrap(); @@ -151,7 +149,7 @@ async fn update() { .await; let result = coll - .insert_many((0i32..5).map(|_| doc! { "x": 3 }).collect::>(), None) + .insert_many((0i32..5).map(|_| doc! { "x": 3 }).collect::>()) .await .unwrap(); assert_eq!(result.inserted_ids.len(), 5); @@ -188,7 +186,7 @@ async fn delete() { .await; let result = coll - .insert_many((0i32..5).map(|_| doc! { "x": 3 }).collect::>(), None) + .insert_many((0i32..5).map(|_| doc! { "x": 3 }).collect::>()) .await .unwrap(); assert_eq!(result.inserted_ids.len(), 5); @@ -212,7 +210,7 @@ async fn aggregate_out() { drop_collection(&coll).await; let result = coll - .insert_many((0i32..5).map(|n| doc! { "x": n }).collect::>(), None) + .insert_many((0i32..5).map(|n| doc! { "x": n }).collect::>()) .await .unwrap(); assert_eq!(result.inserted_ids.len(), 5); @@ -262,7 +260,7 @@ async fn kill_cursors_on_drop() { drop_collection(&coll).await; - coll.insert_many(vec![doc! { "x": 1 }, doc! { "x": 2 }], None) + coll.insert_many(vec![doc! { "x": 1 }, doc! { "x": 2 }]) .await .unwrap(); @@ -271,10 +269,7 @@ async fn kill_cursors_on_drop() { .database(function_name!()) .collection::(function_name!()); - let cursor = coll - .find(None, FindOptions::builder().batch_size(1).build()) - .await - .unwrap(); + let cursor = coll.find(doc! {}).batch_size(1).await.unwrap(); assert!(!kill_cursors_sent(&event_client)); @@ -297,7 +292,7 @@ async fn no_kill_cursors_on_exhausted() { drop_collection(&coll).await; - coll.insert_many(vec![doc! { "x": 1 }, doc! { "x": 2 }], None) + coll.insert_many(vec![doc! { "x": 1 }, doc! { "x": 2 }]) .await .unwrap(); @@ -306,10 +301,7 @@ async fn no_kill_cursors_on_exhausted() { .database(function_name!()) .collection::(function_name!()); - let cursor = coll - .find(None, FindOptions::builder().build()) - .await - .unwrap(); + let cursor = coll.find(doc! {}).await.unwrap(); assert!(!kill_cursors_sent(&event_client)); @@ -388,11 +380,7 @@ async fn large_insert() { .init_db_and_coll(function_name!(), function_name!()) .await; assert_eq!( - coll.insert_many(docs, None) - .await - .unwrap() - .inserted_ids - .len(), + coll.insert_many(docs).await.unwrap().inserted_ids.len(), 35000 ); } @@ -434,10 +422,10 @@ async fn large_insert_unordered_with_errors() { let coll = client .init_db_and_coll(function_name!(), function_name!()) .await; - let options = InsertManyOptions::builder().ordered(false).build(); match *coll - .insert_many(docs, options) + .insert_many(docs) + .ordered(false) .await .expect_err("should get error") .kind @@ -472,10 +460,10 @@ async fn large_insert_ordered_with_errors() { let coll = client .init_db_and_coll(function_name!(), function_name!()) .await; - let options = InsertManyOptions::builder().ordered(true).build(); match *coll - .insert_many(docs, options) + .insert_many(docs) + .ordered(true) .await .expect_err("should get error") .kind @@ -506,7 +494,7 @@ async fn empty_insert() { .database(function_name!()) .collection::(function_name!()); match *coll - .insert_many(Vec::::new(), None) + .insert_many(Vec::::new()) .await .expect_err("should get error") .kind @@ -544,7 +532,7 @@ async fn allow_disk_use_test(options: FindOptions, expected_value: Option) let coll = event_client .database(function_name!()) .collection::(function_name!()); - coll.find(None, options).await.unwrap(); + coll.find(doc! {}).with_options(options).await.unwrap(); let events = event_client.get_command_started_events(&["find"]); assert_eq!(events.len(), 1); @@ -615,7 +603,10 @@ async fn find_one_and_delete_hint_test(options: Option, } let coll = client.database(name).collection(name); - let _: Result> = coll.find_one_and_delete(doc! {}, options.clone()).await; + let _: Result> = coll + .find_one_and_delete(doc! {}) + .with_options(options.clone()) + .await; let events = client.get_command_started_events(&["findAndModify"]); assert_eq!(events.len(), 1); @@ -661,10 +652,10 @@ async fn find_one_and_delete_hint_server_version() { .database(function_name!()) .collection::("coll"); - let options = FindOneAndDeleteOptions::builder() + let res = coll + .find_one_and_delete(doc! {}) .hint(Hint::Name(String::new())) - .build(); - let res = coll.find_one_and_delete(doc! {}, options).await; + .await; let req1 = VersionReq::parse("< 4.2").unwrap(); let req2 = VersionReq::parse("4.2.*").unwrap(); @@ -689,18 +680,15 @@ async fn no_read_preference_to_standalone() { return; } - let options = FindOneOptions::builder() + client + .database(function_name!()) + .collection::(function_name!()) + .find_one(doc! {}) .selection_criteria(SelectionCriteria::ReadPreference( ReadPreference::SecondaryPreferred { options: Default::default(), }, )) - .build(); - - client - .database(function_name!()) - .collection::(function_name!()) - .find_one(None, options) .await .unwrap(); @@ -747,9 +735,9 @@ async fn insert_one_and_find(coll: &Collection, insert_data: T) where T: Serialize + DeserializeOwned + Clone + PartialEq + Debug + Unpin + Send + Sync, { - coll.insert_one(insert_data.clone(), None).await.unwrap(); + coll.insert_one(insert_data.clone()).await.unwrap(); let result = coll - .find_one(to_document(&insert_data).unwrap(), None) + .find_one(to_document(&insert_data).unwrap()) .await .unwrap(); match result { @@ -778,11 +766,11 @@ async fn typed_insert_many() { str: "b".into(), }, ]; - coll.insert_many(insert_data.clone(), None).await.unwrap(); + coll.insert_many(insert_data.clone()).await.unwrap(); - let options = FindOptions::builder().sort(doc! { "x": 1 }).build(); let actual: Vec = coll - .find(doc! { "x": 2 }, options) + .find(doc! { "x": 2 }) + .sort(doc! { "x": 1 }) .await .unwrap() .try_collect() @@ -803,20 +791,20 @@ async fn typed_find_one_and_replace() { x: 1, str: "a".into(), }; - coll.insert_one(insert_data.clone(), None).await.unwrap(); + coll.insert_one(insert_data.clone()).await.unwrap(); let replacement = UserType { x: 2, str: "b".into(), }; let result = coll - .find_one_and_replace(doc! { "x": 1 }, replacement.clone(), None) + .find_one_and_replace(doc! { "x": 1 }, replacement.clone()) .await .unwrap() .unwrap(); assert_eq!(result, insert_data); - let result = coll.find_one(doc! { "x": 2 }, None).await.unwrap().unwrap(); + let result = coll.find_one(doc! { "x": 2 }).await.unwrap().unwrap(); assert_eq!(result, replacement); } @@ -836,12 +824,12 @@ async fn typed_replace_one() { x: 2, str: "b".into(), }; - coll.insert_one(insert_data, None).await.unwrap(); - coll.replace_one(doc! { "x": 1 }, replacement.clone(), None) + coll.insert_one(insert_data).await.unwrap(); + coll.replace_one(doc! { "x": 1 }, replacement.clone()) .await .unwrap(); - let result = coll.find_one(doc! { "x": 2 }, None).await.unwrap().unwrap(); + let result = coll.find_one(doc! { "x": 2 }).await.unwrap().unwrap(); assert_eq!(result, replacement); } @@ -857,17 +845,17 @@ async fn typed_returns() { x: 1, str: "a".into(), }; - coll.insert_one(insert_data.clone(), None).await.unwrap(); + coll.insert_one(insert_data.clone()).await.unwrap(); let result = coll - .find_one_and_update(doc! { "x": 1 }, doc! { "$inc": { "x": 1 } }, None) + .find_one_and_update(doc! { "x": 1 }, doc! { "$inc": { "x": 1 } }) .await .unwrap() .unwrap(); assert_eq!(result, insert_data); let result = coll - .find_one_and_delete(doc! { "x": 2 }, None) + .find_one_and_delete(doc! { "x": 2 }) .await .unwrap() .unwrap(); @@ -895,7 +883,7 @@ async fn count_documents_with_wc() { .database(function_name!()) .collection(function_name!()); - coll.insert_one(doc! {}, None).await.unwrap(); + coll.insert_one(doc! {}).await.unwrap(); coll.count_documents(doc! {}) .await @@ -920,10 +908,10 @@ async fn collection_options_inherited() { .database(function_name!()) .collection_with_options::(function_name!(), options); - coll.find(None, None).await.unwrap(); + coll.find(doc! {}).await.unwrap(); assert_options_inherited(&client, "find").await; - coll.find_one(None, None).await.unwrap(); + coll.find_one(doc! {}).await.unwrap(); assert_options_inherited(&client, "find").await; coll.count_documents(doc! {}).await.unwrap(); @@ -963,7 +951,7 @@ async fn collection_generic_bounds() { let coll: Collection = client .database(function_name!()) .collection(function_name!()); - let _result: Result> = coll.find_one(None, None).await; + let _result: Result> = coll.find_one(doc! {}).await; #[derive(Serialize)] struct Bar; @@ -972,7 +960,7 @@ async fn collection_generic_bounds() { let coll: Collection = client .database(function_name!()) .collection(function_name!()); - let _result = coll.insert_one(Bar {}, None).await; + let _result = coll.insert_one(Bar {}).await; } /// Verify that a cursor with multiple batches whose last batch isn't full @@ -985,10 +973,10 @@ async fn cursor_batch_size() { .await; let doc = Document::new(); - coll.insert_many(vec![&doc; 10], None).await.unwrap(); + coll.insert_many(vec![&doc; 10]).await.unwrap(); let opts = FindOptions::builder().batch_size(3).build(); - let cursor_no_session = coll.find(doc! {}, opts.clone()).await.unwrap(); + let cursor_no_session = coll.find(doc! {}).with_options(opts.clone()).await.unwrap(); let docs: Vec<_> = cursor_no_session.try_collect().await.unwrap(); assert_eq!(docs.len(), 10); @@ -999,7 +987,9 @@ async fn cursor_batch_size() { } let mut session = client.start_session().await.unwrap(); let mut cursor = coll - .find_with_session(doc! {}, opts.clone(), &mut session) + .find(doc! {}) + .with_options(opts.clone()) + .session(&mut session) .await .unwrap(); let mut docs = Vec::new(); @@ -1009,7 +999,9 @@ async fn cursor_batch_size() { assert_eq!(docs.len(), 10); let mut cursor = coll - .find_with_session(doc! {}, opts, &mut session) + .find(doc! {}) + .with_options(opts) + .session(&mut session) .await .unwrap(); let docs: Vec<_> = cursor.stream(&mut session).try_collect().await.unwrap(); @@ -1036,13 +1028,13 @@ async fn invalid_utf8_response() { // a document containing a long string with multi-byte unicode characters. taken from a user // repro in RUBY-2560. let long_unicode_str_doc = doc! {"name": "(╯°□°)╯︵ ┻━┻(╯°□°)╯︵ ┻━┻(╯°□°)╯︵ ┻━┻(╯°□°)╯︵ ┻━┻(╯°□°)╯︵ ┻━┻(╯°□°)╯︵ ┻━┻"}; - coll.insert_one(&long_unicode_str_doc, None) + coll.insert_one(&long_unicode_str_doc) .await .expect("first insert of document should succeed"); // test triggering an invalid error message via an insert_one. let insert_err = coll - .insert_one(&long_unicode_str_doc, None) + .insert_one(&long_unicode_str_doc) .await .expect_err("second insert of document should fail") .kind; @@ -1050,14 +1042,14 @@ async fn invalid_utf8_response() { // test triggering an invalid error message via an insert_many. let insert_err = coll - .insert_many([&long_unicode_str_doc], None) + .insert_many([&long_unicode_str_doc]) .await .expect_err("second insert of document should fail") .kind; assert_duplicate_key_error_with_utf8_replacement(&insert_err); // test triggering an invalid error message via an update_one. - coll.insert_one(doc! {"x": 1}, None) + coll.insert_one(doc! {"x": 1}) .await .expect("inserting new document should succeed"); @@ -1078,7 +1070,7 @@ async fn invalid_utf8_response() { // test triggering an invalid error message via a replace_one. let replace_err = coll - .replace_one(doc! {"x": 1}, &long_unicode_str_doc, None) + .replace_one(doc! {"x": 1}, &long_unicode_str_doc) .await .expect_err("replacement with duplicate key should fail") .kind; @@ -1162,13 +1154,10 @@ async fn configure_human_readable_serialization() { non_human_readable_collection.drop().await.unwrap(); non_human_readable_collection - .insert_one( - Data { - id: 0, - s: StringOrBytes("non human readable!".into()), - }, - None, - ) + .insert_one(Data { + id: 0, + s: StringOrBytes("non human readable!".into()), + }) .await .unwrap(); @@ -1176,7 +1165,7 @@ async fn configure_human_readable_serialization() { // instead. let document_collection = non_human_readable_collection.clone_with_type::(); let doc = document_collection - .find_one(doc! { "id": 0 }, None) + .find_one(doc! { "id": 0 }) .await .unwrap() .unwrap(); @@ -1189,13 +1178,12 @@ async fn configure_human_readable_serialization() { id: 1, s: StringOrBytes("non human readable!".into()), }, - None, ) .await .unwrap(); let doc = document_collection - .find_one(doc! { "id": 1 }, None) + .find_one(doc! { "id": 1 }) .await .unwrap() .unwrap(); @@ -1211,20 +1199,17 @@ async fn configure_human_readable_serialization() { human_readable_collection.drop().await.unwrap(); human_readable_collection - .insert_one( - Data { - id: 0, - s: StringOrBytes("human readable!".into()), - }, - None, - ) + .insert_one(Data { + id: 0, + s: StringOrBytes("human readable!".into()), + }) .await .unwrap(); // Proper deserialization to a string demonstrates that the data was correctly serialized as a // string. human_readable_collection - .find_one(doc! { "id": 0 }, None) + .find_one(doc! { "id": 0 }) .await .unwrap(); @@ -1235,13 +1220,12 @@ async fn configure_human_readable_serialization() { id: 1, s: StringOrBytes("human readable!".into()), }, - None, ) .await .unwrap(); human_readable_collection - .find_one(doc! { "id": 1 }, None) + .find_one(doc! { "id": 1 }) .await .unwrap(); } @@ -1277,7 +1261,7 @@ async fn insert_many_document_sequences() { rawdoc! { "s": "a".repeat((max_object_size / 2) as usize) }, rawdoc! { "s": "b".repeat((max_object_size / 2) as usize) }, ]; - collection.insert_many(docs, None).await.unwrap(); + collection.insert_many(docs).await.unwrap(); let event = subscriber .filter_map_event(Duration::from_millis(500), |e| match e { @@ -1305,7 +1289,7 @@ async fn insert_many_document_sequences() { docs.push(doc); } let total_docs = docs.len(); - collection.insert_many(docs, None).await.unwrap(); + collection.insert_many(docs).await.unwrap(); let first_event = subscriber .filter_map_event(Duration::from_millis(500), |e| match e { diff --git a/src/test/csfle.rs b/src/test/csfle.rs index b37c25d27..d7bf6e55d 100644 --- a/src/test/csfle.rs +++ b/src/test/csfle.rs @@ -39,7 +39,6 @@ use crate::{ Credential, FindOptions, IndexOptions, - InsertOneOptions, ReadConcern, TlsOptions, WriteConcern, @@ -212,13 +211,13 @@ async fn custom_key_material() -> Result<()> { .key_material(key) .await?; let mut key_doc = datakeys - .find_one(doc! { "_id": id.clone() }, None) + .find_one(doc! { "_id": id.clone() }) .await? .unwrap(); datakeys.delete_one(doc! { "_id": id}).await?; let new_key_id = bson::Binary::from_uuid(bson::Uuid::from_bytes([0; 16])); key_doc.insert("_id", new_key_id.clone()); - datakeys.insert_one(key_doc, None).await?; + datakeys.insert_one(key_doc).await?; let encrypted = enc .encrypt( @@ -331,7 +330,7 @@ async fn data_key_double_encryption() -> Result<()> { let docs: Vec<_> = client .database("keyvault") .collection::("datakeys") - .find(doc! { "_id": datakey_id.clone() }, None) + .find(doc! { "_id": datakey_id.clone() }) .await? .try_collect() .await?; @@ -378,12 +377,9 @@ async fn data_key_double_encryption() -> Result<()> { let coll = client_encrypted .database("db") .collection::("coll"); - coll.insert_one( - doc! { "_id": provider.name(), "value": encrypted.clone() }, - None, - ) - .await?; - let found = coll.find_one(doc! { "_id": provider.name() }, None).await?; + coll.insert_one(doc! { "_id": provider.name(), "value": encrypted.clone() }) + .await?; + let found = coll.find_one(doc! { "_id": provider.name() }).await?; assert_eq!( found.as_ref().and_then(|doc| doc.get("value")), Some(&Bson::String(format!("hello {}", provider.name()))), @@ -402,7 +398,7 @@ async fn data_key_double_encryption() -> Result<()> { // Attempt to auto-encrypt an already encrypted field. let result = coll - .insert_one(doc! { "encrypted_placeholder": encrypted }, None) + .insert_one(doc! { "encrypted_placeholder": encrypted }) .await; let err = result.unwrap_err(); assert!( @@ -438,7 +434,7 @@ async fn external_key_vault() -> Result<()> { // Setup: initialize db. let (client, datakeys) = init_client().await?; datakeys - .insert_one(load_testdata("external/external-key.json")?, None) + .insert_one(load_testdata("external/external-key.json")?) .await?; // Setup: test options. @@ -478,7 +474,7 @@ async fn external_key_vault() -> Result<()> { let result = client_encrypted .database("db") .collection::("coll") - .insert_one(doc! { "encrypted": "test" }, None) + .insert_one(doc! { "encrypted": "test" }) .await; if with_external_key_vault { let err = result.unwrap_err(); @@ -543,7 +539,7 @@ async fn bson_size_limits() -> Result<()> { .validator(doc! { "$jsonSchema": load_testdata("limits/limits-schema.json")? }) .await?; datakeys - .insert_one(load_testdata("limits/limits-key.json")?, None) + .insert_one(load_testdata("limits/limits-key.json")?) .await?; // Setup: encrypted client. @@ -563,37 +559,31 @@ async fn bson_size_limits() -> Result<()> { // Tests // Test operation 1 - coll.insert_one( - doc! { - "_id": "over_2mib_under_16mib", - "unencrypted": "a".repeat(2097152), - }, - None, - ) + coll.insert_one(doc! { + "_id": "over_2mib_under_16mib", + "unencrypted": "a".repeat(2097152), + }) .await?; // Test operation 2 let mut doc: Document = load_testdata("limits/limits-doc.json")?; doc.insert("_id", "encryption_exceeds_2mib"); doc.insert("unencrypted", "a".repeat(2_097_152 - 2_000)); - coll.insert_one(doc, None).await?; + coll.insert_one(doc).await?; // Test operation 3 let value = "a".repeat(2_097_152); events.clear_events(Duration::from_millis(500)).await; - coll.insert_many( - vec![ - doc! { - "_id": "over_2mib_1", - "unencrypted": value.clone(), - }, - doc! { - "_id": "over_2mib_2", - "unencrypted": value, - }, - ], - None, - ) + coll.insert_many(vec![ + doc! { + "_id": "over_2mib_1", + "unencrypted": value.clone(), + }, + doc! { + "_id": "over_2mib_2", + "unencrypted": value, + }, + ]) .await?; let inserts = events .collect_events(Duration::from_millis(500), |ev| { @@ -613,7 +603,7 @@ async fn bson_size_limits() -> Result<()> { let mut doc2 = doc.clone(); doc2.insert("_id", "encryption_exceeds_2mib_2"); events.clear_events(Duration::from_millis(500)).await; - coll.insert_many(vec![doc, doc2], None).await?; + coll.insert_many(vec![doc, doc2]).await?; let inserts = events .collect_events(Duration::from_millis(500), |ev| { let ev = match ev.as_command_started_event() { @@ -630,13 +620,13 @@ async fn bson_size_limits() -> Result<()> { "_id": "under_16mib", "unencrypted": "a".repeat(16_777_216 - 2_000), }; - coll.insert_one(doc, None).await?; + coll.insert_one(doc).await?; // Test operation 6 let mut doc: Document = load_testdata("limits/limits-doc.json")?; doc.insert("_id", "encryption_exceeds_16mib"); doc.insert("unencrypted", "a".repeat(16_777_216 - 2_000)); - let result = coll.insert_one(doc, None).await; + let result = coll.insert_one(doc).await; let err = result.unwrap_err(); assert!( matches!(*err.kind, ErrorKind::Write(_)), @@ -682,7 +672,7 @@ async fn views_prohibited() -> Result<()> { let result = client_encrypted .database("db") .collection::("view") - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await; let err = result.unwrap_err(); assert!( @@ -759,7 +749,7 @@ async fn run_corpus_test(local_schema: bool) -> Result<()> { "corpus/corpus-key-gcp.json", "corpus/corpus-key-kmip.json", ] { - datakeys.insert_one(load_testdata(f)?, None).await?; + datakeys.insert_one(load_testdata(f)?).await?; } // Setup: encrypted client and manual encryption. @@ -856,9 +846,9 @@ async fn run_corpus_test(local_schema: bool) -> Result<()> { let coll = client_encrypted .database("db") .collection::("coll"); - let id = coll.insert_one(corpus_copied, None).await?.inserted_id; + let id = coll.insert_one(corpus_copied).await?.inserted_id; let corpus_decrypted = coll - .find_one(doc! { "_id": id.clone() }, None) + .find_one(doc! { "_id": id.clone() }) .await? .expect("document lookup failed"); assert_eq!(corpus, corpus_decrypted); @@ -868,7 +858,7 @@ async fn run_corpus_test(local_schema: bool) -> Result<()> { let corpus_encrypted_actual = client .database("db") .collection::("coll") - .find_one(doc! { "_id": id }, None) + .find_one(doc! { "_id": id }) .await? .expect("encrypted document lookup failed"); for (name, field) in &corpus_encrypted_expected { @@ -1281,7 +1271,7 @@ async fn bypass_mongocryptd_via_shared_library() -> Result<()> { client_encrypted .database("db") .collection::("coll") - .insert_one(doc! { "unencrypted": "test" }, None) + .insert_one(doc! { "unencrypted": "test" }) .await?; // Test: mongocryptd not spawned. assert!(!client_encrypted.mongocryptd_spawned().await); @@ -1322,7 +1312,7 @@ async fn bypass_mongocryptd_via_bypass_spawn() -> Result<()> { let err = client_encrypted .database("db") .collection::("coll") - .insert_one(doc! { "encrypted": "test" }, None) + .insert_one(doc! { "encrypted": "test" }) .await .unwrap_err(); assert!(err.is_server_selection_error(), "unexpected error: {}", err); @@ -1357,7 +1347,7 @@ async fn bypass_mongocryptd_unencrypted_insert(bypass: Bypass) -> Result<()> { client_encrypted .database("db") .collection::("coll") - .insert_one(doc! { "unencrypted": "test" }, None) + .insert_one(doc! { "unencrypted": "test" }) .await?; // Test: mongocryptd not spawned. assert!(!client_encrypted.mongocryptd_spawned().await); @@ -1528,12 +1518,8 @@ impl DeadlockTestCase { client_keyvault .database("keyvault") .collection::("datakeys") - .insert_one( - load_testdata("external/external-key.json")?, - InsertOneOptions::builder() - .write_concern(WriteConcern::majority()) - .build(), - ) + .insert_one(load_testdata("external/external-key.json")?) + .write_concern(WriteConcern::majority()) .await?; client_test .database("db") @@ -1579,20 +1565,20 @@ impl DeadlockTestCase { client_test .database("db") .collection::("coll") - .insert_one(doc! { "_id": 0, "encrypted": ciphertext }, None) + .insert_one(doc! { "_id": 0, "encrypted": ciphertext }) .await?; } else { client_encrypted .database("db") .collection::("coll") - .insert_one(doc! { "_id": 0, "encrypted": "string0" }, None) + .insert_one(doc! { "_id": 0, "encrypted": "string0" }) .await?; } let found = client_encrypted .database("db") .collection::("coll") - .find_one(doc! { "_id": 0 }, None) + .find_one(doc! { "_id": 0 }) .await?; assert_eq!(found, Some(doc! { "_id": 0, "encrypted": "string0" })); @@ -2005,7 +1991,7 @@ async fn explicit_encryption_case_1() -> Result<()> { .contention_factor(0) .await?; enc_coll - .insert_one(doc! { "encryptedIndexed": insert_payload }, None) + .insert_one(doc! { "encryptedIndexed": insert_payload }) .await?; let find_payload = testdata @@ -2019,7 +2005,7 @@ async fn explicit_encryption_case_1() -> Result<()> { .contention_factor(0) .await?; let found: Vec<_> = enc_coll - .find(doc! { "encryptedIndexed": find_payload }, None) + .find(doc! { "encryptedIndexed": find_payload }) .await? .try_collect() .await?; @@ -2063,7 +2049,7 @@ async fn explicit_encryption_case_2() -> Result<()> { .contention_factor(10) .await?; enc_coll - .insert_one(doc! { "encryptedIndexed": insert_payload }, None) + .insert_one(doc! { "encryptedIndexed": insert_payload }) .await?; } @@ -2078,7 +2064,7 @@ async fn explicit_encryption_case_2() -> Result<()> { .contention_factor(0) .await?; let found: Vec<_> = enc_coll - .find(doc! { "encryptedIndexed": find_payload }, None) + .find(doc! { "encryptedIndexed": find_payload }) .await? .try_collect() .await?; @@ -2098,7 +2084,7 @@ async fn explicit_encryption_case_2() -> Result<()> { .contention_factor(10) .await?; let found: Vec<_> = enc_coll - .find(doc! { "encryptedIndexed": find_payload2 }, None) + .find(doc! { "encryptedIndexed": find_payload2 }) .await? .try_collect() .await?; @@ -2138,14 +2124,11 @@ async fn explicit_encryption_case_3() -> Result<()> { ) .await?; enc_coll - .insert_one( - doc! { "_id": 1, "encryptedUnindexed": insert_payload }, - None, - ) + .insert_one(doc! { "_id": 1, "encryptedUnindexed": insert_payload }) .await?; let found: Vec<_> = enc_coll - .find(doc! { "_id": 1 }, None) + .find(doc! { "_id": 1 }) .await? .try_collect() .await?; @@ -2262,12 +2245,8 @@ async fn explicit_encryption_setup() -> Result("datakeys") - .insert_one( - key1_document, - InsertOneOptions::builder() - .write_concern(WriteConcern::majority()) - .build(), - ) + .insert_one(key1_document) + .write_concern(WriteConcern::majority()) .await?; let client_encryption = ClientEncryption::new( @@ -2489,7 +2468,7 @@ async fn decryption_events_decrypt_error() -> Result<()> { None => return Ok(()), }; td.decryption_events - .insert_one(doc! { "encrypted": td.malformed_ciphertext }, None) + .insert_one(doc! { "encrypted": td.malformed_ciphertext }) .await?; let err = td.decryption_events.aggregate(vec![]).await.unwrap_err(); assert!(err.is_csfle_error()); @@ -2520,7 +2499,7 @@ async fn decryption_events_decrypt_success() -> Result<()> { None => return Ok(()), }; td.decryption_events - .insert_one(doc! { "encrypted": td.ciphertext }, None) + .insert_one(doc! { "encrypted": td.ciphertext }) .await?; td.decryption_events.aggregate(vec![]).await?; let guard = td.ev_handler.succeeded.lock().unwrap(); @@ -2862,7 +2841,7 @@ async fn bypass_mongocryptd_client() -> Result<()> { client_encrypted .database("db") .collection::("coll") - .insert_one(doc! { "unencrypted": "test" }, None) + .insert_one(doc! { "unencrypted": "test" }) .await?; assert!(!client_encrypted.has_mongocryptd_client().await); @@ -2929,7 +2908,7 @@ async fn auto_encryption_keys(master_key: MasterKey) -> Result<()> { .await .1?; let coll = db.collection::("case_1"); - let result = coll.insert_one(doc! { "ssn": "123-45-6789" }, None).await; + let result = coll.insert_one(doc! { "ssn": "123-45-6789" }).await; assert!( result.as_ref().unwrap_err().code() == Some(121), "Expected error 121 (failed validation), got {:?}", @@ -2988,8 +2967,7 @@ async fn auto_encryption_keys(master_key: MasterKey) -> Result<()> { }; let encrypted_payload = ce.encrypt("123-45-6789", key, Algorithm::Unindexed).await?; let coll = db.collection::("case_1"); - coll.insert_one(doc! { "ssn": encrypted_payload }, None) - .await?; + coll.insert_one(doc! { "ssn": encrypted_payload }).await?; Ok(()) } @@ -3106,12 +3084,8 @@ async fn range_explicit_encryption_test( .await?; datakeys_collection - .insert_one( - key1_document, - InsertOneOptions::builder() - .write_concern(WriteConcern::majority()) - .build(), - ) + .insert_one(key1_document) + .write_concern(WriteConcern::majority()) .await?; let key_vault_client = TestClient::new().await; @@ -3152,13 +3126,10 @@ async fn range_explicit_encryption_test( .await?; explicit_encryption_collection - .insert_one( - doc! { - &key: encrypted_value, - "_id": id as i32, - }, - None, - ) + .insert_one(doc! { + &key: encrypted_value, + "_id": id as i32, + }) .await?; } @@ -3206,7 +3177,8 @@ async fn range_explicit_encryption_test( .await?; let docs: Vec = explicit_encryption_collection - .find(find_payload, find_options.clone()) + .find(find_payload) + .with_options(find_options.clone()) .await? .try_collect() .await?; @@ -3228,7 +3200,8 @@ async fn range_explicit_encryption_test( let docs: Vec = encrypted_client .database("db") .collection("explicit_encryption") - .find(find_payload, find_options.clone()) + .find(find_payload) + .with_options(find_options.clone()) .await? .try_collect() .await?; @@ -3249,7 +3222,8 @@ async fn range_explicit_encryption_test( let docs: Vec = encrypted_client .database("db") .collection("explicit_encryption") - .find(find_payload, find_options.clone()) + .find(find_payload) + .with_options(find_options.clone()) .await? .try_collect() .await?; @@ -3266,7 +3240,8 @@ async fn range_explicit_encryption_test( let docs: Vec = encrypted_client .database("db") .collection("explicit_encryption") - .find(doc! { "$expr": find_payload }, find_options.clone()) + .find(doc! { "$expr": find_payload }) + .with_options(find_options.clone()) .await? .try_collect() .await?; @@ -3426,24 +3401,18 @@ async fn fle2_example() -> Result<()> { // Encrypt an insert. encrypted_coll - .insert_one( - doc! { - "_id": 1, - "encryptedIndexed": "indexedValue", - "encryptedUnindexed": "unindexedValue", - }, - None, - ) + .insert_one(doc! { + "_id": 1, + "encryptedIndexed": "indexedValue", + "encryptedUnindexed": "unindexedValue", + }) .await?; // Encrypt a find. let found = encrypted_coll - .find_one( - doc! { - "encryptedIndexed": "indexedValue", - }, - None, - ) + .find_one(doc! { + "encryptedIndexed": "indexedValue", + }) .await? .unwrap(); assert_eq!("indexedValue", found.get_str("encryptedIndexed")?); @@ -3453,10 +3422,7 @@ async fn fle2_example() -> Result<()> { let unencrypted_coll = test_client .database("docsExamples") .collection::("encrypted"); - let found = unencrypted_coll - .find_one(doc! { "_id": 1 }, None) - .await? - .unwrap(); + let found = unencrypted_coll.find_one(doc! { "_id": 1 }).await?.unwrap(); assert_eq!( Some(ElementType::Binary), found.get("encryptedIndexed").map(Bson::element_type) diff --git a/src/test/cursor.rs b/src/test/cursor.rs index 4eda10693..94891e0e6 100644 --- a/src/test/cursor.rs +++ b/src/test/cursor.rs @@ -33,20 +33,16 @@ async fn tailable_cursor() { ) .await; - coll.insert_many((0..5).map(|i| doc! { "_id": i }), None) + coll.insert_many((0..5).map(|i| doc! { "_id": i })) .await .unwrap(); let await_time = Duration::from_millis(500); let mut cursor = coll - .find( - None, - FindOptions::builder() - .cursor_type(CursorType::TailableAwait) - .max_await_time(await_time) - .build(), - ) + .find(doc! {}) + .cursor_type(CursorType::TailableAwait) + .max_await_time(await_time) .await .unwrap(); @@ -70,7 +66,7 @@ async fn tailable_cursor() { }; runtime::spawn(async move { - coll.insert_one(doc! { "_id": 5 }, None).await.unwrap(); + coll.insert_one(doc! { "_id": 5 }).await.unwrap(); }); let delay = tokio::time::sleep(await_time); @@ -93,13 +89,15 @@ async fn session_cursor_next() { .create_fresh_collection(function_name!(), function_name!(), None) .await; - coll.insert_many_with_session((0..5).map(|i| doc! { "_id": i }), None, &mut session) + coll.insert_many((0..5).map(|i| doc! { "_id": i })) + .session(&mut session) .await .unwrap(); - let opts = FindOptions::builder().batch_size(1).build(); let mut cursor = coll - .find_with_session(None, opts, &mut session) + .find(doc! {}) + .batch_size(1) + .session(&mut session) .await .unwrap(); @@ -122,25 +120,19 @@ async fn batch_exhaustion() { None, ) .await; - coll.insert_many( - vec![ - doc! { "foo": 1 }, - doc! { "foo": 2 }, - doc! { "foo": 3 }, - doc! { "foo": 4 }, - doc! { "foo": 5 }, - doc! { "foo": 6 }, - ], - None, - ) + coll.insert_many(vec![ + doc! { "foo": 1 }, + doc! { "foo": 2 }, + doc! { "foo": 3 }, + doc! { "foo": 4 }, + doc! { "foo": 5 }, + doc! { "foo": 6 }, + ]) .await .unwrap(); // Start a find where batch size will line up with limit. - let cursor = coll - .find(None, FindOptions::builder().batch_size(2).limit(4).build()) - .await - .unwrap(); + let cursor = coll.find(doc! {}).batch_size(2).limit(4).await.unwrap(); let v: Vec<_> = cursor.try_collect().await.unwrap(); assert_eq!(4, v.len()); @@ -195,14 +187,18 @@ async fn borrowed_deserialization() { Doc { id: 5, foo: "1" }, ]; - coll.insert_many(&docs, None).await.unwrap(); + coll.insert_many(&docs).await.unwrap(); let options = FindOptions::builder() .batch_size(2) .sort(doc! { "_id": 1 }) .build(); - let mut cursor = coll.find(None, options.clone()).await.unwrap(); + let mut cursor = coll + .find(doc! {}) + .with_options(options.clone()) + .await + .unwrap(); let mut i = 0; while cursor.advance().await.unwrap() { @@ -213,7 +209,9 @@ async fn borrowed_deserialization() { let mut session = client.start_session().await.unwrap(); let mut cursor = coll - .find_with_session(None, options.clone(), &mut session) + .find(doc! {}) + .with_options(options.clone()) + .session(&mut session) .await .unwrap(); @@ -233,19 +231,14 @@ async fn session_cursor_with_type() { let coll = client.database("db").collection("coll"); coll.drop().session(&mut session).await.unwrap(); - coll.insert_many_with_session( - vec![doc! { "x": 1 }, doc! { "x": 2 }, doc! { "x": 3 }], - None, - &mut session, - ) - .await - .unwrap(); - - let mut cursor: crate::SessionCursor = coll - .find_with_session(doc! {}, None, &mut session) + coll.insert_many(vec![doc! { "x": 1 }, doc! { "x": 2 }, doc! { "x": 3 }]) + .session(&mut session) .await .unwrap(); + let mut cursor: crate::SessionCursor = + coll.find(doc! {}).session(&mut session).await.unwrap(); + let _ = cursor.next(&mut session).await.unwrap().unwrap(); let mut cursor_with_type: crate::SessionCursor = cursor.with_type(); @@ -259,23 +252,17 @@ async fn cursor_final_batch() { let coll = client .create_fresh_collection("test_cursor_final_batch", "test", None) .await; - coll.insert_many( - vec![ - doc! { "foo": 1 }, - doc! { "foo": 2 }, - doc! { "foo": 3 }, - doc! { "foo": 4 }, - doc! { "foo": 5 }, - ], - None, - ) + coll.insert_many(vec![ + doc! { "foo": 1 }, + doc! { "foo": 2 }, + doc! { "foo": 3 }, + doc! { "foo": 4 }, + doc! { "foo": 5 }, + ]) .await .unwrap(); - let mut cursor = coll - .find(None, FindOptions::builder().batch_size(3).build()) - .await - .unwrap(); + let mut cursor = coll.find(doc! {}).batch_size(3).await.unwrap(); let mut found = 0; while cursor.advance().await.unwrap() { found += 1; diff --git a/src/test/db.rs b/src/test/db.rs index b699294d3..c8e82ce24 100644 --- a/src/test/db.rs +++ b/src/test/db.rs @@ -52,7 +52,7 @@ async fn list_collections() { for coll_name in coll_names { db.collection(coll_name) - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); } @@ -80,7 +80,7 @@ async fn list_collections_filter() { let coll_names = &["bar", "baz", "foo"]; for coll_name in coll_names { db.collection(coll_name) - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); } @@ -119,7 +119,7 @@ async fn list_collection_names() { for coll in expected_colls { db.collection(coll) - .insert_one(doc! { "x": 1 }, None) + .insert_one(doc! { "x": 1 }) .await .unwrap(); } diff --git a/src/test/documentation_examples.rs b/src/test/documentation_examples.rs index 07a4e3bd2..00145b913 100644 --- a/src/test/documentation_examples.rs +++ b/src/test/documentation_examples.rs @@ -7,7 +7,7 @@ use semver::Version; use crate::{ bson::{doc, Bson}, error::Result, - options::{ClientOptions, FindOptions, ServerApi, ServerApiVersion}, + options::{ClientOptions, ServerApi, ServerApiVersion}, test::{log_uncaptured, TestClient, DEFAULT_URI}, Client, Collection, @@ -39,26 +39,23 @@ async fn insert_examples(collection: &Collection) -> Result<()> { // Start Example 1 collection - .insert_one( - doc! { - "item": "canvas", - "qty": 100, - "tags": ["cotton"], - "size": { - "h": 28, - "w": 35.5, - "uom": "cm", - } - }, - None, - ) + .insert_one(doc! { + "item": "canvas", + "qty": 100, + "tags": ["cotton"], + "size": { + "h": 28, + "w": 35.5, + "uom": "cm", + } + }) .await?; // End Example 1 assert_coll_count!(collection, 1); // Start Example 2 - let cursor = collection.find(doc! { "item": "canvas" }, None).await?; + let cursor = collection.find(doc! { "item": "canvas" }).await?; // End Example 2 assert_cursor_count!(cursor, 1); @@ -97,7 +94,7 @@ async fn insert_examples(collection: &Collection) -> Result<()> { }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 3 assert_coll_count!(collection, 4); @@ -162,33 +159,30 @@ async fn query_top_level_fields_examples(collection: &Collection) -> R }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 6 assert_coll_count!(collection, 5); // Start Example 7 - let cursor = collection.find(None, None).await?; + let cursor = collection.find(doc! {}).await?; // End Example 7 assert_cursor_count!(cursor, 5); // Start Example 9 - let cursor = collection.find(doc! { "status": "D" }, None).await?; + let cursor = collection.find(doc! { "status": "D" }).await?; // End Example 9 assert_cursor_count!(cursor, 2); // Start Example 10 let cursor = collection - .find( - doc! { - "status": { - "$in": ["A", "D"], - } - }, - None, - ) + .find(doc! { + "status": { + "$in": ["A", "D"], + } + }) .await?; // End Example 10 @@ -196,13 +190,10 @@ async fn query_top_level_fields_examples(collection: &Collection) -> R // Start Example 11 let cursor = collection - .find( - doc! { - "status": "A", - "qty": { "$lt": 30 }, - }, - None, - ) + .find(doc! { + "status": "A", + "qty": { "$lt": 30 }, + }) .await?; // End Example 11 @@ -210,17 +201,14 @@ async fn query_top_level_fields_examples(collection: &Collection) -> R // Start Example 12 let cursor = collection - .find( - doc! { - "$or": [ - { "status": "A" }, - { - "qty": { "$lt": 30 }, - } - ], - }, - None, - ) + .find(doc! { + "$or": [ + { "status": "A" }, + { + "qty": { "$lt": 30 }, + } + ], + }) .await?; // End Example 12 @@ -228,20 +216,17 @@ async fn query_top_level_fields_examples(collection: &Collection) -> R // Start Example 13 let cursor = collection - .find( - doc! { - "status": "A", - "$or": [ - { - "qty": { "$lt": 30 }, - }, - { - "item": { "$regex": "^p" }, - }, - ], - }, - None, - ) + .find(doc! { + "status": "A", + "$or": [ + { + "qty": { "$lt": 30 }, + }, + { + "item": { "$regex": "^p" }, + }, + ], + }) .await?; // End Example 13 @@ -307,23 +292,20 @@ async fn query_embedded_documents_examples(collection: &Collection) -> }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 14 assert_coll_count!(collection, 5); // Start Example 15 let cursor = collection - .find( - doc! { - "size": { - "h": 14, - "w": 21, - "uom": "cm", - }, + .find(doc! { + "size": { + "h": 14, + "w": 21, + "uom": "cm", }, - None, - ) + }) .await?; // End Example 15 @@ -331,35 +313,29 @@ async fn query_embedded_documents_examples(collection: &Collection) -> // Start Example 16 let cursor = collection - .find( - doc! { - "size": { - "w": 21, - "h": 14, - "uom": "cm", - }, + .find(doc! { + "size": { + "w": 21, + "h": 14, + "uom": "cm", }, - None, - ) + }) .await?; // End Example 16 assert_cursor_count!(cursor, 0); // Start Example 17 - let cursor = collection.find(doc! { "size.uom": "in" }, None).await?; + let cursor = collection.find(doc! { "size.uom": "in" }).await?; // End Example 17 assert_cursor_count!(cursor, 2); // Start Example 18 let cursor = collection - .find( - doc! { - "size.h": { "$lt": 15 }, - }, - None, - ) + .find(doc! { + "size.h": { "$lt": 15 }, + }) .await?; // End Example 18 @@ -367,14 +343,11 @@ async fn query_embedded_documents_examples(collection: &Collection) -> // Start Example 19 let cursor = collection - .find( - doc! { - "size.h": { "$lt": 15 }, - "size.uom": "in", - "status": "D", - }, - None, - ) + .find(doc! { + "size.h": { "$lt": 15 }, + "size.uom": "in", + "status": "D", + }) .await?; // End Example 19 @@ -420,19 +393,16 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 20 assert_coll_count!(collection, 5); // Start Example 21 let cursor = collection - .find( - doc! { - "tags": ["red", "blank"], - }, - None, - ) + .find(doc! { + "tags": ["red", "blank"], + }) .await?; // End Example 21 @@ -440,14 +410,11 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 22 let cursor = collection - .find( - doc! { - "tags": { - "$all": ["red", "blank"], - } - }, - None, - ) + .find(doc! { + "tags": { + "$all": ["red", "blank"], + } + }) .await?; // End Example 22 @@ -455,12 +422,9 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 23 let cursor = collection - .find( - doc! { - "tags": "red", - }, - None, - ) + .find(doc! { + "tags": "red", + }) .await?; // End Example 23 @@ -468,12 +432,9 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 24 let cursor = collection - .find( - doc! { - "dim_cm": { "$gt": 25 }, - }, - None, - ) + .find(doc! { + "dim_cm": { "$gt": 25 }, + }) .await?; // End Example 24 @@ -481,15 +442,12 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 25 let cursor = collection - .find( - doc! { - "dim_cm": { - "$gt": 15, - "$lt": 20, - }, + .find(doc! { + "dim_cm": { + "$gt": 15, + "$lt": 20, }, - None, - ) + }) .await?; // End Example 25 @@ -497,17 +455,14 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 26 let cursor = collection - .find( - doc! { - "dim_cm": { - "$elemMatch": { - "$gt": 22, - "$lt": 30, - } - }, + .find(doc! { + "dim_cm": { + "$elemMatch": { + "$gt": 22, + "$lt": 30, + } }, - None, - ) + }) .await?; // End Example 26 @@ -515,12 +470,9 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 27 let cursor = collection - .find( - doc! { - "dim_cm.1": { "$gt": 25 }, - }, - None, - ) + .find(doc! { + "dim_cm.1": { "$gt": 25 }, + }) .await?; // End Example 27 @@ -528,12 +480,9 @@ async fn query_arrays_examples(collection: &Collection) -> Result<()> // Start Example 28 let cursor = collection - .find( - doc! { - "tags": { "$size": 3 }, - }, - None, - ) + .find(doc! { + "tags": { "$size": 3 }, + }) .await?; // End Example 28 @@ -581,22 +530,19 @@ async fn query_array_embedded_documents_examples(collection: &Collection }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 38 assert_coll_count!(collection, 2); // Start Example 39 let cursor = collection - .find( - doc! { - "item": Bson::Null, - }, - None, - ) + .find(doc! { + "item": Bson::Null, + }) .await?; // End Example 39 @@ -749,12 +671,9 @@ async fn query_null_or_missing_fields_examples(collection: &Collection // Start Example 40 let cursor = collection - .find( - doc! { - "item": { "$type": 10 }, - }, - None, - ) + .find(doc! { + "item": { "$type": 10 }, + }) .await?; // End Example 40 @@ -762,12 +681,9 @@ async fn query_null_or_missing_fields_examples(collection: &Collection // Start Example 41 let cursor = collection - .find( - doc! { - "item": { "$exists": false }, - }, - None, - ) + .find(doc! { + "item": { "$exists": false }, + }) .await?; // End Example 41 @@ -863,39 +779,30 @@ async fn projection_examples(collection: &Collection) -> Result<()> { }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 42 assert_coll_count!(collection, 5); // Start Example 43 let cursor = collection - .find( - doc! { - "status": "A", - }, - None, - ) + .find(doc! { + "status": "A", + }) .await?; // End Example 43 assert_cursor_count!(cursor, 3); // Start Example 44 - let options = FindOptions::builder() + let cursor = collection + .find(doc! { + "status": "A", + }) .projection(doc! { "item": 1, "status": 1, }) - .build(); - - let cursor = collection - .find( - doc! { - "status": "A", - }, - options, - ) .await?; // End Example 44 @@ -908,21 +815,15 @@ async fn projection_examples(collection: &Collection) -> Result<()> { }); // Start Example 45 - let options = FindOptions::builder() + let cursor = collection + .find(doc! { + "status": "A", + }) .projection(doc! { "item": 1, "status": 1, "_id": 0, }) - .build(); - - let cursor = collection - .find( - doc! { - "status": "A", - }, - options, - ) .await?; // End Example 45 @@ -935,20 +836,14 @@ async fn projection_examples(collection: &Collection) -> Result<()> { }); // Start Example 46 - let options = FindOptions::builder() + let cursor = collection + .find(doc! { + "status": "A", + }) .projection(doc! { "status": 0, "instock": 0, }) - .build(); - - let cursor = collection - .find( - doc! { - "status": "A", - }, - options, - ) .await?; // End Example 46 @@ -961,21 +856,15 @@ async fn projection_examples(collection: &Collection) -> Result<()> { }); // Start Example 47 - let options = FindOptions::builder() + let cursor = collection + .find(doc! { + "status": "A", + }) .projection(doc! { "item": 1, "status": 1, "size.uom": 1, }) - .build(); - - let cursor = collection - .find( - doc! { - "status": "A", - }, - options, - ) .await?; // End Example 47 @@ -994,19 +883,13 @@ async fn projection_examples(collection: &Collection) -> Result<()> { }); // Start Example 48 - let options = FindOptions::builder() + let cursor = collection + .find(doc! { + "status": "A", + }) .projection(doc! { "size.uom": 0, }) - .build(); - - let cursor = collection - .find( - doc! { - "status": "A", - }, - options, - ) .await?; // End Example 48 @@ -1025,21 +908,15 @@ async fn projection_examples(collection: &Collection) -> Result<()> { }); // Start Example 50 - let options = FindOptions::builder() + let cursor = collection + .find(doc! { + "status": "A", + }) .projection(doc! { "item": 1, "status": 1, "instock": { "$slice": -1 }, }) - .build(); - - let cursor = collection - .find( - doc! { - "status": "A", - }, - options, - ) .await?; // End Example 50 @@ -1165,7 +1042,7 @@ async fn update_examples(collection: &Collection) -> Result<()> { }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 51 assert_coll_count!(collection, 10); @@ -1186,10 +1063,7 @@ async fn update_examples(collection: &Collection) -> Result<()> { // End Example 52 run_on_each_doc!( - collection - .find(doc! { "item": "paper" }, None) - .await - .unwrap(), + collection.find(doc! { "item": "paper" }).await.unwrap(), doc, { let uom = doc.get_document("size").unwrap().get_str("uom").unwrap(); @@ -1221,12 +1095,9 @@ async fn update_examples(collection: &Collection) -> Result<()> { run_on_each_doc!( collection - .find( - doc! { - "qty": { "$lt": 50 }, - }, - None, - ) + .find(doc! { + "qty": { "$lt": 50 }, + }) .await .unwrap(), doc, @@ -1258,16 +1129,12 @@ async fn update_examples(collection: &Collection) -> Result<()> { }, ], }, - None, ) .await?; // End Example 54 run_on_each_doc!( - collection - .find(doc! { "item": "paper" }, None,) - .await - .unwrap(), + collection.find(doc! { "item": "paper" }).await.unwrap(), doc, { assert_eq!(doc.len(), 3); @@ -1340,7 +1207,7 @@ async fn delete_examples(collection: &Collection) -> Result<()> { }, ]; - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; // End Example 55 assert_coll_count!(collection, 5); @@ -1453,7 +1320,7 @@ async fn stable_api_examples() -> GenericResult<()> { doc! { "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : iso_date("2021-02-15T12:05:10Z")? }, doc! { "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : iso_date("2021-02-15T14:12:12Z")? }, doc! { "_id" : 8, "item" : "abc", "price" : 10, "quantity" : 5, "date" : iso_date("2021-03-16T20:20:13Z")? } - ], None).await?; + ]).await?; // End Versioned API Example 5 // Start Versioned API Example 6 @@ -1635,16 +1502,13 @@ async fn run_command_examples() -> Result<()> { let db = client.database("run_command_examples"); db.drop().await?; db.collection::("restaurants") - .insert_one( - doc! { - "name": "Chez Panisse", - "city": "Oakland", - "state": "California", - "country": "United States", - "rating": 4.4, - }, - None, - ) + .insert_one(doc! { + "name": "Chez Panisse", + "city": "Oakland", + "state": "California", + "country": "United States", + "rating": 4.4, + }) .await?; #[allow(unused)] @@ -1665,46 +1529,40 @@ async fn index_examples() -> Result<()> { let db = client.database("index_examples"); db.drop().await?; db.collection::("records") - .insert_many( - vec![ - doc! { - "student": "Marty McFly", - "classYear": 1986, - "school": "Hill Valley High", - "score": 56.5, - }, - doc! { - "student": "Ferris F. Bueller", - "classYear": 1987, - "school": "Glenbrook North High", - "status": "Suspended", - "score": 76.0, - }, - ], - None, - ) + .insert_many(vec![ + doc! { + "student": "Marty McFly", + "classYear": 1986, + "school": "Hill Valley High", + "score": 56.5, + }, + doc! { + "student": "Ferris F. Bueller", + "classYear": 1987, + "school": "Glenbrook North High", + "status": "Suspended", + "score": 76.0, + }, + ]) .await?; db.collection::("restaurants") - .insert_many( - vec![ - doc! { - "name": "Chez Panisse", - "city": "Oakland", - "state": "California", - "country": "United States", - "rating": 4.4, - }, - doc! { - "name": "Eleven Madison Park", - "cuisine": "French", - "city": "New York City", - "state": "New York", - "country": "United States", - "rating": 7.1, - }, - ], - None, - ) + .insert_many(vec![ + doc! { + "name": "Chez Panisse", + "city": "Oakland", + "state": "California", + "country": "United States", + "rating": 4.4, + }, + doc! { + "name": "Eleven Madison Park", + "cuisine": "French", + "city": "New York City", + "state": "New York", + "country": "United States", + "rating": 7.1, + }, + ]) .await?; use crate::IndexModel; @@ -1747,7 +1605,7 @@ async fn change_streams_examples() -> Result<()> { db.drop().await?; let inventory = db.collection::("inventory"); // Populate an item so the collection exists for the change stream to watch. - inventory.insert_one(doc! {}, None).await?; + inventory.insert_one(doc! {}).await?; // Background writer thread so that the `stream.next()` calls return something. let (tx, mut rx) = tokio::sync::oneshot::channel(); @@ -1757,7 +1615,7 @@ async fn change_streams_examples() -> Result<()> { loop { tokio::select! { _ = interval.tick() => { - writer_inventory.insert_one(doc! {}, None).await?; + writer_inventory.insert_one(doc! {}).await?; } _ = &mut rx => break, } @@ -1832,12 +1690,12 @@ async fn convenient_transaction_examples() -> Result<()> { client .database("mydb1") .collection::("foo") - .insert_one(doc! { "abc": 0}, None) + .insert_one(doc! { "abc": 0}) .await?; client .database("mydb2") .collection::("bar") - .insert_one(doc! { "xyz": 0}, None) + .insert_one(doc! { "xyz": 0}) .await?; // Step 1: Define the callback that specifies the sequence of operations to perform inside the @@ -1854,10 +1712,12 @@ async fn convenient_transaction_examples() -> Result<()> { // Important: You must pass the session to the operations. collection_one - .insert_one_with_session(doc! { "abc": 1 }, None, session) + .insert_one(doc! { "abc": 1 }) + .session(&mut *session) .await?; collection_two - .insert_one_with_session(doc! { "xyz": 999 }, None, session) + .insert_one(doc! { "xyz": 999 }) + .session(session) .await?; Ok(()) diff --git a/src/test/documentation_examples/aggregation_data.rs b/src/test/documentation_examples/aggregation_data.rs index d32476c0d..b4fd5d449 100644 --- a/src/test/documentation_examples/aggregation_data.rs +++ b/src/test/documentation_examples/aggregation_data.rs @@ -13,242 +13,233 @@ pub(crate) async fn populate(db: &Database) -> GenericResult<()> { let date_20180111 = DateTime::parse_rfc3339_str("2018-01-11T07:15:00.000Z")?; db.collection("sales") - .insert_many( - vec![ - doc! { - "date": date_20180208, - "items": [ - doc! { - "fruit": "kiwi", - "quantity": 2, - "price": 0.5, - }, - doc! { - "fruit": "apple", - "quantity": 1, - "price": 1.0, - }, - ], - }, - doc! { - "date": date_20180109, - "items": [ - doc! { - "fruit": "banana", - "quantity": 8, - "price": 1.0, - }, - doc! { - "fruit": "apple", - "quantity": 1, - "price": 1.0, - }, - doc! { - "fruit": "papaya", - "quantity": 1, - "price": 4.0, - }, - ], - }, - doc! { - "date": date_20180127, - "items": [ - doc! { - "fruit": "banana", - "quantity": 1, - "price": 1.0, - }, - ], - }, - doc! { - "date": date_20180203, - "items": [ - doc! { - "fruit": "banana", - "quantity": 1, - "price": 1.0, - }, - ], - }, - doc! { - "date": date_20180205, - "items": [ - doc! { - "fruit": "banana", - "quantity": 1, - "price": 1.0, - }, - doc! { - "fruit": "mango", - "quantity": 2, - "price": 2.0, - }, - doc! { - "fruit": "apple", - "quantity": 1, - "price": 1.0, - }, - ], - }, - doc! { - "date": date_20180111, - "items": [ - doc! { - "fruit": "banana", - "quantity": 1, - "price": 1.0, - }, - doc! { - "fruit": "apple", - "quantity": 1, - "price": 1.0, - }, - doc! { - "fruit": "papaya", - "quantity": 3, - "price": 4.0, - }, - ], - }, - ], - None, - ) + .insert_many(vec![ + doc! { + "date": date_20180208, + "items": [ + doc! { + "fruit": "kiwi", + "quantity": 2, + "price": 0.5, + }, + doc! { + "fruit": "apple", + "quantity": 1, + "price": 1.0, + }, + ], + }, + doc! { + "date": date_20180109, + "items": [ + doc! { + "fruit": "banana", + "quantity": 8, + "price": 1.0, + }, + doc! { + "fruit": "apple", + "quantity": 1, + "price": 1.0, + }, + doc! { + "fruit": "papaya", + "quantity": 1, + "price": 4.0, + }, + ], + }, + doc! { + "date": date_20180127, + "items": [ + doc! { + "fruit": "banana", + "quantity": 1, + "price": 1.0, + }, + ], + }, + doc! { + "date": date_20180203, + "items": [ + doc! { + "fruit": "banana", + "quantity": 1, + "price": 1.0, + }, + ], + }, + doc! { + "date": date_20180205, + "items": [ + doc! { + "fruit": "banana", + "quantity": 1, + "price": 1.0, + }, + doc! { + "fruit": "mango", + "quantity": 2, + "price": 2.0, + }, + doc! { + "fruit": "apple", + "quantity": 1, + "price": 1.0, + }, + ], + }, + doc! { + "date": date_20180111, + "items": [ + doc! { + "fruit": "banana", + "quantity": 1, + "price": 1.0, + }, + doc! { + "fruit": "apple", + "quantity": 1, + "price": 1.0, + }, + doc! { + "fruit": "papaya", + "quantity": 3, + "price": 4.0, + }, + ], + }, + ]) .await?; db.collection("airlines") - .insert_many( - vec![ - doc! { - "airline": 17, - "name": "Air Canada", - "alias": "AC", - "iata": "ACA", - "icao": "AIR CANADA", - "active": "Y", - "country": "Canada", - "base": "TAL", - }, - doc! { - "airline": 18, - "name": "Turkish Airlines", - "alias": "YK", - "iata": "TRK", - "icao": "TURKISH", - "active": "Y", - "country": "Turkey", - "base": "AET", - }, - doc! { - "airline": 22, - "name": "Saudia", - "alias": "SV", - "iata": "SVA", - "icao": "SAUDIA", - "active": "Y", - "country": "Saudi Arabia", - "base": "JSU", - }, - doc! { - "airline": 29, - "name": "Finnair", - "alias": "AY", - "iata": "FIN", - "icao": "FINNAIR", - "active": "Y", - "country": "Finland", - "base": "JMZ", - }, - doc! { - "airline": 34, - "name": "Afric'air Express", - "alias": "", - "iata": "AAX", - "icao": "AFREX", - "active": "N", - "country": "Ivory Coast", - "base": "LOK", - }, - doc! { - "airline": 37, - "name": "Artem-Avia", - "alias": "", - "iata": "ABA", - "icao": "ARTEM-AVIA", - "active": "N", - "country": "Ukraine", - "base": "JBR", - }, - doc! { - "airline": 38, - "name": "Lufthansa", - "alias": "LH", - "iata": "DLH", - "icao": "LUFTHANSA", - "active": "Y", - "country": "Germany", - "base": "CYS", - }, - ], - None, - ) + .insert_many(vec![ + doc! { + "airline": 17, + "name": "Air Canada", + "alias": "AC", + "iata": "ACA", + "icao": "AIR CANADA", + "active": "Y", + "country": "Canada", + "base": "TAL", + }, + doc! { + "airline": 18, + "name": "Turkish Airlines", + "alias": "YK", + "iata": "TRK", + "icao": "TURKISH", + "active": "Y", + "country": "Turkey", + "base": "AET", + }, + doc! { + "airline": 22, + "name": "Saudia", + "alias": "SV", + "iata": "SVA", + "icao": "SAUDIA", + "active": "Y", + "country": "Saudi Arabia", + "base": "JSU", + }, + doc! { + "airline": 29, + "name": "Finnair", + "alias": "AY", + "iata": "FIN", + "icao": "FINNAIR", + "active": "Y", + "country": "Finland", + "base": "JMZ", + }, + doc! { + "airline": 34, + "name": "Afric'air Express", + "alias": "", + "iata": "AAX", + "icao": "AFREX", + "active": "N", + "country": "Ivory Coast", + "base": "LOK", + }, + doc! { + "airline": 37, + "name": "Artem-Avia", + "alias": "", + "iata": "ABA", + "icao": "ARTEM-AVIA", + "active": "N", + "country": "Ukraine", + "base": "JBR", + }, + doc! { + "airline": 38, + "name": "Lufthansa", + "alias": "LH", + "iata": "DLH", + "icao": "LUFTHANSA", + "active": "Y", + "country": "Germany", + "base": "CYS", + }, + ]) .await?; db.collection("air_alliances") - .insert_many( - vec![ - doc! { - "name": "Star Alliance", - "airlines": [ - "Air Canada", - "Avianca", - "Air China", - "Air New Zealand", - "Asiana Airlines", - "Brussels Airlines", - "Copa Airlines", - "Croatia Airlines", - "EgyptAir", - "TAP Portugal", - "United Airlines", - "Turkish Airlines", - "Swiss International Air Lines", - "Lufthansa", - ], - }, - doc! { - "name": "SkyTeam", - "airlines": [ - "Aerolinias Argentinas", - "Aeromexico", - "Air Europa", - "Air France", - "Alitalia", - "Delta Air Lines", - "Garuda Indonesia", - "Kenya Airways", - "KLM", - "Korean Air", - "Middle East Airlines", - "Saudia", - ], - }, - doc! { - "name": "OneWorld", - "airlines": [ - "Air Berlin", - "American Airlines", - "British Airways", - "Cathay Pacific", - "Finnair", - "Iberia Airlines", - "Japan Airlines", - "LATAM Chile", - "LATAM Brasil", - "Malasya Airlines", - "Canadian Airlines", - ], - }, - ], - None, - ) + .insert_many(vec![ + doc! { + "name": "Star Alliance", + "airlines": [ + "Air Canada", + "Avianca", + "Air China", + "Air New Zealand", + "Asiana Airlines", + "Brussels Airlines", + "Copa Airlines", + "Croatia Airlines", + "EgyptAir", + "TAP Portugal", + "United Airlines", + "Turkish Airlines", + "Swiss International Air Lines", + "Lufthansa", + ], + }, + doc! { + "name": "SkyTeam", + "airlines": [ + "Aerolinias Argentinas", + "Aeromexico", + "Air Europa", + "Air France", + "Alitalia", + "Delta Air Lines", + "Garuda Indonesia", + "Kenya Airways", + "KLM", + "Korean Air", + "Middle East Airlines", + "Saudia", + ], + }, + doc! { + "name": "OneWorld", + "airlines": [ + "Air Berlin", + "American Airlines", + "British Airways", + "Cathay Pacific", + "Finnair", + "Iberia Airlines", + "Japan Airlines", + "LATAM Chile", + "LATAM Brasil", + "Malasya Airlines", + "Canadian Airlines", + ], + }, + ]) .await?; Ok(()) diff --git a/src/test/spec/connection_stepdown.rs b/src/test/spec/connection_stepdown.rs index 2e9249e2a..79fb9cc00 100644 --- a/src/test/spec/connection_stepdown.rs +++ b/src/test/spec/connection_stepdown.rs @@ -5,7 +5,7 @@ use futures::stream::StreamExt; use crate::{ bson::{doc, Document}, error::{CommandError, ErrorKind}, - options::{Acknowledgment, ClientOptions, FindOptions, InsertManyOptions, WriteConcern}, + options::{Acknowledgment, ClientOptions, WriteConcern}, selection_criteria::SelectionCriteria, test::{get_client_options, log_uncaptured, util::EventClient}, Collection, @@ -57,22 +57,13 @@ async fn get_more() { } let docs = vec![doc! { "x": 1 }; 5]; - coll.insert_many( - docs, - Some( - InsertManyOptions::builder() - .write_concern(WriteConcern::builder().w(Acknowledgment::Majority).build()) - .build(), - ), - ) - .await - .unwrap(); - - let mut cursor = coll - .find(None, Some(FindOptions::builder().batch_size(2).build())) + coll.insert_many(docs) + .write_concern(WriteConcern::majority()) .await .unwrap(); + let mut cursor = coll.find(doc! {}).batch_size(2).await.unwrap(); + let db = client.database("admin"); db.run_command(doc! { "replSetFreeze": 0 }) @@ -131,7 +122,7 @@ async fn notwritableprimary_keep_pool() { .await .unwrap(); - let result = coll.insert_one(doc! { "test": 1 }, None).await; + let result = coll.insert_one(doc! { "test": 1 }).await; assert!( matches!( result.map_err(|e| *e.kind), @@ -140,7 +131,7 @@ async fn notwritableprimary_keep_pool() { "insert should have failed" ); - coll.insert_one(doc! { "test": 1 }, None) + coll.insert_one(doc! { "test": 1 }) .await .expect("insert should have succeeded"); @@ -183,7 +174,7 @@ async fn notwritableprimary_reset_pool() { .await .unwrap(); - let result = coll.insert_one(doc! { "test": 1 }, None).await; + let result = coll.insert_one(doc! { "test": 1 }).await; assert!( matches!( result.map_err(|e| *e.kind), @@ -195,7 +186,7 @@ async fn notwritableprimary_reset_pool() { tokio::time::sleep(Duration::from_millis(250)).await; assert_eq!(client.count_pool_cleared_events(), 1); - coll.insert_one(doc! { "test": 1 }, None) + coll.insert_one(doc! { "test": 1 }) .await .expect("insert should have succeeded"); } @@ -232,7 +223,7 @@ async fn shutdown_in_progress() { .await .unwrap(); - let result = coll.insert_one(doc! { "test": 1 }, None).await; + let result = coll.insert_one(doc! { "test": 1 }).await; assert!( matches!( result.map_err(|e| *e.kind), @@ -244,7 +235,7 @@ async fn shutdown_in_progress() { tokio::time::sleep(Duration::from_millis(250)).await; assert_eq!(client.count_pool_cleared_events(), 1); - coll.insert_one(doc! { "test": 1 }, None) + coll.insert_one(doc! { "test": 1 }) .await .expect("insert should have succeeded"); } @@ -277,7 +268,7 @@ async fn interrupted_at_shutdown() { .await .unwrap(); - let result = coll.insert_one(doc! { "test": 1 }, None).await; + let result = coll.insert_one(doc! { "test": 1 }).await; assert!( matches!( result.map_err(|e| *e.kind), @@ -289,7 +280,7 @@ async fn interrupted_at_shutdown() { tokio::time::sleep(Duration::from_millis(250)).await; assert_eq!(client.count_pool_cleared_events(), 1); - coll.insert_one(doc! { "test": 1 }, None) + coll.insert_one(doc! { "test": 1 }) .await .expect("insert should have succeeded"); diff --git a/src/test/spec/crud_v1.rs b/src/test/spec/crud_v1.rs index 1b955d50d..e817b361b 100644 --- a/src/test/spec/crud_v1.rs +++ b/src/test/spec/crud_v1.rs @@ -20,7 +20,6 @@ use serde::Deserialize; use crate::{ bson::{doc, Document}, - coll::options::FindOptions, test::log_uncaptured, Collection, }; @@ -63,8 +62,8 @@ pub struct CollectionOutcome { } pub async fn find_all(coll: &Collection) -> Vec { - let options = FindOptions::builder().sort(doc! { "_id": 1 }).build(); - coll.find(None, options) + coll.find(doc! {}) + .sort(doc! { "_id": 1 }) .await .unwrap() .try_collect() diff --git a/src/test/spec/crud_v1/aggregate.rs b/src/test/spec/crud_v1/aggregate.rs index c6ed4acfb..b126b895e 100644 --- a/src/test/spec/crud_v1/aggregate.rs +++ b/src/test/spec/crud_v1/aggregate.rs @@ -34,7 +34,7 @@ async fn run_aggregate_test(test_file: TestFile) { &test_case.description.replace('$', "%").replace(' ', "_"), ) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); diff --git a/src/test/spec/crud_v1/count.rs b/src/test/spec/crud_v1/count.rs index 5fca5a8d3..9ea6c9790 100644 --- a/src/test/spec/crud_v1/count.rs +++ b/src/test/spec/crud_v1/count.rs @@ -35,7 +35,7 @@ async fn run_count_test(test_file: TestFile) { .await; if !data.is_empty() { - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); } diff --git a/src/test/spec/crud_v1/delete_many.rs b/src/test/spec/crud_v1/delete_many.rs index adf8a372d..aade4c8c0 100644 --- a/src/test/spec/crud_v1/delete_many.rs +++ b/src/test/spec/crud_v1/delete_many.rs @@ -36,7 +36,7 @@ async fn run_delete_many_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); diff --git a/src/test/spec/crud_v1/delete_one.rs b/src/test/spec/crud_v1/delete_one.rs index 48e1b6f7a..84fb209a8 100644 --- a/src/test/spec/crud_v1/delete_one.rs +++ b/src/test/spec/crud_v1/delete_one.rs @@ -36,7 +36,7 @@ async fn run_delete_one_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); diff --git a/src/test/spec/crud_v1/distinct.rs b/src/test/spec/crud_v1/distinct.rs index 28dc84fe4..112f527d6 100644 --- a/src/test/spec/crud_v1/distinct.rs +++ b/src/test/spec/crud_v1/distinct.rs @@ -30,7 +30,7 @@ async fn run_distinct_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); diff --git a/src/test/spec/crud_v1/find.rs b/src/test/spec/crud_v1/find.rs index dcff05e5b..2db5a522b 100644 --- a/src/test/spec/crud_v1/find.rs +++ b/src/test/spec/crud_v1/find.rs @@ -33,7 +33,7 @@ async fn run_find_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -57,7 +57,8 @@ async fn run_find_test(test_file: TestFile) { }; let cursor = coll - .find(arguments.filter, options) + .find(arguments.filter) + .with_options(options) .await .expect(&test_case.description); assert_eq!( diff --git a/src/test/spec/crud_v1/find_one_and_delete.rs b/src/test/spec/crud_v1/find_one_and_delete.rs index eba24a45b..23aca2c7e 100644 --- a/src/test/spec/crud_v1/find_one_and_delete.rs +++ b/src/test/spec/crud_v1/find_one_and_delete.rs @@ -31,7 +31,7 @@ async fn run_find_one_and_delete_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -54,7 +54,8 @@ async fn run_find_one_and_delete_test(test_file: TestFile) { }; let result = coll - .find_one_and_delete(arguments.filter, options) + .find_one_and_delete(arguments.filter) + .with_options(options) .await .expect(&test_case.description); assert_eq!(result, outcome.result, "{}", test_case.description); diff --git a/src/test/spec/crud_v1/find_one_and_replace.rs b/src/test/spec/crud_v1/find_one_and_replace.rs index b2501d4a9..fd0728bfb 100644 --- a/src/test/spec/crud_v1/find_one_and_replace.rs +++ b/src/test/spec/crud_v1/find_one_and_replace.rs @@ -37,7 +37,7 @@ async fn run_find_one_and_replace_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description[..sub]) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -68,7 +68,8 @@ async fn run_find_one_and_replace_test(test_file: TestFile) { }; let result = coll - .find_one_and_replace(arguments.filter, arguments.replacement, options) + .find_one_and_replace(arguments.filter, arguments.replacement) + .with_options(options) .await .expect(&test_case.description); assert_eq!( diff --git a/src/test/spec/crud_v1/find_one_and_update.rs b/src/test/spec/crud_v1/find_one_and_update.rs index 66c48f265..db91c4c87 100644 --- a/src/test/spec/crud_v1/find_one_and_update.rs +++ b/src/test/spec/crud_v1/find_one_and_update.rs @@ -38,7 +38,7 @@ async fn run_find_one_and_update_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description[..sub]) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -71,7 +71,8 @@ async fn run_find_one_and_update_test(test_file: TestFile) { }; let result = coll - .find_one_and_update(arguments.filter, arguments.update, options) + .find_one_and_update(arguments.filter, arguments.update) + .with_options(options) .await .expect(&test_case.description); assert_eq!( diff --git a/src/test/spec/crud_v1/insert_many.rs b/src/test/spec/crud_v1/insert_many.rs index 7a59c4725..5a3b46ae7 100644 --- a/src/test/spec/crud_v1/insert_many.rs +++ b/src/test/spec/crud_v1/insert_many.rs @@ -3,7 +3,6 @@ use serde::Deserialize; use super::{run_crud_v1_test, Outcome, TestFile}; use crate::{ bson::{Bson, Document}, - options::InsertManyOptions, test::util::TestClient, }; @@ -37,7 +36,7 @@ async fn run_insert_many_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -46,11 +45,11 @@ async fn run_insert_many_test(test_file: TestFile) { let outcome: Outcome = bson::from_bson(Bson::Document(test_case.outcome)).expect(&test_case.description); - let options = InsertManyOptions::builder() + let result = match coll + .insert_many(arguments.documents) .ordered(arguments.options.ordered) - .build(); - - let result = match coll.insert_many(arguments.documents, options).await { + .await + { Ok(result) => { assert_ne!(outcome.error, Some(true), "{}", test_case.description); result.inserted_ids diff --git a/src/test/spec/crud_v1/insert_one.rs b/src/test/spec/crud_v1/insert_one.rs index 8ed8ec5f8..5f159b1f1 100644 --- a/src/test/spec/crud_v1/insert_one.rs +++ b/src/test/spec/crud_v1/insert_one.rs @@ -32,7 +32,7 @@ async fn run_insert_one_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -48,7 +48,7 @@ async fn run_insert_one_test(test_file: TestFile) { } let result = coll - .insert_one(arguments.document, None) + .insert_one(arguments.document) .await .expect(&test_case.description); assert_eq!( diff --git a/src/test/spec/crud_v1/replace_one.rs b/src/test/spec/crud_v1/replace_one.rs index f5cfb1609..42f56ee46 100644 --- a/src/test/spec/crud_v1/replace_one.rs +++ b/src/test/spec/crud_v1/replace_one.rs @@ -41,7 +41,7 @@ async fn run_replace_one_test(test_file: TestFile) { &test_case.description.replace('$', "%").replace(' ', "_"), ) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); @@ -63,7 +63,8 @@ async fn run_replace_one_test(test_file: TestFile) { }; let result = coll - .replace_one(arguments.filter, arguments.replacement, options) + .replace_one(arguments.filter, arguments.replacement) + .with_options(options) .await .expect(&test_case.description); assert_eq!( diff --git a/src/test/spec/crud_v1/update_many.rs b/src/test/spec/crud_v1/update_many.rs index 1f4e33c0e..7b53a92c8 100644 --- a/src/test/spec/crud_v1/update_many.rs +++ b/src/test/spec/crud_v1/update_many.rs @@ -41,7 +41,7 @@ async fn run_update_many_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); diff --git a/src/test/spec/crud_v1/update_one.rs b/src/test/spec/crud_v1/update_one.rs index cfe08e259..3b7288231 100644 --- a/src/test/spec/crud_v1/update_one.rs +++ b/src/test/spec/crud_v1/update_one.rs @@ -41,7 +41,7 @@ async fn run_update_one_test(test_file: TestFile) { let coll = client .init_db_and_coll(function_name!(), &test_case.description) .await; - coll.insert_many(data.clone(), None) + coll.insert_many(data.clone()) .await .expect(&test_case.description); diff --git a/src/test/spec/gridfs.rs b/src/test/spec/gridfs.rs index bf55830a6..f08aada17 100644 --- a/src/test/spec/gridfs.rs +++ b/src/test/spec/gridfs.rs @@ -319,7 +319,7 @@ async fn assert_no_chunks_written(bucket: &GridFsBucket, id: &Bson) { assert!(bucket .chunks() .clone_with_type::() - .find_one(doc! { "files_id": id }, None) + .find_one(doc! { "files_id": id }) .await .unwrap() .is_none()); diff --git a/src/test/spec/oidc.rs b/src/test/spec/oidc.rs index bfb55a6f8..d3ec5f5b8 100644 --- a/src/test/spec/oidc.rs +++ b/src/test/spec/oidc.rs @@ -1,3 +1,5 @@ +use bson::doc; + use crate::{ client::{ auth::{oidc, AuthMechanism, Credential}, @@ -45,7 +47,7 @@ async fn machine_single_principal_implicit_username() -> anyhow::Result<()> { client .database("test") .collection::("test") - .find_one(None, None) + .find_one(doc! {}) .await?; assert_eq!(1, *(*call_count).lock().unwrap()); Ok(()) @@ -96,7 +98,7 @@ async fn human_single_principal_implicit_username() -> anyhow::Result<()> { client .database("test") .collection::("test") - .find_one(None, None) + .find_one(doc! {}) .await?; assert_eq!(1, *(*call_count).lock().unwrap()); Ok(()) diff --git a/src/test/spec/retryable_reads.rs b/src/test/spec/retryable_reads.rs index c680c2b42..e29b98c2e 100644 --- a/src/test/spec/retryable_reads.rs +++ b/src/test/spec/retryable_reads.rs @@ -1,4 +1,4 @@ -use std::{sync::Arc, time::Duration}; +use std::{future::IntoFuture, sync::Arc, time::Duration}; use bson::doc; @@ -52,7 +52,7 @@ async fn retry_releases_connection() { let collection = client .database("retry_releases_connection") .collection("retry_releases_connection"); - collection.insert_one(doc! { "x": 1 }, None).await.unwrap(); + collection.insert_one(doc! { "x": 1 }).await.unwrap(); // Use a connection error to ensure streaming monitor checks get cancelled. Otherwise, we'd have // to wait for the entire heartbeatFrequencyMS before the find succeeds. @@ -60,10 +60,13 @@ async fn retry_releases_connection() { let failpoint = FailPoint::fail_command(&["find"], FailPointMode::Times(1), Some(options)); let _fp_guard = client.enable_failpoint(failpoint, None).await.unwrap(); - runtime::timeout(Duration::from_secs(1), collection.find_one(doc! {}, None)) - .await - .expect("operation should not time out") - .expect("find should succeed"); + runtime::timeout( + Duration::from_secs(1), + collection.find_one(doc! {}).into_future(), + ) + .await + .expect("operation should not time out") + .expect("find should succeed"); } /// Prose test from retryable reads spec verifying that PoolClearedErrors are retried. @@ -96,7 +99,7 @@ async fn retry_read_pool_cleared() { let collection = client .database("retry_read_pool_cleared") .collection("retry_read_pool_cleared"); - collection.insert_one(doc! { "x": 1 }, None).await.unwrap(); + collection.insert_one(doc! { "x": 1 }).await.unwrap(); let options = FailCommandOptions::builder() .error_code(91) @@ -110,7 +113,7 @@ async fn retry_read_pool_cleared() { let mut tasks: Vec> = Vec::new(); for _ in 0..2 { let coll = collection.clone(); - let task = runtime::spawn(async move { coll.find_one(doc! {}, None).await }); + let task = runtime::spawn(async move { coll.find_one(doc! {}).await }); tasks.push(task); } @@ -197,7 +200,7 @@ async fn retry_read_different_mongos() { let result = client .database("test") .collection::("retry_read_different_mongos") - .find(doc! {}, None) + .find(doc! {}) .await; assert!(result.is_err()); let events = client.get_command_events(&["find"]); @@ -254,7 +257,7 @@ async fn retry_read_same_mongos() { let result = client .database("test") .collection::("retry_read_same_mongos") - .find(doc! {}, None) + .find(doc! {}) .await; assert!(result.is_ok(), "{:?}", result); let events = client.get_command_events(&["find"]); diff --git a/src/test/spec/retryable_writes.rs b/src/test/spec/retryable_writes.rs index 085ea4ab5..f9ae725d3 100644 --- a/src/test/spec/retryable_writes.rs +++ b/src/test/spec/retryable_writes.rs @@ -16,7 +16,7 @@ use crate::{ cmap::{CmapEvent, ConnectionCheckoutFailedReason}, command::CommandEvent, }, - options::{ClientOptions, FindOptions, InsertManyOptions}, + options::ClientOptions, runtime, runtime::{spawn, AcknowledgedMessage, AsyncJoinHandle}, sdam::MIN_HEARTBEAT_FREQUENCY, @@ -78,7 +78,7 @@ async fn run_legacy() { let coll = client.init_db_and_coll(&db_name, coll_name).await; if !test_file.data.is_empty() { - coll.insert_many(test_file.data.clone(), None) + coll.insert_many(test_file.data.clone()) .await .expect(&test_case.description); } @@ -163,9 +163,9 @@ async fn run_legacy() { }; let coll = client.get_coll(&db_name, &coll_name); - let options = FindOptions::builder().sort(doc! { "_id": 1 }).build(); let actual_data: Vec = coll - .find(None, options) + .find(doc! {}) + .sort(doc! { "_id": 1 }) .await .unwrap() .try_collect() @@ -242,7 +242,7 @@ async fn transaction_ids_included() { started.command.contains_key("txnNumber") }; - coll.insert_one(doc! { "x": 1 }, None).await.unwrap(); + coll.insert_one(doc! { "x": 1 }).await.unwrap(); assert!(includes_txn_number("insert")); coll.update_one(doc! {}, doc! { "$set": doc! { "x": 1 } }) @@ -250,35 +250,33 @@ async fn transaction_ids_included() { .unwrap(); assert!(includes_txn_number("update")); - coll.replace_one(doc! {}, doc! { "x": 1 }, None) - .await - .unwrap(); + coll.replace_one(doc! {}, doc! { "x": 1 }).await.unwrap(); assert!(includes_txn_number("update")); coll.delete_one(doc! {}).await.unwrap(); assert!(includes_txn_number("delete")); - coll.find_one_and_delete(doc! {}, None).await.unwrap(); + coll.find_one_and_delete(doc! {}).await.unwrap(); assert!(includes_txn_number("findAndModify")); - coll.find_one_and_replace(doc! {}, doc! { "x": 1 }, None) + coll.find_one_and_replace(doc! {}, doc! { "x": 1 }) .await .unwrap(); assert!(includes_txn_number("findAndModify")); - coll.find_one_and_update(doc! {}, doc! { "$set": doc! { "x": 1 } }, None) + coll.find_one_and_update(doc! {}, doc! { "$set": doc! { "x": 1 } }) .await .unwrap(); assert!(includes_txn_number("findAndModify")); - let options = InsertManyOptions::builder().ordered(true).build(); - coll.insert_many(vec![doc! { "x": 1 }], options) + coll.insert_many(vec![doc! { "x": 1 }]) + .ordered(true) .await .unwrap(); assert!(includes_txn_number("insert")); - let options = InsertManyOptions::builder().ordered(false).build(); - coll.insert_many(vec![doc! { "x": 1 }], options) + coll.insert_many(vec![doc! { "x": 1 }]) + .ordered(false) .await .unwrap(); assert!(includes_txn_number("insert")); @@ -312,7 +310,7 @@ async fn mmapv1_error_raised() { return; } - let err = coll.insert_one(doc! { "x": 1 }, None).await.unwrap_err(); + let err = coll.insert_one(doc! { "x": 1 }).await.unwrap_err(); match *err.kind { ErrorKind::Command(err) => { assert_eq!( @@ -373,7 +371,7 @@ async fn label_not_added(retry_reads: bool) { .await .unwrap(); - let err = coll.find(doc! {}, None).await.unwrap_err(); + let err = coll.find(doc! {}).await.unwrap_err(); assert!(!err.contains_label("RetryableWriteError")); } @@ -428,7 +426,7 @@ async fn retry_write_pool_cleared() { let mut tasks: Vec> = Vec::new(); for _ in 0..2 { let coll = collection.clone(); - let task = runtime::spawn(async move { coll.insert_one(doc! {}, None).await }); + let task = runtime::spawn(async move { coll.insert_one(doc! {}).await }); tasks.push(task); } @@ -556,7 +554,7 @@ async fn retry_write_retryable_write_error() { let result = client .database("test") .collection::("test") - .insert_one(doc! { "hello": "there" }, None) + .insert_one(doc! { "hello": "there" }) .await; assert_eq!(result.unwrap_err().code(), Some(91)); @@ -605,7 +603,7 @@ async fn retry_write_different_mongos() { let result = client .database("test") .collection::("retry_write_different_mongos") - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await; assert!(result.is_err()); let events = client.get_command_events(&["insert"]); @@ -663,7 +661,7 @@ async fn retry_write_same_mongos() { let result = client .database("test") .collection::("retry_write_same_mongos") - .insert_one(doc! {}, None) + .insert_one(doc! {}) .await; assert!(result.is_ok(), "{:?}", result); let events = client.get_command_events(&["insert"]); diff --git a/src/test/spec/sdam.rs b/src/test/spec/sdam.rs index e72fd3377..2a47f43ac 100644 --- a/src/test/spec/sdam.rs +++ b/src/test/spec/sdam.rs @@ -183,7 +183,7 @@ async fn rtt_is_updated() { client .database("foo") .collection::("bar") - .find(None, None) + .find(doc! {}) .await .unwrap(); diff --git a/src/test/spec/sessions.rs b/src/test/spec/sessions.rs index 27994a0f6..2a36c722e 100644 --- a/src/test/spec/sessions.rs +++ b/src/test/spec/sessions.rs @@ -74,7 +74,8 @@ async fn explicit_session_created_on_same_client() { .database(function_name!()) .collection(function_name!()); let err = coll - .insert_one_with_session(doc! {}, None, &mut session0) + .insert_one(doc! {}) + .session(&mut session0) .await .unwrap_err(); match *err.kind { @@ -124,7 +125,12 @@ async fn implicit_session_after_connection() { fn ignore_val(r: Result) -> Result<()> { r.map(|_| ()) } - ops.push(coll.insert_one(doc! {}, None).map(ignore_val).boxed()); + ops.push( + coll.insert_one(doc! {}) + .into_future() + .map(ignore_val) + .boxed(), + ); ops.push( coll.delete_one(doc! {}) .into_future() @@ -138,23 +144,26 @@ async fn implicit_session_after_connection() { .boxed(), ); ops.push( - coll.find_one_and_delete(doc! {}, None) + coll.find_one_and_delete(doc! {}) + .into_future() .map(ignore_val) .boxed(), ); ops.push( - coll.find_one_and_update(doc! {}, doc! { "$set": { "a": 1 } }, None) + coll.find_one_and_update(doc! {}, doc! { "$set": { "a": 1 } }) + .into_future() .map(ignore_val) .boxed(), ); ops.push( - coll.find_one_and_replace(doc! {}, doc! { "a": 1 }, None) + coll.find_one_and_replace(doc! {}, doc! { "a": 1 }) + .into_future() .map(ignore_val) .boxed(), ); ops.push( async { - let cursor = coll.find(doc! {}, None).await.unwrap(); + let cursor = coll.find(doc! {}).await.unwrap(); let r: Result> = cursor.try_collect().await; r.map(|_| ()) } @@ -241,7 +250,7 @@ async fn sessions_not_supported_implicit_session_ignored() { let mut subscriber = client.handler.subscribe(); let coll = client.database(name).collection(name); - let _ = coll.find(doc! {}, None).await; + let _ = coll.find(doc! {}).await; let event = subscriber .filter_map_event(Duration::from_millis(500), |event| match event { Event::Command(CommandEvent::Started(command_started_event)) @@ -255,7 +264,7 @@ async fn sessions_not_supported_implicit_session_ignored() { .expect("Did not observe a command started event for find operation"); assert!(!event.command.contains_key("lsid")); - let _ = coll.insert_one(doc! { "x": 1 }, None).await; + let _ = coll.insert_one(doc! { "x": 1 }).await; let event = subscriber .filter_map_event(Duration::from_millis(500), |event| match event { Event::Command(CommandEvent::Started(command_started_event)) @@ -285,13 +294,15 @@ async fn sessions_not_supported_explicit_session_error() { let coll = client.database(name).collection(name); let error = coll - .find_one_with_session(doc! {}, None, &mut session) + .find_one(doc! {}) + .session(&mut session) .await .unwrap_err(); assert!(matches!(*error.kind, ErrorKind::SessionsNotSupported)); let error = coll - .insert_one_with_session(doc! { "x": 1 }, None, &mut session) + .insert_one(doc! { "x": 1 }) + .session(&mut session) .await .unwrap_err(); assert!(matches!(*error.kind, ErrorKind::SessionsNotSupported)); diff --git a/src/test/spec/trace.rs b/src/test/spec/trace.rs index 625fa2aa1..015168bd0 100644 --- a/src/test/spec/trace.rs +++ b/src/test/spec/trace.rs @@ -3,7 +3,6 @@ use std::{collections::HashMap, iter, sync::Arc, time::Duration}; use crate::{ bson::{doc, Document}, client::options::ServerAddress, - coll::options::FindOptions, error::{ BulkWriteError, BulkWriteFailure, @@ -88,7 +87,7 @@ async fn command_logging_truncation_default_limit() { let mut tracing_subscriber = DEFAULT_GLOBAL_TRACING_HANDLER.subscribe(); let docs = iter::repeat(doc! { "x": "y" }).take(100); - coll.insert_many(docs, None) + coll.insert_many(docs) .await .expect("insert many should succeed"); @@ -105,7 +104,7 @@ async fn command_logging_truncation_default_limit() { let reply = succeeded.get_value_as_string("reply"); assert!(reply.len() <= DEFAULT_MAX_DOCUMENT_LENGTH_BYTES + 3); // +3 for trailing "..." - coll.find(None, None).await.expect("find should succeed"); + coll.find(doc! {}).await.expect("find should succeed"); let succeeded = tracing_subscriber .wait_for_event(Duration::from_millis(500), |e| { e.get_value_as_string("message") == "Command succeeded" @@ -179,7 +178,7 @@ async fn command_logging_truncation_mid_codepoint() { let mut tracing_subscriber = DEFAULT_GLOBAL_TRACING_HANDLER.subscribe(); let docs = iter::repeat(doc! { "🤔": "🤔🤔🤔🤔🤔🤔" }).take(10); - coll.insert_many(docs, None) + coll.insert_many(docs) .await .expect("insert many should succeed"); @@ -196,10 +195,8 @@ async fn command_logging_truncation_mid_codepoint() { // trailing "..." assert_eq!(command.len(), 221); - let find_options = FindOptions::builder() + coll.find(doc! {}) .projection(doc! { "_id": 0, "🤔": 1 }) - .build(); - coll.find(None, find_options) .await .expect("find should succeed"); let succeeded = tracing_subscriber diff --git a/src/test/spec/transactions.rs b/src/test/spec/transactions.rs index 5fd40d39f..1820de454 100644 --- a/src/test/spec/transactions.rs +++ b/src/test/spec/transactions.rs @@ -78,7 +78,7 @@ async fn deserialize_recovery_token() { let coll = client .database(function_name!()) .collection(function_name!()); - coll.insert_one(A { num: 4 }, None).await.unwrap(); + coll.insert_one(A { num: 4 }).await.unwrap(); // Attempt to execute Find on a document with schema B. let coll: Collection = client @@ -86,7 +86,7 @@ async fn deserialize_recovery_token() { .collection(function_name!()); session.start_transaction(None).await.unwrap(); assert!(session.transaction.recovery_token.is_none()); - let result = coll.find_one_with_session(None, None, &mut session).await; + let result = coll.find_one(doc! {}).session(&mut session).await; assert!(result.is_err()); // Assert that the deserialization failed. // Nevertheless, the recovery token should have been retrieved from the ok: 1 response. @@ -111,7 +111,7 @@ async fn convenient_api_custom_error() { coll, |session, coll| { async move { - coll.find_one_with_session(None, None, session).await?; + coll.find_one(doc! {}).session(session).await?; Err(Error::custom(MyErr)) } .boxed() @@ -144,7 +144,7 @@ async fn convenient_api_returned_value() { coll, |session, coll| { async move { - coll.find_one_with_session(None, None, session).await?; + coll.find_one(doc! {}).session(session).await?; Ok(42) } .boxed() @@ -175,7 +175,7 @@ async fn convenient_api_retry_timeout_callback() { coll, |session, coll| { async move { - coll.find_one_with_session(None, None, session).await?; + coll.find_one(doc! {}).session(session).await?; let mut err = Error::custom(42); err.add_label(TRANSIENT_TRANSACTION_ERROR); Err(err) @@ -232,7 +232,7 @@ async fn convenient_api_retry_timeout_commit_unknown() { coll, |session, coll| { async move { - coll.find_one_with_session(None, None, session).await?; + coll.find_one(doc! {}).session(session).await?; Ok(()) } .boxed() @@ -286,7 +286,7 @@ async fn convenient_api_retry_timeout_commit_transient() { coll, |session, coll| { async move { - coll.find_one_with_session(None, None, session).await?; + coll.find_one(doc! {}).session(session).await?; Ok(()) } .boxed() diff --git a/src/test/spec/unified_runner/operation.rs b/src/test/spec/unified_runner/operation.rs index 143a7b225..f8e7164e3 100644 --- a/src/test/spec/unified_runner/operation.rs +++ b/src/test/spec/unified_runner/operation.rs @@ -585,12 +585,11 @@ impl Find { selection_criteria: None, let_vars: self.let_vars.clone(), }; + let act = collection.find(self.filter.clone()).with_options(options); match &self.session { Some(session_id) => { let cursor = with_mut_session!(test_runner, session_id, |session| async { - collection - .find_with_session(self.filter.clone(), options, session) - .await + act.session(session.deref_mut()).await }) .await?; Ok(TestCursor::Session { @@ -599,7 +598,7 @@ impl Find { }) } None => { - let cursor = collection.find(self.filter.clone(), options).await?; + let cursor = act.await?; Ok(TestCursor::Normal(Mutex::new(cursor))) } } @@ -728,27 +727,17 @@ impl TestOperation for InsertMany { ) -> BoxFuture<'a, Result>> { async move { let collection = test_runner.get_collection(id).await; + let action = collection + .insert_many(&self.documents) + .with_options(self.options.clone()); let result = match &self.session { Some(session_id) => { with_mut_session!(test_runner, session_id, |session| { - async move { - collection - .insert_many_with_session( - self.documents.clone(), - self.options.clone(), - session, - ) - .await - } - .boxed() + async move { action.session(session.deref_mut()).await }.boxed() }) .await? } - None => { - collection - .insert_many(self.documents.clone(), self.options.clone()) - .await? - } + None => action.await?, }; let ids: HashMap = result .inserted_ids @@ -779,24 +768,17 @@ impl TestOperation for InsertOne { ) -> BoxFuture<'a, Result>> { async move { let collection = test_runner.get_collection(id).await; + let action = collection + .insert_one(self.document.clone()) + .with_options(self.options.clone()); let result = match &self.session { Some(session_id) => { with_mut_session!(test_runner, session_id, |session| async { - collection - .insert_one_with_session( - self.document.clone(), - self.options.clone(), - session, - ) - .await + action.session(session.deref_mut()).await }) .await? } - None => { - collection - .insert_one(self.document.clone(), self.options.clone()) - .await? - } + None => action.await?, }; let result = to_bson(&result)?; Ok(Some(result.into())) @@ -1089,7 +1071,8 @@ impl TestOperation for FindOne { async move { let collection = test_runner.get_collection(id).await; let result = collection - .find_one(self.filter.clone(), self.options.clone()) + .find_one(self.filter.clone().unwrap_or_default()) + .with_options(self.options.clone()) .await?; match result { Some(result) => Ok(Some(Bson::from(result).into())), @@ -1256,11 +1239,8 @@ impl TestOperation for ReplaceOne { async move { let collection = test_runner.get_collection(id).await; let result = collection - .replace_one( - self.filter.clone(), - self.replacement.clone(), - self.options.clone(), - ) + .replace_one(self.filter.clone(), self.replacement.clone()) + .with_options(self.options.clone()) .await?; let result = to_bson(&result)?; Ok(Some(result.into())) @@ -1287,29 +1267,17 @@ impl TestOperation for FindOneAndUpdate { ) -> BoxFuture<'a, Result>> { async move { let collection = test_runner.get_collection(id).await; + let act = collection + .find_one_and_update(self.filter.clone(), self.update.clone()) + .with_options(self.options.clone()); let result = match &self.session { Some(session_id) => { with_mut_session!(test_runner, session_id, |session| async { - collection - .find_one_and_update_with_session( - self.filter.clone(), - self.update.clone(), - self.options.clone(), - session, - ) - .await + act.session(session.deref_mut()).await }) .await? } - None => { - collection - .find_one_and_update( - self.filter.clone(), - self.update.clone(), - self.options.clone(), - ) - .await? - } + None => act.await?, }; let result = to_bson(&result)?; Ok(Some(result.into())) @@ -1336,11 +1304,8 @@ impl TestOperation for FindOneAndReplace { async move { let collection = test_runner.get_collection(id).await; let result = collection - .find_one_and_replace( - self.filter.clone(), - self.replacement.clone(), - self.options.clone(), - ) + .find_one_and_replace(self.filter.clone(), self.replacement.clone()) + .with_options(self.options.clone()) .await?; let result = to_bson(&result)?; @@ -1367,7 +1332,8 @@ impl TestOperation for FindOneAndDelete { async move { let collection = test_runner.get_collection(id).await; let result = collection - .find_one_and_delete(self.filter.clone(), self.options.clone()) + .find_one_and_delete(self.filter.clone()) + .with_options(self.options.clone()) .await?; let result = to_bson(&result)?; Ok(Some(result.into())) diff --git a/src/test/spec/unified_runner/test_runner.rs b/src/test/spec/unified_runner/test_runner.rs index 2c6db3b5e..5f1a3f927 100644 --- a/src/test/spec/unified_runner/test_runner.rs +++ b/src/test/spec/unified_runner/test_runner.rs @@ -12,7 +12,6 @@ use crate::{ options::{ CollectionOptions, CreateCollectionOptions, - FindOptions, ReadConcern, ReadPreference, SelectionCriteria, @@ -357,9 +356,9 @@ impl TestRunner { .internal_client .get_coll_with_options(db_name, coll_name, options); - let options = FindOptions::builder().sort(doc! { "_id": 1 }).build(); let actual_data: Vec = collection - .find(doc! {}, options) + .find(doc! {}) + .sort(doc! { "_id": 1 }) .await .unwrap() .try_collect() @@ -387,9 +386,7 @@ impl TestRunner { collection_options, ) .await; - coll.insert_many(data.documents.clone(), None) - .await - .unwrap(); + coll.insert_many(data.documents.clone()).await.unwrap(); } else { let collection_options = CreateCollectionOptions::builder() .write_concern(write_concern) diff --git a/src/test/spec/v2_runner.rs b/src/test/spec/v2_runner.rs index 88066d181..059719923 100644 --- a/src/test/spec/v2_runner.rs +++ b/src/test/spec/v2_runner.rs @@ -13,7 +13,7 @@ use crate::{ bson::{doc, from_bson}, coll::options::DropCollectionOptions, concern::WriteConcern, - options::{ClientOptions, CreateCollectionOptions, InsertManyOptions}, + options::{ClientOptions, CreateCollectionOptions}, sdam::{ServerInfo, MIN_HEARTBEAT_FREQUENCY}, selection_criteria::SelectionCriteria, test::{ @@ -180,10 +180,10 @@ impl TestContext { match data { TestData::Single(data) => { if !data.is_empty() { - let options = InsertManyOptions::builder() + coll.insert_many(data.clone()) .write_concern(WriteConcern::majority()) - .build(); - coll.insert_many(data.clone(), options).await.unwrap(); + .await + .unwrap(); } } TestData::Many(_) => panic!("{}: invalid data format", &test.description), diff --git a/src/test/spec/v2_runner/csfle.rs b/src/test/spec/v2_runner/csfle.rs index 310eb57ad..f80e23172 100644 --- a/src/test/spec/v2_runner/csfle.rs +++ b/src/test/spec/v2_runner/csfle.rs @@ -22,7 +22,7 @@ pub(crate) async fn populate_key_vault(client: &Client, kv_data: Option<&Vec, ) -> BoxFuture<'a, Result>> { async move { + let act = collection + .find(self.filter.clone().unwrap_or_default()) + .with_options(self.options.clone()); let result = match session { Some(session) => { - let mut cursor = collection - .find_with_session(self.filter.clone(), self.options.clone(), session) - .await?; + let mut cursor = act.session(&mut *session).await?; cursor .stream(session) .try_collect::>() .await? } None => { - let cursor = collection - .find(self.filter.clone(), self.options.clone()) - .await?; + let cursor = act.await?; cursor.try_collect::>().await? } }; @@ -426,14 +425,11 @@ impl TestOperation for InsertMany { let options = self.options.clone(); async move { - let result = match session { - Some(session) => { - collection - .insert_many_with_session(documents, options, session) - .await? - } - None => collection.insert_many(documents, options).await?, - }; + let result = collection + .insert_many(documents) + .with_options(options) + .optional(session, |a, s| a.session(s)) + .await?; let ids: HashMap = result .inserted_ids .into_iter() @@ -462,14 +458,11 @@ impl TestOperation for InsertOne { let document = self.document.clone(); let options = self.options.clone(); async move { - let result = match session { - Some(session) => { - collection - .insert_one_with_session(document, options, session) - .await? - } - None => collection.insert_one(document, options).await?, - }; + let result = collection + .insert_one(document) + .with_options(options) + .optional(session, |a, s| a.session(s)) + .await?; let result = bson::to_bson(&result)?; Ok(Some(result)) } @@ -685,17 +678,12 @@ impl TestOperation for FindOne { session: Option<&'a mut ClientSession>, ) -> BoxFuture<'a, Result>> { async move { + let action = collection + .find_one(self.filter.clone().unwrap_or_default()) + .with_options(self.options.clone()); let result = match session { - Some(session) => { - collection - .find_one_with_session(self.filter.clone(), self.options.clone(), session) - .await? - } - None => { - collection - .find_one(self.filter.clone(), self.options.clone()) - .await? - } + Some(session) => action.session(session).await?, + None => action.await?, }; match result { Some(result) => Ok(Some(Bson::from(result))), @@ -783,27 +771,11 @@ impl TestOperation for ReplaceOne { session: Option<&'a mut ClientSession>, ) -> BoxFuture<'a, Result>> { async move { - let result = match session { - Some(session) => { - collection - .replace_one_with_session( - self.filter.clone(), - self.replacement.clone(), - self.options.clone(), - session, - ) - .await? - } - None => { - collection - .replace_one( - self.filter.clone(), - self.replacement.clone(), - self.options.clone(), - ) - .await? - } - }; + let result = collection + .replace_one(self.filter.clone(), self.replacement.clone()) + .with_options(self.options.clone()) + .optional(session, |a, s| a.session(s)) + .await?; let result = bson::to_bson(&result)?; Ok(Some(result)) } @@ -826,27 +798,11 @@ impl TestOperation for FindOneAndUpdate { session: Option<&'a mut ClientSession>, ) -> BoxFuture<'a, Result>> { async move { - let result = match session { - Some(session) => { - collection - .find_one_and_update_with_session( - self.filter.clone(), - self.update.clone(), - self.options.clone(), - session, - ) - .await? - } - None => { - collection - .find_one_and_update( - self.filter.clone(), - self.update.clone(), - self.options.clone(), - ) - .await? - } - }; + let result = collection + .find_one_and_update(self.filter.clone(), self.update.clone()) + .with_options(self.options.clone()) + .optional(session, |a, s| a.session(s)) + .await?; let result = bson::to_bson(&result)?; Ok(Some(result)) } @@ -869,27 +825,11 @@ impl TestOperation for FindOneAndReplace { session: Option<&'a mut ClientSession>, ) -> BoxFuture<'a, Result>> { async move { - let result = match session { - Some(session) => { - collection - .find_one_and_replace_with_session( - self.filter.clone(), - self.replacement.clone(), - self.options.clone(), - session, - ) - .await? - } - None => { - collection - .find_one_and_replace( - self.filter.clone(), - self.replacement.clone(), - self.options.clone(), - ) - .await? - } - }; + let result = collection + .find_one_and_replace(self.filter.clone(), self.replacement.clone()) + .with_options(self.options.clone()) + .optional(session, |a, s| a.session(s)) + .await?; let result = bson::to_bson(&result)?; Ok(Some(result)) } @@ -911,22 +851,11 @@ impl TestOperation for FindOneAndDelete { session: Option<&'a mut ClientSession>, ) -> BoxFuture<'a, Result>> { async move { - let result = match session { - Some(session) => { - collection - .find_one_and_delete_with_session( - self.filter.clone(), - self.options.clone(), - session, - ) - .await? - } - None => { - collection - .find_one_and_delete(self.filter.clone(), self.options.clone()) - .await? - } - }; + let result = collection + .find_one_and_delete(self.filter.clone()) + .with_options(self.options.clone()) + .optional(session, |a, s| a.session(s)) + .await?; let result = bson::to_bson(&result)?; Ok(Some(result)) } diff --git a/src/test/spec/v2_runner/test_file.rs b/src/test/spec/v2_runner/test_file.rs index 033279a16..b622162ab 100644 --- a/src/test/spec/v2_runner/test_file.rs +++ b/src/test/spec/v2_runner/test_file.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Deserializer}; use crate::{ bson::Document, - options::{FindOptions, ReadPreference, SelectionCriteria, SessionOptions}, + options::{ReadPreference, SelectionCriteria, SessionOptions}, test::{ log_uncaptured, spec::merge_uri_options, @@ -177,12 +177,10 @@ impl Outcome { .database(db_name) .collection_with_options(coll_name, coll_opts); let selection_criteria = SelectionCriteria::ReadPreference(ReadPreference::Primary); - let options = FindOptions::builder() + let actual_data: Vec = coll + .find(doc! {}) .sort(doc! { "_id": 1 }) .selection_criteria(selection_criteria) - .build(); - let actual_data: Vec = coll - .find(None, options) .await .unwrap() .try_collect() diff --git a/src/test/spec/write_error.rs b/src/test/spec/write_error.rs index 0efeb47fb..7600f991d 100644 --- a/src/test/spec/write_error.rs +++ b/src/test/spec/write_error.rs @@ -24,7 +24,7 @@ async fn details() { .await .unwrap(); let coll: Collection = db.collection("test"); - let err = coll.insert_one(doc! { "x": 1 }, None).await.unwrap_err(); + let err = coll.insert_one(doc! { "x": 1 }).await.unwrap_err(); let write_err = match *err.kind { ErrorKind::Write(WriteFailure::WriteError(e)) => e, _ => panic!("expected WriteError, got {:?}", err.kind), diff --git a/src/test/util/event.rs b/src/test/util/event.rs index 7478ad83c..7d0d83990 100644 --- a/src/test/util/event.rs +++ b/src/test/util/event.rs @@ -728,7 +728,7 @@ async fn command_started_event_count() { let coll = client.database("foo").collection("bar"); for i in 0..10 { - coll.insert_one(doc! { "x": i }, None).await.unwrap(); + coll.insert_one(doc! { "x": i }).await.unwrap(); } assert_eq!(client.get_command_started_events(&["insert"]).len(), 10); diff --git a/tests/readme_examples.rs b/tests/readme_examples.rs index 2d3eab2e6..1b291c54d 100644 --- a/tests/readme_examples.rs +++ b/tests/readme_examples.rs @@ -56,7 +56,7 @@ async fn _inserting_documents_into_a_collection(db: mongodb::Database) -> Result ]; // Insert some documents into the "mydb.books" collection. - collection.insert_many(docs, None).await?; + collection.insert_many(docs).await?; Ok(()) } @@ -84,7 +84,7 @@ async fn _inserting_documents_into_a_typed_collection(db: mongodb::Database) -> ]; // Insert the books into "mydb.books" collection, no manual conversion to BSON necessary. - typed_collection.insert_many(books, None).await?; + typed_collection.insert_many(books).await?; Ok(()) } @@ -94,12 +94,11 @@ async fn _finding_documents_into_a_collection( ) -> Result<()> { // This trait is required to use `try_next()` on the cursor use futures::stream::TryStreamExt; - use mongodb::{bson::doc, options::FindOptions}; + use mongodb::bson::doc; // Query the books in the collection with a filter and an option. let filter = doc! { "author": "George Orwell" }; - let find_options = FindOptions::builder().sort(doc! { "title": 1 }).build(); - let mut cursor = typed_collection.find(filter, find_options).await?; + let mut cursor = typed_collection.find(filter).sort(doc! { "title": 1 }).await?; // Iterate over the results of the cursor. while let Some(book) = cursor.try_next().await? { @@ -133,9 +132,9 @@ async fn _using_the_sync_api() -> Result<()> { ]; // Insert some books into the "mydb.books" collection. - collection.insert_many(docs, None)?; + collection.insert_many(docs).run()?; - let cursor = collection.find(doc! { "author": "George Orwell" }, None)?; + let cursor = collection.find(doc! { "author": "George Orwell" }).run()?; for result in cursor { println!("title: {}", result?.title); } diff --git a/tests/transactions_example.rs b/tests/transactions_example.rs index b9d4ca8cf..602bb7967 100644 --- a/tests/transactions_example.rs +++ b/tests/transactions_example.rs @@ -64,11 +64,10 @@ async fn execute_transaction(session: &mut ClientSession) -> Result<()> { .await?; events - .insert_one_with_session( - doc! { "employee": 3, "status": { "new": "Inactive", "old": "Active" } }, - None, - session, + .insert_one( + doc! { "employee": 3, "status": { "new": "Inactive", "old": "Active" } } ) + .session(&mut *session) .await?; commit_with_retry(session).await