couchbase 3.1.1-universal-darwin-20 → 3.2.0-universal-darwin-20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/CMakeLists.txt +3 -1
  4. data/ext/build_version.hxx.in +1 -1
  5. data/ext/cmake/Testing.cmake +1 -0
  6. data/ext/cmake/ThirdPartyDependencies.cmake +6 -0
  7. data/ext/cmake/VersionInfo.cmake +3 -0
  8. data/ext/couchbase/bucket.hxx +47 -28
  9. data/ext/couchbase/cbsasl/client.h +1 -1
  10. data/ext/couchbase/cbsasl/context.cc +1 -1
  11. data/ext/couchbase/cbsasl/context.h +3 -3
  12. data/ext/couchbase/cbsasl/mechanism.cc +5 -8
  13. data/ext/couchbase/cbsasl/mechanism.h +1 -4
  14. data/ext/couchbase/cbsasl/plain/plain.cc +1 -1
  15. data/ext/couchbase/cbsasl/scram-sha/scram-sha.cc +30 -36
  16. data/ext/couchbase/cluster.hxx +40 -22
  17. data/ext/couchbase/cluster_options.hxx +7 -1
  18. data/ext/couchbase/configuration.hxx +37 -16
  19. data/ext/couchbase/couchbase.cxx +1145 -291
  20. data/ext/couchbase/error_map.hxx +1 -1
  21. data/ext/couchbase/errors.hxx +25 -17
  22. data/ext/couchbase/io/dns_client.hxx +3 -3
  23. data/ext/couchbase/io/dns_codec.hxx +4 -5
  24. data/ext/couchbase/io/dns_config.hxx +5 -6
  25. data/ext/couchbase/io/dns_message.hxx +3 -3
  26. data/ext/couchbase/io/http_command.hxx +70 -35
  27. data/ext/couchbase/io/http_session.hxx +4 -3
  28. data/ext/couchbase/io/http_session_manager.hxx +28 -19
  29. data/ext/couchbase/io/mcbp_command.hxx +51 -19
  30. data/ext/couchbase/io/mcbp_context.hxx +1 -1
  31. data/ext/couchbase/io/mcbp_parser.hxx +4 -4
  32. data/ext/couchbase/io/mcbp_session.hxx +91 -101
  33. data/ext/couchbase/io/query_cache.hxx +2 -2
  34. data/ext/couchbase/io/retry_orchestrator.hxx +2 -4
  35. data/ext/couchbase/io/retry_reason.hxx +2 -2
  36. data/ext/couchbase/io/retry_strategy.hxx +1 -6
  37. data/ext/couchbase/io/streams.hxx +7 -7
  38. data/ext/couchbase/metrics/logging_meter.hxx +228 -0
  39. data/ext/couchbase/metrics/logging_meter_options.hxx +28 -0
  40. data/ext/couchbase/metrics/meter.hxx +49 -0
  41. data/ext/couchbase/metrics/noop_meter.hxx +43 -0
  42. data/ext/couchbase/operations.hxx +4 -0
  43. data/ext/couchbase/operations/analytics_dataset_create.hxx +16 -12
  44. data/ext/couchbase/operations/analytics_dataset_drop.hxx +11 -11
  45. data/ext/couchbase/operations/analytics_dataset_get_all.hxx +6 -6
  46. data/ext/couchbase/operations/analytics_dataverse_create.hxx +10 -11
  47. data/ext/couchbase/operations/analytics_dataverse_drop.hxx +10 -11
  48. data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +9 -11
  49. data/ext/couchbase/operations/analytics_index_create.hxx +14 -13
  50. data/ext/couchbase/operations/analytics_index_drop.hxx +18 -12
  51. data/ext/couchbase/operations/analytics_index_get_all.hxx +8 -6
  52. data/ext/couchbase/operations/analytics_link.hxx +39 -0
  53. data/ext/couchbase/operations/analytics_link_azure_blob_external.hxx +145 -0
  54. data/ext/couchbase/operations/analytics_link_connect.hxx +14 -12
  55. data/ext/couchbase/operations/analytics_link_couchbase_remote.hxx +220 -0
  56. data/ext/couchbase/operations/analytics_link_create.hxx +128 -0
  57. data/ext/couchbase/operations/analytics_link_disconnect.hxx +11 -12
  58. data/ext/couchbase/operations/analytics_link_drop.hxx +130 -0
  59. data/ext/couchbase/operations/analytics_link_get_all.hxx +160 -0
  60. data/ext/couchbase/operations/analytics_link_replace.hxx +128 -0
  61. data/ext/couchbase/operations/analytics_link_s3_external.hxx +122 -0
  62. data/ext/couchbase/operations/bucket_create.hxx +8 -8
  63. data/ext/couchbase/operations/bucket_drop.hxx +5 -5
  64. data/ext/couchbase/operations/bucket_flush.hxx +5 -5
  65. data/ext/couchbase/operations/bucket_get.hxx +7 -7
  66. data/ext/couchbase/operations/bucket_get_all.hxx +7 -5
  67. data/ext/couchbase/operations/bucket_settings.hxx +40 -49
  68. data/ext/couchbase/operations/bucket_update.hxx +8 -8
  69. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +7 -7
  70. data/ext/couchbase/operations/collection_create.hxx +11 -11
  71. data/ext/couchbase/operations/collection_drop.hxx +12 -10
  72. data/ext/couchbase/operations/collections_manifest_get.hxx +3 -3
  73. data/ext/couchbase/operations/design_document.hxx +2 -2
  74. data/ext/couchbase/operations/document_analytics.hxx +29 -36
  75. data/ext/couchbase/operations/document_append.hxx +3 -3
  76. data/ext/couchbase/operations/document_decrement.hxx +3 -3
  77. data/ext/couchbase/operations/document_exists.hxx +2 -2
  78. data/ext/couchbase/operations/document_get.hxx +3 -3
  79. data/ext/couchbase/operations/document_get_and_lock.hxx +5 -3
  80. data/ext/couchbase/operations/document_get_and_touch.hxx +5 -3
  81. data/ext/couchbase/operations/document_get_projected.hxx +10 -11
  82. data/ext/couchbase/operations/document_increment.hxx +3 -3
  83. data/ext/couchbase/operations/document_insert.hxx +3 -3
  84. data/ext/couchbase/operations/document_lookup_in.hxx +12 -18
  85. data/ext/couchbase/operations/document_mutate_in.hxx +13 -18
  86. data/ext/couchbase/operations/document_prepend.hxx +3 -3
  87. data/ext/couchbase/operations/document_query.hxx +39 -41
  88. data/ext/couchbase/operations/document_remove.hxx +3 -3
  89. data/ext/couchbase/operations/document_replace.hxx +3 -3
  90. data/ext/couchbase/operations/document_search.hxx +56 -61
  91. data/ext/couchbase/operations/document_touch.hxx +3 -3
  92. data/ext/couchbase/operations/document_unlock.hxx +3 -3
  93. data/ext/couchbase/operations/document_upsert.hxx +3 -3
  94. data/ext/couchbase/operations/document_view.hxx +23 -23
  95. data/ext/couchbase/operations/group_drop.hxx +5 -5
  96. data/ext/couchbase/operations/group_get.hxx +7 -7
  97. data/ext/couchbase/operations/group_get_all.hxx +6 -6
  98. data/ext/couchbase/operations/group_upsert.hxx +11 -11
  99. data/ext/couchbase/operations/http_noop.hxx +6 -6
  100. data/ext/couchbase/operations/mcbp_noop.hxx +3 -3
  101. data/ext/couchbase/operations/query_index_build_deferred.hxx +6 -6
  102. data/ext/couchbase/operations/query_index_create.hxx +10 -8
  103. data/ext/couchbase/operations/query_index_drop.hxx +8 -8
  104. data/ext/couchbase/operations/query_index_get_all.hxx +43 -39
  105. data/ext/couchbase/operations/rbac.hxx +40 -63
  106. data/ext/couchbase/operations/role_get_all.hxx +6 -6
  107. data/ext/couchbase/operations/scope_create.hxx +10 -10
  108. data/ext/couchbase/operations/scope_drop.hxx +9 -9
  109. data/ext/couchbase/operations/scope_get_all.hxx +8 -8
  110. data/ext/couchbase/operations/search_get_stats.hxx +5 -3
  111. data/ext/couchbase/operations/search_index.hxx +6 -15
  112. data/ext/couchbase/operations/search_index_analyze_document.hxx +11 -11
  113. data/ext/couchbase/operations/search_index_control_ingest.hxx +9 -9
  114. data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +9 -9
  115. data/ext/couchbase/operations/search_index_control_query.hxx +9 -9
  116. data/ext/couchbase/operations/search_index_drop.hxx +11 -9
  117. data/ext/couchbase/operations/search_index_get.hxx +11 -9
  118. data/ext/couchbase/operations/search_index_get_all.hxx +11 -11
  119. data/ext/couchbase/operations/search_index_get_documents_count.hxx +10 -10
  120. data/ext/couchbase/operations/search_index_get_stats.hxx +10 -8
  121. data/ext/couchbase/operations/search_index_upsert.hxx +12 -10
  122. data/ext/couchbase/operations/user_drop.hxx +5 -5
  123. data/ext/couchbase/operations/user_get.hxx +7 -7
  124. data/ext/couchbase/operations/user_get_all.hxx +6 -6
  125. data/ext/couchbase/operations/user_upsert.hxx +9 -9
  126. data/ext/couchbase/operations/view_index_drop.hxx +10 -10
  127. data/ext/couchbase/operations/view_index_get.hxx +13 -15
  128. data/ext/couchbase/operations/view_index_get_all.hxx +17 -20
  129. data/ext/couchbase/operations/view_index_upsert.hxx +9 -7
  130. data/ext/couchbase/origin.hxx +14 -10
  131. data/ext/couchbase/platform/backtrace.c +1 -1
  132. data/ext/couchbase/platform/base64.cc +5 -5
  133. data/ext/couchbase/platform/base64.h +2 -5
  134. data/ext/couchbase/protocol/client_opcode.hxx +7 -4
  135. data/ext/couchbase/protocol/client_request.hxx +2 -2
  136. data/ext/couchbase/protocol/client_response.hxx +41 -16
  137. data/ext/couchbase/protocol/cmd_append.hxx +17 -16
  138. data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +4 -4
  139. data/ext/couchbase/protocol/cmd_decrement.hxx +10 -11
  140. data/ext/couchbase/protocol/cmd_exists.hxx +12 -15
  141. data/ext/couchbase/protocol/cmd_get.hxx +11 -14
  142. data/ext/couchbase/protocol/cmd_get_and_lock.hxx +10 -12
  143. data/ext/couchbase/protocol/cmd_get_and_touch.hxx +10 -12
  144. data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +13 -18
  145. data/ext/couchbase/protocol/cmd_get_collection_id.hxx +12 -15
  146. data/ext/couchbase/protocol/cmd_get_collections_manifest.hxx +12 -16
  147. data/ext/couchbase/protocol/cmd_get_error_map.hxx +14 -17
  148. data/ext/couchbase/protocol/cmd_hello.hxx +8 -10
  149. data/ext/couchbase/protocol/cmd_increment.hxx +9 -10
  150. data/ext/couchbase/protocol/cmd_insert.hxx +9 -9
  151. data/ext/couchbase/protocol/cmd_lookup_in.hxx +12 -13
  152. data/ext/couchbase/protocol/cmd_mutate_in.hxx +11 -11
  153. data/ext/couchbase/protocol/cmd_noop.hxx +16 -20
  154. data/ext/couchbase/protocol/cmd_prepend.hxx +9 -10
  155. data/ext/couchbase/protocol/cmd_remove.hxx +10 -13
  156. data/ext/couchbase/protocol/cmd_replace.hxx +7 -7
  157. data/ext/couchbase/protocol/cmd_sasl_auth.hxx +8 -10
  158. data/ext/couchbase/protocol/cmd_sasl_list_mechs.hxx +10 -15
  159. data/ext/couchbase/protocol/cmd_sasl_step.hxx +10 -12
  160. data/ext/couchbase/protocol/cmd_select_bucket.hxx +14 -18
  161. data/ext/couchbase/protocol/cmd_touch.hxx +8 -11
  162. data/ext/couchbase/protocol/cmd_unlock.hxx +10 -14
  163. data/ext/couchbase/protocol/cmd_upsert.hxx +8 -8
  164. data/ext/couchbase/protocol/datatype.hxx +3 -3
  165. data/ext/couchbase/protocol/durability_level.hxx +2 -2
  166. data/ext/couchbase/protocol/frame_info_id.hxx +4 -4
  167. data/ext/couchbase/protocol/hello_feature.hxx +2 -2
  168. data/ext/couchbase/protocol/magic.hxx +2 -2
  169. data/ext/couchbase/protocol/server_opcode.hxx +2 -2
  170. data/ext/couchbase/protocol/server_request.hxx +1 -1
  171. data/ext/couchbase/protocol/status.hxx +4 -7
  172. data/ext/couchbase/protocol/unsigned_leb128.h +5 -20
  173. data/ext/couchbase/service_type.hxx +4 -4
  174. data/ext/couchbase/tracing/constants.hxx +261 -0
  175. data/ext/couchbase/tracing/noop_tracer.hxx +50 -0
  176. data/ext/couchbase/tracing/request_tracer.hxx +77 -0
  177. data/ext/couchbase/tracing/threshold_logging_options.hxx +64 -0
  178. data/ext/couchbase/tracing/threshold_logging_tracer.hxx +366 -0
  179. data/ext/couchbase/utils/byteswap.hxx +1 -1
  180. data/ext/couchbase/utils/connection_string.hxx +21 -1
  181. data/ext/couchbase/utils/name_codec.hxx +41 -0
  182. data/ext/couchbase/utils/url_codec.hxx +236 -0
  183. data/ext/couchbase/version.hxx +1 -1
  184. data/ext/test/CMakeLists.txt +1 -0
  185. data/ext/test/test_native_trivial_query.cxx +60 -0
  186. data/ext/third_party/hdr_histogram_c/CMakeLists.txt +84 -0
  187. data/ext/third_party/hdr_histogram_c/COPYING.txt +121 -0
  188. data/ext/third_party/hdr_histogram_c/LICENSE.txt +41 -0
  189. data/ext/third_party/hdr_histogram_c/config.cmake.in +6 -0
  190. data/ext/third_party/hdr_histogram_c/src/CMakeLists.txt +83 -0
  191. data/ext/third_party/hdr_histogram_c/src/hdr_atomic.h +146 -0
  192. data/ext/third_party/hdr_histogram_c/src/hdr_encoding.c +322 -0
  193. data/ext/third_party/hdr_histogram_c/src/hdr_encoding.h +79 -0
  194. data/ext/third_party/hdr_histogram_c/src/hdr_endian.h +116 -0
  195. data/ext/third_party/hdr_histogram_c/src/hdr_histogram.c +1196 -0
  196. data/ext/third_party/hdr_histogram_c/src/hdr_histogram.h +516 -0
  197. data/ext/third_party/hdr_histogram_c/src/hdr_histogram_log.c +1290 -0
  198. data/ext/third_party/hdr_histogram_c/src/hdr_histogram_log.h +236 -0
  199. data/ext/third_party/hdr_histogram_c/src/hdr_histogram_log_no_op.c +171 -0
  200. data/ext/third_party/hdr_histogram_c/src/hdr_interval_recorder.c +227 -0
  201. data/ext/third_party/hdr_histogram_c/src/hdr_interval_recorder.h +109 -0
  202. data/ext/third_party/hdr_histogram_c/src/hdr_malloc.h +19 -0
  203. data/ext/third_party/hdr_histogram_c/src/hdr_tests.h +22 -0
  204. data/ext/third_party/hdr_histogram_c/src/hdr_thread.c +108 -0
  205. data/ext/third_party/hdr_histogram_c/src/hdr_thread.h +55 -0
  206. data/ext/third_party/hdr_histogram_c/src/hdr_time.c +98 -0
  207. data/ext/third_party/hdr_histogram_c/src/hdr_time.h +49 -0
  208. data/ext/third_party/hdr_histogram_c/src/hdr_writer_reader_phaser.c +143 -0
  209. data/ext/third_party/hdr_histogram_c/src/hdr_writer_reader_phaser.h +51 -0
  210. data/lib/couchbase/cluster.rb +1 -0
  211. data/lib/couchbase/errors.rb +3 -0
  212. data/lib/couchbase/libcouchbase.bundle +0 -0
  213. data/lib/couchbase/management/analytics_index_manager.rb +920 -226
  214. data/lib/couchbase/management/bucket_manager.rb +207 -69
  215. data/lib/couchbase/management/collection_manager.rb +173 -61
  216. data/lib/couchbase/management/query_index_manager.rb +357 -169
  217. data/lib/couchbase/options.rb +75 -3
  218. data/lib/couchbase/scope.rb +102 -0
  219. data/lib/couchbase/utils/time.rb +4 -0
  220. data/lib/couchbase/version.rb +6 -6
  221. metadata +48 -5
@@ -17,9 +17,9 @@
17
17
 
18
18
  #pragma once
19
19
 
20
- #include <utility>
21
- #include <thread>
22
20
  #include <fstream>
21
+ #include <thread>
22
+ #include <utility>
23
23
 
24
24
  #include <asio/ssl.hpp>
25
25
 
@@ -32,6 +32,11 @@
32
32
  #include <operations.hxx>
33
33
  #include <operations/document_query.hxx>
34
34
 
35
+ #include <tracing/noop_tracer.hxx>
36
+ #include <tracing/threshold_logging_tracer.hxx>
37
+ #include <metrics/noop_meter.hxx>
38
+ #include <metrics/logging_meter.hxx>
39
+
35
40
  #include <diagnostics.hxx>
36
41
 
37
42
  namespace couchbase
