Skip to content

Commit 899ea9f

Browse files
authored
RUST-438 Add more detailed documentation examples (#176)
1 parent a0984fa commit 899ea9f

File tree

3 files changed

+310
-43
lines changed

3 files changed

+310
-43
lines changed

README.md

Lines changed: 151 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,20 @@
77

88
Encoding and decoding support for BSON in Rust
99

10+
## Index
11+
- [Overview of BSON Format](#overview-of-bson-format)
12+
- [Usage](#usage)
13+
- [BSON Values](#bson-values)
14+
- [BSON Documents](#bson-documents)
15+
- [Modeling BSON with strongly typed data structures](#modeling-bson-with-strongly-typed-data-structures)
16+
- [Breaking Changes](#breaking-changes)
17+
- [Contributing](#contributing)
18+
- [Running the Tests](#running-the-tests)
19+
- [Continuous Integration](#continuous-integration)
20+
1021
## Useful links
1122
- [API Documentation](https://docs.rs/bson/)
12-
- [Serde](https://serde.rs/)
23+
- [Serde Documentation](https://serde.rs/)
1324

1425
## Installation
1526
This crate works with Cargo and can be found on
@@ -20,53 +31,164 @@ This crate works with Cargo and can be found on
2031
bson = "0.14"
2132
```
2233

34+
## Overview of BSON Format
35+
36+
BSON, short for Binary JSON, is a binary-encoded serialization of JSON-like documents.
37+
Like JSON, BSON supports the embedding of documents and arrays within other documents
38+
and arrays. BSON also contains extensions that allow representation of data types that
39+
are not part of the JSON spec. For example, BSON has a datetime type and a binary data type.
40+
41+
```text
42+
// JSON equivalent
43+
{"hello": "world"}
44+
45+
// BSON encoding
46+
\x16\x00\x00\x00 // total document size
47+
\x02 // 0x02 = type String
48+
hello\x00 // field name
49+
\x06\x00\x00\x00world\x00 // field value
50+
\x00 // 0x00 = type EOO ('end of object')
51+
```
52+
53+
BSON is the primary data representation for [MongoDB](https://www.mongodb.com/), and this crate is used in the
54+
[`mongodb`](https://docs.rs/mongodb/0.10.0/mongodb/) driver crate in its API and implementation.
55+
56+
For more information about BSON itself, see [bsonspec.org](http://bsonspec.org).
57+
2358
## Usage
2459

25-
Prepare your struct for Serde serialization:
60+
### BSON values
61+
62+
Many different types can be represented as a BSON value, including 32-bit and 64-bit signed
63+
integers, 64 bit floating point numbers, strings, datetimes, embedded documents, and more. To
64+
see a full list of possible BSON values, see the [BSON specification](http://bsonspec.org/spec.html). The various
65+
possible BSON values are modeled in this crate by the [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) enum.
66+
67+
#### Creating [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) instances
68+
69+
[`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) values can be instantiated directly or via the
70+
[`bson!`](https://docs.rs/bson/latest/bson/macro.bson.html) macro:
2671

2772
```rust
28-
#[derive(Serialize, Deserialize, Debug)]
29-
pub struct Person {
30-
#[serde(rename = "_id")] // Use MongoDB's special primary key field name when serializing
31-
pub id: bson::oid::ObjectId,
32-
pub name: String,
33-
pub age: i32
34-
}
73+
let string = Bson::String("hello world".to_string());
74+
let int = Bson::I32(5);
75+
let array = Bson::Array(vec![Bson::I32(5), Bson::Boolean(false)]);
76+
77+
let string: Bson = "hello world".into();
78+
let int: Bson = 5i32.into();
79+
80+
let string = bson!("hello world");
81+
let int = bson!(5);
82+
let array = bson!([5, false]);
3583
```
84+
[`bson!`](https://docs.rs/bson/latest/bson/macro.bson.html) has supports both array and object literals, and it automatically converts any values specified to [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html), provided they are `Into<Bson>`.
85+
86+
#### [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) value unwrapping
3687

37-
Serialize the struct:
88+
[`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html) has a number of helper methods for accessing the underlying native Rust types. These helpers can be useful in circumstances in which the specific type of a BSON value
89+
is known ahead of time.
3890

91+
e.g.:
3992
```rust
40-
use bson;
93+
let value = Bson::I32(5);
94+
let int = value.as_i32(); // Some(5)
95+
let bool = value.as_bool(); // None
4196

42-
let person = Person {
43-
id: "12345",
44-
name: "Emma",
45-
age: 3
46-
};
97+
let value = bson!([true]);
98+
let array = value.as_array(); // Some(&Vec<Bson>)
99+
```
47100

48-
let serialized_person = bson::to_bson(&person)?; // Serialize
101+
### BSON documents
49102

50-
if let bson::Bson::Document(document) = serialized_person {
51-
mongoCollection.insert_one(document, None)?; // Insert into a MongoDB collection
52-
} else {
53-
println!("Error converting the BSON object into a MongoDB document");
54-
}
103+
BSON documents are ordered maps of UTF-8 encoded strings to BSON values. They are logically similar to JSON objects in that they can contain subdocuments, arrays, and values of several different types. This crate models BSON documents via the
104+
[`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) struct.
105+
106+
#### Creating [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html)s
107+
108+
[`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html)s can be created directly either from a byte
109+
reader containing BSON data or via the `doc!` macro:
110+
```rust
111+
let mut bytes = hex::decode("0C0000001069000100000000").unwrap();
112+
let doc = Document::decode(&mut bytes.as_slice()).unwrap(); // { "i": 1 }
113+
114+
let doc = doc! {
115+
"hello": "world",
116+
"int": 5,
117+
"subdoc": { "cat": true },
118+
};
55119
```
120+
[`doc!`](https://docs.rs/bson/latest/bson/macro.doc.html) works similarly to [`bson!`](https://docs.rs/bson/latest/bson/macro.bson.html), except that it always
121+
returns a [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) rather than a [`Bson`](https://docs.rs/bson/latest/bson/enum.Bson.html).
122+
123+
#### [`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) member access
56124

57-
Deserialize the struct:
125+
[`Document`](https://docs.rs/bson/latest/bson/document/struct.Document.html) has a number of methods on it to facilitate member
126+
access:
58127

59128
```rust
60-
use bson::doc;
129+
let doc = doc! {
130+
"string": "string",
131+
"bool": true,
132+
"i32": 5,
133+
"doc": { "x": true },
134+
};
61135

62-
// Read the document from a MongoDB collection
63-
let person_document = mongoCollection.find_one(Some(doc! { "_id": bson::oid::ObjectId::with_string("12345").expect("Id not valid") }), None)?
64-
.expect("Document not found");
136+
// attempt get values as untyped Bson
137+
let none = doc.get("asdfadsf"); // None
138+
let value = doc.get("string"); // Some(&Bson::String("string"))
65139

66-
// Deserialize the document into a Person instance
67-
let person = bson::from_bson(bson::Bson::Document(person_document))?
140+
// attempt to get values with explicit typing
141+
let string = doc.get_str("string"); // Ok("string")
142+
let subdoc = doc.get_document("doc"); // Some(Document({ "x": true }))
143+
let error = doc.get_i64("i32"); // Err(...)
68144
```
69145

146+
### Modeling BSON with strongly typed data structures
147+
148+
While it is possible to work with documents and BSON values directly, it will often introduce a
149+
lot of boilerplate for verifying the necessary keys are present and their values are the correct
150+
types. [`serde`](https://serde.rs/) provides a powerful way of mapping BSON data into Rust data structures largely
151+
automatically, removing the need for all that boilerplate.
152+
153+
e.g.:
154+
```rust
155+
#[derive(Serialize, Deserialize)]
156+
struct Person {
157+
name: String,
158+
age: u8,
159+
phones: Vec<String>,
160+
}
161+
162+
fn typed_example() {
163+
// Some BSON input data as a `Bson`.
164+
let bson_data: Bson = bson!({
165+
"name": "John Doe",
166+
"age": 43,
167+
"phones": [
168+
"+44 1234567",
169+
"+44 2345678"
170+
]
171+
});
172+
173+
// Deserialize the Person struct from the BSON data, automatically
174+
// verifying that the necessary keys are present and that they are of
175+
// the correct types.
176+
let mut person: Person = bson::from_bson(bson_data).unwrap();
177+
178+
// Do things just like with any other Rust data structure.
179+
println!("Redacting {}'s record.", person.name);
180+
person.name = "REDACTED".to_string();
181+
182+
// Get a serialized version of the input data as a `Bson`.
183+
let redacted_bson = bson::to_bson(&person).unwrap();
184+
}
185+
```
186+
187+
Any types that implement `Serialize` and `Deserialize` can be used in this way. Doing so helps
188+
separate the "business logic" that operates over the data from the (de)serialization logic that
189+
translates the data to/from its serialized form. This can lead to more clear and concise code
190+
that is also less error prone.
191+
70192
## Breaking Changes
71193

72194
In the BSON specification, _unsigned integer types_ are unsupported; for example, `u32`. In the older version of this crate (< `v0.8.0`), if you uses `serde` to serialize _unsigned integer types_ into BSON, it will store them with `Bson::FloatingPoint` type. From `v0.8.0`, we removed this behavior and simply returned an error when you want to serialize _unsigned integer types_ to BSON. [#72](https://github.com/zonyitoo/bson-rs/pull/72)

0 commit comments

Comments
 (0)