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 {
auto const doc = bsoncxx::from_json(R"(invalid json)");
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(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) {
using bsoncxx::builder::basic::kvp;
bsoncxx::builder::basic::document builder;
builder.append(kvp("key", "value"));
bsoncxx::document::value original{builder.view()};
try {
builder.append(kvp("too big", big_string)); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
EXPECT(builder.view() == original.view());
}

### Sub-Document Append Failure

void example(bsoncxx::stdx::string_view big_string) {
using bsoncxx::builder::basic::kvp;
bsoncxx::builder::basic::document builder;
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.
}));
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
EXPECT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_doc{original.view()});
EXPECT(builder.view() == original.view());
}

### Sub-Array Append Failure

void example(bsoncxx::stdx::string_view big_string) {
using bsoncxx::builder::basic::kvp;
bsoncxx::builder::basic::document builder;
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.
}));
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
EXPECT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_doc{original.view()});
EXPECT(builder.view() == original.view());
}

## Using the Basic Array Builder

### Basic Append Failure

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

### Sub-Document Append Failure

void example(bsoncxx::stdx::string_view big_string) {
using bsoncxx::builder::basic::kvp;
bsoncxx::builder::basic::array builder;
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.
});
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
EXPECT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_array{original.view()});
EXPECT(builder.view() == original.view());
}

### Sub-Array Append Failure

void example(bsoncxx::stdx::string_view big_string) {
bsoncxx::builder::basic::array builder;
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.
});
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_cannot_append_string);
}
// Builder is in an erroneous state.
try {
builder.view(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unmatched_key_in_builder);
}
// Reset builder to a usable state.
builder.clear();
EXPECT(builder.view().empty());
// Restore the original state prior to the append failure.
builder.append(bsoncxx::builder::concatenate_array{original.view()});
EXPECT(builder.view() == original.view());
}

# Access a Document Element

## By Iteration

### End Iterators

// {"a": 1, "b": 2}
void example(bsoncxx::document::view doc) {
EXPECT(doc.begin() != doc.end());
auto iter = doc.begin(); // "a": 1
++iter; // "b": 2
++iter; // End iterator.
EXPECT(iter == doc.end());
++iter; // DO NOT DO THIS
EXPECT(iter == doc.end()); // Incrementing an end iterator results in an end iterator.
bsoncxx::document::element e = *iter; // DO NOT DO THIS
EXPECT(!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();
EXPECT(iter == doc.end()); // An invalid BSON document returns an end iterator.
bsoncxx::document::element e = *iter; // DO NOT DO THIS
EXPECT(!e); // An end iterator returns an invalid element.
}

## By Key

### Missing Element

// {"a": 1, "b": 2}
void example(bsoncxx::document::view doc) {
EXPECT(doc["a"]);
EXPECT(doc["b"]);
bsoncxx::document::element e = doc["c"];
EXPECT(!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) {
EXPECT(arr.begin() != arr.end());
auto iter = arr.begin(); // 1
++iter; // 2
++iter; // 3
++iter; // End iterator.
EXPECT(iter == arr.end());
++iter; // DO NOT DO THIS
EXPECT(iter == arr.end()); // Incrementing an end iterator results in an end iterator.
bsoncxx::array::element e = *iter; // DO NOT DO THIS
EXPECT(!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();
EXPECT(iter == arr.end()); // An invalid BSON document returns an end iterator.
bsoncxx::array::element e = *iter; // DO NOT DO THIS
EXPECT(!e); // An end iterator returns an invalid element.
}

## By Key

### Missing Element

// [1, 2, 3]
void example(bsoncxx::array::view arr) {
EXPECT(std::distance(arr.begin(), arr.end()) == 3);
bsoncxx::array::element e = arr[3];
EXPECT(!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();
bsoncxx::document::element e = doc["x"];
EXPECT(!e); // An invalid BSON document returns an invalid element.
try {
bsoncxx::stdx::string_view key = e.key(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unset_element);
}
try {
bsoncxx::type type = e.type(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unset_element);
}
}

### Invalid Type

// {"x": 1}
void example(bsoncxx::document::element e) {
EXPECT(e.key() == "x");
EXPECT(e.type() == bsoncxx::type::k_int32);
EXPECT(e.get_int32().value == 1);
try {
bsoncxx::types::b_double d = e.get_double(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_need_element_type_k_double);
}
try {
bsoncxx::types::b_string str = e.get_string(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(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();
bsoncxx::array::element e = arr[0];
EXPECT(!e); // An invalid BSON array returns an invalid element.
try {
bsoncxx::stdx::string_view key = e.key(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unset_element);
}
try {
bsoncxx::type type = e.type(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_unset_element);
}
}

### Invalid Type

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

# Use a BSON Value

## Query an Invalid Type

void example() {
bsoncxx::types::bson_value::view v;
EXPECT(v.type() == bsoncxx::type::k_null);
EXPECT(v.get_null() == bsoncxx::types::b_null{});
try {
bsoncxx::types::b_int32 i = v.get_int32(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_need_element_type_k_int32);
}
try {
bsoncxx::types::b_int64 i = v.get_int64(); // Throws.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(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.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_invalid_bson_type_id);
}
}

## From an Invalid Element

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

# Convert to a JSON String

## From an Invalid BSON Document

void example() {
using bsoncxx::ExtendedJsonMode;
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.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_failed_converting_bson_to_json);
}
}

## From an Invalid BSON Array

void example() {
using bsoncxx::ExtendedJsonMode;
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.
EXPECT(false && "should not reach this point");
} catch (bsoncxx::exception const& ex) {
EXPECT(ex.code() == bsoncxx::error_code::k_failed_converting_bson_to_json);
}
}