@@ -88,12 +93,9 @@ class cluster
88
93
  {
89
94
  public:
90
95
  explicit cluster(asio::io_context& ctx)
91
- : id_(uuid::to_string(uuid::random()))
92
- , ctx_(ctx)
96
+ : ctx_(ctx)
93
97
  , work_(asio::make_work_guard(ctx_))
94
- , tls_(asio::ssl::context::tls_client)
95
98
  , session_manager_(std::make_shared<io::http_session_manager>(id_, ctx_, tls_))
96
- , dns_config_(io::dns::dns_config::get())
97
99
  , dns_client_(ctx_)
98
100
  {
99
101
  }
@@ -102,6 +104,17 @@ class cluster
102
104
  void open(const couchbase::origin& origin, Handler&& handler)
103
105
  {
104
106
  origin_ = origin;
107
+ if (origin_.options().enable_tracing) {
108
+ tracer_ = new tracing::threshold_logging_tracer(ctx_, origin.options().tracing_options);
109
+ } else {
110
+ tracer_ = new tracing::noop_tracer();
111
+ }
112
+ if (origin_.options().enable_metrics) {
113
+ meter_ = new metrics::logging_meter(ctx_, origin.options().metrics_options);
114
+ } else {
115
+ meter_ = new metrics::noop_meter();
116
+ }
117
+ session_manager_->set_tracer(tracer_);
105
118
  if (origin_.options().enable_dns_srv) {
106
119
  return asio::post(asio::bind_executor(
107
120
  ctx_, [this, handler = std::forward<Handler>(handler)]() mutable { return do_dns_srv(std::forward<Handler>(handler)); }));
@@ -122,21 +135,24 @@ class cluster
122
135
  session_manager_->close();
123
136
  handler();
124
137
  work_.reset();
138
+ delete tracer_;
139
+ tracer_ = nullptr;
140
+ delete meter_;
141
+ meter_ = nullptr;
125
142
  }));
126
143
  }
127
144
 
128
145
  template<typename Handler>
129
146
  void open_bucket(const std::string& bucket_name, Handler&& handler)
