|
| 1 | +# Migrating from 2.x to 3.0 |
| 2 | +3.0 introduces a wide variety of improvements that required backwards-incompatible API changes; in most cases these changes should require only minor updates in application code. |
| 3 | + |
| 4 | +## Fluent API |
| 5 | +Async methods that accepted options have been updated to allow the individual options to be given directly in line with the call to reduce required boilerplate. A session can now also be set using a chained method rather than a distinct `_with_session` method. |
| 6 | + |
| 7 | +In 2.x: |
| 8 | +```rust |
| 9 | +// Without options |
| 10 | +let cursor = collection.find(doc! { "status": "A" }, None).await?; |
| 11 | +// With options |
| 12 | +let cursor = collection |
| 13 | + .find( |
| 14 | + doc! { "status": "A" }, |
| 15 | + FindOptions::builder() |
| 16 | + .projection(doc! { |
| 17 | + "status": 0, |
| 18 | + "instock": 0, |
| 19 | + }) |
| 20 | + .build(), |
| 21 | + ) |
| 22 | + .await?; |
| 23 | +// With options and a session |
| 24 | +let cursor = collection |
| 25 | + .find_with_session( |
| 26 | + doc! { "status": "A" }, |
| 27 | + FindOptions::builder() |
| 28 | + .projection(doc! { |
| 29 | + "status": 0, |
| 30 | + "instock": 0, |
| 31 | + }) |
| 32 | + .build(), |
| 33 | + &mut session, |
| 34 | + ) |
| 35 | + .await?; |
| 36 | +``` |
| 37 | + |
| 38 | +In 3.0: |
| 39 | +```rust |
| 40 | +// Without options |
| 41 | +let cursor = collection.find(doc! { "status": "A" }).await?; |
| 42 | +// With options |
| 43 | +let cursor = collection |
| 44 | + .find(doc! { "status": "A" }) |
| 45 | + .projection(doc! { |
| 46 | + "status": 0, |
| 47 | + "instock": 0, |
| 48 | + }) |
| 49 | + .await?; |
| 50 | +// With options and a session |
| 51 | +let cursor = collection |
| 52 | + .find(doc! { "status": "A" }) |
| 53 | + .projection(doc! { |
| 54 | + "status": 0, |
| 55 | + "instock": 0, |
| 56 | + }) |
| 57 | + .session(&mut session) |
| 58 | + .await?; |
| 59 | +``` |
| 60 | + |
| 61 | +If an option needs to be conditionally set, the `optional` convenience method can be used: |
| 62 | +```rust |
| 63 | +async fn run_find(opt_projection: Option<Document>) -> Result<()> { |
| 64 | + let cursor = collection |
| 65 | + .find(doc! { "status": "A" }) |
| 66 | + .optional(opt_projection, |f, p| f.projection(p)) |
| 67 | + .await?; |
| 68 | + ... |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +For those cases where options still need to be constructed independently, the `with_options` method is provided: |
| 73 | +```rust |
| 74 | +let options = FindOptions::builder() |
| 75 | + .projection(doc! { |
| 76 | + "status": 0, |
| 77 | + "instock": 0, |
| 78 | + }) |
| 79 | + .build(); |
| 80 | +let cursor = collection |
| 81 | + .find(doc! { "status": "A" }) |
| 82 | + .with_options(options) |
| 83 | + .await?; |
| 84 | +``` |
| 85 | + |
| 86 | +## Listening for Events |
| 87 | +The 2.x event API required that applications provide an `Arc<dyn CmapEventHandler>` (or `CommandEventHandler` / `SdamEventHandler`). This required a fair amount of boilerplate, especially for simpler handlers (e.g. logging), and did not provide any way for event handlers to perform async work. To address both of those, 3.0 introduces the `EventHandler` type. |
| 88 | + |
| 89 | +In 2.x: |
| 90 | +```rust |
| 91 | +struct CmapEventLogger; |
| 92 | +impl CmapEventHandler for CmapEventLogger { |
| 93 | + fn handle_pool_created_event(&self, event: PoolCreatedEvent) { |
| 94 | + println!("{:?}", event); |
| 95 | + } |
| 96 | + /// repeat for handle_pool_ready_event, etc. |
| 97 | +} |
| 98 | +let options = ClientOptions::builder() |
| 99 | + .cmap_event_handler(Arc::new(CmapEventLogger)) |
| 100 | + .build(); |
| 101 | +``` |
| 102 | + |
| 103 | +In 3.0: |
| 104 | +```rust |
| 105 | +let options = ClientOptions::builder() |
| 106 | + .cmap_event_handler(EventHandler::callback(|ev| println!("{:?}", ev))) |
| 107 | + .build(); |
| 108 | +``` |
| 109 | + |
| 110 | +`EventHandler` can be constructed from a callback, async callback, or an async channel sender. To ease migration, it can also be constructed from the now-deprecated 2.x `CmapEventHandler`/`CommandEventHandler`/`SdamEventHandler` types. |
| 111 | + |
| 112 | +## Async Runtime |
| 113 | +2.x supported both `tokio` (default) and `async-std` as async runtimes. Maintaining this dual support was a significant ongoing development cost, and with both Rust mongodb driver usage and overall Rust ecosystem usage heavily favoring `tokio`, 3.0 only supports `tokio`. |
| 114 | + |
| 115 | +## Future-proof Features |
| 116 | +Starting in 3.0, if the Rust driver is compiled with `no-default-features` it will require the use of a `compat` feature; this provides the flexibility to make features optional in future versions of the driver. Lack of this had prevented `rustls` and `dns-resolution` from becoming optional in 2.x; they are now optional in 3.0. |
| 117 | + |
| 118 | +In addition, we have removed the various `bson-*` features from the driver, as those can be selected by including `bson` as a direct dependency. |
| 119 | + |
| 120 | +## ReadConcern / WriteConcern Helpers |
| 121 | +The Rust driver provides convenience helpers for constructing commonly used read or write concerns (e.g. "majority"). In 2.x, these were an overlapping mix of constants and methods (`ReadConcern::MAJORITY` and `ReadConcern::majority()`). In 3.0, these are only provided as methods. |
| 122 | + |
| 123 | +## `Send + Sync` Constraints on `Collection` |
| 124 | +In 2.x, whether a method on `Collection<T>` required `T: Send` or `T: Send + Sync` was ad-hoc and inconsistent. Whether these constraints were required for compilation depended on details like whether the transitive call graph of the implementation held a value of `T` over an `await` point, which could easily change as development continued. For consistency and to allow for future development, in 3.0 `Collection<T>` requires `T: Send + Sync`. |
| 125 | + |
| 126 | +## Compression Option Behind Feature Flags |
| 127 | +In 2.x, the `ClientOptions::compressor` field was always present, but with no compressor features selected could not be populated. For simplicity and consistency with our other optional features, in 3.0 that field will not be present if no compressor features are enabled. |
| 128 | + |
| 129 | +## Optional `ReadPreferenceOptions` |
| 130 | +In 3.0, the `ReadPreferenceOptions` fields of `ReadPreference` arms are now `Option<ReadPreferenceOptions>`. |
| 131 | + |
| 132 | +## `human_readable_serialization` Option Removed in favor of `HumanReadable` |
| 133 | +In some uncommon cases, applications prefer user data types to be serialized in their human-readable form; the `CollectionOptions::human_readable_serialization` option enabled that. In 3.x, this option has been removed; the `bson::HumanReadable` wrapper type can be used to achieve the same effect. |
| 134 | + |
| 135 | +## Consistent Defaults for `TypedBuilder` Implementations |
| 136 | +In 2.x, most but not all option struct builders would allow value conversion via `Into` and would use the `default()` value if not set; this is now the behavior across all option struct builders. |
| 137 | + |
| 138 | +## `comment_bson` is now `comment` |
| 139 | +In 2.x, the `AggregateOptions`, `FindOptions`, and `FindOneOptions` structs had both `comment_bson` and legacy `comment` fields. In 3.x, `comment_bson` has been renamed to `comment`, replacing the legacy field. |
0 commit comments