Skip to content

Commit

Permalink
Expose spec-specific errors in the public API for lookup in (#443)
Browse files Browse the repository at this point in the history
  • Loading branch information
DemetrisChr committed Aug 17, 2023
1 parent c6be14e commit 43cf66a
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/impl/lookup_in.cxx
Expand Up @@ -60,6 +60,7 @@ initiate_lookup_in_operation(std::shared_ptr<couchbase::core::cluster> core,
std::move(entry.value),
entry.original_index,
entry.exists,
entry.ec,
});
}
return handler(std::move(resp.ctx), lookup_in_result{ resp.cas, std::move(entries), resp.deleted });
Expand Down
26 changes: 26 additions & 0 deletions couchbase/lookup_in_result.hxx
Expand Up @@ -44,6 +44,7 @@ class lookup_in_result : public result
codec::binary value;
std::size_t original_index;
bool exists;
std::error_code ec;
};

/**
Expand Down Expand Up @@ -84,6 +85,11 @@ class lookup_in_result : public result
{
for (const entry& e : entries_) {
if (e.original_index == index) {
if (e.ec) {
throw std::system_error(
e.ec, "error getting result for spec at index " + std::to_string(index) + ", path \"" + e.path + "\"");
}

return codec::tao_json_serializer::deserialize<Document>(e.value);
}
}
Expand All @@ -105,6 +111,10 @@ class lookup_in_result : public result
{
for (const entry& e : entries_) {
if (e.path == path) {
if (e.ec) {
throw std::system_error(e.ec, "error getting result for path \"" + e.path + "\"");
}

return codec::tao_json_serializer::deserialize<Document>(e.value);
}
}
Expand All @@ -127,6 +137,10 @@ class lookup_in_result : public result
const auto& macro_string = subdoc::to_string(macro);
for (const entry& e : entries_) {
if (e.path == macro_string) {
if (e.ec) {
throw std::system_error(e.ec, "error getting result for macro \"" + macro_string + "\"");
}

return codec::tao_json_serializer::deserialize<Document>(e.value);
}
}
Expand All @@ -147,6 +161,10 @@ class lookup_in_result : public result
{
for (const entry& e : entries_) {
if (e.original_index == index) {
if (e.ec && e.ec != couchbase::errc::key_value::path_not_found) {
throw std::system_error(e.ec, "error getting result for path \"" + e.path + "\"");
}

return e.exists;
}
}
Expand All @@ -167,6 +185,10 @@ class lookup_in_result : public result
const auto& macro_string = subdoc::to_string(macro);
for (const entry& e : entries_) {
if (e.path == macro_string) {
if (e.ec && e.ec != couchbase::errc::key_value::path_not_found) {
throw std::system_error(e.ec, "error getting result for macro \"" + macro_string + "\"");
}

return e.exists;
}
}
Expand All @@ -186,6 +208,10 @@ class lookup_in_result : public result
{
for (const entry& e : entries_) {
if (e.path == path) {
if (e.ec && e.ec != couchbase::errc::key_value::path_not_found) {
throw std::system_error(e.ec, "error getting result for path \"" + e.path + "\"");
}

return e.exists;
}
}
Expand Down
86 changes: 86 additions & 0 deletions test/test_integration_subdoc.cxx
Expand Up @@ -1542,3 +1542,89 @@ TEST_CASE("integration: subdoc any replica reads", "[integration]")
}
}
}

TEST_CASE("integration: public API lookup in per-spec errors", "[integration]")
{
test::utils::integration_test_guard integration;

auto collection = couchbase::cluster(integration.cluster).bucket(integration.ctx.bucket).scope("_default").collection("_default");

auto key = test::utils::uniq_id("lookup_in_path_invalid");
{
auto value_json = couchbase::core::utils::json::parse(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
auto [ctx, result] = collection.upsert(key, value_json).get();
REQUIRE_SUCCESS(ctx.ec());
}

SECTION("path invalid")
{
auto specs = couchbase::lookup_in_specs{
couchbase::lookup_in_specs::get("..dictkey"),
};
auto [ctx, result] = collection.lookup_in(key, specs).get();
std::error_code ec{};
try {
std::ignore = result.content_as<std::string>(0);
} catch (std::system_error& exc) {
ec = exc.code();
}
REQUIRE(ec == couchbase::errc::key_value::path_invalid);

ec.clear();
try {
std::ignore = result.exists(0);
} catch (std::system_error& exc) {
ec = exc.code();
}
REQUIRE(ec == couchbase::errc::key_value::path_invalid);
}

SECTION("path mismatch")
{
auto specs = couchbase::lookup_in_specs{
couchbase::lookup_in_specs::count("dictkey"),
};
auto [ctx, result] = collection.lookup_in(key, specs).get();

std::error_code ec{};
try {
std::ignore = result.content_as<std::string>(0);
} catch (std::system_error& exc) {
ec = exc.code();
}
REQUIRE(ec == couchbase::errc::key_value::path_mismatch);

ec.clear();
try {
std::ignore = result.exists(0);
} catch (std::system_error& exc) {
ec = exc.code();
}
REQUIRE(ec == couchbase::errc::key_value::path_mismatch);
}

SECTION("path not found")
{
auto specs = couchbase::lookup_in_specs{
couchbase::lookup_in_specs::get("dictkey2"),
};
auto [ctx, result] = collection.lookup_in(key, specs).get();

std::error_code ec{};
try {
std::ignore = result.content_as<std::string>(0);
} catch (std::system_error& exc) {
ec = exc.code();
}
REQUIRE(ec == couchbase::errc::key_value::path_not_found);

ec.clear();
try {
auto exists = result.exists(0);
REQUIRE_FALSE(exists);
} catch (std::system_error& exc) {
ec = exc.code();
}
REQUIRE_SUCCESS(ec);
}
}

0 comments on commit 43cf66a

Please sign in to comment.