130
147
  {
131
- auto ptr = buckets_.find(bucket_name);
132
- if (ptr != buckets_.end()) {
148
+ if (buckets_.find(bucket_name) != buckets_.end()) {
133
149
  return handler({});
134
150
  }
135
151
  std::vector<protocol::hello_feature> known_features;
136
152
  if (session_ && session_->has_config()) {
137
153
  known_features = session_->supported_features();
138
154
  }
139
- auto b = std::make_shared<bucket>(id_, ctx_, tls_, bucket_name, origin_, known_features);
155
+ auto b = std::make_shared<bucket>(id_, ctx_, tls_, tracer_, meter_, bucket_name, origin_, known_features);
140
156
  b->bootstrap([this, handler = std::forward<Handler>(handler)](std::error_code ec, const configuration& config) mutable {
141
157
  if (!ec && !session_->supports_gcccp()) {
142
158
  session_manager_->set_configuration(config, origin_.options());
@@ -153,7 +169,7 @@ class cluster
153
169
  if (bucket == buckets_.end()) {
154
170
  error_context::key_value ctx{};
155
171
  ctx.id = request.id;
156
- ctx.ec = std::make_error_code(error::common_errc::bucket_not_found);
172
+ ctx.ec = error::common_errc::bucket_not_found;
157
173
  using response_type = typename Request::encoded_response_type;
158
174
  return handler(operations::make_response(std::move(ctx), request, response_type{}));
159
175
  }
@@ -166,10 +182,10 @@ class cluster
166
182
  auto session = session_manager_->check_out(Request::type, origin_.credentials());
167
183
  if (!session) {
168
184
  typename Request::error_context_type ctx{};
169
- ctx.ec = std::make_error_code(error::common_errc::service_not_available);
185
+ ctx.ec = error::common_errc::service_not_available;
170
186
  return handler(operations::make_response(std::move(ctx), request, {}));
171
187
  }
172
- auto cmd = std::make_shared<operations::http_command<Request>>(ctx_, request);
188
+ auto cmd = std::make_shared<operations::http_command<Request>>(ctx_, request, tracer_, meter_);
173
189
  cmd->send_to(session, [this, session, handler = std::forward<Handler>(handler)](typename Request::response_type resp) mutable {
174
190
  handler(std::move(resp));
175
191
  session_manager_->check_in(Request::type, session);
@@ -185,10 +201,10 @@ class cluster
185
201
  asio::post(asio::bind_executor(ctx_, [this, report_id, handler = std::forward<Handler>(handler)]() mutable {
186
202
  diag::diagnostics_result res{ report_id.value(), couchbase::sdk_id() };
187
203
  if (session_) {
188
- res.services[service_type::kv].emplace_back(session_->diag_info());
204
+ res.services[service_type::key_value].emplace_back(session_->diag_info());
189
205
  }
190
- for (const auto& bucket : buckets_) {
191
- bucket.second->export_diag_info(res);
206
+ for (const auto& [name, bucket] : buckets_) {
207
+ bucket->export_diag_info(res);
192
208
  }
193
209
  session_manager_->export_diag_info(res);
194
210
  handler(std::move(res));
@@ -204,19 +220,19 @@ class cluster
204
220
  report_id = std::make_optional(uuid::to_string(uuid::random()));
205
221
  }
206
222
  if (services.empty()) {
207
- services = { service_type::kv, service_type::views, service_type::query, service_type::search, service_type::analytics };
223
+ services = { service_type::key_value, service_type::view, service_type::query, service_type::search, service_type::analytics };
208
224
  }
209
225
  asio::post(asio::bind_executor(ctx_, [this, report_id, bucket_name, services, handler = std::move(handler)]() mutable {
210
226
  auto collector = std::make_shared<ping_collector>(report_id.value(), std::move(handler));
211
227
  if (bucket_name) {
212
- if (services.find(service_type::kv) != services.end()) {
228
+ if (services.find(service_type::key_value) != services.end()) {
213
229
  auto bucket = buckets_.find(bucket_name.value());
214
230
  if (bucket != buckets_.end()) {
215
231
  bucket->second->ping(collector);
216
232
  }
217
233
  }
218
234
  } else {
219
- if (services.find(service_type::kv) != services.end()) {
235
+ if (services.find(service_type::key_value) != services.end()) {
220
236
  if (session_) {
221
237
  session_->ping(collector->build_reporter());
222
238
  }
@@ -322,7 +338,7 @@ class cluster
322
338
  origin::node_list nodes;
323
339
  nodes.reserve(config.nodes.size());
324
340
  for (const auto& address : config.nodes) {
325
- auto port = address.port_or(origin_.options().network, service_type::kv, origin_.options().enable_tls, 0);
341
+ auto port = address.port_or(origin_.options().network, service_type::key_value, origin_.options().enable_tls, 0);
326
342
  if (port == 0) {
327
343
  continue;
328
344
  }
@@ -342,15 +358,17 @@ class cluster
342
358
  });
343
359
  }
344
360
 
345
- std::string id_;
361
+ std::string id_{ uuid::to_string(uuid::random()) };
346
362
  asio::io_context& ctx_;
347
363
  asio::executor_work_guard<asio::io_context::executor_type> work_;
348
- asio::ssl::context tls_;
364
+ asio::ssl::context tls_{ asio::ssl::context::tls_client };
349
365
  std::shared_ptr<io::http_session_manager> session_manager_;
350
- io::dns::dns_config& dns_config_;
366
+ io::dns::dns_config& dns_config_{ io::dns::dns_config::get() };
351
367
  couchbase::io::dns::dns_client dns_client_;
352
368
  std::shared_ptr<io::mcbp_session> session_{};
353
369
  std::map<std::string, std::shared_ptr<bucket>> buckets_{};
354
370
  couchbase::origin origin_{};
371
+ tracing::request_tracer* tracer_{ nullptr };
372
+ metrics::meter* meter_{ nullptr };
355
373
  };
356
374
  } // namespace couchbase
@@ -18,6 +18,8 @@
18
18
  #pragma once
19
19
 
20
20
  #include <timeout_defaults.hxx>
21
+ #include <tracing/threshold_logging_options.hxx>
22
+ #include <metrics/logging_meter_options.hxx>
21
23
 
22
24
  namespace couchbase
23
25
  {
@@ -43,14 +45,18 @@ struct cluster_options {
43
45
  bool enable_unordered_execution{ true };
44
46
  bool enable_clustermap_notification{ true };
45
47
  bool enable_compression{ true };
48
+ bool enable_tracing{ true };
49
+ bool enable_metrics{ true };
46
50
  std::string network{ "auto" };
51
+ tracing::threshold_logging_options tracing_options{};
52
+ metrics::logging_meter_options metrics_options{};
47
53
 
48
54
  std::chrono::milliseconds tcp_keep_alive_interval = timeout_defaults::tcp_keep_alive_interval;
49
55
  std::chrono::milliseconds config_poll_interval = timeout_defaults::config_poll_interval;
50
56
  std::chrono::milliseconds config_poll_floor = timeout_defaults::config_poll_floor;
51
57
  std::chrono::milliseconds config_idle_redial_timeout = timeout_defaults::config_idle_redial_timeout;
52
58
 
53
- size_t max_http_connections{ 0 };
59
+ std::size_t max_http_connections{ 0 };
54
60
  std::chrono::milliseconds idle_http_connection_timeout = timeout_defaults::idle_http_connection_timeout;
55
61
  };
56
62
 
@@ -21,13 +21,13 @@
21
21
 
22
22
  #include <gsl/gsl_util>
23
23
 
24
- #include <tao/json.hpp>
24
+ #include <platform/uuid.h>
25
25
  #include <spdlog/spdlog.h>
26
+ #include <tao/json.hpp>
26
27
  #include <utils/crc32.hxx>
27
- #include <platform/uuid.h>
28
28
 
29
- #include <service_type.hxx>
30
29
  #include <capabilities.hxx>
30
+ #include <service_type.hxx>
31
31
 
32
32
  namespace couchbase
33
33
  {
@@ -73,13 +73,13 @@ struct configuration {
73
73
  case service_type::search:
74
74
  return services_tls.search.value_or(default_value);
75
75
 
76
- case service_type::views:
76
+ case service_type::view:
77
77
  return services_tls.views.value_or(default_value);
78
78
 
79
79
  case service_type::management:
80
80
  return services_tls.management.value_or(default_value);
81
81
 
82
- case service_type::kv:
82
+ case service_type::key_value:
83
83
  return services_tls.key_value.value_or(default_value);
84
84
  }
85
85
  }
@@ -93,13 +93,13 @@ struct configuration {
93
93
  case service_type::search:
94
94
  return services_plain.search.value_or(default_value);
95
95
 
96
- case service_type::views:
96
+ case service_type::view:
97
97
  return services_plain.views.value_or(default_value);
98
98
 
99
99
  case service_type::management:
100
100
  return services_plain.management.value_or(default_value);
101
101
 
102
- case service_type::kv:
102
+ case service_type::key_value:
103
103
  return services_plain.key_value.value_or(default_value);
104
104
  }
105
105
  return default_value;
@@ -139,13 +139,13 @@ struct configuration {
139
139
  case service_type::search:
140
140
  return address->second.services_tls.search.value_or(default_value);
141
141
 
142
- case service_type::views:
142
+ case service_type::view:
143
143
  return address->second.services_tls.views.value_or(default_value);
144
144
 
145
145
  case service_type::management:
146
146
  return address->second.services_tls.management.value_or(default_value);
147
147
 
148
- case service_type::kv:
148
+ case service_type::key_value:
149
149
  return address->second.services_tls.key_value.value_or(default_value);
150
150
  }
151
151
  }
@@ -159,13 +159,13 @@ struct configuration {
159
159
  case service_type::search:
160
160
  return address->second.services_plain.search.value_or(default_value);
161
161
 
162
- case service_type::views:
162
+ case service_type::view:
163
163
  return address->second.services_plain.views.value_or(default_value);
164
164
 
165
165
  case service_type::management:
166
166
  return address->second.services_plain.management.value_or(default_value);
167
167
 
168
- case service_type::kv:
168
+ case service_type::key_value:
169
169
  return address->second.services_plain.key_value.value_or(default_value);
170
170
  }
171
171
  return default_value;
@@ -191,7 +191,8 @@ struct configuration {
191
191
 
192
192
  using vbucket_map = typename std::vector<std::vector<std::int16_t>>;
193
193
 
194
- std::optional<std::uint64_t> rev{};
194
+ std::optional<std::int64_t> epoch{};
195
+ std::optional<std::int64_t> rev{};
195
196
  couchbase::uuid::uuid_t id{};
196
197
  std::optional<std::uint32_t> num_replicas{};
197
198
  std::vector<node> nodes{};
@@ -203,8 +204,26 @@ struct configuration {
203
204
  std::set<cluster_capability> cluster_capabilities{};
204
205
  node_locator_type node_locator{ node_locator_type::unknown };
205
206
 
207
+ bool operator==(const configuration& other) const
208
+ {
209
+ return epoch == other.epoch && rev == other.rev;
210
+ }
211
+
212
+ bool operator<(const configuration& other) const
213
+ {
214
+ return epoch < other.epoch && rev < other.rev;
215
+ }
216
+
217
+ bool operator>(const configuration& other) const
218
+ {
219
+ return other < *this;
220
+ }
221
+
206
222
  [[nodiscard]] std::string rev_str() const
207
223
  {
224
+ if (epoch) {
225
+ return fmt::format("{}:{}", epoch.value(), rev.value_or(0));
226
+ }
208
227
  return rev ? fmt::format("{}", *rev) : "(none)";
209
228
  }
210
229
 
@@ -240,8 +259,8 @@ struct configuration {
240
259
  throw std::runtime_error("cannot map key: partition map is not available");
241
260
  }
242
261
  uint32_t crc = utils::hash_crc32(key.data(), key.size());
243
- uint16_t vbucket = uint16_t(crc % vbmap->size());
244
- return std::make_pair(vbucket, vbmap->at(vbucket)[0]);
262
+ auto vbucket = uint16_t(crc % vbmap->size());
263
+ return { vbucket, vbmap->at(vbucket)[0] };
245
264
  }
246
265
  };
247
266
 
@@ -250,6 +269,7 @@ make_blank_configuration(const std::string& hostname, std::uint16_t plain_port,
250
269
  {
251
270
  configuration result;
252
271
  result.id = couchbase::uuid::random();
272
+ result.epoch = 0;
253
273
  result.rev = 0;
254
274
  result.nodes.resize(1);
255
275
  result.nodes[0].hostname = hostname;
@@ -400,7 +420,8 @@ struct traits<couchbase::configuration> {
400
420
  {
401
421
  couchbase::configuration result;
402
422
  result.id = couchbase::uuid::random();
403
- result.rev = v.template optional<std::uint64_t>("rev");
423
+ result.epoch = v.template optional<std::int64_t>("revEpoch");
424
+ result.rev = v.template optional<std::int64_t>("rev");
404
425
  auto* node_locator = v.find("nodeLocator");
405
426
  if (node_locator != nullptr && node_locator->is_string()) {
406
427
  if (node_locator->get_string() == "ketama") {
@@ -423,7 +444,7 @@ struct traits<couchbase::configuration> {
423
444
  const auto& hostname = o.find("hostname");
424
445
  if (hostname != o.end()) {
425
446
  n.hostname = hostname->second.get_string();
426
- n.hostname = n.hostname.substr(0, n.hostname.rfind(":"));
447
+ n.hostname = n.hostname.substr(0, n.hostname.rfind(':'));
427
448
  }
428
449
  const auto& s = o.at("services");
429
450
  n.services_plain.key_value = s.template optional<std::uint16_t>("kv");
@@ -57,6 +57,15 @@ cb_str_new(const std::string& str)
57
57
  return rb_external_str_new(str.data(), static_cast<long>(str.size()));
58
58
  }
59
59
 
60
+ static inline VALUE
61
+ cb_str_new(const std::optional<std::string>& str)
62
+ {
63
+ if (str) {
64
+ return rb_external_str_new(str->data(), static_cast<long>(str->size()));
65
+ }
66
+ return Qnil;
67
+ }
68
+
60
69
  static void
61
70
  init_versions(VALUE mCouchbase)
62
71
  {
@@ -97,11 +106,12 @@ init_versions(VALUE mCouchbase)
97
106
  #endif
98
107
 
99
108
  VALUE version_info = rb_inspect(cb_Version);
100
- spdlog::info("couchbase backend has been initialized: {}",
101
- std::string_view(RSTRING_PTR(version_info), static_cast<std::size_t>(RSTRING_LEN(version_info))));
109
+ spdlog::debug("couchbase backend has been initialized: {}",
110
+ std::string_view(RSTRING_PTR(version_info), static_cast<std::size_t>(RSTRING_LEN(version_info))));
102
111
 
103
112
  VALUE cb_BuildInfo = rb_hash_new();
104
113
  rb_const_set(mCouchbase, rb_intern("BUILD_INFO"), cb_BuildInfo);
114
+ rb_hash_aset(cb_BuildInfo, rb_id2sym(rb_intern("cmake_version")), rb_str_freeze(rb_str_new_cstr(CMAKE_VERSION)));
105
115
  rb_hash_aset(cb_BuildInfo, rb_id2sym(rb_intern("cmake_build_type")), rb_str_freeze(rb_str_new_cstr(CMAKE_BUILD_TYPE)));
106
116
  rb_hash_aset(cb_BuildInfo, rb_id2sym(rb_intern("compile_definitions")), rb_str_freeze(rb_str_new_cstr(BACKEND_COMPILE_DEFINITIONS)));
107
117
  rb_hash_aset(cb_BuildInfo, rb_id2sym(rb_intern("compile_features")), rb_str_freeze(rb_str_new_cstr(BACKEND_COMPILE_FEATURES)));
@@ -235,6 +245,7 @@ static VALUE eInternalServerFailure;
235
245
  static VALUE eInvalidArgument;
236
246
  static VALUE eJobQueueFull;
237
247
  static VALUE eLinkNotFound;
248
+ static VALUE eLinkExists;
238
249
  static VALUE eNumberTooBig;
239
250
  static VALUE eParsingFailure;
240
251
  static VALUE ePathExists;
@@ -317,6 +328,7 @@ init_exceptions(VALUE mCouchbase)
317
328
  eInvalidArgument = rb_define_class_under(mError, "InvalidArgument", rb_eArgError);
318
329
  eJobQueueFull = rb_define_class_under(mError, "JobQueueFull", eCouchbaseError);
319
330
  eLinkNotFound = rb_define_class_under(mError, "LinkNotFound", eCouchbaseError);
331
+ eLinkExists = rb_define_class_under(mError, "LinkExists", eCouchbaseError);
320
332
  eNumberTooBig = rb_define_class_under(mError, "NumberTooBig", eCouchbaseError);
321
333
  eParsingFailure = rb_define_class_under(mError, "ParsingFailure", eCouchbaseError);
322
334
  ePathExists = rb_define_class_under(mError, "PathExists", eCouchbaseError);
@@ -358,7 +370,7 @@ static VALUE
358
370
  cb_map_error_code(std::error_code ec, const std::string& message)
359
371
  {
360
372
  if (ec.category() == couchbase::error::detail::get_common_category()) {
361
- switch (static_cast<couchbase::error::common_errc>(ec.value())) {
373
+ switch (couchbase::error::common_errc(ec.value())) {
362
374
  case couchbase::error::common_errc::unambiguous_timeout:
363
375
  return rb_exc_new_cstr(eUnambiguousTimeout, fmt::format("{}: {}", message, ec.message()).c_str());
364
376
 
@@ -417,7 +429,7 @@ cb_map_error_code(std::error_code ec, const std::string& message)
417
429
  return rb_exc_new_cstr(eIndexExists, fmt::format("{}: {}", message, ec.message()).c_str());
418
430
  }
419
431
  } else if (ec.category() == couchbase::error::detail::get_key_value_category()) {
420
- switch (static_cast<couchbase::error::key_value_errc>(ec.value())) {
432
+ switch (couchbase::error::key_value_errc(ec.value())) {
421
433
  case couchbase::error::key_value_errc::document_not_found:
422
434
  return rb_exc_new_cstr(eDocumentNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
423
435
 
@@ -494,7 +506,7 @@ cb_map_error_code(std::error_code ec, const std::string& message)
494
506
  return rb_exc_new_cstr(eXattrCannotModifyVirtualAttribute, fmt::format("{}: {}", message, ec.message()).c_str());
495
507
  }
496
508
  } else if (ec.category() == couchbase::error::detail::get_query_category()) {
497
- switch (static_cast<couchbase::error::query_errc>(ec.value())) {
509
+ switch (couchbase::error::query_errc(ec.value())) {
498
510
  case couchbase::error::query_errc::planning_failure:
499
511
  return rb_exc_new_cstr(ePlanningFailure, fmt::format("{}: {}", message, ec.message()).c_str());
500
512
 
@@ -505,14 +517,14 @@ cb_map_error_code(std::error_code ec, const std::string& message)
505
517
  return rb_exc_new_cstr(ePreparedStatementFailure, fmt::format("{}: {}", message, ec.message()).c_str());
506
518
  }
507
519
  } else if (ec.category() == couchbase::error::detail::get_search_category()) {
508
- switch (static_cast<couchbase::error::search_errc>(ec.value())) {
520
+ switch (couchbase::error::search_errc(ec.value())) {
509
521
  case couchbase::error::search_errc::index_not_ready:
510
522
  return rb_exc_new_cstr(eIndexNotReady, fmt::format("{}: {}", message, ec.message()).c_str());
511
523
  case couchbase::error::search_errc::consistency_mismatch:
512
524
  return rb_exc_new_cstr(eConsistencyMismatch, fmt::format("{}: {}", message, ec.message()).c_str());
513
525
  }
514
526
  } else if (ec.category() == couchbase::error::detail::get_view_category()) {
515
- switch (static_cast<couchbase::error::view_errc>(ec.value())) {
527
+ switch (couchbase::error::view_errc(ec.value())) {
516
528
  case couchbase::error::view_errc::view_not_found:
517
529
  return rb_exc_new_cstr(eViewNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
518
530
 
@@ -520,7 +532,7 @@ cb_map_error_code(std::error_code ec, const std::string& message)
520
532
  return rb_exc_new_cstr(eDesignDocumentNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
521
533
  }
522
534
  } else if (ec.category() == couchbase::error::detail::get_analytics_category()) {
523
- switch (static_cast<couchbase::error::analytics_errc>(ec.value())) {
535
+ switch (couchbase::error::analytics_errc(ec.value())) {
524
536
  case couchbase::error::analytics_errc::compilation_failure:
525
537
  return rb_exc_new_cstr(eCompilationFailure, fmt::format("{}: {}", message, ec.message()).c_str());
526
538
 
@@ -541,9 +553,12 @@ cb_map_error_code(std::error_code ec, const std::string& message)
541
553
 
542
554
  case couchbase::error::analytics_errc::link_not_found:
543
555
  return rb_exc_new_cstr(eLinkNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
556
+
557
+ case couchbase::error::analytics_errc::link_exists:
558
+ return rb_exc_new_cstr(eLinkExists, fmt::format("{}: {}", message, ec.message()).c_str());
544
559
  }
545
560
  } else if (ec.category() == couchbase::error::detail::get_management_category()) {
546
- switch (static_cast<couchbase::error::management_errc>(ec.value())) {
561
+ switch (couchbase::error::management_errc(ec.value())) {
547
562
  case couchbase::error::management_errc::collection_exists:
548
563
  return rb_exc_new_cstr(eCollectionExists, fmt::format("{}: {}", message, ec.message()).c_str());
549
564
 
@@ -566,7 +581,7 @@ cb_map_error_code(std::error_code ec, const std::string& message)
566
581
  return rb_exc_new_cstr(eBucketNotFlushable, fmt::format("{}: {}", message, ec.message()).c_str());
567
582
  }
568
583
  } else if (ec.category() == couchbase::error::detail::network_error_category()) {
569
- switch (static_cast<couchbase::error::network_errc>(ec.value())) {
584
+ switch (couchbase::error::network_errc(ec.value())) {
570
585
  case couchbase::error::network_errc::resolve_failure:
571
586
  return rb_exc_new_cstr(eResolveFailure, fmt::format("{}: {}", message, ec.message()).c_str());
572
587
 
@@ -836,6 +851,126 @@ cb_wait_for_future(Future&& f) -> decltype(f.get())
836
851
  return std::move(arg.res);
837
852
  }
838
853
 
854
+ template<typename Request>
855
+ [[nodiscard]] VALUE
856
+ cb_extract_timeout(Request& req, VALUE options)
857
+ {
858
+ if (!NIL_P(options)) {
859
+ switch (TYPE(options)) {
860
+ case T_HASH:
861
+ return cb_extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
862
+ case T_FIXNUM:
863
+ case T_BIGNUM:
864
+ req.timeout = std::chrono::milliseconds(NUM2ULL(options));
865
+ break;
866
+ default:
867
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("timeout must be an Integer, but given %+" PRIsVALUE, options));
868
+ }
869
+ }
870
+ return Qnil;
871
+ }
872
+
873
+ [[nodiscard]] VALUE
874
+ cb_extract_timeout(std::chrono::milliseconds& timeout, VALUE options)
875
+ {
876
+ if (!NIL_P(options)) {
877
+ switch (TYPE(options)) {
878
+ case T_HASH:
879
+ return cb_extract_timeout(timeout, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
880
+ case T_FIXNUM:
881
+ case T_BIGNUM:
882
+ timeout = std::chrono::milliseconds(NUM2ULL(options));
883
+ break;
884
+ default:
885
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("timeout must be an Integer, but given %+" PRIsVALUE, options));
886
+ }
887
+ }
888
+ return Qnil;
889
+ }
890
+
891
+ [[nodiscard]] VALUE
892
+ cb_extract_option_bool(bool& field, VALUE options, const char* name)
893
+ {
894
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
895
+ VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
896
+ if (NIL_P(val)) {
897
+ return Qnil;
898
+ }
899
+ switch (TYPE(val)) {
900
+ case T_TRUE:
901
+ field = true;
902
+ break;
903
+ case T_FALSE:
904
+ field = false;
905
+ break;
906
+ default:
907
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be a Boolean, but given %+" PRIsVALUE, name, val));
908
+ }
909
+ }
910
+ return Qnil;
911
+ }
912
+
913
+ [[nodiscard]] VALUE
914
+ cb_extract_option_number(std::size_t& field, VALUE options, const char* name)
915
+ {
916
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
917
+ VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
918
+ if (NIL_P(val)) {
919
+ return Qnil;
920
+ }
921
+ switch (TYPE(val)) {
922
+ case T_FIXNUM:
923
+ field = FIX2ULONG(val);
924
+ break;
925
+ case T_BIGNUM:
926
+ field = NUM2ULL(val);
927
+ break;
928
+ default:
929
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be a Integer, but given %+" PRIsVALUE, name, val));
930
+ }
931
+ }
932
+ return Qnil;
933
+ }
934
+
935
+ [[nodiscard]] VALUE
936
+ cb_extract_option_milliseconds(std::chrono::milliseconds& field, VALUE options, const char* name)
937
+ {
938
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
939
+ VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
940
+ if (NIL_P(val)) {
941
+ return Qnil;
942
+ }
943
+ switch (TYPE(val)) {
944
+ case T_FIXNUM:
945
+ field = std::chrono::milliseconds(FIX2ULONG(val));
946
+ break;
947
+ case T_BIGNUM:
948
+ field = std::chrono::milliseconds(NUM2ULL(val));
949
+ break;
950
+ default:
951
+ return rb_exc_new_str(rb_eArgError,
952
+ rb_sprintf("%s must be a Integer representing milliseconds, but given %+" PRIsVALUE, name, val));
953
+ }
954
+ }
955
+ return Qnil;
956
+ }
957
+
958
+ [[nodiscard]] VALUE
959
+ cb_extract_option_array(VALUE& val, VALUE options, const char* name)
960
+ {
961
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
962
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
963
+ if (NIL_P(val)) {
964
+ return Qnil;
965
+ }
966
+ if (TYPE(val) == T_ARRAY) {
967
+ return Qnil;
968
+ }
969
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Array, but given %+" PRIsVALUE, name, val));
970
+ }
971
+ return Qnil;
972
+ }
973
+
839
974
  static VALUE
840
975
  cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE options)
841
976
  {
@@ -880,21 +1015,28 @@ cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE op
880
1015
  if (NIL_P(certificate_path) || NIL_P(key_path)) {
881
1016
  auth.username.assign(RSTRING_PTR(username), static_cast<size_t>(RSTRING_LEN(username)));
882
1017
  auth.password.assign(RSTRING_PTR(password), static_cast<size_t>(RSTRING_LEN(password)));
883
- VALUE allowed_mechanisms = rb_hash_aref(options, rb_id2sym(rb_intern("allowed_sasl_mechanisms")));
884
- if (!NIL_P(allowed_mechanisms)) {
885
- Check_Type(allowed_mechanisms, T_ARRAY);
886
- auto allowed_mechanisms_size = static_cast<size_t>(RARRAY_LEN(allowed_mechanisms));
887
- auth.allowed_sasl_mechanisms.reserve(allowed_mechanisms_size);
888
- for (size_t i = 0; i < allowed_mechanisms_size; ++i) {
889
- VALUE mechanism = rb_ary_entry(allowed_mechanisms, static_cast<long>(i));
890
- if (mechanism == rb_id2sym(rb_intern("scram_sha512"))) {
891
- auth.allowed_sasl_mechanisms.emplace_back("SCRAM-SHA512");
892
- } else if (mechanism == rb_id2sym(rb_intern("scram_sha256"))) {
893
- auth.allowed_sasl_mechanisms.emplace_back("SCRAM-SHA256");
894
- } else if (mechanism == rb_id2sym(rb_intern("scram_sha1"))) {
895
- auth.allowed_sasl_mechanisms.emplace_back("SCRAM-SHA1");
896
- } else if (mechanism == rb_id2sym(rb_intern("plain"))) {
897
- auth.allowed_sasl_mechanisms.emplace_back("PLAIN");
1018
+ if (!NIL_P(options)) {
1019
+ VALUE allowed_mechanisms = rb_hash_aref(options, rb_id2sym(rb_intern("allowed_sasl_mechanisms")));
1020
+ if (!NIL_P(allowed_mechanisms)) {
1021
+ Check_Type(allowed_mechanisms, T_ARRAY);
1022
+ auto allowed_mechanisms_size = static_cast<size_t>(RARRAY_LEN(allowed_mechanisms));
1023
+ if (allowed_mechanisms_size < 1) {
1024
+ exc = rb_exc_new_cstr(eInvalidArgument, "allowed_sasl_mechanisms list cannot be empty");
1025
+ break;
1026
+ }
1027
+ auth.allowed_sasl_mechanisms.clear();
1028
+ auth.allowed_sasl_mechanisms.reserve(allowed_mechanisms_size);
1029
+ for (size_t i = 0; i < allowed_mechanisms_size; ++i) {
1030
+ VALUE mechanism = rb_ary_entry(allowed_mechanisms, static_cast<long>(i));
1031
+ if (mechanism == rb_id2sym(rb_intern("scram_sha512"))) {
1032
+ auth.allowed_sasl_mechanisms.emplace_back("SCRAM-SHA512");
1033
+ } else if (mechanism == rb_id2sym(rb_intern("scram_sha256"))) {
1034
+ auth.allowed_sasl_mechanisms.emplace_back("SCRAM-SHA256");
1035
+ } else if (mechanism == rb_id2sym(rb_intern("scram_sha1"))) {
1036
+ auth.allowed_sasl_mechanisms.emplace_back("SCRAM-SHA1");
1037
+ } else if (mechanism == rb_id2sym(rb_intern("plain"))) {
1038
+ auth.allowed_sasl_mechanisms.emplace_back("PLAIN");
1039
+ }
898
1040
  }
899
1041
  }
900
1042
  }
@@ -909,6 +1051,66 @@ cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE op
909
1051
  auth.key_path.assign(RSTRING_PTR(key_path), static_cast<size_t>(RSTRING_LEN(key_path)));
910
1052
  }
911
1053
  couchbase::origin origin(auth, connstr);
1054
+ exc = cb_extract_option_bool(origin.options().enable_tracing, options, "enable_tracing");
1055
+ if (!NIL_P(exc)) {
1056
+ break;
1057
+ }
1058
+ if (origin.options().enable_tracing) {
1059
+ exc =
1060
+ cb_extract_option_milliseconds(origin.options().tracing_options.orphaned_emit_interval, options, "orphaned_emit_interval");
1061
+ if (!NIL_P(exc)) {
1062
+ break;
1063
+ }
1064
+ exc = cb_extract_option_number(origin.options().tracing_options.orphaned_sample_size, options, "orphaned_sample_size");
1065
+ if (!NIL_P(exc)) {
1066
+ break;
1067
+ }
1068
+
1069
+ exc =
1070
+ cb_extract_option_milliseconds(origin.options().tracing_options.threshold_emit_interval, options, "threshold_emit_interval");
1071
+ if (!NIL_P(exc)) {
1072
+ break;
1073
+ }
1074
+ exc = cb_extract_option_number(origin.options().tracing_options.threshold_sample_size, options, "threshold_sample_size");
1075
+ if (!NIL_P(exc)) {
1076
+ break;
1077
+ }
1078
+ exc = cb_extract_option_milliseconds(origin.options().tracing_options.key_value_threshold, options, "key_value_threshold");
1079
+ if (!NIL_P(exc)) {
1080
+ break;
1081
+ }
1082
+ exc = cb_extract_option_milliseconds(origin.options().tracing_options.query_threshold, options, "query_threshold");
1083
+ if (!NIL_P(exc)) {
1084
+ break;
1085
+ }
1086
+ exc = cb_extract_option_milliseconds(origin.options().tracing_options.view_threshold, options, "view_threshold");
1087
+ if (!NIL_P(exc)) {
1088
+ break;
1089
+ }
1090
+ exc = cb_extract_option_milliseconds(origin.options().tracing_options.search_threshold, options, "search_threshold");
1091
+ if (!NIL_P(exc)) {
1092
+ break;
1093
+ }
1094
+ exc = cb_extract_option_milliseconds(origin.options().tracing_options.analytics_threshold, options, "analytics_threshold");
1095
+ if (!NIL_P(exc)) {
1096
+ break;
1097
+ }
1098
+ exc = cb_extract_option_milliseconds(origin.options().tracing_options.management_threshold, options, "management_threshold");
1099
+ if (!NIL_P(exc)) {
1100
+ break;
1101
+ }
1102
+ }
1103
+ exc = cb_extract_option_bool(origin.options().enable_metrics, options, "enable_metrics");
1104
+ if (!NIL_P(exc)) {
1105
+ break;
1106
+ }
1107
+ if (origin.options().enable_metrics) {
1108
+ exc = cb_extract_option_milliseconds(origin.options().metrics_options.emit_interval, options, "metrics_emit_interval");
1109
+ if (!NIL_P(exc)) {
1110
+ break;
1111
+ }
1112
+ }
1113
+
912
1114
  auto barrier = std::make_shared<std::promise<std::error_code>>();
913
1115
  auto f = barrier->get_future();
914
1116
  backend->cluster->open(origin, [barrier](std::error_code ec) mutable { barrier->set_value(ec); });
@@ -966,7 +1168,7 @@ cb_Backend_diagnostics(VALUE self, VALUE report_id)
966
1168
  for (const auto& svcs : resp.services) {
967
1169
  VALUE type = Qnil;
968
1170
  switch (svcs.first) {
969
- case couchbase::service_type::kv:
1171
+ case couchbase::service_type::key_value:
970
1172
  type = rb_id2sym(rb_intern("kv"));
971
1173
  break;
972
1174
  case couchbase::service_type::query:
@@ -978,7 +1180,7 @@ cb_Backend_diagnostics(VALUE self, VALUE report_id)
978
1180
  case couchbase::service_type::search:
979
1181
  type = rb_id2sym(rb_intern("search"));
980
1182
  break;
981
- case couchbase::service_type::views:
1183
+ case couchbase::service_type::view:
982
1184
  type = rb_id2sym(rb_intern("views"));
983
1185
  break;
984
1186
  case couchbase::service_type::management:
@@ -1059,81 +1261,6 @@ cb_Backend_open_bucket(VALUE self, VALUE bucket, VALUE wait_until_ready)
1059
1261
  return Qnil;
1060
1262
  }
1061
1263
 
1062
- template<typename Request>
1063
- [[nodiscard]] VALUE
1064
- cb_extract_timeout(Request& req, VALUE options)
1065
- {
1066
- if (!NIL_P(options)) {
1067
- switch (TYPE(options)) {
1068
- case T_HASH:
1069
- return cb_extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
1070
- case T_FIXNUM:
1071
- case T_BIGNUM:
1072
- req.timeout = std::chrono::milliseconds(NUM2ULL(options));
1073
- break;
1074
- default:
1075
- return rb_exc_new_str(rb_eArgError, rb_sprintf("timeout must be an Integer, but given %+" PRIsVALUE, options));
1076
- }
1077
- }
1078
- return Qnil;
1079
- }
1080
-
1081
- [[nodiscard]] VALUE
1082
- cb_extract_timeout(std::chrono::milliseconds& timeout, VALUE options)
1083
- {
1084
- if (!NIL_P(options)) {
1085
- switch (TYPE(options)) {
1086
- case T_HASH:
1087
- return cb_extract_timeout(timeout, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
1088
- case T_FIXNUM:
1089
- case T_BIGNUM:
1090
- timeout = std::chrono::milliseconds(NUM2ULL(options));
1091
- break;
1092
- default:
1093
- return rb_exc_new_str(rb_eArgError, rb_sprintf("timeout must be an Integer, but given %+" PRIsVALUE, options));
1094
- }
1095
- }
1096
- return Qnil;
1097
- }
1098
-
1099
- [[nodiscard]] VALUE
1100
- cb_extract_option_bool(bool& field, VALUE options, const char* name)
1101
- {
1102
- if (!NIL_P(options) && TYPE(options) == T_HASH) {
1103
- VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1104
- if (NIL_P(val)) {
1105
- return Qnil;
1106
- }
1107
- switch (TYPE(val)) {
1108
- case T_TRUE:
1109
- field = true;
1110
- break;
1111
- case T_FALSE:
1112
- field = false;
1113
- break;
1114
- default:
1115
- return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be a Boolean, but given %+" PRIsVALUE, name, val));
1116
- }
1117
- }
1118
- return Qnil;
1119
- }
1120
-
1121
- [[nodiscard]] VALUE
1122
- cb_extract_option_array(VALUE& val, VALUE options, const char* name)
1123
- {
1124
- if (!NIL_P(options) && TYPE(options) == T_HASH) {
1125
- val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1126
- if (NIL_P(val)) {
1127
- return Qnil;
1128
- }
1129
- if (TYPE(val) == T_ARRAY) {
1130
- return Qnil;
1131
- }
1132
- return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Array, but given %+" PRIsVALUE, name, val));
1133
- }
1134
- return Qnil;
1135
- }
1136
-
1137
1264
  [[nodiscard]] VALUE
1138
1265
  cb_extract_array_of_ids(std::vector<couchbase::document_id>& ids, VALUE arg)
1139
1266
  {
@@ -1189,7 +1316,7 @@ cb_extract_array_of_id_content(std::vector<std::tuple<couchbase::document_id, st
1189
1316
  if (TYPE(entry) != T_ARRAY || RARRAY_LEN(entry) != 5) {
1190
1317
  return rb_exc_new_str(
1191
1318
  rb_eArgError,
1192
- rb_sprintf("ID/content tuple must be represented as an Array[bucket, collection, id, content], but given %+" PRIsVALUE,
1319
+ rb_sprintf("ID/content tuple must be represented as an Array[bucket, collection, id, content, flags], but given %+" PRIsVALUE,
1193
1320
  entry));
1194
1321
  }
1195
1322
  VALUE bucket = rb_ary_entry(entry, 0);
@@ -1268,13 +1395,12 @@ cb_extract_array_of_id_cas(std::vector<std::pair<couchbase::document_id, std::ui
1268
1395
  }
1269
1396
  }
1270
1397
 
1271
- id_cas.emplace_back(std::make_pair(
1272
- couchbase::document_id{
1273
- std::string(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket))),
1274
- std::string(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection))),
1275
- std::string(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id))),
1276
- },
1277
- cas_val));
1398
+ id_cas.emplace_back(std::pair{ couchbase::document_id{
1399
+ std::string(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket))),
1400
+ std::string(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection))),
1401
+ std::string(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id))),
1402
+ },
1403
+ cas_val });
1278
1404
  }
1279
1405
 
1280
1406
  return Qnil;
@@ -1313,37 +1439,71 @@ cb_extract_option_string(VALUE& val, VALUE options, const char* name)
1313
1439
  }
1314
1440
 
1315
1441
  [[nodiscard]] VALUE
1316
- cb_extract_option_fixnum(VALUE& val, VALUE options, const char* name)
1442
+ cb_extract_option_string(std::string& target, VALUE options, const char* name)
1317
1443
  {
1318
1444
  if (!NIL_P(options) && TYPE(options) == T_HASH) {
1319
- val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1445
+ VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1320
1446
  if (NIL_P(val)) {
1321
1447
  return Qnil;
1322
1448
  }
1323
- if (TYPE(val) == T_FIXNUM) {
1449
+ if (TYPE(val) == T_STRING) {
1450
+ target.assign(RSTRING_PTR(val), static_cast<size_t>(RSTRING_LEN(val)));
1324
1451
  return Qnil;
1325
1452
  }
1326
- return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Integer, but given %+" PRIsVALUE, name, val));
1453
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an String, but given %+" PRIsVALUE, name, val));
1327
1454
  }
1328
1455
  return Qnil;
1329
1456
  }
1330
1457
 
1331
1458
  [[nodiscard]] VALUE
1332
- cb_extract_option_bignum(VALUE& val, VALUE options, const char* name)
1459
+ cb_extract_option_string(std::optional<std::string>& target, VALUE options, const char* name)
1333
1460
  {
1334
1461
  if (!NIL_P(options) && TYPE(options) == T_HASH) {
1335
- val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1462
+ VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1336
1463
  if (NIL_P(val)) {
1337
1464
  return Qnil;
1338
1465
  }
1339
- switch (TYPE(val)) {
1340
- case T_FIXNUM:
1341
- case T_BIGNUM:
1342
- return Qnil;
1343
- default:
1344
- break;
1466
+ if (TYPE(val) == T_STRING) {
1467
+ target.emplace(std::string(RSTRING_PTR(val), static_cast<size_t>(RSTRING_LEN(val))));
1468
+ return Qnil;
1345
1469
  }
1346
- return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Integer, but given %+" PRIsVALUE, name, val));
1470
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an String, but given %+" PRIsVALUE, name, val));
1471
+ }
1472
+ return Qnil;
1473
+ }
1474
+
1475
+ [[nodiscard]] VALUE
1476
+ cb_extract_option_fixnum(VALUE& val, VALUE options, const char* name)
1477
+ {
1478
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1479
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1480
+ if (NIL_P(val)) {
1481
+ return Qnil;
1482
+ }
1483
+ if (TYPE(val) == T_FIXNUM) {
1484
+ return Qnil;
1485
+ }
1486
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Integer, but given %+" PRIsVALUE, name, val));
1487
+ }
1488
+ return Qnil;
1489
+ }
1490
+
1491
+ [[nodiscard]] VALUE
1492
+ cb_extract_option_bignum(VALUE& val, VALUE options, const char* name)
1493
+ {
1494
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1495
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1496
+ if (NIL_P(val)) {
1497
+ return Qnil;
1498
+ }
1499
+ switch (TYPE(val)) {
1500
+ case T_FIXNUM:
1501
+ case T_BIGNUM:
1502
+ return Qnil;
1503
+ default:
1504
+ break;
1505
+ }
1506
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Integer, but given %+" PRIsVALUE, name, val));
1347
1507
  }
1348
1508
  return Qnil;
1349
1509
  }
@@ -1432,7 +1592,7 @@ cb_Backend_ping(VALUE self, VALUE bucket, VALUE options)
1432
1592
  for (size_t i = 0; i < entries_num; ++i) {
1433
1593
  VALUE entry = rb_ary_entry(services, static_cast<long>(i));
1434
1594
  if (entry == rb_id2sym(rb_intern("kv"))) {
1435
- selected_services.insert(couchbase::service_type::kv);
1595
+ selected_services.insert(couchbase::service_type::key_value);
1436
1596
  } else if (entry == rb_id2sym(rb_intern("query"))) {
1437
1597
  selected_services.insert(couchbase::service_type::query);
1438
1598
  } else if (entry == rb_id2sym(rb_intern("analytics"))) {
@@ -1440,7 +1600,7 @@ cb_Backend_ping(VALUE self, VALUE bucket, VALUE options)
1440
1600
  } else if (entry == rb_id2sym(rb_intern("search"))) {
1441
1601
  selected_services.insert(couchbase::service_type::search);
1442
1602
  } else if (entry == rb_id2sym(rb_intern("views"))) {
1443
- selected_services.insert(couchbase::service_type::views);
1603
+ selected_services.insert(couchbase::service_type::view);
1444
1604
  }
1445
1605
  }
1446
1606
  }
@@ -1459,7 +1619,7 @@ cb_Backend_ping(VALUE self, VALUE bucket, VALUE options)
1459
1619
  for (const auto& svcs : resp.services) {
1460
1620
  VALUE type = Qnil;
1461
1621
  switch (svcs.first) {
1462
- case couchbase::service_type::kv:
1622
+ case couchbase::service_type::key_value:
1463
1623
  type = rb_id2sym(rb_intern("kv"));
1464
1624
  break;
1465
1625
  case couchbase::service_type::query:
@@ -1471,7 +1631,7 @@ cb_Backend_ping(VALUE self, VALUE bucket, VALUE options)
1471
1631
  case couchbase::service_type::search:
1472
1632
  type = rb_id2sym(rb_intern("search"));
1473
1633
  break;
1474
- case couchbase::service_type::views:
1634
+ case couchbase::service_type::view:
1475
1635
  type = rb_id2sym(rb_intern("views"));
1476
1636
  break;
1477
1637
  case couchbase::service_type::management:
@@ -3516,7 +3676,7 @@ cb_generate_bucket_settings(VALUE bucket, couchbase::operations::bucket_settings
3516
3676
  }
3517
3677
 
3518
3678
  static VALUE
3519
- cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE timeout)
3679
+ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE options)
3520
3680
  {
3521
3681
  cb_backend_data* backend = nullptr;
3522
3682
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -3527,11 +3687,14 @@ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE timeout)
3527
3687
  }
3528
3688
 
3529
3689
  Check_Type(bucket_settings, T_HASH);
3690
+ if (!NIL_P(options)) {
3691
+ Check_Type(options, T_HASH);
3692
+ }
3530
3693
 
3531
3694
  VALUE exc = Qnil;
3532
3695
  do {
3533
3696
  couchbase::operations::bucket_create_request req{};
3534
- exc = cb_extract_timeout(req, timeout);
3697
+ exc = cb_extract_timeout(req, options);
3535
3698
  if (!NIL_P(exc)) {
3536
3699
  break;
3537
3700
  }
@@ -3557,7 +3720,7 @@ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE timeout)
3557
3720
  }
3558
3721
 
3559
3722
  static VALUE
3560
- cb_Backend_bucket_update(VALUE self, VALUE bucket_settings, VALUE timeout)
3723
+ cb_Backend_bucket_update(VALUE self, VALUE bucket_settings, VALUE options)
3561
3724
  {
3562
3725
  cb_backend_data* backend = nullptr;
3563
3726
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -3568,10 +3731,13 @@ cb_Backend_bucket_update(VALUE self, VALUE bucket_settings, VALUE timeout)
3568
3731
  }
3569
3732
 
3570
3733
  Check_Type(bucket_settings, T_HASH);
3734
+ if (!NIL_P(options)) {
3735
+ Check_Type(options, T_HASH);
3736
+ }
3571
3737
  VALUE exc = Qnil;
3572
3738
  do {
3573
3739
  couchbase::operations::bucket_update_request req{};
3574
- exc = cb_extract_timeout(req, timeout);
3740
+ exc = cb_extract_timeout(req, options);
3575
3741
  if (!NIL_P(exc)) {
3576
3742
  break;
3577
3743
  }
@@ -3596,7 +3762,7 @@ cb_Backend_bucket_update(VALUE self, VALUE bucket_settings, VALUE timeout)
3596
3762
  }
3597
3763
 
3598
3764
  static VALUE
3599
- cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE timeout)
3765
+ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE options)
3600
3766
  {
3601
3767
  cb_backend_data* backend = nullptr;
3602
3768
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -3607,11 +3773,14 @@ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE timeout)
3607
3773
  }
3608
3774
 
3609
3775
  Check_Type(bucket_name, T_STRING);
3776
+ if (!NIL_P(options)) {
3777
+ Check_Type(options, T_HASH);
3778
+ }
3610
3779
 
3611
3780
  VALUE exc = Qnil;
3612
3781
  do {
3613
3782
  couchbase::operations::bucket_drop_request req{};
3614
- exc = cb_extract_timeout(req, timeout);
3783
+ exc = cb_extract_timeout(req, options);
3615
3784
  if (!NIL_P(exc)) {
3616
3785
  break;
3617
3786
  }
@@ -3632,7 +3801,7 @@ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE timeout)
3632
3801
  }
3633
3802
 
3634
3803
  static VALUE
3635
- cb_Backend_bucket_flush(VALUE self, VALUE bucket_name, VALUE timeout)
3804
+ cb_Backend_bucket_flush(VALUE self, VALUE bucket_name, VALUE options)
3636
3805
  {
3637
3806
  cb_backend_data* backend = nullptr;
3638
3807
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -3643,11 +3812,14 @@ cb_Backend_bucket_flush(VALUE self, VALUE bucket_name, VALUE timeout)
3643
3812
  }
3644
3813
 
3645
3814
  Check_Type(bucket_name, T_STRING);
3815
+ if (!NIL_P(options)) {
3816
+ Check_Type(options, T_HASH);
3817
+ }
3646
3818
 
3647
3819
  VALUE exc = Qnil;
3648
3820
  do {
3649
3821
  couchbase::operations::bucket_flush_request req{};
3650
- exc = cb_extract_timeout(req, timeout);
3822
+ exc = cb_extract_timeout(req, options);
3651
3823
  if (!NIL_P(exc)) {
3652
3824
  break;
3653
3825
  }
@@ -3768,7 +3940,7 @@ cb_extract_bucket_settings(const couchbase::operations::bucket_settings& entry,
3768
3940
  }
3769
3941
 
3770
3942
  static VALUE
3771
- cb_Backend_bucket_get_all(VALUE self, VALUE timeout)
3943
+ cb_Backend_bucket_get_all(VALUE self, VALUE options)
3772
3944
  {
3773
3945
  cb_backend_data* backend = nullptr;
3774
3946
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -3778,10 +3950,14 @@ cb_Backend_bucket_get_all(VALUE self, VALUE timeout)
3778
3950
  return Qnil;
3779
3951
  }
3780
3952
 
3953
+ if (!NIL_P(options)) {
3954
+ Check_Type(options, T_HASH);
3955
+ }
3956
+
3781
3957
  VALUE exc = Qnil;
3782
3958
  do {
3783
3959
  couchbase::operations::bucket_get_all_request req{};
3784
- exc = cb_extract_timeout(req, timeout);
3960
+ exc = cb_extract_timeout(req, options);
3785
3961
  if (!NIL_P(exc)) {
3786
3962
  break;
3787
3963
  }
@@ -3809,7 +3985,7 @@ cb_Backend_bucket_get_all(VALUE self, VALUE timeout)
3809
3985
  }
3810
3986
 
3811
3987
  static VALUE
3812
- cb_Backend_bucket_get(VALUE self, VALUE bucket_name, VALUE timeout)
3988
+ cb_Backend_bucket_get(VALUE self, VALUE bucket_name, VALUE options)
3813
3989
  {
3814
3990
  cb_backend_data* backend = nullptr;
3815
3991
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -3820,11 +3996,14 @@ cb_Backend_bucket_get(VALUE self, VALUE bucket_name, VALUE timeout)
3820
3996
  }
3821
3997
 
3822
3998
  Check_Type(bucket_name, T_STRING);
3999
+ if (!NIL_P(options)) {
4000
+ Check_Type(options, T_HASH);
4001
+ }
3823
4002
 
3824
4003
  VALUE exc = Qnil;
3825
4004
  do {
3826
4005
  couchbase::operations::bucket_get_request req{};
3827
- exc = cb_extract_timeout(req, timeout);
4006
+ exc = cb_extract_timeout(req, options);
3828
4007
  if (!NIL_P(exc)) {
3829
4008
  break;
3830
4009
  }
@@ -4475,7 +4654,7 @@ cb_Backend_cluster_enable_developer_preview(VALUE self)
4475
4654
  }
4476
4655
 
4477
4656
  static VALUE
4478
- cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
4657
+ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE options)
4479
4658
  {
4480
4659
  cb_backend_data* backend = nullptr;
4481
4660
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4486,11 +4665,14 @@ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
4486
4665
  }
4487
4666
 
4488
4667
  Check_Type(bucket_name, T_STRING);
4668
+ if (!NIL_P(options)) {
4669
+ Check_Type(options, T_HASH);
4670
+ }
4489
4671
 
4490
4672
  VALUE exc = Qnil;
4491
4673
  do {
4492
4674
  couchbase::operations::scope_get_all_request req{};
4493
- exc = cb_extract_timeout(req, timeout);
4675
+ exc = cb_extract_timeout(req, options);
4494
4676
  if (!NIL_P(exc)) {
4495
4677
  break;
4496
4678
  }
@@ -4587,7 +4769,7 @@ cb_Backend_collections_manifest_get(VALUE self, VALUE bucket_name, VALUE timeout
4587
4769
  }
4588
4770
 
4589
4771
  static VALUE
4590
- cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE timeout)
4772
+ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE options)
4591
4773
  {
4592
4774
  cb_backend_data* backend = nullptr;
4593
4775
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4599,11 +4781,14 @@ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE t
4599
4781
 
4600
4782
  Check_Type(bucket_name, T_STRING);
4601
4783
  Check_Type(scope_name, T_STRING);
4784
+ if (!NIL_P(options)) {
4785
+ Check_Type(options, T_HASH);
4786
+ }
4602
4787
 
4603
4788
  VALUE exc = Qnil;
4604
4789
  do {
4605
4790
  couchbase::operations::scope_create_request req{};
4606
- exc = cb_extract_timeout(req, timeout);
4791
+ exc = cb_extract_timeout(req, options);
4607
4792
  if (!NIL_P(exc)) {
4608
4793
  break;
4609
4794
  }
@@ -4626,7 +4811,7 @@ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE t
4626
4811
  }
4627
4812
 
4628
4813
  static VALUE
4629
- cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE timeout)
4814
+ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE options)
4630
4815
  {
4631
4816
  cb_backend_data* backend = nullptr;
4632
4817
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4638,11 +4823,14 @@ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE tim
4638
4823
 
4639
4824
  Check_Type(bucket_name, T_STRING);
4640
4825
  Check_Type(scope_name, T_STRING);
4826
+ if (!NIL_P(options)) {
4827
+ Check_Type(options, T_HASH);
4828
+ }
4641
4829
 
4642
4830
  VALUE exc = Qnil;
4643
4831
  do {
4644
4832
  couchbase::operations::scope_drop_request req{};
4645
- exc = cb_extract_timeout(req, timeout);
4833
+ exc = cb_extract_timeout(req, options);
4646
4834
  if (!NIL_P(exc)) {
4647
4835
  break;
4648
4836
  }
@@ -4665,7 +4853,7 @@ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE tim
4665
4853
  }
4666
4854
 
4667
4855
  static VALUE
4668
- cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE max_expiry, VALUE timeout)
4856
+ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE max_expiry, VALUE options)
4669
4857
  {
4670
4858
  cb_backend_data* backend = nullptr;
4671
4859
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4678,11 +4866,14 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
4678
4866
  Check_Type(bucket_name, T_STRING);
4679
4867
  Check_Type(scope_name, T_STRING);
4680
4868
  Check_Type(collection_name, T_STRING);
4869
+ if (!NIL_P(options)) {
4870
+ Check_Type(options, T_HASH);
4871
+ }
4681
4872
 
4682
4873
  VALUE exc = Qnil;
4683
4874
  do {
4684
4875
  couchbase::operations::collection_create_request req{};
4685
- exc = cb_extract_timeout(req, timeout);
4876
+ exc = cb_extract_timeout(req, options);
4686
4877
  if (!NIL_P(exc)) {
4687
4878
  break;
4688
4879
  }
@@ -4713,7 +4904,7 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
4713
4904
  }
4714
4905
 
4715
4906
  static VALUE
4716
- cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE timeout)
4907
+ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE options)
4717
4908
  {
4718
4909
  cb_backend_data* backend = nullptr;
4719
4910
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4726,11 +4917,14 @@ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALU
4726
4917
  Check_Type(bucket_name, T_STRING);
4727
4918
  Check_Type(scope_name, T_STRING);
4728
4919
  Check_Type(collection_name, T_STRING);
4920
+ if (!NIL_P(options)) {
4921
+ Check_Type(options, T_HASH);
4922
+ }
4729
4923
 
4730
4924
  VALUE exc = Qnil;
4731
4925
  do {
4732
4926
  couchbase::operations::collection_drop_request req{};
4733
- exc = cb_extract_timeout(req, timeout);
4927
+ exc = cb_extract_timeout(req, options);
4734
4928
  if (!NIL_P(exc)) {
4735
4929
  break;
4736
4930
  }
@@ -4757,7 +4951,7 @@ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALU
4757
4951
  }
4758
4952
 
4759
4953
  static VALUE
4760
- cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
4954
+ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE options)
4761
4955
  {
4762
4956
  cb_backend_data* backend = nullptr;
4763
4957
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4768,11 +4962,14 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
4768
4962
  }
4769
4963
 
4770
4964
  Check_Type(bucket_name, T_STRING);
4965
+ if (!NIL_P(options)) {
4966
+ Check_Type(options, T_HASH);
4967
+ }
4771
4968
 
4772
4969
  VALUE exc = Qnil;
4773
4970
  do {
4774
4971
  couchbase::operations::query_index_get_all_request req{};
4775
- exc = cb_extract_timeout(req, timeout);
4972
+ exc = cb_extract_timeout(req, options);
4776
4973
  if (!NIL_P(exc)) {
4777
4974
  break;
4778
4975
  }
@@ -4814,6 +5011,9 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
4814
5011
  if (idx.condition) {
4815
5012
  rb_hash_aset(index, rb_id2sym(rb_intern("condition")), cb_str_new(idx.condition.value()));
4816
5013
  }
5014
+ if (idx.partition) {
5015
+ rb_hash_aset(index, rb_id2sym(rb_intern("partition")), cb_str_new(idx.partition.value()));
5016
+ }
4817
5017
  rb_ary_push(indexes, index);
4818
5018
  }
4819
5019
 
@@ -4826,7 +5026,7 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
4826
5026
  }
4827
5027
 
4828
5028
  static VALUE
4829
- cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, VALUE fields, VALUE options, VALUE timeout)
5029
+ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, VALUE fields, VALUE options)
4830
5030
  {
4831
5031
  cb_backend_data* backend = nullptr;
4832
5032
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4839,11 +5039,14 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
4839
5039
  Check_Type(bucket_name, T_STRING);
4840
5040
  Check_Type(index_name, T_STRING);
4841
5041
  Check_Type(fields, T_ARRAY);
5042
+ if (!NIL_P(options)) {
5043
+ Check_Type(options, T_HASH);
5044
+ }
4842
5045
 
4843
5046
  VALUE exc = Qnil;
4844
5047
  do {
4845
5048
  couchbase::operations::query_index_create_request req{};
4846
- exc = cb_extract_timeout(req, timeout);
5049
+ exc = cb_extract_timeout(req, options);
4847
5050
  if (!NIL_P(exc)) {
4848
5051
  break;
4849
5052
  }
@@ -4857,7 +5060,6 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
4857
5060
  req.fields.emplace_back(RSTRING_PTR(entry), static_cast<std::size_t>(RSTRING_LEN(entry)));
4858
5061
  }
4859
5062
  if (!NIL_P(options)) {
4860
- Check_Type(options, T_HASH);
4861
5063
  VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
4862
5064
  if (ignore_if_exists == Qtrue) {
4863
5065
  req.ignore_if_exists = true;
@@ -4927,7 +5129,7 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
4927
5129
  }
4928
5130
 
4929
5131
  static VALUE
4930
- cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VALUE options, VALUE timeout)
5132
+ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VALUE options)
4931
5133
  {
4932
5134
  cb_backend_data* backend = nullptr;
4933
5135
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -4939,18 +5141,20 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
4939
5141
 
4940
5142
  Check_Type(bucket_name, T_STRING);
4941
5143
  Check_Type(index_name, T_STRING);
5144
+ if (!NIL_P(options)) {
5145
+ Check_Type(options, T_HASH);
5146
+ }
4942
5147
 
4943
5148
  VALUE exc = Qnil;
4944
5149
  do {
4945
5150
  couchbase::operations::query_index_drop_request req{};
4946
- exc = cb_extract_timeout(req, timeout);
5151
+ exc = cb_extract_timeout(req, options);
4947
5152
  if (!NIL_P(exc)) {
4948
5153
  break;
4949
5154
  }
4950
5155
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
4951
5156
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4952
5157
  if (!NIL_P(options)) {
4953
- Check_Type(options, T_HASH);
4954
5158
  VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
4955
5159
  if (ignore_if_does_not_exist == Qtrue) {
4956
5160
  req.ignore_if_does_not_exist = true;
@@ -5006,7 +5210,7 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
5006
5210
  }
5007
5211
 
5008
5212
  static VALUE
5009
- cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE options, VALUE timeout)
5213
+ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE options)
5010
5214
  {
5011
5215
  cb_backend_data* backend = nullptr;
5012
5216
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -5024,14 +5228,13 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
5024
5228
  VALUE exc = Qnil;
5025
5229
  do {
5026
5230
  couchbase::operations::query_index_create_request req{};
5027
- exc = cb_extract_timeout(req, timeout);
5231
+ exc = cb_extract_timeout(req, options);
5028
5232
  if (!NIL_P(exc)) {
5029
5233
  break;
5030
5234
  }
5031
5235
  req.is_primary = true;
5032
5236
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
5033
5237
  if (!NIL_P(options)) {
5034
- Check_Type(options, T_HASH);
5035
5238
  VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
5036
5239
  if (ignore_if_exists == Qtrue) {
5037
5240
  req.ignore_if_exists = true;
@@ -5100,7 +5303,7 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
5100
5303
  }
5101
5304
 
5102
5305
  static VALUE
5103
- cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options, VALUE timeout)
5306
+ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options)
5104
5307
  {
5105
5308
  cb_backend_data* backend = nullptr;
5106
5309
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -5111,18 +5314,20 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
5111
5314
  }
5112
5315
 
5113
5316
  Check_Type(bucket_name, T_STRING);
5317
+ if (!NIL_P(options)) {
5318
+ Check_Type(options, T_HASH);
5319
+ }
5114
5320
 
5115
5321
  VALUE exc = Qnil;
5116
5322
  do {
5117
5323
  couchbase::operations::query_index_drop_request req{};
5118
- exc = cb_extract_timeout(req, timeout);
5324
+ exc = cb_extract_timeout(req, options);
5119
5325
  if (!NIL_P(exc)) {
5120
5326
  break;
5121
5327
  }
5122
5328
  req.is_primary = true;
5123
5329
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
5124
5330
  if (!NIL_P(options)) {
5125
- Check_Type(options, T_HASH);
5126
5331
  VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
5127
5332
  if (ignore_if_does_not_exist == Qtrue) {
5128
5333
  req.ignore_if_does_not_exist = true;
@@ -5181,7 +5386,7 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
5181
5386
  }
5182
5387
 
5183
5388
  static VALUE
5184
- cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE timeout)
5389
+ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE options)
5185
5390
  {
5186
5391
  cb_backend_data* backend = nullptr;
5187
5392
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -5192,11 +5397,14 @@ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE timeo
5192
5397
  }
5193
5398
 
5194
5399
  Check_Type(bucket_name, T_STRING);
5400
+ if (!NIL_P(options)) {
5401
+ Check_Type(options, T_HASH);
5402
+ }
5195
5403
 
5196
5404
  VALUE exc = Qnil;
5197
5405
  do {
5198
5406
  couchbase::operations::query_index_build_deferred_request req{};
5199
- exc = cb_extract_timeout(req, timeout);
5407
+ exc = cb_extract_timeout(req, options);
5200
5408
  if (!NIL_P(exc)) {
5201
5409
  break;
5202
5410
  }
@@ -5273,7 +5481,7 @@ cb_extract_search_index(VALUE index, const couchbase::operations::search_index&
5273
5481
  }
5274
5482
 
5275
5483
  static VALUE
5276
- cb_Backend_search_index_get_all(VALUE self, VALUE timeout)
5484
+ cb_Backend_search_index_get_all(VALUE self, VALUE options)
5277
5485
  {
5278
5486
  cb_backend_data* backend = nullptr;
5279
5487
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -5286,7 +5494,7 @@ cb_Backend_search_index_get_all(VALUE self, VALUE timeout)
5286
5494
  VALUE exc = Qnil;
5287
5495
  do {
5288
5496
  couchbase::operations::search_index_get_all_request req{};
5289
- exc = cb_extract_timeout(req, timeout);
5497
+ exc = cb_extract_timeout(req, options);
5290
5498
  if (!NIL_P(exc)) {
5291
5499
  break;
5292
5500
  }
@@ -5922,7 +6130,9 @@ cb_Backend_document_search(VALUE self, VALUE index_name, VALUE query, VALUE opti
5922
6130
 
5923
6131
  Check_Type(index_name, T_STRING);
5924
6132
  Check_Type(query, T_STRING);
5925
- Check_Type(options, T_HASH);
6133
+ if (!NIL_P(options)) {
6134
+ Check_Type(options, T_HASH);
6135
+ }
5926
6136
 
5927
6137
  VALUE exc = Qnil;
5928
6138
  do {
@@ -6041,6 +6251,22 @@ cb_Backend_document_search(VALUE self, VALUE index_name, VALUE query, VALUE opti
6041
6251
  }
6042
6252
  }
6043
6253
 
6254
+ VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name")));
6255
+ if (!NIL_P(scope_name) && TYPE(scope_name) == T_STRING) {
6256
+ req.scope_name.emplace(std::string(RSTRING_PTR(scope_name), static_cast<std::size_t>(RSTRING_LEN(scope_name))));
6257
+ VALUE collections = rb_hash_aref(options, rb_id2sym(rb_intern("collections")));
6258
+ if (!NIL_P(collections)) {
6259
+ Check_Type(collections, T_ARRAY);
6260
+ auto collections_size = static_cast<size_t>(RARRAY_LEN(collections));
6261
+ req.collections.reserve(collections_size);
6262
+ for (size_t i = 0; i < collections_size; ++i) {
6263
+ VALUE collection = rb_ary_entry(collections, static_cast<long>(i));
6264
+ Check_Type(collection, T_STRING);
6265
+ req.collections.emplace_back(std::string(RSTRING_PTR(collection), static_cast<std::size_t>(RSTRING_LEN(collection))));
6266
+ }
6267
+ }
6268
+ }
6269
+
6044
6270
  VALUE sort = rb_hash_aref(options, rb_id2sym(rb_intern("sort")));
6045
6271
  if (!NIL_P(sort)) {
6046
6272
  Check_Type(sort, T_ARRAY);
@@ -6271,7 +6497,7 @@ cb_Backend_dns_srv(VALUE self, VALUE hostname, VALUE service)
6271
6497
  }
6272
6498
 
6273
6499
  static VALUE
6274
- cb_Backend_analytics_get_pending_mutations(VALUE self, VALUE timeout)
6500
+ cb_Backend_analytics_get_pending_mutations(VALUE self, VALUE options)
6275
6501
  {
6276
6502
  cb_backend_data* backend = nullptr;
6277
6503
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6284,7 +6510,7 @@ cb_Backend_analytics_get_pending_mutations(VALUE self, VALUE timeout)
6284
6510
  VALUE exc = Qnil;
6285
6511
  do {
6286
6512
  couchbase::operations::analytics_get_pending_mutations_request req{};
6287
- exc = cb_extract_timeout(req, timeout);
6513
+ exc = cb_extract_timeout(req, options);
6288
6514
  if (!NIL_P(exc)) {
6289
6515
  break;
6290
6516
  }
@@ -6315,7 +6541,7 @@ cb_Backend_analytics_get_pending_mutations(VALUE self, VALUE timeout)
6315
6541
  }
6316
6542
 
6317
6543
  static VALUE
6318
- cb_Backend_analytics_dataset_get_all(VALUE self, VALUE timeout)
6544
+ cb_Backend_analytics_dataset_get_all(VALUE self, VALUE options)
6319
6545
  {
6320
6546
  cb_backend_data* backend = nullptr;
6321
6547
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6328,7 +6554,7 @@ cb_Backend_analytics_dataset_get_all(VALUE self, VALUE timeout)
6328
6554
  VALUE exc = Qnil;
6329
6555
  do {
6330
6556
  couchbase::operations::analytics_dataset_get_all_request req{};
6331
- exc = cb_extract_timeout(req, timeout);
6557
+ exc = cb_extract_timeout(req, options);
6332
6558
  if (!NIL_P(exc)) {
6333
6559
  break;
6334
6560
  }
@@ -6363,7 +6589,7 @@ cb_Backend_analytics_dataset_get_all(VALUE self, VALUE timeout)
6363
6589
  }
6364
6590
 
6365
6591
  static VALUE
6366
- cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE dataverse_name, VALUE ignore_if_does_not_exist, VALUE timeout)
6592
+ cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE options)
6367
6593
  {
6368
6594
  cb_backend_data* backend = nullptr;
6369
6595
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6374,23 +6600,26 @@ cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE datavers
6374
6600
  }
6375
6601
 
6376
6602
  Check_Type(dataset_name, T_STRING);
6377
- if (!NIL_P(dataverse_name)) {
6378
- Check_Type(dataverse_name, T_STRING);
6379
- }
6380
6603
 
6381
6604
  VALUE exc = Qnil;
6382
6605
  do {
6383
6606
  couchbase::operations::analytics_dataset_drop_request req{};
6384
- exc = cb_extract_timeout(req, timeout);
6607
+ exc = cb_extract_timeout(req, options);
6385
6608
  if (!NIL_P(exc)) {
6386
6609
  break;
6387
6610
  }
6388
6611
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
6612
+ VALUE dataverse_name = Qnil;
6613
+ exc = cb_extract_option_string(dataverse_name, options, "dataverse_name");
6614
+ if (!NIL_P(exc)) {
6615
+ break;
6616
+ }
6389
6617
  if (!NIL_P(dataverse_name)) {
6390
6618
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6391
6619
  }
6392
- if (!NIL_P(ignore_if_does_not_exist)) {
6393
- req.ignore_if_does_not_exist = RTEST(ignore_if_does_not_exist);
6620
+ exc = cb_extract_option_bool(req.ignore_if_does_not_exist, options, "ignore_if_does_not_exist");
6621
+ if (!NIL_P(exc)) {
6622
+ break;
6394
6623
  }
6395
6624
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataset_drop_response>>();
6396
6625
  auto f = barrier->get_future();
@@ -6418,13 +6647,7 @@ cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE datavers
6418
6647
  }
6419
6648
 
6420
6649
  static VALUE
6421
- cb_Backend_analytics_dataset_create(VALUE self,
6422
- VALUE dataset_name,
6423
- VALUE bucket_name,
6424
- VALUE condition,
6425
- VALUE dataverse_name,
6426
- VALUE ignore_if_exists,
6427
- VALUE timeout)
6650
+ cb_Backend_analytics_dataset_create(VALUE self, VALUE dataset_name, VALUE bucket_name, VALUE options)
6428
6651
  {
6429
6652
  cb_backend_data* backend = nullptr;
6430
6653
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6436,30 +6659,35 @@ cb_Backend_analytics_dataset_create(VALUE self,
6436
6659
 
6437
6660
  Check_Type(dataset_name, T_STRING);
6438
6661
  Check_Type(bucket_name, T_STRING);
6439
- if (!NIL_P(condition)) {
6440
- Check_Type(condition, T_STRING);
6441
- }
6442
- if (!NIL_P(dataverse_name)) {
6443
- Check_Type(dataverse_name, T_STRING);
6444
- }
6445
6662
 
6446
6663
  VALUE exc = Qnil;
6447
6664
  do {
6448
6665
  couchbase::operations::analytics_dataset_create_request req{};
6449
- exc = cb_extract_timeout(req, timeout);
6666
+ exc = cb_extract_timeout(req, options);
6450
6667
  if (!NIL_P(exc)) {
6451
6668
  break;
6452
6669
  }
6453
6670
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
6454
6671
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
6672
+ VALUE condition = Qnil;
6673
+ exc = cb_extract_option_string(condition, options, "condition");
6674
+ if (!NIL_P(exc)) {
6675
+ break;
6676
+ }
6455
6677
  if (!NIL_P(condition)) {
6456
6678
  req.condition.emplace(std::string(RSTRING_PTR(condition), static_cast<size_t>(RSTRING_LEN(condition))));
6457
6679
  }
6680
+ VALUE dataverse_name = Qnil;
6681
+ exc = cb_extract_option_string(dataverse_name, options, "dataverse_name");
6682
+ if (!NIL_P(exc)) {
6683
+ break;
6684
+ }
6458
6685
  if (!NIL_P(dataverse_name)) {
6459
6686
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6460
6687
  }
6461
- if (!NIL_P(ignore_if_exists)) {
6462
- req.ignore_if_exists = RTEST(ignore_if_exists);
6688
+ exc = cb_extract_option_bool(req.ignore_if_exists, options, "ignore_if_exists");
6689
+ if (!NIL_P(exc)) {
6690
+ break;
6463
6691
  }
6464
6692
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataset_create_response>>();
6465
6693
  auto f = barrier->get_future();
@@ -6487,7 +6715,7 @@ cb_Backend_analytics_dataset_create(VALUE self,
6487
6715
  }
6488
6716
 
6489
6717
  static VALUE
6490
- cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE ignore_if_does_not_exist, VALUE timeout)
6718
+ cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE options)
6491
6719
  {
6492
6720
  cb_backend_data* backend = nullptr;
6493
6721
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6502,11 +6730,12 @@ cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE igno
6502
6730
  VALUE exc = Qnil;
6503
6731
  do {
6504
6732
  couchbase::operations::analytics_dataverse_drop_request req{};
6505
- exc = cb_extract_timeout(req, timeout);
6733
+ exc = cb_extract_timeout(req, options);
6506
6734
  if (!NIL_P(exc)) {
6507
6735
  break;
6508
6736
  }
6509
6737
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6738
+ VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
6510
6739
  if (!NIL_P(ignore_if_does_not_exist)) {
6511
6740
  req.ignore_if_does_not_exist = RTEST(ignore_if_does_not_exist);
6512
6741
  }
@@ -6533,7 +6762,7 @@ cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE igno
6533
6762
  }
6534
6763
 
6535
6764
  static VALUE
6536
- cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE ignore_if_exists, VALUE timeout)
6765
+ cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE options)
6537
6766
  {
6538
6767
  cb_backend_data* backend = nullptr;
6539
6768
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6551,11 +6780,12 @@ cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE ig
6551
6780
  VALUE exc = Qnil;
6552
6781
  do {
6553
6782
  couchbase::operations::analytics_dataverse_create_request req{};
6554
- exc = cb_extract_timeout(req, timeout);
6783
+ exc = cb_extract_timeout(req, options);
6555
6784
  if (!NIL_P(exc)) {
6556
6785
  break;
6557
6786
  }
6558
6787
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6788
+ VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
6559
6789
  if (!NIL_P(ignore_if_exists)) {
6560
6790
  req.ignore_if_exists = RTEST(ignore_if_exists);
6561
6791
  }
@@ -6582,7 +6812,7 @@ cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE ig
6582
6812
  }
6583
6813
 
6584
6814
  static VALUE
6585
- cb_Backend_analytics_index_get_all(VALUE self, VALUE timeout)
6815
+ cb_Backend_analytics_index_get_all(VALUE self, VALUE options)
6586
6816
  {
6587
6817
  cb_backend_data* backend = nullptr;
6588
6818
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6595,7 +6825,7 @@ cb_Backend_analytics_index_get_all(VALUE self, VALUE timeout)
6595
6825
  VALUE exc = Qnil;
6596
6826
  do {
6597
6827
  couchbase::operations::analytics_index_get_all_request req{};
6598
- exc = cb_extract_timeout(req, timeout);
6828
+ exc = cb_extract_timeout(req, options);
6599
6829
  if (!NIL_P(exc)) {
6600
6830
  break;
6601
6831
  }
@@ -6630,13 +6860,7 @@ cb_Backend_analytics_index_get_all(VALUE self, VALUE timeout)
6630
6860
  }
6631
6861
 
6632
6862
  static VALUE
6633
- cb_Backend_analytics_index_create(VALUE self,
6634
- VALUE index_name,
6635
- VALUE dataset_name,
6636
- VALUE fields,
6637
- VALUE dataverse_name,
6638
- VALUE ignore_if_exists,
6639
- VALUE timeout)
6863
+ cb_Backend_analytics_index_create(VALUE self, VALUE index_name, VALUE dataset_name, VALUE fields, VALUE options)
6640
6864
  {
6641
6865
  cb_backend_data* backend = nullptr;
6642
6866
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6649,14 +6873,11 @@ cb_Backend_analytics_index_create(VALUE self,
6649
6873
  Check_Type(index_name, T_STRING);
6650
6874
  Check_Type(dataset_name, T_STRING);
6651
6875
  Check_Type(fields, T_ARRAY);
6652
- if (!NIL_P(dataverse_name)) {
6653
- Check_Type(dataverse_name, T_STRING);
6654
- }
6655
6876
 
6656
6877
  VALUE exc = Qnil;
6657
6878
  do {
6658
6879
  couchbase::operations::analytics_index_create_request req{};
6659
- exc = cb_extract_timeout(req, timeout);
6880
+ exc = cb_extract_timeout(req, options);
6660
6881
  if (!NIL_P(exc)) {
6661
6882
  break;
6662
6883
  }
@@ -6669,15 +6890,22 @@ cb_Backend_analytics_index_create(VALUE self,
6669
6890
  if (RARRAY_LEN(entry) == 2) {
6670
6891
  VALUE field = rb_ary_entry(entry, 0);
6671
6892
  VALUE type = rb_ary_entry(entry, 1);
6672
- req.fields.emplace(std::string(RSTRING_PTR(field), static_cast<std::size_t>(RSTRING_LEN(field))),
6673
- std::string(RSTRING_PTR(type), static_cast<std::size_t>(RSTRING_LEN(type))));
6893
+ req.fields.try_emplace(std::string(RSTRING_PTR(field), static_cast<std::size_t>(RSTRING_LEN(field))),
6894
+ std::string(RSTRING_PTR(type), static_cast<std::size_t>(RSTRING_LEN(type))));
6674
6895
  }
6675
6896
  }
6897
+
6898
+ VALUE dataverse_name = Qnil;
6899
+ exc = cb_extract_option_string(dataverse_name, options, "dataverse_name");
6900
+ if (!NIL_P(exc)) {
6901
+ break;
6902
+ }
6676
6903
  if (!NIL_P(dataverse_name)) {
6677
6904
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6678
6905
  }
6679
- if (!NIL_P(ignore_if_exists)) {
6680
- req.ignore_if_exists = RTEST(ignore_if_exists);
6906
+ exc = cb_extract_option_bool(req.ignore_if_exists, options, "ignore_if_exists");
6907
+ if (!NIL_P(exc)) {
6908
+ break;
6681
6909
  }
6682
6910
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_index_create_response>>();
6683
6911
  auto f = barrier->get_future();
@@ -6707,12 +6935,7 @@ cb_Backend_analytics_index_create(VALUE self,
6707
6935
  }
6708
6936
 
6709
6937
  static VALUE
6710
- cb_Backend_analytics_index_drop(VALUE self,
6711
- VALUE index_name,
6712
- VALUE dataset_name,
6713
- VALUE dataverse_name,
6714
- VALUE ignore_if_does_not_exist,
6715
- VALUE timeout)
6938
+ cb_Backend_analytics_index_drop(VALUE self, VALUE index_name, VALUE dataset_name, VALUE options)
6716
6939
  {
6717
6940
  cb_backend_data* backend = nullptr;
6718
6941
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6724,24 +6947,27 @@ cb_Backend_analytics_index_drop(VALUE self,
6724
6947
 
6725
6948
  Check_Type(index_name, T_STRING);
6726
6949
  Check_Type(dataset_name, T_STRING);
6727
- if (!NIL_P(dataverse_name)) {
6728
- Check_Type(dataverse_name, T_STRING);
6729
- }
6730
6950
 
6731
6951
  VALUE exc = Qnil;
6732
6952
  do {
6733
6953
  couchbase::operations::analytics_index_drop_request req{};
6734
- exc = cb_extract_timeout(req, timeout);
6954
+ exc = cb_extract_timeout(req, options);
6735
6955
  if (!NIL_P(exc)) {
6736
6956
  break;
6737
6957
  }
6738
6958
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
6739
6959
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
6960
+ VALUE dataverse_name = Qnil;
6961
+ exc = cb_extract_option_string(dataverse_name, options, "dataverse_name");
6962
+ if (!NIL_P(exc)) {
6963
+ break;
6964
+ }
6740
6965
  if (!NIL_P(dataverse_name)) {
6741
6966
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6742
6967
  }
6743
- if (!NIL_P(ignore_if_does_not_exist)) {
6744
- req.ignore_if_does_not_exist = RTEST(ignore_if_does_not_exist);
6968
+ exc = cb_extract_option_bool(req.ignore_if_does_not_exist, options, "ignore_if_does_not_exist");
6969
+ if (!NIL_P(exc)) {
6970
+ break;
6745
6971
  }
6746
6972
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_index_drop_response>>();
6747
6973
  auto f = barrier->get_future();
@@ -6771,7 +6997,7 @@ cb_Backend_analytics_index_drop(VALUE self,
6771
6997
  }
6772
6998
 
6773
6999
  static VALUE
6774
- cb_Backend_analytics_link_connect(VALUE self, VALUE link_name, VALUE force, VALUE dataverse_name, VALUE timeout)
7000
+ cb_Backend_analytics_link_connect(VALUE self, VALUE options)
6775
7001
  {
6776
7002
  cb_backend_data* backend = nullptr;
6777
7003
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6781,24 +7007,32 @@ cb_Backend_analytics_link_connect(VALUE self, VALUE link_name, VALUE force, VALU
6781
7007
  return Qnil;
6782
7008
  }
6783
7009
 
6784
- Check_Type(link_name, T_STRING);
6785
- if (!NIL_P(dataverse_name)) {
6786
- Check_Type(dataverse_name, T_STRING);
6787
- }
6788
-
6789
7010
  VALUE exc = Qnil;
6790
7011
  do {
6791
7012
  couchbase::operations::analytics_link_connect_request req{};
6792
- exc = cb_extract_timeout(req, timeout);
7013
+ exc = cb_extract_timeout(req, options);
7014
+ if (!NIL_P(exc)) {
7015
+ break;
7016
+ }
7017
+ VALUE link_name = Qnil;
7018
+ exc = cb_extract_option_string(link_name, options, "link_name");
7019
+ if (!NIL_P(exc)) {
7020
+ break;
7021
+ }
7022
+ if (!NIL_P(link_name)) {
7023
+ req.link_name.assign(RSTRING_PTR(link_name), static_cast<size_t>(RSTRING_LEN(link_name)));
7024
+ }
7025
+ VALUE dataverse_name = Qnil;
7026
+ exc = cb_extract_option_string(link_name, options, "dataverse_name");
6793
7027
  if (!NIL_P(exc)) {
6794
7028
  break;
6795
7029
  }
6796
- req.link_name.assign(RSTRING_PTR(link_name), static_cast<size_t>(RSTRING_LEN(link_name)));
6797
7030
  if (!NIL_P(dataverse_name)) {
6798
7031
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6799
7032
  }
6800
- if (!NIL_P(force)) {
6801
- req.force = RTEST(force);
7033
+ exc = cb_extract_option_bool(req.force, options, "force");
7034
+ if (!NIL_P(exc)) {
7035
+ break;
6802
7036
  }
6803
7037
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_connect_response>>();
6804
7038
  auto f = barrier->get_future();
@@ -6826,7 +7060,7 @@ cb_Backend_analytics_link_connect(VALUE self, VALUE link_name, VALUE force, VALU
6826
7060
  }
6827
7061
 
6828
7062
  static VALUE
6829
- cb_Backend_analytics_link_disconnect(VALUE self, VALUE link_name, VALUE dataverse_name, VALUE timeout)
7063
+ cb_Backend_analytics_link_disconnect(VALUE self, VALUE options)
6830
7064
  {
6831
7065
  cb_backend_data* backend = nullptr;
6832
7066
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -6836,19 +7070,26 @@ cb_Backend_analytics_link_disconnect(VALUE self, VALUE link_name, VALUE datavers
6836
7070
  return Qnil;
6837
7071
  }
6838
7072
 
6839
- Check_Type(link_name, T_STRING);
6840
- if (!NIL_P(dataverse_name)) {
6841
- Check_Type(dataverse_name, T_STRING);
6842
- }
6843
-
6844
7073
  VALUE exc = Qnil;
6845
7074
  do {
6846
7075
  couchbase::operations::analytics_link_disconnect_request req{};
6847
- exc = cb_extract_timeout(req, timeout);
7076
+ exc = cb_extract_timeout(req, options);
7077
+ if (!NIL_P(exc)) {
7078
+ break;
7079
+ }
7080
+ VALUE link_name = Qnil;
7081
+ exc = cb_extract_option_string(link_name, options, "link_name");
7082
+ if (!NIL_P(exc)) {
7083
+ break;
7084
+ }
7085
+ if (!NIL_P(link_name)) {
7086
+ req.link_name.assign(RSTRING_PTR(link_name), static_cast<size_t>(RSTRING_LEN(link_name)));
7087
+ }
7088
+ VALUE dataverse_name = Qnil;
7089
+ exc = cb_extract_option_string(link_name, options, "dataverse_name");
6848
7090
  if (!NIL_P(exc)) {
6849
7091
  break;
6850
7092
  }
6851
- req.link_name.assign(RSTRING_PTR(link_name), static_cast<size_t>(RSTRING_LEN(link_name)));
6852
7093
  if (!NIL_P(dataverse_name)) {
6853
7094
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
6854
7095
  }
@@ -6877,42 +7118,606 @@ cb_Backend_analytics_link_disconnect(VALUE self, VALUE link_name, VALUE datavers
6877
7118
  return Qnil;
6878
7119
  }
6879
7120
 
6880
- static int
6881
- cb_for_each_named_param_analytics(VALUE key, VALUE value, VALUE arg)
6882
- {
6883
- auto* preq = reinterpret_cast<couchbase::operations::analytics_request*>(arg);
6884
- Check_Type(key, T_STRING);
6885
- Check_Type(value, T_STRING);
6886
- preq->named_parameters.emplace(
6887
- std::string_view(RSTRING_PTR(key), static_cast<std::size_t>(RSTRING_LEN(key))),
6888
- tao::json::from_string(std::string_view(RSTRING_PTR(value), static_cast<std::size_t>(RSTRING_LEN(value)))));
6889
- return ST_CONTINUE;
6890
- }
6891
-
6892
7121
  static VALUE
6893
- cb_Backend_document_analytics(VALUE self, VALUE statement, VALUE options)
7122
+ cb_fill_link(couchbase::operations::analytics_link::couchbase_remote& dst, VALUE src)
6894
7123
  {
6895
- cb_backend_data* backend = nullptr;
6896
- TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
7124
+ VALUE exc = Qnil;
6897
7125
 
6898
- if (!backend->cluster) {
6899
- rb_raise(rb_eArgError, "Cluster has been closed already");
6900
- return Qnil;
7126
+ exc = cb_extract_option_string(dst.link_name, src, "link_name");
7127
+ if (!NIL_P(exc)) {
7128
+ return exc;
6901
7129
  }
6902
-
6903
- Check_Type(statement, T_STRING);
6904
- Check_Type(options, T_HASH);
6905
-
6906
- VALUE exc = Qnil;
6907
- do {
6908
- couchbase::operations::analytics_request req;
6909
- req.statement.assign(RSTRING_PTR(statement), static_cast<size_t>(RSTRING_LEN(statement)));
6910
- VALUE client_context_id = rb_hash_aref(options, rb_id2sym(rb_intern("client_context_id")));
6911
- if (!NIL_P(client_context_id)) {
6912
- Check_Type(client_context_id, T_STRING);
6913
- req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
6914
- }
6915
- exc = cb_extract_timeout(req, options);
7130
+ exc = cb_extract_option_string(dst.dataverse, src, "dataverse");
7131
+ if (!NIL_P(exc)) {
7132
+ return exc;
7133
+ }
7134
+ exc = cb_extract_option_string(dst.hostname, src, "hostname");
7135
+ if (!NIL_P(exc)) {
7136
+ return exc;
7137
+ }
7138
+ exc = cb_extract_option_string(dst.username, src, "username");
7139
+ if (!NIL_P(exc)) {
7140
+ return exc;
7141
+ }
7142
+ exc = cb_extract_option_string(dst.password, src, "password");
7143
+ if (!NIL_P(exc)) {
7144
+ return exc;
7145
+ }
7146
+ VALUE encryption_level = Qnil;
7147
+ exc = cb_extract_option_symbol(encryption_level, src, "encryption_level");
7148
+ if (!NIL_P(exc)) {
7149
+ return exc;
7150
+ }
7151
+ if (NIL_P(encryption_level)) {
7152
+ encryption_level = rb_id2sym(rb_intern("none"));
7153
+ }
7154
+ ID level = rb_sym2id(encryption_level);
7155
+ if (level == rb_intern("none")) {
7156
+ dst.encryption.level = couchbase::operations::analytics_link::encryption_level::none;
7157
+ } else if (level == rb_intern("half")) {
7158
+ dst.encryption.level = couchbase::operations::analytics_link::encryption_level::half;
7159
+ } else if (level == rb_intern("full")) {
7160
+ dst.encryption.level = couchbase::operations::analytics_link::encryption_level::full;
7161
+ }
7162
+ exc = cb_extract_option_string(dst.encryption.certificate, src, "certificate");
7163
+ if (!NIL_P(exc)) {
7164
+ return exc;
7165
+ }
7166
+ exc = cb_extract_option_string(dst.encryption.client_certificate, src, "client_certificate");
7167
+ if (!NIL_P(exc)) {
7168
+ return exc;
7169
+ }
7170
+ exc = cb_extract_option_string(dst.encryption.client_key, src, "client_key");
7171
+ if (!NIL_P(exc)) {
7172
+ return exc;
7173
+ }
7174
+ return Qnil;
7175
+ }
7176
+
7177
+ static VALUE
7178
+ cb_fill_link(couchbase::operations::analytics_link::azure_blob_external& dst, VALUE src)
7179
+ {
7180
+ VALUE exc = Qnil;
7181
+
7182
+ exc = cb_extract_option_string(dst.link_name, src, "link_name");
7183
+ if (!NIL_P(exc)) {
7184
+ return exc;
7185
+ }
7186
+ exc = cb_extract_option_string(dst.dataverse, src, "dataverse");
7187
+ if (!NIL_P(exc)) {
7188
+ return exc;
7189
+ }
7190
+ exc = cb_extract_option_string(dst.connection_string, src, "connection_string");
7191
+ if (!NIL_P(exc)) {
7192
+ return exc;
7193
+ }
7194
+ exc = cb_extract_option_string(dst.account_name, src, "account_name");
7195
+ if (!NIL_P(exc)) {
7196
+ return exc;
7197
+ }
7198
+ exc = cb_extract_option_string(dst.account_key, src, "account_key");
7199
+ if (!NIL_P(exc)) {
7200
+ return exc;
7201
+ }
7202
+ exc = cb_extract_option_string(dst.shared_access_signature, src, "shared_access_signature");
7203
+ if (!NIL_P(exc)) {
7204
+ return exc;
7205
+ }
7206
+ exc = cb_extract_option_string(dst.blob_endpoint, src, "blob_endpoint");
7207
+ if (!NIL_P(exc)) {
7208
+ return exc;
7209
+ }
7210
+ exc = cb_extract_option_string(dst.endpoint_suffix, src, "endpoint_suffix");
7211
+ if (!NIL_P(exc)) {
7212
+ return exc;
7213
+ }
7214
+ return Qnil;
7215
+ }
7216
+
7217
+ static VALUE
7218
+ cb_fill_link(couchbase::operations::analytics_link::s3_external& dst, VALUE src)
7219
+ {
7220
+ VALUE exc = Qnil;
7221
+
7222
+ exc = cb_extract_option_string(dst.link_name, src, "link_name");
7223
+ if (!NIL_P(exc)) {
7224
+ return exc;
7225
+ }
7226
+ exc = cb_extract_option_string(dst.dataverse, src, "dataverse");
7227
+ if (!NIL_P(exc)) {
7228
+ return exc;
7229
+ }
7230
+ exc = cb_extract_option_string(dst.access_key_id, src, "access_key_id");
7231
+ if (!NIL_P(exc)) {
7232
+ return exc;
7233
+ }
7234
+ exc = cb_extract_option_string(dst.secret_access_key, src, "secret_access_key");
7235
+ if (!NIL_P(exc)) {
7236
+ return exc;
7237
+ }
7238
+ exc = cb_extract_option_string(dst.session_token, src, "session_token");
7239
+ if (!NIL_P(exc)) {
7240
+ return exc;
7241
+ }
7242
+ exc = cb_extract_option_string(dst.region, src, "region");
7243
+ if (!NIL_P(exc)) {
7244
+ return exc;
7245
+ }
7246
+ exc = cb_extract_option_string(dst.service_endpoint, src, "service_endpoint");
7247
+ if (!NIL_P(exc)) {
7248
+ return exc;
7249
+ }
7250
+ return Qnil;
7251
+ }
7252
+
7253
+ static VALUE
7254
+ cb_Backend_analytics_link_create(VALUE self, VALUE link, VALUE options)
7255
+ {
7256
+ cb_backend_data* backend = nullptr;
7257
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
7258
+
7259
+ if (!backend->cluster) {
7260
+ rb_raise(rb_eArgError, "Cluster has been closed already");
7261
+ return Qnil;
7262
+ }
7263
+
7264
+ if (!NIL_P(options)) {
7265
+ Check_Type(options, T_HASH);
7266
+ }
7267
+
7268
+ VALUE exc = Qnil;
7269
+ do {
7270
+ VALUE link_type = Qnil;
7271
+ exc = cb_extract_option_symbol(link_type, link, "type");
7272
+ if (!NIL_P(exc)) {
7273
+ return exc;
7274
+ }
7275
+
7276
+ ID type = rb_sym2id(link_type);
7277
+ if (type == rb_intern("couchbase")) {
7278
+ couchbase::operations::analytics_link_create_request<couchbase::operations::analytics_link::couchbase_remote> req{};
7279
+ exc = cb_extract_timeout(req, options);
7280
+ if (!NIL_P(exc)) {
7281
+ break;
7282
+ }
7283
+ exc = cb_fill_link(req.link, link);
7284
+ if (!NIL_P(exc)) {
7285
+ break;
7286
+ }
7287
+
7288
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_create_response>>();
7289
+ auto f = barrier->get_future();
7290
+ backend->cluster->execute_http(
7291
+ req, [barrier](couchbase::operations::analytics_link_create_response&& resp) mutable { barrier->set_value(resp); });
7292
+ auto resp = cb_wait_for_future(f);
7293
+
7294
+ if (resp.ctx.ec) {
7295
+ if (resp.errors.empty()) {
7296
+ exc = cb_map_error_code(
7297
+ resp.ctx, fmt::format("unable to create couchbase_remote link `{}` on `{}`", req.link.link_name, req.link.dataverse));
7298
+ } else {
7299
+ const auto& first_error = resp.errors.front();
7300
+ exc = cb_map_error_code(resp.ctx,
7301
+ fmt::format("unable to create couchbase_remote link `{}` on `{}` ({}: {})",
7302
+ req.link.link_name,
7303
+ req.link.dataverse,
7304
+ first_error.code,
7305
+ first_error.message));
7306
+ }
7307
+ break;
7308
+ }
7309
+
7310
+ } else if (type == rb_intern("azureblob")) {
7311
+ couchbase::operations::analytics_link_create_request<couchbase::operations::analytics_link::azure_blob_external> req{};
7312
+ exc = cb_extract_timeout(req, options);
7313
+ if (!NIL_P(exc)) {
7314
+ break;
7315
+ }
7316
+
7317
+ exc = cb_fill_link(req.link, link);
7318
+ if (!NIL_P(exc)) {
7319
+ break;
7320
+ }
7321
+
7322
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_create_response>>();
7323
+ auto f = barrier->get_future();
7324
+ backend->cluster->execute_http(
7325
+ req, [barrier](couchbase::operations::analytics_link_create_response&& resp) mutable { barrier->set_value(resp); });
7326
+ auto resp = cb_wait_for_future(f);
7327
+
7328
+ if (resp.ctx.ec) {
7329
+ if (resp.errors.empty()) {
7330
+ exc = cb_map_error_code(
7331
+ resp.ctx,
7332
+ fmt::format("unable to create azure_blob_external link `{}` on `{}`", req.link.link_name, req.link.dataverse));
7333
+ } else {
7334
+ const auto& first_error = resp.errors.front();
7335
+ exc = cb_map_error_code(resp.ctx,
7336
+ fmt::format("unable to create azure_blob_external link `{}` on `{}` ({}: {})",
7337
+ req.link.link_name,
7338
+ req.link.dataverse,
7339
+ first_error.code,
7340
+ first_error.message));
7341
+ }
7342
+ break;
7343
+ }
7344
+
7345
+ } else if (type == rb_intern("s3")) {
7346
+ couchbase::operations::analytics_link_create_request<couchbase::operations::analytics_link::s3_external> req{};
7347
+ exc = cb_extract_timeout(req, options);
7348
+ if (!NIL_P(exc)) {
7349
+ break;
7350
+ }
7351
+
7352
+ exc = cb_fill_link(req.link, link);
7353
+ if (!NIL_P(exc)) {
7354
+ break;
7355
+ }
7356
+
7357
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_create_response>>();
7358
+ auto f = barrier->get_future();
7359
+ backend->cluster->execute_http(
7360
+ req, [barrier](couchbase::operations::analytics_link_create_response&& resp) mutable { barrier->set_value(resp); });
7361
+ auto resp = cb_wait_for_future(f);
7362
+
7363
+ if (resp.ctx.ec) {
7364
+ if (resp.errors.empty()) {
7365
+ exc = cb_map_error_code(
7366
+ resp.ctx, fmt::format("unable to create s3_external link `{}` on `{}`", req.link.link_name, req.link.dataverse));
7367
+ } else {
7368
+ const auto& first_error = resp.errors.front();
7369
+ exc = cb_map_error_code(resp.ctx,
7370
+ fmt::format("unable to create s3_external link `{}` on `{}` ({}: {})",
7371
+ req.link.link_name,
7372
+ req.link.dataverse,
7373
+ first_error.code,
7374
+ first_error.message));
7375
+ }
7376
+ break;
7377
+ }
7378
+ }
7379
+
7380
+ return Qtrue;
7381
+ } while (false);
7382
+ rb_exc_raise(exc);
7383
+ return Qnil;
7384
+ }
7385
+
7386
+ static VALUE
7387
+ cb_Backend_analytics_link_replace(VALUE self, VALUE link, VALUE options)
7388
+ {
7389
+ cb_backend_data* backend = nullptr;
7390
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
7391
+
7392
+ if (!backend->cluster) {
7393
+ rb_raise(rb_eArgError, "Cluster has been closed already");
7394
+ return Qnil;
7395
+ }
7396
+
7397
+ if (!NIL_P(options)) {
7398
+ Check_Type(options, T_HASH);
7399
+ }
7400
+
7401
+ VALUE exc = Qnil;
7402
+ do {
7403
+ VALUE link_type = Qnil;
7404
+ exc = cb_extract_option_symbol(link_type, link, "type");
7405
+ if (!NIL_P(exc)) {
7406
+ return exc;
7407
+ }
7408
+
7409
+ ID type = rb_sym2id(link_type);
7410
+ if (type == rb_intern("couchbase")) {
7411
+ couchbase::operations::analytics_link_replace_request<couchbase::operations::analytics_link::couchbase_remote> req{};
7412
+ exc = cb_extract_timeout(req, options);
7413
+ if (!NIL_P(exc)) {
7414
+ break;
7415
+ }
7416
+ exc = cb_fill_link(req.link, link);
7417
+ if (!NIL_P(exc)) {
7418
+ break;
7419
+ }
7420
+
7421
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_replace_response>>();
7422
+ auto f = barrier->get_future();
7423
+ backend->cluster->execute_http(
7424
+ req, [barrier](couchbase::operations::analytics_link_replace_response&& resp) mutable { barrier->set_value(resp); });
7425
+ auto resp = cb_wait_for_future(f);
7426
+
7427
+ if (resp.ctx.ec) {
7428
+ if (resp.errors.empty()) {
7429
+ exc = cb_map_error_code(
7430
+ resp.ctx,
7431
+ fmt::format("unable to replace couchbase_remote link `{}` on `{}`", req.link.link_name, req.link.dataverse));
7432
+ } else {
7433
+ const auto& first_error = resp.errors.front();
7434
+ exc = cb_map_error_code(resp.ctx,
7435
+ fmt::format("unable to replace couchbase_remote link `{}` on `{}` ({}: {})",
7436
+ req.link.link_name,
7437
+ req.link.dataverse,
7438
+ first_error.code,
7439
+ first_error.message));
7440
+ }
7441
+ break;
7442
+ }
7443
+
7444
+ } else if (type == rb_intern("azureblob")) {
7445
+ couchbase::operations::analytics_link_replace_request<couchbase::operations::analytics_link::azure_blob_external> req{};
7446
+ exc = cb_extract_timeout(req, options);
7447
+ if (!NIL_P(exc)) {
7448
+ break;
7449
+ }
7450
+
7451
+ exc = cb_fill_link(req.link, link);
7452
+ if (!NIL_P(exc)) {
7453
+ break;
7454
+ }
7455
+
7456
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_replace_response>>();
7457
+ auto f = barrier->get_future();
7458
+ backend->cluster->execute_http(
7459
+ req, [barrier](couchbase::operations::analytics_link_replace_response&& resp) mutable { barrier->set_value(resp); });
7460
+ auto resp = cb_wait_for_future(f);
7461
+
7462
+ if (resp.ctx.ec) {
7463
+ if (resp.errors.empty()) {
7464
+ exc = cb_map_error_code(
7465
+ resp.ctx,
7466
+ fmt::format("unable to replace azure_blob_external link `{}` on `{}`", req.link.link_name, req.link.dataverse));
7467
+ } else {
7468
+ const auto& first_error = resp.errors.front();
7469
+ exc = cb_map_error_code(resp.ctx,
7470
+ fmt::format("unable to replace azure_blob_external link `{}` on `{}` ({}: {})",
7471
+ req.link.link_name,
7472
+ req.link.dataverse,
7473
+ first_error.code,
7474
+ first_error.message));
7475
+ }
7476
+ break;
7477
+ }
7478
+
7479
+ } else if (type == rb_intern("s3")) {
7480
+ couchbase::operations::analytics_link_replace_request<couchbase::operations::analytics_link::s3_external> req{};
7481
+ exc = cb_extract_timeout(req, options);
7482
+ if (!NIL_P(exc)) {
7483
+ break;
7484
+ }
7485
+
7486
+ exc = cb_fill_link(req.link, link);
7487
+ if (!NIL_P(exc)) {
7488
+ break;
7489
+ }
7490
+
7491
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_replace_response>>();
7492
+ auto f = barrier->get_future();
7493
+ backend->cluster->execute_http(
7494
+ req, [barrier](couchbase::operations::analytics_link_replace_response&& resp) mutable { barrier->set_value(resp); });
7495
+ auto resp = cb_wait_for_future(f);
7496
+
7497
+ if (resp.ctx.ec) {
7498
+ if (resp.errors.empty()) {
7499
+ exc = cb_map_error_code(
7500
+ resp.ctx, fmt::format("unable to replace s3_external link `{}` on `{}`", req.link.link_name, req.link.dataverse));
7501
+ } else {
7502
+ const auto& first_error = resp.errors.front();
7503
+ exc = cb_map_error_code(resp.ctx,
7504
+ fmt::format("unable to replace s3_external link `{}` on `{}` ({}: {})",
7505
+ req.link.link_name,
7506
+ req.link.dataverse,
7507
+ first_error.code,
7508
+ first_error.message));
7509
+ }
7510
+ break;
7511
+ }
7512
+ }
7513
+
7514
+ return Qtrue;
7515
+ } while (false);
7516
+ rb_exc_raise(exc);
7517
+ return Qnil;
7518
+ }
7519
+
7520
+ static VALUE
7521
+ cb_Backend_analytics_link_drop(VALUE self, VALUE link, VALUE dataverse, VALUE options)
7522
+ {
7523
+ cb_backend_data* backend = nullptr;
7524
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
7525
+
7526
+ if (!backend->cluster) {
7527
+ rb_raise(rb_eArgError, "Cluster has been closed already");
7528
+ return Qnil;
7529
+ }
7530
+
7531
+ Check_Type(link, T_STRING);
7532
+ Check_Type(dataverse, T_STRING);
7533
+ if (!NIL_P(options)) {
7534
+ Check_Type(options, T_HASH);
7535
+ }
7536
+
7537
+ VALUE exc = Qnil;
7538
+ do {
7539
+ couchbase::operations::analytics_link_drop_request req{};
7540
+ exc = cb_extract_timeout(req, options);
7541
+ if (!NIL_P(exc)) {
7542
+ break;
7543
+ }
7544
+
7545
+ req.link_name.assign(RSTRING_PTR(link), static_cast<size_t>(RSTRING_LEN(link)));
7546
+ req.dataverse_name.assign(RSTRING_PTR(dataverse), static_cast<size_t>(RSTRING_LEN(dataverse)));
7547
+
7548
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_drop_response>>();
7549
+ auto f = barrier->get_future();
7550
+ backend->cluster->execute_http(
7551
+ req, [barrier](couchbase::operations::analytics_link_drop_response&& resp) mutable { barrier->set_value(resp); });
7552
+ auto resp = cb_wait_for_future(f);
7553
+
7554
+ if (resp.ctx.ec) {
7555
+ if (resp.errors.empty()) {
7556
+ exc = cb_map_error_code(resp.ctx, fmt::format("unable to drop link `{}` on `{}`", req.link_name, req.dataverse_name));
7557
+ } else {
7558
+ const auto& first_error = resp.errors.front();
7559
+ exc = cb_map_error_code(
7560
+ resp.ctx,
7561
+ fmt::format(
7562
+ "unable to drop link `{}` on `{}` ({}: {})", req.link_name, req.dataverse_name, first_error.code, first_error.message));
7563
+ }
7564
+ break;
7565
+ }
7566
+
7567
+ return Qtrue;
7568
+ } while (false);
7569
+ rb_exc_raise(exc);
7570
+ return Qnil;
7571
+ }
7572
+
7573
+ static VALUE
7574
+ cb_Backend_analytics_link_get_all(VALUE self, VALUE options)
7575
+ {
7576
+ cb_backend_data* backend = nullptr;
7577
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
7578
+
7579
+ if (!backend->cluster) {
7580
+ rb_raise(rb_eArgError, "Cluster has been closed already");
7581
+ return Qnil;
7582
+ }
7583
+
7584
+ if (!NIL_P(options)) {
7585
+ Check_Type(options, T_HASH);
7586
+ }
7587
+
7588
+ VALUE exc = Qnil;
7589
+ do {
7590
+ couchbase::operations::analytics_link_get_all_request req{};
7591
+ exc = cb_extract_timeout(req, options);
7592
+ if (!NIL_P(exc)) {
7593
+ break;
7594
+ }
7595
+
7596
+ exc = cb_extract_option_string(req.link_type, options, "link_type");
7597
+ if (!NIL_P(exc)) {
7598
+ return exc;
7599
+ }
7600
+ exc = cb_extract_option_string(req.dataverse_name, options, "dataverse");
7601
+ if (!NIL_P(exc)) {
7602
+ return exc;
7603
+ }
7604
+ exc = cb_extract_option_string(req.link_name, options, "link_name");
7605
+ if (!NIL_P(exc)) {
7606
+ return exc;
7607
+ }
7608
+
7609
+ auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_get_all_response>>();
7610
+ auto f = barrier->get_future();
7611
+ backend->cluster->execute_http(
7612
+ req, [barrier](couchbase::operations::analytics_link_get_all_response&& resp) mutable { barrier->set_value(resp); });
7613
+ auto resp = cb_wait_for_future(f);
7614
+
7615
+ if (resp.ctx.ec) {
7616
+ if (resp.errors.empty()) {
7617
+ exc = cb_map_error_code(
7618
+ resp.ctx,
7619
+ fmt::format(
7620
+ R"(unable to retrieve links type={}, dataverse="{}", name="{}")", req.link_type, req.link_name, req.dataverse_name));
7621
+ } else {
7622
+ const auto& first_error = resp.errors.front();
7623
+ exc = cb_map_error_code(resp.ctx,
7624
+ fmt::format(R"(unable to retrieve links type={}, dataverse="{}", name="{}" ({}: {}))",
7625
+ req.link_type,
7626
+ req.link_name,
7627
+ req.dataverse_name,
7628
+ first_error.code,
7629
+ first_error.message));
7630
+ }
7631
+ break;
7632
+ }
7633
+
7634
+ VALUE res = rb_ary_new_capa(static_cast<long>(resp.couchbase.size() + resp.s3.size() + resp.azure_blob.size()));
7635
+ for (const auto& link : resp.couchbase) {
7636
+ VALUE row = rb_hash_new();
7637
+ rb_hash_aset(row, rb_id2sym(rb_intern("type")), rb_id2sym(rb_intern("couchbase")));
7638
+ rb_hash_aset(row, rb_id2sym(rb_intern("dataverse")), cb_str_new(link.dataverse));
7639
+ rb_hash_aset(row, rb_id2sym(rb_intern("link_name")), cb_str_new(link.link_name));
7640
+ rb_hash_aset(row, rb_id2sym(rb_intern("hostname")), cb_str_new(link.hostname));
7641
+ switch (link.encryption.level) {
7642
+ case couchbase::operations::analytics_link::encryption_level::none:
7643
+ rb_hash_aset(row, rb_id2sym(rb_intern("encryption_level")), rb_id2sym(rb_intern("none")));
7644
+ break;
7645
+ case couchbase::operations::analytics_link::encryption_level::half:
7646
+ rb_hash_aset(row, rb_id2sym(rb_intern("encryption_level")), rb_id2sym(rb_intern("half")));
7647
+ break;
7648
+ case couchbase::operations::analytics_link::encryption_level::full:
7649
+ rb_hash_aset(row, rb_id2sym(rb_intern("encryption_level")), rb_id2sym(rb_intern("full")));
7650
+ break;
7651
+ }
7652
+ rb_hash_aset(row, rb_id2sym(rb_intern("username")), cb_str_new(link.username));
7653
+ rb_hash_aset(row, rb_id2sym(rb_intern("certificate")), cb_str_new(link.encryption.certificate));
7654
+ rb_hash_aset(row, rb_id2sym(rb_intern("client_certificate")), cb_str_new(link.encryption.client_certificate));
7655
+ rb_ary_push(res, row);
7656
+ }
7657
+ for (const auto& link : resp.s3) {
7658
+ VALUE row = rb_hash_new();
7659
+ rb_hash_aset(row, rb_id2sym(rb_intern("type")), rb_id2sym(rb_intern("s3")));
7660
+ rb_hash_aset(row, rb_id2sym(rb_intern("dataverse")), cb_str_new(link.dataverse));
7661
+ rb_hash_aset(row, rb_id2sym(rb_intern("link_name")), cb_str_new(link.link_name));
7662
+ rb_hash_aset(row, rb_id2sym(rb_intern("access_key_id")), cb_str_new(link.access_key_id));
7663
+ rb_hash_aset(row, rb_id2sym(rb_intern("region")), cb_str_new(link.region));
7664
+ rb_hash_aset(row, rb_id2sym(rb_intern("service_endpoint")), cb_str_new(link.service_endpoint));
7665
+ rb_ary_push(res, row);
7666
+ }
7667
+ for (const auto& link : resp.azure_blob) {
7668
+ VALUE row = rb_hash_new();
7669
+ rb_hash_aset(row, rb_id2sym(rb_intern("type")), rb_id2sym(rb_intern("azureblob")));
7670
+ rb_hash_aset(row, rb_id2sym(rb_intern("dataverse")), cb_str_new(link.dataverse));
7671
+ rb_hash_aset(row, rb_id2sym(rb_intern("link_name")), cb_str_new(link.link_name));
7672
+ rb_hash_aset(row, rb_id2sym(rb_intern("account_name")), cb_str_new(link.account_name));
7673
+ rb_hash_aset(row, rb_id2sym(rb_intern("blob_endpoint")), cb_str_new(link.blob_endpoint));
7674
+ rb_hash_aset(row, rb_id2sym(rb_intern("endpoint_suffix")), cb_str_new(link.endpoint_suffix));
7675
+ rb_ary_push(res, row);
7676
+ }
7677
+
7678
+ return res;
7679
+ } while (false);
7680
+ rb_exc_raise(exc);
7681
+ return Qnil;
7682
+ }
7683
+ static int
7684
+ cb_for_each_named_param_analytics(VALUE key, VALUE value, VALUE arg)
7685
+ {
7686
+ auto* preq = reinterpret_cast<couchbase::operations::analytics_request*>(arg);
7687
+ Check_Type(key, T_STRING);
7688
+ Check_Type(value, T_STRING);
7689
+ preq->named_parameters.emplace(
7690
+ std::string_view(RSTRING_PTR(key), static_cast<std::size_t>(RSTRING_LEN(key))),
7691
+ tao::json::from_string(std::string_view(RSTRING_PTR(value), static_cast<std::size_t>(RSTRING_LEN(value)))));
7692
+ return ST_CONTINUE;
7693
+ }
7694
+
7695
+ static VALUE
7696
+ cb_Backend_document_analytics(VALUE self, VALUE statement, VALUE options)
7697
+ {
7698
+ cb_backend_data* backend = nullptr;
7699
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
7700
+
7701
+ if (!backend->cluster) {
7702
+ rb_raise(rb_eArgError, "Cluster has been closed already");
7703
+ return Qnil;
7704
+ }
7705
+
7706
+ Check_Type(statement, T_STRING);
7707
+ if (!NIL_P(options)) {
7708
+ Check_Type(options, T_HASH);
7709
+ }
7710
+
7711
+ VALUE exc = Qnil;
7712
+ do {
7713
+ couchbase::operations::analytics_request req;
7714
+ req.statement.assign(RSTRING_PTR(statement), static_cast<size_t>(RSTRING_LEN(statement)));
7715
+ VALUE client_context_id = rb_hash_aref(options, rb_id2sym(rb_intern("client_context_id")));
7716
+ if (!NIL_P(client_context_id)) {
7717
+ Check_Type(client_context_id, T_STRING);
7718
+ req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
7719
+ }
7720
+ exc = cb_extract_timeout(req, options);
6916
7721
  if (!NIL_P(exc)) {
6917
7722
  break;
6918
7723
  }
@@ -6993,7 +7798,7 @@ cb_Backend_document_analytics(VALUE self, VALUE statement, VALUE options)
6993
7798
  VALUE res = rb_hash_new();
6994
7799
  VALUE rows = rb_ary_new_capa(static_cast<long>(resp.payload.rows.size()));
6995
7800
  rb_hash_aset(res, rb_id2sym(rb_intern("rows")), rows);
6996
- for (auto& row : resp.payload.rows) {
7801
+ for (const auto& row : resp.payload.rows) {
6997
7802
  rb_ary_push(rows, cb_str_new(row));
6998
7803
  }
6999
7804
  VALUE meta = rb_hash_new();
@@ -7686,6 +8491,48 @@ cb_Backend_leb128_decode(VALUE self, VALUE data)
7686
8491
  return Qnil;
7687
8492
  }
7688
8493
 
8494
+ static VALUE
8495
+ cb_Backend_query_escape(VALUE self, VALUE data)
8496
+ {
8497
+ (void)self;
8498
+ Check_Type(data, T_STRING);
8499
+ auto encoded =
8500
+ couchbase::utils::string_codec::v2::query_escape(std::string(RSTRING_PTR(data), static_cast<std::size_t>(RSTRING_LEN(data))));
8501
+ return cb_str_new(encoded);
8502
+ }
8503
+
8504
+ static VALUE
8505
+ cb_Backend_path_escape(VALUE self, VALUE data)
8506
+ {
8507
+ (void)self;
8508
+ Check_Type(data, T_STRING);
8509
+ auto encoded =
8510
+ couchbase::utils::string_codec::v2::path_escape(std::string(RSTRING_PTR(data), static_cast<std::size_t>(RSTRING_LEN(data))));
8511
+ return cb_str_new(encoded);
8512
+ }
8513
+
8514
+ static int
8515
+ cb_for_each_form_encode_value(VALUE key, VALUE value, VALUE arg)
8516
+ {
8517
+ auto* values = reinterpret_cast<std::map<std::string, std::string>*>(arg);
8518
+ VALUE key_str = rb_obj_as_string(key);
8519
+ VALUE value_str = rb_obj_as_string(value);
8520
+ values->emplace(std::string(RSTRING_PTR(key_str), static_cast<std::size_t>(RSTRING_LEN(key_str))),
8521
+ std::string(RSTRING_PTR(value_str), static_cast<std::size_t>(RSTRING_LEN(value_str))));
8522
+ return ST_CONTINUE;
8523
+ }
8524
+
8525
+ static VALUE
8526
+ cb_Backend_form_encode(VALUE self, VALUE data)
8527
+ {
8528
+ (void)self;
8529
+ Check_Type(data, T_HASH);
8530
+ std::map<std::string, std::string> values{};
8531
+ rb_hash_foreach(data, INT_FUNC(cb_for_each_form_encode_value), reinterpret_cast<VALUE>(&values));
8532
+ auto encoded = couchbase::utils::string_codec::v2::form_encode(values);
8533
+ return cb_str_new(encoded);
8534
+ }
8535
+
7689
8536
  static void
7690
8537
  init_backend(VALUE mCouchbase)
7691
8538
  {
@@ -7748,10 +8595,10 @@ init_backend(VALUE mCouchbase)
7748
8595
  rb_define_method(cBackend, "collection_drop", VALUE_FUNC(cb_Backend_collection_drop), 4);
7749
8596
 
7750
8597
  rb_define_method(cBackend, "query_index_get_all", VALUE_FUNC(cb_Backend_query_index_get_all), 2);
7751
- rb_define_method(cBackend, "query_index_create", VALUE_FUNC(cb_Backend_query_index_create), 5);
7752
- rb_define_method(cBackend, "query_index_create_primary", VALUE_FUNC(cb_Backend_query_index_create_primary), 3);
7753
- rb_define_method(cBackend, "query_index_drop", VALUE_FUNC(cb_Backend_query_index_drop), 4);
7754
- rb_define_method(cBackend, "query_index_drop_primary", VALUE_FUNC(cb_Backend_query_index_drop_primary), 3);
8598
+ rb_define_method(cBackend, "query_index_create", VALUE_FUNC(cb_Backend_query_index_create), 4);
8599
+ rb_define_method(cBackend, "query_index_create_primary", VALUE_FUNC(cb_Backend_query_index_create_primary), 2);
8600
+ rb_define_method(cBackend, "query_index_drop", VALUE_FUNC(cb_Backend_query_index_drop), 3);
8601
+ rb_define_method(cBackend, "query_index_drop_primary", VALUE_FUNC(cb_Backend_query_index_drop_primary), 2);
7755
8602
  rb_define_method(cBackend, "query_index_build_deferred", VALUE_FUNC(cb_Backend_query_index_build_deferred), 2);
7756
8603
  rb_define_method(cBackend, "query_index_watch", VALUE_FUNC(cb_Backend_query_index_watch), 4);
7757
8604
 
@@ -7771,16 +8618,20 @@ init_backend(VALUE mCouchbase)
7771
8618
  rb_define_method(cBackend, "search_index_analyze_document", VALUE_FUNC(cb_Backend_search_index_analyze_document), 3);
7772
8619
 
7773
8620
  rb_define_method(cBackend, "analytics_get_pending_mutations", VALUE_FUNC(cb_Backend_analytics_get_pending_mutations), 1);
7774
- rb_define_method(cBackend, "analytics_dataverse_drop", VALUE_FUNC(cb_Backend_analytics_dataverse_drop), 3);
7775
- rb_define_method(cBackend, "analytics_dataverse_create", VALUE_FUNC(cb_Backend_analytics_dataverse_create), 3);
7776
- rb_define_method(cBackend, "analytics_dataset_create", VALUE_FUNC(cb_Backend_analytics_dataset_create), 6);
7777
- rb_define_method(cBackend, "analytics_dataset_drop", VALUE_FUNC(cb_Backend_analytics_dataset_drop), 4);
8621
+ rb_define_method(cBackend, "analytics_dataverse_drop", VALUE_FUNC(cb_Backend_analytics_dataverse_drop), 2);
8622
+ rb_define_method(cBackend, "analytics_dataverse_create", VALUE_FUNC(cb_Backend_analytics_dataverse_create), 2);
8623
+ rb_define_method(cBackend, "analytics_dataset_create", VALUE_FUNC(cb_Backend_analytics_dataset_create), 3);
8624
+ rb_define_method(cBackend, "analytics_dataset_drop", VALUE_FUNC(cb_Backend_analytics_dataset_drop), 2);
7778
8625
  rb_define_method(cBackend, "analytics_dataset_get_all", VALUE_FUNC(cb_Backend_analytics_dataset_get_all), 1);
7779
8626
  rb_define_method(cBackend, "analytics_index_get_all", VALUE_FUNC(cb_Backend_analytics_index_get_all), 1);
7780
- rb_define_method(cBackend, "analytics_index_create", VALUE_FUNC(cb_Backend_analytics_index_create), 6);
7781
- rb_define_method(cBackend, "analytics_index_drop", VALUE_FUNC(cb_Backend_analytics_index_drop), 5);
7782
- rb_define_method(cBackend, "analytics_link_connect", VALUE_FUNC(cb_Backend_analytics_link_connect), 4);
7783
- rb_define_method(cBackend, "analytics_link_disconnect", VALUE_FUNC(cb_Backend_analytics_link_disconnect), 3);
8627
+ rb_define_method(cBackend, "analytics_index_create", VALUE_FUNC(cb_Backend_analytics_index_create), 4);
8628
+ rb_define_method(cBackend, "analytics_index_drop", VALUE_FUNC(cb_Backend_analytics_index_drop), 3);
8629
+ rb_define_method(cBackend, "analytics_link_connect", VALUE_FUNC(cb_Backend_analytics_link_connect), 1);
8630
+ rb_define_method(cBackend, "analytics_link_disconnect", VALUE_FUNC(cb_Backend_analytics_link_disconnect), 1);
8631
+ rb_define_method(cBackend, "analytics_link_create", VALUE_FUNC(cb_Backend_analytics_link_create), 2);
8632
+ rb_define_method(cBackend, "analytics_link_replace", VALUE_FUNC(cb_Backend_analytics_link_replace), 2);
8633
+ rb_define_method(cBackend, "analytics_link_drop", VALUE_FUNC(cb_Backend_analytics_link_drop), 3);
8634
+ rb_define_method(cBackend, "analytics_link_get_all", VALUE_FUNC(cb_Backend_analytics_link_get_all), 1);
7784
8635
 
7785
8636
  rb_define_method(cBackend, "view_index_get_all", VALUE_FUNC(cb_Backend_view_index_get_all), 3);
7786
8637
  rb_define_method(cBackend, "view_index_get", VALUE_FUNC(cb_Backend_view_index_get), 4);
@@ -7797,6 +8648,9 @@ init_backend(VALUE mCouchbase)
7797
8648
  rb_define_singleton_method(cBackend, "snappy_uncompress", VALUE_FUNC(cb_Backend_snappy_uncompress), 1);
7798
8649
  rb_define_singleton_method(cBackend, "leb128_encode", VALUE_FUNC(cb_Backend_leb128_encode), 1);
7799
8650
  rb_define_singleton_method(cBackend, "leb128_decode", VALUE_FUNC(cb_Backend_leb128_decode), 1);
8651
+ rb_define_singleton_method(cBackend, "query_escape", VALUE_FUNC(cb_Backend_query_escape), 1);
8652
+ rb_define_singleton_method(cBackend, "path_escape", VALUE_FUNC(cb_Backend_path_escape), 1);
8653
+ rb_define_singleton_method(cBackend, "form_encode", VALUE_FUNC(cb_Backend_form_encode), 1);
7800
8654
  }
7801
8655
 
7802
8656
  void