Skip to main content

mongodb/sync/
client.rs

1pub mod session;
2
3use super::Database;
4use crate::{
5    concern::{ReadConcern, WriteConcern},
6    error::Result,
7    options::{ClientOptions, DatabaseOptions, SelectionCriteria},
8    Client as AsyncClient,
9};
10
11/// This is the main entry point for the synchronous API. A `Client` is used to connect to a MongoDB
12/// cluster. By default, it will monitor the topology of the cluster, keeping track of any changes,
13/// such as servers being added or removed.
14///
15/// `Client` is a wrapper around the asynchronous [`mongodb::Client`](../struct.Client.html), and it
16/// starts up a tokio runtime internally to run that wrapped client on.
17///
18/// `Client` uses [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) internally,
19/// so it can safely be shared across threads. For example:
20///
21/// ```rust
22/// # use mongodb::{bson::Document, sync::Client, error::Result};
23/// #
24/// # fn start_workers() -> Result<()> {
25/// let client = Client::with_uri_str("mongodb://example.com")?;
26///
27/// for i in 0..5 {
28///     let client_ref = client.clone();
29///
30///     std::thread::spawn(move || {
31///         let collection = client_ref.database("items").collection::<Document>(&format!("coll{}", i));
32///
33///         // Do something with the collection
34///     });
35/// }
36/// #
37/// # // Technically we should join the threads here, but for the purpose of the example, we'll just
38/// # // sleep for a bit.
39/// # std::thread::sleep(std::time::Duration::from_secs(3));
40/// # Ok(())
41/// # }
42/// ```
43///
44/// ## TCP Keepalive
45/// TCP keepalive is enabled by default with ``tcp_keepalive_time`` set to 120 seconds. The
46/// driver does not set ``tcp_keepalive_intvl``. See the
47/// [MongoDB Diagnostics FAQ keepalive section](https://www.mongodb.com/docs/manual/faq/diagnostics/#does-tcp-keepalive-time-affect-mongodb-deployments)
48/// for instructions on setting these values at the system level.
49///
50/// ## Clean shutdown
51/// Because Rust has no async equivalent of `Drop`, values that require server-side cleanup when
52/// dropped spawn a new async task to perform that cleanup.  This can cause two potential issues:
53///
54/// * Drop tasks pending or in progress when the async runtime shuts down may not complete, causing
55///   server-side resources to not be freed.
56/// * Drop tasks may run at an arbitrary time even after no `Client` values exist, making it hard to
57///   reason about associated resources (e.g. event handlers).
58///
59/// To address these issues, we highly recommend you use [`Client::shutdown`] in the termination
60/// path of your application.  This will ensure that outstanding resources have been cleaned up and
61/// terminate internal worker tasks before returning.  Please note that `shutdown` will wait for
62/// _all_ outstanding resource handles to be dropped, so they must either have been dropped before
63/// calling `shutdown` or in a concurrent task; see the documentation of `shutdown` for more
64/// details.
65
66#[derive(Clone, Debug)]
67pub struct Client {
68    pub(crate) async_client: AsyncClient,
69}
70
71impl From<AsyncClient> for Client {
72    fn from(async_client: AsyncClient) -> Self {
73        Self { async_client }
74    }
75}
76
77impl Client {
78    /// Creates a new `Client` connected to the cluster specified by `uri`. `uri` must be a valid
79    /// MongoDB connection string.
80    ///
81    /// See the documentation on
82    /// [`ClientOptions::parse`](../options/struct.ClientOptions.html#method.parse) for more
83    /// details.
84    pub fn with_uri_str(uri: impl AsRef<str>) -> Result<Self> {
85        let async_client =
86            crate::sync::TOKIO_RUNTIME.block_on(AsyncClient::with_uri_str(uri.as_ref()))?;
87        Ok(Self { async_client })
88    }
89
90    /// Creates a new `Client` connected to the cluster specified by `options`.
91    pub fn with_options(options: ClientOptions) -> Result<Self> {
92        let async_client = AsyncClient::with_options(options)?;
93        Ok(Self { async_client })
94    }
95
96    /// Gets the default selection criteria the `Client` uses for operations..
97    pub fn selection_criteria(&self) -> Option<&SelectionCriteria> {
98        self.async_client.selection_criteria()
99    }
100
101    /// Gets the default read concern the `Client` uses for operations.
102    pub fn read_concern(&self) -> Option<&ReadConcern> {
103        self.async_client.read_concern()
104    }
105
106    /// Gets the default write concern the `Client` uses for operations.
107    pub fn write_concern(&self) -> Option<&WriteConcern> {
108        self.async_client.write_concern()
109    }
110
111    /// Gets a handle to a database specified by `name` in the cluster the `Client` is connected to.
112    /// The `Database` options (e.g. read preference and write concern) will default to those of the
113    /// `Client`.
114    ///
115    /// This method does not send or receive anything across the wire to the database, so it can be
116    /// used repeatedly without incurring any costs from I/O.
117    pub fn database(&self, name: &str) -> Database {
118        Database::new(self.async_client.database(name))
119    }
120
121    /// Gets a handle to a database specified by `name` in the cluster the `Client` is connected to.
122    /// Operations done with this `Database` will use the options specified by `options` by default
123    /// and will otherwise default to those of the `Client`.
124    ///
125    /// This method does not send or receive anything across the wire to the database, so it can be
126    /// used repeatedly without incurring any costs from I/O.
127    pub fn database_with_options(&self, name: &str, options: DatabaseOptions) -> Database {
128        Database::new(self.async_client.database_with_options(name, options))
129    }
130
131    /// Gets a handle to the default database specified in the `ClientOptions` or MongoDB connection
132    /// string used to construct this `Client`.
133    ///
134    /// If no default database was specified, `None` will be returned.
135    pub fn default_database(&self) -> Option<Database> {
136        self.async_client.default_database().map(Database::new)
137    }
138}