From e0966ea199c98e6237ecee26932af6646f7ea5bf Mon Sep 17 00:00:00 2001 From: Sergey Avseyev Date: Wed, 26 Jan 2022 19:54:02 +0000 Subject: [PATCH] fix naming for responses of the HTTP queries (#117) --- couchbase/operations/document_analytics.cxx | 128 ++++++++--------- couchbase/operations/document_analytics.hxx | 10 +- couchbase/operations/document_query.cxx | 144 +++++++++----------- couchbase/operations/document_query.hxx | 13 +- couchbase/operations/document_search.cxx | 17 +-- couchbase/operations/document_search.hxx | 2 +- couchbase/operations/document_view.cxx | 4 +- couchbase/operations/document_view.hxx | 2 +- test/test_integration_diagnostics.cxx | 8 +- test/test_integration_query.cxx | 22 +-- 10 files changed, 158 insertions(+), 192 deletions(-) diff --git a/couchbase/operations/document_analytics.cxx b/couchbase/operations/document_analytics.cxx index 6b21f9a6..a8b25d8f 100644 --- a/couchbase/operations/document_analytics.cxx +++ b/couchbase/operations/document_analytics.cxx @@ -23,71 +23,6 @@ #include -namespace tao::json -{ -template<> -struct traits { - template class Traits> - static couchbase::operations::analytics_response_payload as(const tao::json::basic_value& v) - { - couchbase::operations::analytics_response_payload result; - result.meta_data.request_id = v.at("requestID").get_string(); - result.meta_data.client_context_id = v.at("clientContextID").get_string(); - result.meta_data.status = v.at("status").get_string(); - - if (const auto* s = v.find("signature"); s != nullptr) { - result.meta_data.signature = couchbase::utils::json::generate(*s); - } - - if (const auto* p = v.find("profile"); p != nullptr) { - result.meta_data.profile = couchbase::utils::json::generate(*p); - } - - if (const auto* m = v.find("metrics"); m != nullptr) { - result.meta_data.metrics.result_count = m->at("resultCount").get_unsigned(); - result.meta_data.metrics.result_size = m->at("resultSize").get_unsigned(); - result.meta_data.metrics.elapsed_time = m->at("elapsedTime").get_string(); - result.meta_data.metrics.execution_time = m->at("executionTime").get_string(); - result.meta_data.metrics.sort_count = m->template optional("sortCount"); - result.meta_data.metrics.mutation_count = m->template optional("mutationCount"); - result.meta_data.metrics.error_count = m->template optional("errorCount"); - result.meta_data.metrics.warning_count = m->template optional("warningCount"); - } - - if (const auto* e = v.find("errors"); e != nullptr) { - std::vector problems{}; - for (auto& err : e->get_array()) { - couchbase::operations::analytics_response_payload::analytics_problem problem; - problem.code = err.at("code").get_unsigned(); - problem.message = err.at("msg").get_string(); - problems.emplace_back(problem); - } - result.meta_data.errors.emplace(problems); - } - - if (const auto* w = v.find("warnings"); w != nullptr) { - std::vector problems{}; - for (auto& warn : w->get_array()) { - couchbase::operations::analytics_response_payload::analytics_problem problem; - problem.code = warn.at("code").get_unsigned(); - problem.message = warn.at("msg").get_string(); - problems.emplace_back(problem); - } - result.meta_data.warnings.emplace(problems); - } - - if (const auto* r = v.find("results"); r != nullptr) { - result.rows.reserve(result.meta_data.metrics.result_count); - for (auto& row : r->get_array()) { - result.rows.emplace_back(couchbase::utils::json::generate(row)); - } - } - - return result; - } -}; -} // namespace tao::json - namespace couchbase::operations { std::error_code @@ -164,14 +99,67 @@ analytics_request::make_response(error_context::analytics&& ctx, const encoded_r response.ctx.statement = statement; response.ctx.parameters = body_str; if (!response.ctx.ec) { + tao::json::value payload; try { - response.payload = utils::json::parse(encoded.body.data()).as(); + payload = utils::json::parse(encoded.body.data()); } catch (const tao::pegtl::parse_error&) { response.ctx.ec = error::common_errc::parsing_failure; return response; } - Expects(response.payload.meta_data.client_context_id == client_context_id); - if (response.payload.meta_data.status != "success") { + response.meta.request_id = payload.at("requestID").get_string(); + response.meta.client_context_id = payload.at("clientContextID").get_string(); + response.meta.status = payload.at("status").get_string(); + + if (const auto* s = payload.find("signature"); s != nullptr) { + response.meta.signature = couchbase::utils::json::generate(*s); + } + + if (const auto* p = payload.find("profile"); p != nullptr) { + response.meta.profile = couchbase::utils::json::generate(*p); + } + + if (const auto* m = payload.find("metrics"); m != nullptr) { + response.meta.metrics.result_count = m->at("resultCount").get_unsigned(); + response.meta.metrics.result_size = m->at("resultSize").get_unsigned(); + response.meta.metrics.elapsed_time = m->at("elapsedTime").get_string(); + response.meta.metrics.execution_time = m->at("executionTime").get_string(); + response.meta.metrics.sort_count = m->template optional("sortCount"); + response.meta.metrics.mutation_count = m->template optional("mutationCount"); + response.meta.metrics.error_count = m->template optional("errorCount"); + response.meta.metrics.warning_count = m->template optional("warningCount"); + } + + if (const auto* e = payload.find("errors"); e != nullptr) { + std::vector problems{}; + for (const auto& err : e->get_array()) { + couchbase::operations::analytics_response::analytics_problem problem; + problem.code = err.at("code").get_unsigned(); + problem.message = err.at("msg").get_string(); + problems.emplace_back(problem); + } + response.meta.errors.emplace(problems); + } + + if (const auto* w = payload.find("warnings"); w != nullptr) { + std::vector problems{}; + for (const auto& warn : w->get_array()) { + couchbase::operations::analytics_response::analytics_problem problem; + problem.code = warn.at("code").get_unsigned(); + problem.message = warn.at("msg").get_string(); + problems.emplace_back(problem); + } + response.meta.warnings.emplace(problems); + } + + if (const auto* r = payload.find("results"); r != nullptr) { + response.rows.reserve(response.meta.metrics.result_count); + for (const auto& row : r->get_array()) { + response.rows.emplace_back(couchbase::utils::json::generate(row)); + } + } + + Expects(response.meta.client_context_id == client_context_id); + if (response.meta.status != "success") { bool server_timeout = false; bool job_queue_is_full = false; bool dataset_not_found = false; @@ -181,8 +169,8 @@ analytics_request::make_response(error_context::analytics&& ctx, const encoded_r bool link_not_found = false; bool compilation_failure = false; - if (response.payload.meta_data.errors) { - for (const auto& error : *response.payload.meta_data.errors) { + if (response.meta.errors) { + for (const auto& error : *response.meta.errors) { switch (error.code) { case 21002: /* Request timed out and will be cancelled */ server_timeout = true; diff --git a/couchbase/operations/document_analytics.hxx b/couchbase/operations/document_analytics.hxx index 726eb97c..bc0e9fb4 100644 --- a/couchbase/operations/document_analytics.hxx +++ b/couchbase/operations/document_analytics.hxx @@ -26,7 +26,7 @@ namespace couchbase::operations { -struct analytics_response_payload { +struct analytics_response { struct analytics_metrics { std::string elapsed_time; std::string execution_time; @@ -54,13 +54,9 @@ struct analytics_response_payload { std::optional> errors; }; - analytics_meta_data meta_data{}; - std::vector rows{}; -}; - -struct analytics_response { error_context::analytics ctx; - analytics_response_payload payload{}; + analytics_meta_data meta{}; + std::vector rows{}; }; struct analytics_request { diff --git a/couchbase/operations/document_query.cxx b/couchbase/operations/document_query.cxx index 7d83d244..f22e7cb7 100644 --- a/couchbase/operations/document_query.cxx +++ b/couchbase/operations/document_query.cxx @@ -24,75 +24,6 @@ #include -namespace tao::json -{ -template<> -struct traits { - template class Traits> - static couchbase::operations::query_response_payload as(const tao::json::basic_value& v) - { - couchbase::operations::query_response_payload result; - result.meta_data.request_id = v.at("requestID").get_string(); - - if (const auto* i = v.find("clientContextID"); i != nullptr) { - result.meta_data.client_context_id = i->get_string(); - } - result.meta_data.status = v.at("status").get_string(); - if (const auto* s = v.find("signature"); s != nullptr) { - result.meta_data.signature = couchbase::utils::json::generate(*s); - } - if (const auto* c = v.find("prepared"); c != nullptr) { - result.prepared = c->get_string(); - } - if (const auto* p = v.find("profile"); p != nullptr) { - result.meta_data.profile = couchbase::utils::json::generate(*p); - } - - if (const auto* m = v.find("metrics"); m != nullptr) { - result.meta_data.metrics.result_count = m->at("resultCount").get_unsigned(); - result.meta_data.metrics.result_size = m->at("resultSize").get_unsigned(); - result.meta_data.metrics.elapsed_time = m->at("elapsedTime").get_string(); - result.meta_data.metrics.execution_time = m->at("executionTime").get_string(); - result.meta_data.metrics.sort_count = m->template optional("sortCount"); - result.meta_data.metrics.mutation_count = m->template optional("mutationCount"); - result.meta_data.metrics.error_count = m->template optional("errorCount"); - result.meta_data.metrics.warning_count = m->template optional("warningCount"); - } - - if (const auto* e = v.find("errors"); e != nullptr) { - std::vector problems{}; - for (auto& err : e->get_array()) { - couchbase::operations::query_response_payload::query_problem problem; - problem.code = err.at("code").get_unsigned(); - problem.message = err.at("msg").get_string(); - problems.emplace_back(problem); - } - result.meta_data.errors.emplace(problems); - } - - if (const auto* w = v.find("warnings"); w != nullptr) { - std::vector problems{}; - for (auto& warn : w->get_array()) { - couchbase::operations::query_response_payload::query_problem problem; - problem.code = warn.at("code").get_unsigned(); - problem.message = warn.at("msg").get_string(); - problems.emplace_back(problem); - } - result.meta_data.warnings.emplace(problems); - } - - if (const auto* r = v.find("results"); r != nullptr) { - result.rows.reserve(result.meta_data.metrics.result_count); - for (auto& row : r->get_array()) { - result.rows.emplace_back(couchbase::utils::json::generate(row)); - } - } - - return result; - } -}; -} // namespace tao::json - namespace couchbase::operations { std::error_code @@ -252,22 +183,79 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_ response.ctx.parameters = body_str; response.served_by_node = response.ctx.last_dispatched_to.value_or(""); if (!response.ctx.ec) { + tao::json::value payload; try { - response.payload = utils::json::parse(encoded.body.data()).as(); + payload = utils::json::parse(encoded.body.data()); } catch (const tao::pegtl::parse_error&) { response.ctx.ec = error::common_errc::parsing_failure; return response; } - Expects(response.payload.meta_data.client_context_id.empty() || response.payload.meta_data.client_context_id == client_context_id); - if (response.payload.meta_data.status == "success") { - if (response.payload.prepared) { - ctx_->cache.put(statement, response.payload.prepared.value()); + response.meta.request_id = payload.at("requestID").get_string(); + + if (const auto* i = payload.find("clientContextID"); i != nullptr) { + response.meta.client_context_id = i->get_string(); + } + response.meta.status = payload.at("status").get_string(); + if (const auto* s = payload.find("signature"); s != nullptr) { + response.meta.signature = couchbase::utils::json::generate(*s); + } + if (const auto* c = payload.find("prepared"); c != nullptr) { + response.prepared = c->get_string(); + } + if (const auto* p = payload.find("profile"); p != nullptr) { + response.meta.profile = couchbase::utils::json::generate(*p); + } + + if (const auto* m = payload.find("metrics"); m != nullptr) { + response.meta.metrics.result_count = m->at("resultCount").get_unsigned(); + response.meta.metrics.result_size = m->at("resultSize").get_unsigned(); + response.meta.metrics.elapsed_time = m->at("elapsedTime").get_string(); + response.meta.metrics.execution_time = m->at("executionTime").get_string(); + response.meta.metrics.sort_count = m->template optional("sortCount"); + response.meta.metrics.mutation_count = m->template optional("mutationCount"); + response.meta.metrics.error_count = m->template optional("errorCount"); + response.meta.metrics.warning_count = m->template optional("warningCount"); + } + + if (const auto* e = payload.find("errors"); e != nullptr) { + std::vector problems{}; + for (const auto& err : e->get_array()) { + couchbase::operations::query_response::query_problem problem; + problem.code = err.at("code").get_unsigned(); + problem.message = err.at("msg").get_string(); + problems.emplace_back(problem); + } + response.meta.errors.emplace(problems); + } + + if (const auto* w = payload.find("warnings"); w != nullptr) { + std::vector problems{}; + for (const auto& warn : w->get_array()) { + couchbase::operations::query_response::query_problem problem; + problem.code = warn.at("code").get_unsigned(); + problem.message = warn.at("msg").get_string(); + problems.emplace_back(problem); + } + response.meta.warnings.emplace(problems); + } + + if (const auto* r = payload.find("results"); r != nullptr) { + response.rows.reserve(response.meta.metrics.result_count); + for (const auto& row : r->get_array()) { + response.rows.emplace_back(couchbase::utils::json::generate(row)); + } + } + + Expects(response.meta.client_context_id.empty() || response.meta.client_context_id == client_context_id); + if (response.meta.status == "success") { + if (response.prepared) { + ctx_->cache.put(statement, response.prepared.value()); } else if (extract_encoded_plan_) { extract_encoded_plan_ = false; - if (response.payload.rows.size() == 1) { + if (response.rows.size() == 1) { tao::json::value row{}; try { - row = utils::json::parse(response.payload.rows[0]); + row = utils::json::parse(response.rows[0]); } catch (const tao::pegtl::parse_error&) { response.ctx.ec = error::common_errc::parsing_failure; return response; @@ -297,8 +285,8 @@ query_request::make_response(error_context::query&& ctx, const encoded_response_ bool authentication_failure = false; std::optional common_ec{}; - if (response.payload.meta_data.errors) { - for (const auto& error : *response.payload.meta_data.errors) { + if (response.meta.errors) { + for (const auto& error : *response.meta.errors) { switch (error.code) { case 1065: /* IKey: "service.io.request.unrecognized_parameter" */ invalid_argument = true; diff --git a/couchbase/operations/document_query.hxx b/couchbase/operations/document_query.hxx index c08d1a4b..d405571c 100644 --- a/couchbase/operations/document_query.hxx +++ b/couchbase/operations/document_query.hxx @@ -28,7 +28,7 @@ namespace couchbase::operations { -struct query_response_payload { +struct query_response { struct query_metrics { std::string elapsed_time; std::string execution_time; @@ -56,17 +56,10 @@ struct query_response_payload { std::optional> errors; }; - query_meta_data meta_data{}; + error_context::query ctx; + query_meta_data meta{}; std::optional prepared{}; std::vector rows{}; -}; -} // namespace couchbase::operations - -namespace couchbase::operations -{ -struct query_response { - error_context::query ctx; - query_response_payload payload{}; std::string served_by_node{}; }; diff --git a/couchbase/operations/document_search.cxx b/couchbase/operations/document_search.cxx index e5d6b87a..d33b1aae 100644 --- a/couchbase/operations/document_search.cxx +++ b/couchbase/operations/document_search.cxx @@ -121,7 +121,7 @@ search_response search_request::make_response(error_context::search&& ctx, const encoded_response_type& encoded) const { search_response response{ std::move(ctx) }; - response.meta_data.client_context_id = client_context_id; + response.meta.client_context_id = client_context_id; response.ctx.index_name = index_name; response.ctx.query = query.str(); response.ctx.parameters = body_str; @@ -134,9 +134,9 @@ search_request::make_response(error_context::search&& ctx, const encoded_respons response.ctx.ec = error::common_errc::parsing_failure; return response; } - response.meta_data.metrics.took = std::chrono::nanoseconds(payload.at("took").get_unsigned()); - response.meta_data.metrics.max_score = payload.at("max_score").as(); - response.meta_data.metrics.total_rows = payload.at("total_hits").get_unsigned(); + response.meta.metrics.took = std::chrono::nanoseconds(payload.at("took").get_unsigned()); + response.meta.metrics.max_score = payload.at("max_score").as(); + response.meta.metrics.total_rows = payload.at("total_hits").get_unsigned(); if (auto& status_prop = payload.at("status"); status_prop.is_string()) { response.status = status_prop.get_string(); @@ -144,11 +144,11 @@ search_request::make_response(error_context::search&& ctx, const encoded_respons return response; } } else if (status_prop.is_object()) { - response.meta_data.metrics.error_partition_count = status_prop.at("failed").get_unsigned(); - response.meta_data.metrics.success_partition_count = status_prop.at("successful").get_unsigned(); + response.meta.metrics.error_partition_count = status_prop.at("failed").get_unsigned(); + response.meta.metrics.success_partition_count = status_prop.at("successful").get_unsigned(); if (const auto* errors = status_prop.find("errors"); errors != nullptr && errors->is_object()) { for (const auto& [location, message] : errors->get_object()) { - response.meta_data.errors.try_emplace(location, message.get_string()); + response.meta.errors.try_emplace(location, message.get_string()); } } } else { @@ -258,7 +258,8 @@ search_request::make_response(error_context::search&& ctx, const encoded_respons } } return response; - } else if (encoded.status_code == 400) { + } + if (encoded.status_code == 400) { tao::json::value payload{}; try { payload = utils::json::parse(encoded.body.data()); diff --git a/couchbase/operations/document_search.hxx b/couchbase/operations/document_search.hxx index ea459af7..72a4ec04 100644 --- a/couchbase/operations/document_search.hxx +++ b/couchbase/operations/document_search.hxx @@ -97,7 +97,7 @@ struct search_response { error_context::search ctx; std::string status{}; - search_meta_data meta_data{}; + search_meta_data meta{}; std::string error{}; std::vector rows{}; std::vector facets{}; diff --git a/couchbase/operations/document_view.cxx b/couchbase/operations/document_view.cxx index 6589d092..03526321 100644 --- a/couchbase/operations/document_view.cxx +++ b/couchbase/operations/document_view.cxx @@ -135,11 +135,11 @@ document_view_request::make_response(error_context::view&& ctx, const encoded_re } if (const auto* total_rows = payload.find("total_rows"); total_rows != nullptr && total_rows->is_unsigned()) { - response.meta_data.total_rows = total_rows->get_unsigned(); + response.meta.total_rows = total_rows->get_unsigned(); } if (const auto* debug_info = payload.find("debug_info"); debug_info != nullptr && debug_info->is_object()) { - response.meta_data.debug_info.emplace(utils::json::generate(*debug_info)); + response.meta.debug_info.emplace(utils::json::generate(*debug_info)); } if (const auto* rows = payload.find("rows"); rows != nullptr && rows->is_array()) { diff --git a/couchbase/operations/document_view.hxx b/couchbase/operations/document_view.hxx index 8f552d03..0bc044ce 100644 --- a/couchbase/operations/document_view.hxx +++ b/couchbase/operations/document_view.hxx @@ -44,7 +44,7 @@ struct document_view_response { }; error_context::view ctx; - document_view_response::meta_data meta_data{}; + meta_data meta{}; std::vector rows{}; std::optional error{}; }; diff --git a/test/test_integration_diagnostics.cxx b/test/test_integration_diagnostics.cxx index ac55da25..05232d2b 100644 --- a/test/test_integration_diagnostics.cxx +++ b/test/test_integration_diagnostics.cxx @@ -327,10 +327,10 @@ TEST_CASE("integration: fetch diagnostics after N1QL query", "[integration]") auto resp = test::utils::execute(integration.cluster, req); INFO(resp.ctx.ec.message()) REQUIRE_FALSE(resp.ctx.ec); - INFO("rows.size() =" << resp.payload.rows.size()) - REQUIRE(resp.payload.rows.size() == 1); - INFO("row=" << resp.payload.rows[0]) - REQUIRE(resp.payload.rows[0] == R"({"greetings":"hello, couchbase"})"); + INFO("rows.size() =" << resp.rows.size()) + REQUIRE(resp.rows.size() == 1); + INFO("row=" << resp.rows[0]) + REQUIRE(resp.rows[0] == R"({"greetings":"hello, couchbase"})"); } { auto barrier = std::make_shared>(); diff --git a/test/test_integration_query.cxx b/test/test_integration_query.cxx index 422c465b..7804cb55 100644 --- a/test/test_integration_query.cxx +++ b/test/test_integration_query.cxx @@ -153,8 +153,8 @@ TEST_CASE("integration: query on a collection", "[integration]") req.mutation_state = { mutation_token }; auto resp = test::utils::execute(integration.cluster, req); REQUIRE_FALSE(resp.ctx.ec); - REQUIRE(resp.payload.rows.size() == 1); - REQUIRE(value == couchbase::utils::json::parse(resp.payload.rows[0])); + REQUIRE(resp.rows.size() == 1); + REQUIRE(value == couchbase::utils::json::parse(resp.rows[0])); } SECTION("missing scope") @@ -186,8 +186,8 @@ TEST_CASE("integration: query on a collection", "[integration]") req.adhoc = false; auto resp = test::utils::execute(integration.cluster, req); REQUIRE_FALSE(resp.ctx.ec); - REQUIRE(resp.payload.rows.size() == 1); - REQUIRE(value == couchbase::utils::json::parse(resp.payload.rows[0])); + REQUIRE(resp.rows.size() == 1); + REQUIRE(value == couchbase::utils::json::parse(resp.rows[0])); } } @@ -203,7 +203,7 @@ TEST_CASE("integration: read only with no results", "[integration]") couchbase::operations::query_request req{ fmt::format("SELECT * FROM {} LIMIT 0", integration.ctx.bucket) }; auto resp = test::utils::execute(integration.cluster, req); REQUIRE_FALSE(resp.ctx.ec); - REQUIRE(resp.payload.rows.empty()); + REQUIRE(resp.rows.empty()); } } @@ -372,8 +372,8 @@ TEST_CASE("integration: sticking query to the service node", "[integration]") couchbase::operations::query_request req{ R"(SELECT 42 AS answer)" }; auto resp = test::utils::execute(integration.cluster, req); REQUIRE_FALSE(resp.ctx.ec); - REQUIRE(resp.payload.rows.size() == 1); - REQUIRE(resp.payload.rows[0] == R"({"answer":42})"); + REQUIRE(resp.rows.size() == 1); + REQUIRE(resp.rows[0] == R"({"answer":42})"); REQUIRE_FALSE(resp.served_by_node.empty()); node_to_stick_queries = resp.served_by_node; } @@ -388,8 +388,8 @@ TEST_CASE("integration: sticking query to the service node", "[integration]") threads.emplace_back([i, &cluster = integration.cluster, node_to_stick_queries, &used_nodes, &used_nodes_mutex]() { couchbase::operations::query_request req{ fmt::format(R"(SELECT {} AS answer)", i) }; auto resp = test::utils::execute(cluster, req); - if (resp.ctx.ec || resp.served_by_node.empty() || resp.payload.rows.size() != 1 || - resp.payload.rows[0] != fmt::format(R"({{"answer":{}}})", i)) { + if (resp.ctx.ec || resp.served_by_node.empty() || resp.rows.size() != 1 || + resp.rows[0] != fmt::format(R"({{"answer":{}}})", i)) { return; } std::scoped_lock lock(used_nodes_mutex); @@ -410,8 +410,8 @@ TEST_CASE("integration: sticking query to the service node", "[integration]") couchbase::operations::query_request req{ fmt::format(R"(SELECT {} AS answer)", i) }; req.send_to_node = node_to_stick_queries; auto resp = test::utils::execute(cluster, req); - if (resp.ctx.ec || resp.served_by_node.empty() || resp.payload.rows.size() != 1 || - resp.payload.rows[0] != fmt::format(R"({{"answer":{}}})", i)) { + if (resp.ctx.ec || resp.served_by_node.empty() || resp.rows.size() != 1 || + resp.rows[0] != fmt::format(R"({{"answer":{}}})", i)) { return; } std::scoped_lock lock(used_nodes_mutex);