couchbase 4.2.1 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CMakeLists.txt +1 -0
  2. package/deps/couchbase-cxx-client/.gitmodules +3 -0
  3. package/deps/couchbase-cxx-client/.idea/misc.xml +1 -0
  4. package/deps/couchbase-cxx-client/.idea/vcs.xml +1 -0
  5. package/deps/couchbase-cxx-client/CMakeLists.txt +11 -1
  6. package/deps/couchbase-cxx-client/README.md +3 -3
  7. package/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake +4 -1
  8. package/deps/couchbase-cxx-client/cmake/VersionInfo.cmake +13 -1
  9. package/deps/couchbase-cxx-client/cmake/build_version.hxx.in +1 -0
  10. package/deps/couchbase-cxx-client/core/cluster.hxx +15 -5
  11. package/deps/couchbase-cxx-client/core/impl/build_deferred_query_indexes.cxx +17 -6
  12. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +1 -1
  13. package/deps/couchbase-cxx-client/core/impl/collection_query_index_manager.cxx +93 -0
  14. package/deps/couchbase-cxx-client/core/impl/configuration_profiles_registry.cxx +11 -0
  15. package/deps/couchbase-cxx-client/core/impl/create_query_index.cxx +119 -0
  16. package/deps/couchbase-cxx-client/core/impl/drop_query_index.cxx +108 -0
  17. package/deps/couchbase-cxx-client/core/impl/get.cxx +1 -1
  18. package/deps/couchbase-cxx-client/core/impl/get_all_query_indexes.cxx +76 -0
  19. package/deps/couchbase-cxx-client/core/impl/query.cxx +5 -7
  20. package/deps/couchbase-cxx-client/core/impl/watch_query_indexes.cxx +168 -0
  21. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +15 -1
  22. package/deps/couchbase-cxx-client/core/logger/configuration.hxx +3 -0
  23. package/deps/couchbase-cxx-client/core/logger/level.hxx +21 -0
  24. package/deps/couchbase-cxx-client/core/logger/logger.hxx +4 -6
  25. package/deps/couchbase-cxx-client/core/meta/CMakeLists.txt +4 -2
  26. package/deps/couchbase-cxx-client/core/meta/features.hxx +31 -0
  27. package/deps/couchbase-cxx-client/core/meta/version.cxx +67 -5
  28. package/deps/couchbase-cxx-client/core/meta/version.hxx +12 -1
  29. package/deps/couchbase-cxx-client/core/metrics/CMakeLists.txt +4 -1
  30. package/deps/couchbase-cxx-client/core/metrics/logging_meter.cxx +46 -5
  31. package/deps/couchbase-cxx-client/core/metrics/logging_meter.hxx +10 -26
  32. package/deps/couchbase-cxx-client/core/operations/document_get_projected.cxx +3 -2
  33. package/deps/couchbase-cxx-client/core/operations/document_query.cxx +10 -12
  34. package/deps/couchbase-cxx-client/core/operations/document_query.hxx +1 -3
  35. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.cxx +8 -14
  36. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.hxx +2 -1
  37. package/deps/couchbase-cxx-client/core/operations/management/query_index_build_deferred.hxx +15 -8
  38. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.cxx +7 -14
  39. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +2 -0
  40. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.cxx +11 -16
  41. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.hxx +2 -0
  42. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.cxx +8 -12
  43. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.hxx +4 -3
  44. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.cxx +21 -12
  45. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.hxx +3 -2
  46. package/deps/couchbase-cxx-client/core/origin.hxx +1 -1
  47. package/deps/couchbase-cxx-client/core/platform/uuid.cc +1 -2
  48. package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +5 -1
  49. package/deps/couchbase-cxx-client/core/query_context.hxx +79 -0
  50. package/deps/couchbase-cxx-client/core/tracing/CMakeLists.txt +3 -1
  51. package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.cxx +19 -4
  52. package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.hxx +2 -2
  53. package/deps/couchbase-cxx-client/core/transactions/async_attempt_context.hxx +10 -4
  54. package/deps/couchbase-cxx-client/core/transactions/atr_cleanup_entry.cxx +52 -63
  55. package/deps/couchbase-cxx-client/core/transactions/attempt_context.hxx +8 -3
  56. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +163 -126
  57. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +24 -37
  58. package/deps/couchbase-cxx-client/core/transactions/forward_compat.hxx +4 -4
  59. package/deps/couchbase-cxx-client/core/transactions/internal/atr_cleanup_entry.hxx +51 -13
  60. package/deps/couchbase-cxx-client/core/transactions/internal/client_record.hxx +26 -1
  61. package/deps/couchbase-cxx-client/core/transactions/internal/doc_record.hxx +21 -0
  62. package/deps/couchbase-cxx-client/core/transactions/internal/logging.hxx +40 -18
  63. package/deps/couchbase-cxx-client/core/transactions/internal/transaction_context.hxx +5 -0
  64. package/deps/couchbase-cxx-client/core/transactions/result.hxx +26 -0
  65. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +48 -47
  66. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +6 -6
  67. package/deps/couchbase-cxx-client/core/transactions/transaction_context.cxx +33 -19
  68. package/deps/couchbase-cxx-client/core/transactions/transaction_get_result.hxx +18 -2
  69. package/deps/couchbase-cxx-client/core/transactions/transaction_links.hxx +25 -2
  70. package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +4 -4
  71. package/deps/couchbase-cxx-client/core/transactions/transactions_cleanup.cxx +49 -56
  72. package/deps/couchbase-cxx-client/core/transactions/waitable_op_list.hxx +7 -7
  73. package/deps/couchbase-cxx-client/core/transactions.hxx +0 -12
  74. package/deps/couchbase-cxx-client/core/utils/binary.hxx +1 -1
  75. package/deps/couchbase-cxx-client/core/utils/keyspace.hxx +55 -0
  76. package/deps/couchbase-cxx-client/couchbase/build_query_index_options.hxx +12 -45
  77. package/deps/couchbase-cxx-client/couchbase/cluster.hxx +1 -1
  78. package/deps/couchbase-cxx-client/couchbase/cluster_options.hxx +6 -7
  79. package/deps/couchbase-cxx-client/couchbase/collection.hxx +8 -0
  80. package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +218 -0
  81. package/deps/couchbase-cxx-client/couchbase/configuration_profiles_registry.hxx +3 -0
  82. package/deps/couchbase-cxx-client/couchbase/create_primary_query_index_options.hxx +166 -0
  83. package/deps/couchbase-cxx-client/couchbase/create_query_index_options.hxx +172 -0
  84. package/deps/couchbase-cxx-client/couchbase/drop_primary_query_index_options.hxx +129 -0
  85. package/deps/couchbase-cxx-client/couchbase/drop_query_index_options.hxx +116 -0
  86. package/deps/couchbase-cxx-client/couchbase/fmt/cas.hxx +1 -1
  87. package/deps/couchbase-cxx-client/couchbase/fmt/query_scan_consistency.hxx +46 -0
  88. package/deps/couchbase-cxx-client/couchbase/fmt/query_status.hxx +70 -0
  89. package/deps/couchbase-cxx-client/couchbase/fmt/tls_verify_mode.hxx +46 -0
  90. package/deps/couchbase-cxx-client/couchbase/get_all_query_indexes_options.hxx +100 -0
  91. package/deps/couchbase-cxx-client/{core → couchbase}/management/query_index.hxx +2 -2
  92. package/deps/couchbase-cxx-client/couchbase/metrics/meter.hxx +16 -0
  93. package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +178 -6
  94. package/deps/couchbase-cxx-client/couchbase/query_options.hxx +1 -18
  95. package/deps/couchbase-cxx-client/couchbase/scope.hxx +5 -2
  96. package/deps/couchbase-cxx-client/couchbase/tracing/request_tracer.hxx +16 -0
  97. package/deps/couchbase-cxx-client/couchbase/transactions/async_attempt_context.hxx +11 -4
  98. package/deps/couchbase-cxx-client/couchbase/transactions/attempt_context.hxx +5 -3
  99. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_keyspace.hxx +16 -0
  100. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_query_options.hxx +0 -6
  101. package/deps/couchbase-cxx-client/couchbase/watch_query_indexes_options.hxx +115 -0
  102. package/deps/couchbase-cxx-client/examples/minimal.cxx +3 -1
  103. package/deps/couchbase-cxx-client/test/test_integration_crud.cxx +72 -0
  104. package/deps/couchbase-cxx-client/test/test_integration_management.cxx +727 -310
  105. package/deps/couchbase-cxx-client/test/test_integration_query.cxx +4 -8
  106. package/deps/couchbase-cxx-client/test/test_integration_transcoders.cxx +14 -0
  107. package/deps/couchbase-cxx-client/test/test_transaction_transaction_public_blocking_api.cxx +34 -19
  108. package/deps/couchbase-cxx-client/test/test_unit_transaction_logging.cxx +66 -22
  109. package/deps/couchbase-cxx-client/test/test_unit_utils.cxx +51 -0
  110. package/deps/couchbase-cxx-client/test/tools/tool_kv_loader.cxx +2 -2
  111. package/deps/couchbase-cxx-client/test/utils/integration_test_guard.cxx +2 -0
  112. package/deps/couchbase-cxx-client/test/utils/wait_until.cxx +4 -4
  113. package/deps/couchbase-cxx-client/third_party/docopt/.travis.yml +103 -0
  114. package/deps/couchbase-cxx-client/third_party/docopt/CMakeLists.txt +129 -0
  115. package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-Boost-1.0 +23 -0
  116. package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-MIT +23 -0
  117. package/deps/couchbase-cxx-client/third_party/docopt/README.rst +479 -0
  118. package/deps/couchbase-cxx-client/third_party/docopt/docopt-config.cmake +1 -0
  119. package/deps/couchbase-cxx-client/third_party/docopt/docopt.cpp +687 -0
  120. package/deps/couchbase-cxx-client/third_party/docopt/docopt.h +98 -0
  121. package/deps/couchbase-cxx-client/third_party/docopt/docopt.pc.in +9 -0
  122. package/deps/couchbase-cxx-client/third_party/docopt/docopt_private.h +676 -0
  123. package/deps/couchbase-cxx-client/third_party/docopt/docopt_util.h +122 -0
  124. package/deps/couchbase-cxx-client/third_party/docopt/docopt_value.h +341 -0
  125. package/deps/couchbase-cxx-client/third_party/docopt/examples/naval_fate.cpp +36 -0
  126. package/deps/couchbase-cxx-client/third_party/docopt/main.cpp +16 -0
  127. package/deps/couchbase-cxx-client/third_party/docopt/run_testcase.cpp +40 -0
  128. package/deps/couchbase-cxx-client/third_party/docopt/run_tests.py +72 -0
  129. package/deps/couchbase-cxx-client/third_party/docopt/testcases.docopt +957 -0
  130. package/deps/couchbase-cxx-client/tools/CMakeLists.txt +14 -0
  131. package/deps/couchbase-cxx-client/tools/cbc.cxx +65 -0
  132. package/deps/couchbase-cxx-client/tools/command.hxx +31 -0
  133. package/deps/couchbase-cxx-client/tools/command_registry.cxx +43 -0
  134. package/deps/couchbase-cxx-client/tools/command_registry.hxx +39 -0
  135. package/deps/couchbase-cxx-client/tools/get.cxx +267 -0
  136. package/deps/couchbase-cxx-client/tools/get.hxx +26 -0
  137. package/deps/couchbase-cxx-client/tools/query.cxx +441 -0
  138. package/deps/couchbase-cxx-client/tools/query.hxx +26 -0
  139. package/deps/couchbase-cxx-client/tools/utils.cxx +418 -0
  140. package/deps/couchbase-cxx-client/tools/utils.hxx +150 -0
  141. package/deps/couchbase-cxx-client/tools/version.cxx +82 -0
  142. package/deps/couchbase-cxx-client/tools/version.hxx +26 -0
  143. package/dist/authenticators.d.ts +2 -2
  144. package/dist/authenticators.js +1 -2
  145. package/dist/binding.d.ts +32 -16
  146. package/dist/cluster.js +14 -7
  147. package/dist/collection.d.ts +6 -0
  148. package/dist/collection.js +8 -0
  149. package/dist/queryexecutor.js +1 -1
  150. package/dist/queryindexmanager.d.ts +100 -4
  151. package/dist/queryindexmanager.js +344 -118
  152. package/dist/transactions.js +0 -2
  153. package/package.json +1 -1
  154. package/src/connection.cpp +2 -0
  155. package/src/connection.hpp +1 -0
  156. package/src/connection_autogen.cpp +16 -0
  157. package/src/jstocbpp_autogen.hpp +93 -23
  158. package/src/jstocbpp_basic.hpp +24 -0
  159. package/src/jstocbpp_transactions.hpp +0 -8
  160. package/tools/gen-bindings-js.js +1 -0
  161. package/tools/gen-bindings-json.py +4 -2
  162. package/deps/couchbase-cxx-client/core/transactions/logging.cxx +0 -107
