mongodb/db.rs
1pub(crate) mod action;
2pub mod options;
3
4use std::{fmt::Debug, sync::Arc};
5
6use crate::{
7 concern::{ReadConcern, WriteConcern},
8 gridfs::{options::GridFsBucketOptions, GridFsBucket},
9 options::{CollectionOptions, DatabaseOptions},
10 selection_criteria::SelectionCriteria,
11 Client,
12 Collection,
13};
14
15/// `Database` is the client-side abstraction of a MongoDB database. It can be used to perform
16/// database-level operations or to obtain handles to specific collections within the database. A
17/// `Database` can only be obtained through a [`Client`](struct.Client.html) by calling either
18/// [`Client::database`](struct.Client.html#method.database) or
19/// [`Client::database_with_options`](struct.Client.html#method.database_with_options).
20///
21/// `Database` uses [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) internally,
22/// so it can safely be shared across threads or async tasks. For example:
23///
24/// ```rust
25///
26/// # use mongodb::{bson::Document, Client, error::Result};
27/// #
28/// #
29/// # async fn start_workers() -> Result<()> {
30/// # let client = Client::with_uri_str("mongodb://example.com").await?;
31/// let db = client.database("items");
32///
33/// for i in 0..5 {
34/// let db_ref = db.clone();
35///
36/// tokio::task::spawn(async move {
37/// let collection = db_ref.collection::<Document>(&format!("coll{}", i));
38///
39/// // Do something with the collection
40/// });
41/// }
42/// #
43/// # Ok(())
44/// # }
45/// ```
46#[derive(Clone, Debug)]
47pub struct Database {
48 inner: Arc<DatabaseInner>,
49}
50
51#[derive(Debug)]
52struct DatabaseInner {
53 client: Client,
54 name: String,
55 selection_criteria: Option<SelectionCriteria>,
56 read_concern: Option<ReadConcern>,
57 write_concern: Option<WriteConcern>,
58}
59
60impl Database {
61 pub(crate) fn new(client: Client, name: &str, options: Option<DatabaseOptions>) -> Self {
62 let options = options.unwrap_or_default();
63 let selection_criteria = options
64 .selection_criteria
65 .or_else(|| client.selection_criteria().cloned());
66
67 let read_concern = options
68 .read_concern
69 .or_else(|| client.read_concern().cloned());
70
71 let write_concern = options
72 .write_concern
73 .or_else(|| client.write_concern().cloned());
74
75 Self {
76 inner: Arc::new(DatabaseInner {
77 client,
78 name: name.to_string(),
79 selection_criteria,
80 read_concern,
81 write_concern,
82 }),
83 }
84 }
85
86 /// Get the `Client` that this collection descended from.
87 pub fn client(&self) -> &Client {
88 &self.inner.client
89 }
90
91 /// Gets the name of the `Database`.
92 pub fn name(&self) -> &str {
93 &self.inner.name
94 }
95
96 /// Gets the read preference of the `Database`.
97 pub fn selection_criteria(&self) -> Option<&SelectionCriteria> {
98 self.inner.selection_criteria.as_ref()
99 }
100
101 /// Gets the read concern of the `Database`.
102 pub fn read_concern(&self) -> Option<&ReadConcern> {
103 self.inner.read_concern.as_ref()
104 }
105
106 /// Gets the write concern of the `Database`.
107 pub fn write_concern(&self) -> Option<&WriteConcern> {
108 self.inner.write_concern.as_ref()
109 }
110
111 /// Gets a handle to a collection in this database with the provided name. The
112 /// [`Collection`] options (e.g. read preference and write concern) will default to those of
113 /// this [`Database`].
114 ///
115 /// For more information on how the generic parameter `T` is used, check out the [`Collection`]
116 /// documentation.
117 ///
118 /// This method does not send or receive anything across the wire to the database, so it can be
119 /// used repeatedly without incurring any costs from I/O.
120 pub fn collection<T: Send + Sync>(&self, name: &str) -> Collection<T> {
121 Collection::new(self.clone(), name, None)
122 }
123
124 /// Gets a handle to a collection in this database with the provided name.
125 /// Operations done with this `Collection` will use the options specified by
126 /// `options` and will otherwise default to those of this [`Database`].
127 ///
128 /// For more information on how the generic parameter `T` is used, check out the [`Collection`]
129 /// documentation.
130 ///
131 /// This method does not send or receive anything across the wire to the database, so it can be
132 /// used repeatedly without incurring any costs from I/O.
133 pub fn collection_with_options<T: Send + Sync>(
134 &self,
135 name: &str,
136 options: CollectionOptions,
137 ) -> Collection<T> {
138 Collection::new(self.clone(), name, Some(options))
139 }
140
141 /// Creates a new [`GridFsBucket`] in the database with the given options.
142 pub fn gridfs_bucket(&self, options: impl Into<Option<GridFsBucketOptions>>) -> GridFsBucket {
143 GridFsBucket::new(self.clone(), options.into().unwrap_or_default())
144 }
145}