Skip to content

Commit fbca7d0

Browse files
authored
RUST-434 Rewrite ReadConcern as a struct (#180)
1 parent 2f403a4 commit fbca7d0

File tree

7 files changed

+86
-32
lines changed

7 files changed

+86
-32
lines changed

src/client/options/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::{
3232
concern::{Acknowledgment, ReadConcern, WriteConcern},
3333
error::{ErrorKind, Result},
3434
event::{cmap::CmapEventHandler, command::CommandEventHandler},
35+
options::ReadConcernLevel,
3536
sdam::MIN_HEARTBEAT_FREQUENCY,
3637
selection_criteria::{ReadPreference, SelectionCriteria, TagSet},
3738
srv::SrvResolver,
@@ -1231,7 +1232,7 @@ impl ClientOptionsParser {
12311232
self.max_pool_size = Some(get_u32!(value, k));
12321233
}
12331234
"readconcernlevel" => {
1234-
self.read_concern = Some(ReadConcern::Custom(value.to_string()));
1235+
self.read_concern = Some(ReadConcernLevel::from_str(value).into());
12351236
}
12361237
"readpreference" => {
12371238
self.read_preference = Some(match &value.to_lowercase()[..] {
@@ -1482,7 +1483,7 @@ mod tests {
14821483

14831484
use super::{ClientOptions, StreamAddress};
14841485
use crate::{
1485-
concern::{Acknowledgment, ReadConcern, WriteConcern},
1486+
concern::{Acknowledgment, ReadConcernLevel, WriteConcern},
14861487
selection_criteria::ReadPreference,
14871488
};
14881489

@@ -1620,7 +1621,7 @@ mod tests {
16201621
hostname: "localhost".to_string(),
16211622
port: Some(27017),
16221623
}],
1623-
read_concern: Some(ReadConcern::Custom("foo".to_string())),
1624+
read_concern: Some(ReadConcernLevel::Custom("foo".to_string()).into()),
16241625
original_uri: Some(uri.into()),
16251626
..Default::default()
16261627
}
@@ -1820,7 +1821,7 @@ mod tests {
18201821
}
18211822
.into()
18221823
),
1823-
read_concern: Some(ReadConcern::Majority),
1824+
read_concern: Some(ReadConcernLevel::Majority.into()),
18241825
write_concern: Some(write_concern),
18251826
repl_set_name: Some("foo".to_string()),
18261827
heartbeat_freq: Some(Duration::from_millis(1000)),

src/client/options/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ fn document_from_client_options(mut options: ClientOptions) -> Document {
167167
}
168168

169169
if let Some(s) = options.read_concern.take() {
170-
doc.insert("readconcernlevel", s.as_str());
170+
doc.insert("readconcernlevel", s.level.as_str());
171171
}
172172

173173
if let Some(i_or_s) = options

src/concern/mod.rs

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,59 @@ use crate::{
2020
///
2121
/// See the documentation [here](https://docs.mongodb.com/manual/reference/read-concern/) for more
2222
/// information about read concerns.
23-
#[derive(Clone, Debug)]
24-
pub enum ReadConcern {
23+
#[derive(Clone, Debug, Serialize, PartialEq)]
24+
#[non_exhaustive]
25+
pub struct ReadConcern {
26+
/// The level of the read concern.
27+
pub level: ReadConcernLevel,
28+
}
29+
30+
impl ReadConcern {
31+
/// Creates a read concern with level "majority".
32+
/// See the specific documentation for this read concern level [here](https://docs.mongodb.com/manual/reference/read-concern-majority/).
33+
pub fn majority() -> Self {
34+
ReadConcernLevel::Majority.into()
35+
}
36+
37+
/// Creates a read concern with level "local".
38+
/// See the specific documentation for this read concern level [here](https://docs.mongodb.com/manual/reference/read-concern-local/).
39+
pub fn local() -> Self {
40+
ReadConcernLevel::Local.into()
41+
}
42+
43+
/// Creates a read concern with level "linearizable".
44+
/// See the specific documentation for this read concern level [here](https://docs.mongodb.com/manual/reference/read-concern-linearizable/).
45+
pub fn linearizable() -> Self {
46+
ReadConcernLevel::Linearizable.into()
47+
}
48+
49+
/// Creates a read concern with level "available".
50+
/// See the specific documentation for this read concern level [here](https://docs.mongodb.com/manual/reference/read-concern-available/).
51+
pub fn available() -> Self {
52+
ReadConcernLevel::Available.into()
53+
}
54+
55+
/// Creates a read concern with a custom read concern level. This is present to provide forwards
56+
/// compatibility with any future read concerns which may be added to new versions of
57+
/// MongoDB.
58+
pub fn custom(level: String) -> Self {
59+
ReadConcernLevel::from_str(level.as_str()).into()
60+
}
61+
}
62+
63+
impl From<ReadConcernLevel> for ReadConcern {
64+
fn from(level: ReadConcernLevel) -> Self {
65+
Self { level }
66+
}
67+
}
68+
69+
/// Specifies the level consistency and isolation properties of a given `ReadCocnern`.
70+
///
71+
/// See the documentation [here](https://docs.mongodb.com/manual/reference/read-concern/) for more
72+
/// information about read concerns.
73+
#[derive(Debug, Clone, PartialEq)]
74+
#[non_exhaustive]
75+
pub enum ReadConcernLevel {
2576
/// See the specific documentation for this read concern level [here](https://docs.mongodb.com/manual/reference/read-concern-local/).
2677
Local,
2778

@@ -39,34 +90,35 @@ pub enum ReadConcern {
3990
Custom(String),
4091
}
4192

42-
impl PartialEq for ReadConcern {
43-
fn eq(&self, other: &Self) -> bool {
44-
self.as_str() == other.as_str()
93+
impl ReadConcernLevel {
94+
pub(crate) fn from_str(s: &str) -> Self {
95+
match s {
96+
"local" => ReadConcernLevel::Local,
97+
"majority" => ReadConcernLevel::Majority,
98+
"linearizable" => ReadConcernLevel::Linearizable,
99+
"available" => ReadConcernLevel::Available,
100+
s => ReadConcernLevel::Custom(s.to_string()),
101+
}
45102
}
46-
}
47103

48-
impl ReadConcern {
49-
/// Gets the string representation of the `ReadConcern`.
50-
pub fn as_str(&self) -> &str {
51-
match *self {
52-
ReadConcern::Local => "local",
53-
ReadConcern::Majority => "majority",
54-
ReadConcern::Linearizable => "linearizable",
55-
ReadConcern::Available => "available",
56-
ReadConcern::Custom(ref s) => s,
104+
/// Gets the string representation of the `ReadConcernLevel`.
105+
pub(crate) fn as_str(&self) -> &str {
106+
match self {
107+
ReadConcernLevel::Local => "local",
108+
ReadConcernLevel::Majority => "majority",
109+
ReadConcernLevel::Linearizable => "linearizable",
110+
ReadConcernLevel::Available => "available",
111+
ReadConcernLevel::Custom(ref s) => s,
57112
}
58113
}
59114
}
60115

61-
impl Serialize for ReadConcern {
116+
impl Serialize for ReadConcernLevel {
62117
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
63118
where
64119
S: Serializer,
65120
{
66-
(doc! {
67-
"level": self.as_str().to_string()
68-
})
69-
.serialize(serializer)
121+
self.as_str().serialize(serializer)
70122
}
71123
}
72124

src/operation/aggregate/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::AggregateTarget;
66
use crate::{
77
bson_util,
88
cmap::{CommandResponse, StreamDescription},
9-
concern::ReadConcern,
9+
concern::{ReadConcern, ReadConcernLevel},
1010
error::{ErrorKind, WriteFailure},
1111
operation::{test, Aggregate, Operation},
1212
options::{AggregateOptions, Hint, StreamAddress},
@@ -47,7 +47,7 @@ async fn build() {
4747
let options = AggregateOptions::builder()
4848
.hint(Hint::Keys(doc! { "x": 1, "y": 2 }))
4949
.bypass_document_validation(true)
50-
.read_concern(ReadConcern::Available)
50+
.read_concern(ReadConcern::from(ReadConcernLevel::Available))
5151
.build();
5252

5353
let expected_body = doc! {

src/operation/count/test.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{
88
concern::ReadConcern,
99
error::ErrorKind,
1010
operation::{test, Count, Operation},
11+
options::ReadConcernLevel,
1112
};
1213

1314
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
@@ -34,7 +35,7 @@ async fn build() {
3435
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
3536
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
3637
async fn build_with_options() {
37-
let read_concern = ReadConcern::Local;
38+
let read_concern: ReadConcern = ReadConcernLevel::Local.into();
3839
let max_time = Duration::from_millis(2 as u64);
3940
let options: EstimatedDocumentCountOptions = EstimatedDocumentCountOptions::builder()
4041
.max_time(max_time)
@@ -54,7 +55,7 @@ async fn build_with_options() {
5455
doc! {
5556
"count": "test_coll",
5657
"maxTimeMS": max_time.as_millis() as i64,
57-
"readConcern": doc!{"level": read_concern.as_str().to_string()}
58+
"readConcern": doc!{"level": read_concern.level.as_str().to_string()}
5859
}
5960
);
6061
assert_eq!(count_command.target_db, "test_db");

src/operation/find/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
bson_util,
77
cmap::{CommandResponse, StreamDescription},
88
operation::{test, Find, Operation},
9-
options::{CursorType, FindOptions, Hint, ReadConcern, StreamAddress},
9+
options::{CursorType, FindOptions, Hint, ReadConcern, ReadConcernLevel, StreamAddress},
1010
Namespace,
1111
};
1212

@@ -46,7 +46,7 @@ async fn build() {
4646
.hint(Hint::Keys(doc! { "x": 1, "y": 2 }))
4747
.projection(doc! { "x": 0 })
4848
.allow_partial_results(true)
49-
.read_concern(ReadConcern::Available)
49+
.read_concern(ReadConcern::from(ReadConcernLevel::Available))
5050
.build();
5151

5252
let expected_body = doc! {

src/test/spec/read_write_concern/connection_string.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ async fn run_connection_string_test(test_file: TestFile) {
4444
let mut actual_read_concern = Document::new();
4545

4646
if let Some(client_read_concern) = options.read_concern {
47-
actual_read_concern.insert("level", client_read_concern.as_str());
47+
actual_read_concern.insert("level", client_read_concern.level.as_str());
4848
}
4949

5050
assert_eq!(

0 commit comments

Comments
 (0)