@@ -0,0 +1,441 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2023-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "query.hxx"
19
+ #include "core/utils/binary.hxx"
20
+ #include "utils.hxx"
21
+
22
+ #include <core/logger/logger.hxx>
23
+ #include <couchbase/cluster.hxx>
24
+ #include <couchbase/fmt/query_status.hxx>
25
+
26
+ #include <asio/io_context.hpp>
27
+ #include <fmt/chrono.h>
28
+ #include <spdlog/fmt/bin_to_hex.h>
29
+ #include <tao/json.hpp>
30
+
31
+ #include <regex>
32
+
33
+ namespace cbc
34
+ {
35
+ namespace
36
+ {
37
+ static auto
38
+ usage() -> std::string
39
+ {
40
+ static const std::string default_bucket_name{ "default" };
41
+
42
+ static const std::string usage_string = fmt::format(
43
+ R"(Display version information.
44
+
45
+ Usage:
46
+ cbc query [options] <statement>...
47
+ cbc query [options] --param=NAME=VALUE... <statement>...
48
+ cbc query [options] --raw=NAME=VALUE... <statement>...
49
+ cbc query (-h|--help)
50
+
51
+ Options:
52
+ -h --help Show this screen.
53
+ --param=NAME=VALUE Parameters for the query. Without '=' sign value will be treated as positional parameter.
54
+ --prepare Prepare statement.
55
+ --read-only Mark query as read only. Any mutations will fail.
56
+ --preserve-expiry Ensure that expiry will be preserved after mutations.
57
+ --disable-metrics Do not request metrics.
58
+ --profile=MODE Request the service to profile the query and return report (allowed values: off, phases, timings).
59
+ --bucket-name=STRING Name of the bucket where the scope is defined (see --scope-name).
60
+ --scope-name=STRING Name of the scope.
61
+ --client-context-id=STRING Override client context ID for the query(-ies).
62
+ --flex-index Tell query service to utilize flex index (full text search).
63
+ --maximum-parallelism=INTEGER Parallelism for query execution (0 to disable).
64
+ --scan-cap=INTEGER Maximum buffer size between indexer and query service.
65
+ --scan-wait=DURATION How long query engine will wait for indexer to catch up on scan consistency.
66
+ --scan-consistency=MODE Set consistency guarantees for the query (allowed values: not_bounded, request_plus).
67
+ --pipeline-batch=INTEGER Number of items execution operators can batch for fetch from the Key/Value service.
68
+ --pipeline-cap=INTEGER Maximum number of items each execution operator can buffer between various operators.
69
+ --raw=NAME=VALUE Set any query option for the query. Read the documentation: https://docs.couchbase.com/server/current/n1ql/n1ql-rest-api.
70
+ --json-lines Use JSON Lines format (https://jsonlines.org/) to print results.
71
+
72
+ {logger_options}{cluster_options}
73
+
74
+ Examples:
75
+
76
+ 1. Query with positional parameters:
77
+
78
+ cbc query --param 1 --param 2 'SELECT $1 + $2'
79
+
80
+ 2. Query with named parameters:
81
+
82
+ cbc query --param a=1 --param b=2 'SELECT $a + $b'
83
+ )",
84
+ fmt::arg("logger_options", usage_block_for_logger()),
85
+ fmt::arg("cluster_options", usage_block_for_cluster_options()));
86
+
87
+ return usage_string;
88
+ }
89
+
90
+ struct console_output_options {
91
+ bool json_lines{ false };
92
+ };
93
+
94
+ struct scope_with_bucket {
95
+ std::string bucket_name;
96
+ std::string scope_name;
97
+ };
98
+
99
+ template<typename QueryEndpoint>
100
+ static auto
101
+ do_query(QueryEndpoint& endpoint, std::string statement, const couchbase::query_options& options)
102
+ {
103
+ return endpoint.query(std::move(statement), options);
104
+ }
105
+
106
+ static void
107
+ print_result_json_line(const std::optional<scope_with_bucket>& scope_id,
108
+ const std::string& statement,
109
+ const couchbase::query_error_context& ctx,
110
+ const couchbase::query_result& resp,
111
+ const couchbase::query_options& query_options)
112
+ {
113
+ auto built_options = query_options.build();
114
+
115
+ tao::json::value line = tao::json::empty_object;
116
+
117
+ tao::json::value meta = {
118
+ { "statement", statement },
119
+ };
120
+ if (scope_id) {
121
+ meta["bucket_name"] = scope_id->bucket_name;
122
+ meta["scope_name"] = scope_id->scope_name;
123
+ }
124
+ if (ctx.parameters()) {
125
+ try {
126
+ auto json = tao::json::from_string(ctx.parameters().value());
127
+ json.erase("statement");
128
+ meta["options"] = json;
129
+ } catch (const tao::pegtl::parse_error&) {
130
+ meta["options"] = ctx.parameters().value();
131
+ }
132
+ }
133
+
134
+ if (ctx.ec()) {
135
+ tao::json::value error = {
136
+ { "code", ctx.ec().value() },
137
+ { "message", ctx.ec().message() },
138
+ };
139
+ try {
140
+ error["body"] = tao::json::from_string(ctx.http_body());
141
+ } catch (const tao::pegtl::parse_error&) {
142
+ error["text"] = ctx.http_body();
143
+ }
144
+ line["error"] = error;
145
+ } else {
146
+ meta["status"] = fmt::format("{}", resp.meta_data().status());
147
+ meta["client_context_id"] = resp.meta_data().client_context_id();
148
+ meta["request_id"] = resp.meta_data().request_id();
149
+ if (const auto& signature = resp.meta_data().signature()) {
150
+ try {
151
+ meta["signature"] = couchbase::core::utils::json::parse_binary(signature.value());
152
+ } catch (const tao::pegtl::parse_error&) {
153
+ meta["signature"] = signature.value();
154
+ }
155
+ }
156
+ if (const auto& metrics = resp.meta_data().metrics(); metrics.has_value()) {
157
+ meta["metrics"] = {
158
+ { "elapsed_time", fmt::format("{}", metrics->elapsed_time()) },
159
+ { "execution_time", fmt::format("{}", metrics->execution_time()) },
160
+ { "result_count", metrics->result_count() },
161
+ { "result_size", metrics->result_size() },
162
+ { "sort_count", metrics->sort_count() },
163
+ { "mutation_count", metrics->mutation_count() },
164
+ { "error_count", metrics->error_count() },
165
+ { "warning_count", metrics->warning_count() },
166
+ };
167
+ }
168
+ if (const auto& profile = resp.meta_data().profile(); profile) {
169
+ try {
170
+ meta["profile"] = couchbase::core::utils::json::parse_binary(profile.value());
171
+ } catch (const tao::pegtl::parse_error&) {
172
+ meta["profile"] = profile.value();
173
+ }
174
+ }
175
+ if (!resp.meta_data().warnings().empty()) {
176
+ tao::json::value warnings = tao::json::empty_array;
177
+ for (const auto& item : resp.meta_data().warnings()) {
178
+ tao::json::value warning = {
179
+ { "message", item.message() },
180
+ { "code", item.code() },
181
+ };
182
+ if (item.reason()) {
183
+ warning["reason"] = item.reason().value();
184
+ }
185
+ if (item.retry()) {
186
+ warning["retry"] = item.retry().value();
187
+ }
188
+ warnings.emplace_back(warning);
189
+ }
190
+ meta["warnings"] = warnings;
191
+ }
192
+ tao::json::value rows = tao::json::empty_array;
193
+ for (const auto& row : resp.rows_as_binary()) {
194
+ try {
195
+ rows.emplace_back(couchbase::core::utils::json::parse_binary(row));
196
+ } catch (const tao::pegtl::parse_error&) {
197
+ rows.emplace_back(row);
198
+ }
199
+ }
200
+ line["rows"] = rows;
201
+ }
202
+ line["meta"] = meta;
203
+ fmt::print(stdout, "{}\n", tao::json::to_string<tao::json::events::binary_to_base64>(line));
204
+ fflush(stdout);
205
+ }
206
+
207
+ static void
208
+ print_result(const std::optional<scope_with_bucket>& scope_id,
209
+ const std::string& statement,
210
+ const couchbase::query_error_context& ctx,
211
+ const couchbase::query_result& resp,
212
+ const couchbase::query_options& query_options)
213
+ {
214
+ auto built_options = query_options.build();
215
+
216
+ auto header = fmt::memory_buffer();
217
+ if (scope_id) {
218
+ fmt::format_to(std::back_inserter(header), "bucket_name: {}, scope_name: {}", scope_id->bucket_name, scope_id->scope_name);
219
+ }
220
+ fmt::format_to(
221
+ std::back_inserter(header), "{}statement: \"{}\"", header.size() == 0 ? "" : ", ", tao::json::internal::escape(statement));
222
+
223
+ if (ctx.parameters()) {
224
+ try {
225
+ auto json = tao::json::from_string(ctx.parameters().value());
226
+ json.erase("statement");
227
+ fmt::format_to(std::back_inserter(header), ", options: {}", tao::json::to_string(json));
228
+ } catch (const tao::pegtl::parse_error&) {
229
+ fmt::format_to(std::back_inserter(header), ", options: {}", ctx.parameters().value());
230
+ }
231
+ }
232
+ fmt::print(stdout, "--- {}\n", std::string_view{ header.data(), header.size() });
233
+
234
+ if (ctx.ec()) {
235
+ fmt::print("ERROR. code: {}, message: {}, server: {} \"{}\")\n",
236
+ ctx.ec().value(),
237
+ ctx.ec().message(),
238
+ ctx.first_error_code(),
239
+ tao::json::internal::escape(ctx.first_error_message()));
240
+ if (!ctx.http_body().empty()) {
241
+ try {
242
+ fmt::print("{}\n", tao::json::to_string(tao::json::from_string(ctx.http_body())));
243
+ } catch (const tao::pegtl::parse_error&) {
244
+ fmt::print("{}\n", ctx.http_body());
245
+ }
246
+ }
247
+ } else {
248
+ auto meta = fmt::memory_buffer();
249
+ fmt::format_to(std::back_inserter(meta),
250
+ "status: {}, client_context_id: \"{}\", request_id: \"{}\"",
251
+ resp.meta_data().status(),
252
+ resp.meta_data().client_context_id(),
253
+ resp.meta_data().request_id());
254
+ if (const auto& metrics = resp.meta_data().metrics(); metrics.has_value()) {
255
+ fmt::format_to(std::back_inserter(meta),
256
+ ", elapsed: {}, execution: {}, result: {}, sort: {}, mutations: {}, errors: {}, warnings: {}",
257
+ metrics->elapsed_time(),
258
+ metrics->execution_time(),
259
+ metrics->result_count(),
260
+ metrics->sort_count(),
261
+ metrics->mutation_count(),
262
+ metrics->error_count(),
263
+ metrics->warning_count());
264
+ }
265
+ fmt::print(stdout, "{}\n", std::string_view{ meta.data(), meta.size() });
266
+ if (!resp.meta_data().warnings().empty()) {
267
+ for (const auto& item : resp.meta_data().warnings()) {
268
+ auto warning = fmt::memory_buffer();
269
+ fmt::format_to(std::back_inserter(warning), "WARNING. code: {}, message: \"{}\"\n", item.code(), item.message());
270
+ if (item.reason()) {
271
+ fmt::format_to(std::back_inserter(warning), ", reason: {}\n", item.reason().value());
272
+ }
273
+ if (item.retry()) {
274
+ fmt::format_to(std::back_inserter(warning), ", retry: {}\n", item.retry().value());
275
+ }
276
+ fmt::print(stdout, "{}\n", std::string_view{ warning.data(), warning.size() });
277
+ }
278
+ }
279
+ if (const auto& profile = resp.meta_data().profile(); profile) {
280
+ try {
281
+ fmt::print("{}\n", tao::json::to_string(couchbase::core::utils::json::parse_binary(profile.value()), 2));
282
+ } catch (const tao::pegtl::parse_error&) {
283
+ fmt::print("{:a}\n", spdlog::to_hex(profile.value()));
284
+ }
285
+ }
286
+ for (const auto& row : resp.rows_as_binary()) {
287
+ try {
288
+ fmt::print("{}\n", tao::json::to_string(couchbase::core::utils::json::parse_binary(row)));
289
+ } catch (const tao::pegtl::parse_error&) {
290
+ fmt::print("{:a}\n", spdlog::to_hex(row));
291
+ }
292
+ }
293
+ }
294
+ fflush(stdout);
295
+ }
296
+
297
+ static void
298
+ do_work(const std::string& connection_string,
299
+ couchbase::cluster_options& cluster_options,
300
+ const std::vector<std::string>& statements,
301
+ const std::optional<scope_with_bucket>& scope_id,
302
+ const couchbase::query_options& query_options,
303
+ const console_output_options& output_options)
304
+ {
305
+ asio::io_context io;
306
+ auto guard = asio::make_work_guard(io);
307
+ std::thread io_thread([&io]() { io.run(); });
308
+
309
+ auto [cluster, ec] = couchbase::cluster::connect(io, connection_string, cluster_options).get();
310
+ if (ec) {
311
+ throw std::system_error(ec);
312
+ }
313
+
314
+ std::optional<couchbase::scope> scope{};
315
+ if (scope_id) {
316
+ scope = cluster.bucket(scope_id->bucket_name).scope(scope_id->scope_name);
317
+ }
318
+
319
+ for (const auto& statement : statements) {
320
+ auto [ctx, resp] = (scope ? do_query(scope.value(), statement, query_options) : do_query(cluster, statement, query_options)).get();
321
+
322
+ if (output_options.json_lines) {
323
+ print_result_json_line(scope_id, statement, ctx, resp, query_options);
324
+ } else {
325
+ print_result(scope_id, statement, ctx, resp, query_options);
326
+ }
327
+ }
328
+
329
+ cluster.close();
330
+ guard.reset();
331
+
332
+ io_thread.join();
333
+ }
334
+ } // namespace
335
+
336
+ void
337
+ cbc::query::execute(const std::vector<std::string>& argv)
338
+ {
339
+ try {
340
+
341
+ auto options = cbc::parse_options(usage(), argv);
342
+ if (options["--help"].asBool()) {
343
+ fmt::print(stdout, usage());
344
+ return;
345
+ }
346
+
347
+ cbc::apply_logger_options(options);
348
+
349
+ couchbase::cluster_options cluster_options{ cbc::default_cluster_options() };
350
+ std::string connection_string{ cbc::default_connection_string() };
351
+ cbc::fill_cluster_options(options, cluster_options, connection_string);
352
+
353
+ couchbase::query_options query_options{};
354
+ parse_disable_option(query_options.adhoc, "--prepare");
355
+ parse_enable_option(query_options.readonly, "--read-only");
356
+ parse_enable_option(query_options.preserve_expiry, "--preserve-expiry");
357
+ parse_disable_option(query_options.metrics, "--disable-metrics");
358
+ parse_enable_option(query_options.flex_index, "--flex-index");
359
+ parse_integer_option(query_options.max_parallelism, "--maximum-parallelism");
360
+ parse_integer_option(query_options.scan_cap, "--scan-cap");
361
+ parse_integer_option(query_options.pipeline_batch, "--pipeline-batch");
362
+ parse_integer_option(query_options.pipeline_cap, "--pipeline-cap");
363
+ parse_duration_option(query_options.scan_wait, "--scan-wait");
364
+ parse_string_option(query_options.client_context_id, "--client-context-id");
365
+
366
+ if (options.find("--scan-consistency") != options.end() && options.at("--scan-consistency")) {
367
+ if (auto value = options.at("--scan-consistency").asString(); value == "not_bounded") {
368
+ query_options.scan_consistency(couchbase::query_scan_consistency::not_bounded);
369
+ } else if (value == "request_plus") {
370
+ query_options.scan_consistency(couchbase::query_scan_consistency::request_plus);
371
+ } else {
372
+ throw docopt::DocoptArgumentError(fmt::format("unexpected value '{}' for --scan-consistency", value));
373
+ }
374
+ }
375
+
376
+ if (options.find("--profile") != options.end() && options.at("--profile")) {
377
+ if (auto value = options.at("--profile").asString(); value == "off") {
378
+ query_options.profile(couchbase::query_profile::off);
379
+ } else if (value == "phases") {
380
+ query_options.profile(couchbase::query_profile::phases);
381
+ } else if (value == "timings") {
382
+ query_options.profile(couchbase::query_profile::phases);
383
+ } else {
384
+ throw docopt::DocoptArgumentError(fmt::format("unexpected value '{}' for --profile", value));
385
+ }
386
+ }
387
+
388
+ std::optional<scope_with_bucket> scope{};
389
+ if (options.find("--bucket-name") != options.end() && options.at("--bucket-name") &&
390
+ options.find("--scope-name") != options.end() && options.at("--scope-name")) {
391
+ scope = { options.at("--bucket-name").asString(), options.at("--scope-name").asString() };
392
+ }
393
+
394
+ static const std::regex named_param_regex{ R"(^([\w\d_]+)=(.*)$)" };
395
+ if (options.find("--param") != options.end() && options.at("--param")) {
396
+ std::vector<couchbase::codec::binary> positional_params{};
397
+ std::map<std::string, couchbase::codec::binary, std::less<>> named_params{};
398
+
399
+ for (const auto& param : options.at("--param").asStringList()) {
400
+ if (std::smatch match; std::regex_match(param, match, named_param_regex)) {
401
+ named_params[match[1].str()] = std::move(couchbase::core::utils::to_binary(match[2].str()));
402
+ } else {
403
+ positional_params.push_back(couchbase::core::utils::to_binary(param));
404
+ }
405
+ }
406
+ if (!positional_params.empty() && !named_params.empty()) {
407
+ throw docopt::DocoptArgumentError("mixing positional and named parameters is not allowed (parameters must be specified "
408
+ "either as --param=VALUE or --param=NAME=VALUE)");
409
+ }
410
+ if (!positional_params.empty()) {
411
+ query_options.encoded_positional_parameters(std::move(positional_params));
412
+ } else if (!named_params.empty()) {
413
+ query_options.encoded_named_parameters(std::move(named_params));
414
+ }
415
+ }
416
+ if (options.find("--raw") != options.end() && options.at("--raw")) {
417
+ std::map<std::string, couchbase::codec::binary, std::less<>> raw_params{};
418
+ for (const auto& param : options.at("--raw").asStringList()) {
419
+ if (std::smatch match; std::regex_match(param, match, named_param_regex)) {
420
+ raw_params.emplace(match[1].str(), couchbase::core::utils::to_binary(match[2].str()));
421
+ } else {
422
+ throw docopt::DocoptArgumentError("raw parameters should be in NAME=VALUE form, (i.e. --raw=NAME=VALUE)");
423
+ }
424
+ }
425
+ if (!raw_params.empty()) {
426
+ query_options.encoded_raw_options(raw_params);
427
+ }
428
+ }
429
+
430
+ console_output_options output_options{};
431
+ output_options.json_lines = cbc::get_bool_option(options, "--json-lines");
432
+
433
+ auto statements{ options["<statement>"].asStringList() };
434
+ do_work(connection_string, cluster_options, statements, scope, query_options, output_options);
435
+ } catch (const docopt::DocoptArgumentError& e) {
436
+ fmt::print(stderr, "Error: {}\n", e.what());
437
+ } catch (const std::system_error& e) {
438
+ fmt::print(stderr, "Error: {}\n", e.what());
439
+ }
440
+ }
441
+ } // namespace cbc
@@ -0,0 +1,26 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2023-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "command.hxx"
19
+
20
+ namespace cbc
21
+ {
22
+ class query : public command
23
+ {
24
+ void execute(const std::vector<std::string>& argv);
25
+ };
26
+ } // namespace cbc