MongoDB C++ Driver mongocxx-3.11.0
Loading...
Searching...
No Matches
BSON Error Handling

How to handle BSON document failures, errors, and exceptions.

Create a BSON Document

From an Invalid JSON String

void example() {
try {
const auto doc = bsoncxx::from_json(R"(invalid json)");
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_json_parse_failure);
}
}

Using the Basic Document Builder

Basic Append Failure

void example(bsoncxx::stdx::string_view big_string) {
builder.append(kvp("key", "value"));
bsoncxx::document::value original{builder.view()};
try {
builder.append(kvp("too big", big_string)); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
ASSERT(builder.view() == original.view());
}

Sub-Document Append Failure

void example(bsoncxx::stdx::string_view big_string) {
builder.append(kvp("key", "value"));
bsoncxx::document::value original{builder.view()}; // Copy of current state.
try {
builder.append(kvp("bad", [&](bsoncxx::builder::basic::sub_document doc) {
doc.append(kvp("too big", big_string)); // Throws.
}));
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
ASSERT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_doc{original.view()});
ASSERT(builder.view() == original.view());
}

Sub-Array Append Failure

void example(bsoncxx::stdx::string_view big_string) {
builder.append(kvp("key", "value"));
bsoncxx::document::value original{builder.view()}; // Copy of current state.
try {
builder.append(kvp("bad", [&](bsoncxx::builder::basic::sub_array arr) {
arr.append(big_string); // Throws.
}));
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
ASSERT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_doc{original.view()});
ASSERT(builder.view() == original.view());
}

Using the Basic Array Builder

Basic Append Failure

void example(bsoncxx::stdx::string_view big_string) {
builder.append("element");
bsoncxx::array::value original{builder.view()};
try {
builder.append(big_string); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
ASSERT(builder.view() == original.view());
}

Sub-Document Append Failure

void example(bsoncxx::stdx::string_view big_string) {
builder.append("element");
bsoncxx::array::value original{builder.view()}; // Copy of current state.
try {
builder.append([&](bsoncxx::builder::basic::sub_document doc) {
doc.append(kvp("too big", big_string)); // Throws.
});
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
ASSERT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_array{original.view()});
ASSERT(builder.view() == original.view());
}

Sub-Array Append Failure

void example(bsoncxx::stdx::string_view big_string) {
builder.append("element");
bsoncxx::array::value original{builder.view()}; // Copy of current state.
try {
builder.append([&](bsoncxx::builder::basic::sub_array arr) {
arr.append(big_string); // Throws.
});
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
ASSERT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_array{original.view()});
ASSERT(builder.view() == original.view());
}

Access a Document Element

By Iteration

End Iterators

// {"a": 1, "b": 2}
void example(bsoncxx::document::view doc) {
ASSERT(doc.begin() != doc.end());
auto iter = doc.begin(); // "a": 1
++iter; // "b": 2
++iter; // End iterator.
ASSERT(iter == doc.end());
++iter; // DO NOT DO THIS
ASSERT(iter == doc.end()); // Incrementing an end iterator results in an end iterator.
bsoncxx::document::element e = *iter; // DO NOT DO THIS
ASSERT(!e); // An end iterator returns an invalid element.
}

Invalid BSON Documents

void example() {
bsoncxx::document::value::deleter_type deleter = [](std::uint8_t*) {};
std::uint8_t data[] = {0u}; // An invalid BSON document.
bsoncxx::document::value owner{data, sizeof(data), deleter};
bsoncxx::document::view doc = owner.view();
auto iter = doc.begin();
ASSERT(iter == doc.end()); // An invalid BSON document returns an end iterator.
bsoncxx::document::element e = *iter; // DO NOT DO THIS
ASSERT(!e); // An end iterator returns an invalid element.
}

By Key

Missing Element

// {"a": 1, "b": 2}
void example(bsoncxx::document::view doc) {
ASSERT(doc["a"]);
ASSERT(doc["b"]);
ASSERT(!e); // A missing element is represented as an invalid element.
}

Access an Array Element

By Iteration

End Iterators

// [1, 2, 3]
void example(bsoncxx::array::view arr) {
ASSERT(arr.begin() != arr.end());
auto iter = arr.begin(); // 1
++iter; // 2
++iter; // 3
++iter; // End iterator.
ASSERT(iter == arr.end());
++iter; // DO NOT DO THIS
ASSERT(iter == arr.end()); // Incrementing an end iterator results in an end iterator.
bsoncxx::array::element e = *iter; // DO NOT DO THIS
ASSERT(!e); // An end iterator returns an invalid element.
}

Invalid BSON Arrays

void example() {
bsoncxx::array::value::deleter_type deleter = [](std::uint8_t*) {};
std::uint8_t data[] = {0u}; // An invalid BSON array.
bsoncxx::array::value owner{data, sizeof(data), deleter};
bsoncxx::array::view arr = owner.view();
auto iter = arr.begin();
ASSERT(iter == arr.end()); // An invalid BSON document returns an end iterator.
bsoncxx::array::element e = *iter; // DO NOT DO THIS
ASSERT(!e); // An end iterator returns an invalid element.
}

By Key

Missing Element

// [1, 2, 3]
void example(bsoncxx::array::view arr) {
ASSERT(std::distance(arr.begin(), arr.end()) == 3);
ASSERT(!e); // A missing element is represented as an invalid element.
}

Query an Element

In a Document

Invalid Element

void example() {
bsoncxx::document::value::deleter_type deleter = [](std::uint8_t*) {};
std::uint8_t data[] = {0u}; // An invalid BSON document.
bsoncxx::document::value owner{data, sizeof(data), deleter};
bsoncxx::document::view doc = owner.view();
ASSERT(!e); // An invalid BSON document returns an invalid element.
try {
bsoncxx::stdx::string_view key = e.key(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unset_element);
}
try {
bsoncxx::type type = e.type(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unset_element);
}
}

Invalid Type

// {"x": 1}
void example(bsoncxx::document::element e) {
ASSERT(e.key().compare("x") == 0);
ASSERT(e.type() == bsoncxx::type::k_int32);
ASSERT(e.get_int32().value == 1);
try {
bsoncxx::types::b_double d = e.get_double(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_need_element_type_k_double);
}
try {
bsoncxx::types::b_string str = e.get_string(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_need_element_type_k_string);
}
}

In an Array

Invalid Element

void example() {
bsoncxx::array::value::deleter_type deleter = [](std::uint8_t*) {};
std::uint8_t data[] = {0u}; // An invalid BSON array.
bsoncxx::array::value owner{data, sizeof(data), deleter};
bsoncxx::array::view arr = owner.view();
ASSERT(!e); // An invalid BSON array returns an invalid element.
try {
bsoncxx::stdx::string_view key = e.key(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unset_element);
}
try {
bsoncxx::type type = e.type(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unset_element);
}
}

Invalid Type

// [1]
void example(bsoncxx::array::element e) {
ASSERT(e.key().compare("0") == 0);
ASSERT(e.type() == bsoncxx::type::k_int32);
ASSERT(e.get_int32().value == 1);
try {
bsoncxx::types::b_double d = e.get_double(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_need_element_type_k_double);
}
try {
bsoncxx::types::b_string str = e.get_string(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_need_element_type_k_string);
}
}

Use a BSON Value

Query an Invalid Type

void example() {
ASSERT(v.type() == bsoncxx::type::k_null);
ASSERT(v.get_null() == bsoncxx::types::b_null{});
try {
bsoncxx::types::b_int32 i = v.get_int32(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_need_element_type_k_int32);
}
try {
bsoncxx::types::b_int64 i = v.get_int64(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_need_element_type_k_int64);
}
}

Create an Invalid Value

void example() {
try {
bsoncxx::types::bson_value::value value{bsoncxx::type::k_null}; // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_invalid_bson_type_id);
}
}

From an Invalid Element

void example() {
try {
bsoncxx::types::bson_value::view v = e.get_value(); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_unset_element);
}
}

Convert to a JSON String

From an Invalid BSON Document

void example() {
bsoncxx::document::value::deleter_type deleter = [](std::uint8_t*) {};
std::uint8_t data[] = {0u}; // Invalid BSON document.
bsoncxx::document::value owner{data, sizeof(data), deleter};
bsoncxx::document::view doc = owner.view();
try {
std::string json = bsoncxx::to_json(doc); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_failed_converting_bson_to_json);
}
}

From an Invalid BSON Array

void example() {
bsoncxx::array::value::deleter_type deleter = [](std::uint8_t*) {};
std::uint8_t data[] = {0u}; // Invalid BSON array.
bsoncxx::array::value owner{data, sizeof(data), deleter};
bsoncxx::array::view doc = owner.view();
try {
std::string json = bsoncxx::to_json(doc); // Throws.
ASSERT(false && "should not reach this point");
} catch (const bsoncxx::exception& ex) {
ASSERT(ex.code() == bsoncxx::error_code::k_failed_converting_bson_to_json);
}
}