couchbase 4.2.10 → 4.2.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. package/deps/couchbase-cxx-client/CMakeLists.txt +1 -0
  2. package/deps/couchbase-cxx-client/cmake/ThirdPartyDependencies.cmake +2 -0
  3. package/deps/couchbase-cxx-client/core/bucket.cxx +25 -10
  4. package/deps/couchbase-cxx-client/core/bucket.hxx +1 -0
  5. package/deps/couchbase-cxx-client/core/cluster.cxx +29 -3
  6. package/deps/couchbase-cxx-client/core/impl/collection.cxx +2 -2
  7. package/deps/couchbase-cxx-client/core/impl/query_index_manager.cxx +6 -6
  8. package/deps/couchbase-cxx-client/core/io/http_session_manager.hxx +7 -1
  9. package/deps/couchbase-cxx-client/core/io/mcbp_command.hxx +10 -0
  10. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +35 -1
  11. package/deps/couchbase-cxx-client/core/io/mcbp_session.hxx +2 -0
  12. package/deps/couchbase-cxx-client/core/management/design_document.hxx +1 -1
  13. package/deps/couchbase-cxx-client/core/meta/features.hxx +16 -1
  14. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +1 -1
  15. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +1 -1
  16. package/deps/couchbase-cxx-client/core/operations/document_query.cxx +2 -2
  17. package/deps/couchbase-cxx-client/core/operations/document_search.cxx +10 -10
  18. package/deps/couchbase-cxx-client/core/operations/document_view.cxx +3 -0
  19. package/deps/couchbase-cxx-client/core/operations/document_view.hxx +1 -0
  20. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.cxx +24 -13
  21. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +1 -1
  22. package/deps/couchbase-cxx-client/core/origin.cxx +14 -0
  23. package/deps/couchbase-cxx-client/core/origin.hxx +6 -0
  24. package/deps/couchbase-cxx-client/core/protocol/status.cxx +2 -0
  25. package/deps/couchbase-cxx-client/core/protocol/status.hxx +1 -0
  26. package/deps/couchbase-cxx-client/core/range_scan_load_balancer.cxx +141 -0
  27. package/deps/couchbase-cxx-client/core/range_scan_load_balancer.hxx +64 -0
  28. package/deps/couchbase-cxx-client/core/range_scan_orchestrator.cxx +224 -336
  29. package/deps/couchbase-cxx-client/core/range_scan_orchestrator.hxx +5 -6
  30. package/deps/couchbase-cxx-client/core/range_scan_orchestrator_options.hxx +6 -4
  31. package/deps/couchbase-cxx-client/core/scan_result.hxx +1 -11
  32. package/deps/couchbase-cxx-client/core/topology/capabilities.hxx +70 -1
  33. package/deps/couchbase-cxx-client/core/topology/capabilities_fmt.hxx +30 -2
  34. package/deps/couchbase-cxx-client/core/topology/configuration.hxx +1 -34
  35. package/deps/couchbase-cxx-client/core/topology/configuration_fmt.hxx +2 -2
  36. package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +43 -20
  37. package/deps/couchbase-cxx-client/core/transactions/internal/exceptions_internal.hxx +5 -0
  38. package/deps/couchbase-cxx-client/couchbase/bucket.hxx +2 -2
  39. package/deps/couchbase-cxx-client/couchbase/cluster.hxx +1 -1
  40. package/deps/couchbase-cxx-client/couchbase/collection.hxx +1 -0
  41. package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +80 -11
  42. package/deps/couchbase-cxx-client/couchbase/error_context.hxx +1 -0
  43. package/deps/couchbase-cxx-client/couchbase/fmt/key_value_status_code.hxx +3 -1
  44. package/deps/couchbase-cxx-client/couchbase/get_links_analytics_options.hxx +2 -2
  45. package/deps/couchbase-cxx-client/couchbase/key_value_status_code.hxx +1 -0
  46. package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +6 -8
  47. package/deps/couchbase-cxx-client/couchbase/scope.hxx +1 -1
  48. package/deps/couchbase-cxx-client/couchbase/search_options.hxx +2 -2
  49. package/deps/couchbase-cxx-client/couchbase/search_result.hxx +1 -1
  50. package/deps/couchbase-cxx-client/couchbase/subdocument_error_context.hxx +1 -0
  51. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_options.hxx +1 -1
  52. package/deps/couchbase-cxx-client/couchbase-sdk-cxx-black-duck-manifest.yaml +1 -0
  53. package/dist/binding.d.ts +24 -2
  54. package/dist/bindingutilities.d.ts +11 -3
  55. package/dist/bindingutilities.js +33 -7
  56. package/dist/couchbase.d.ts +1 -0
  57. package/dist/couchbase.js +1 -0
  58. package/dist/queryindexmanager.d.ts +4 -4
  59. package/dist/queryindexmanager.js +7 -7
  60. package/dist/scope.d.ts +21 -0
  61. package/dist/scope.js +34 -0
  62. package/dist/scopesearchindexmanager.d.ts +116 -0
  63. package/dist/scopesearchindexmanager.js +406 -0
  64. package/dist/sdspecs.js +10 -9
  65. package/dist/sdutils.d.ts +1 -0
  66. package/dist/sdutils.js +4 -0
  67. package/dist/searchexecutor.d.ts +3 -1
  68. package/dist/searchexecutor.js +9 -2
  69. package/dist/searchindexmanager.d.ts +58 -3
  70. package/dist/searchindexmanager.js +188 -104
  71. package/dist/viewexecutor.js +13 -9
  72. package/dist/viewindexmanager.d.ts +70 -7
  73. package/dist/viewindexmanager.js +236 -103
  74. package/dist/viewtypes.d.ts +26 -0
  75. package/dist/viewtypes.js +17 -1
  76. package/package.json +7 -7
  77. package/src/constants.cpp +1 -0
  78. package/src/jstocbpp_autogen.hpp +89 -7
  79. package/deps/couchbase-cxx-client/core/scan_options.hxx +0 -44
@@ -360,6 +360,7 @@ set(couchbase_cxx_client_FILES
360
360
  core/protocol/cmd_upsert.cxx
361
361
  core/protocol/frame_info_utils.cxx
362
362
  core/protocol/status.cxx
363
+ core/range_scan_load_balancer.cxx
363
364
  core/range_scan_options.cxx
364
365
  core/range_scan_orchestrator.cxx
365
366
  core/retry_orchestrator.cxx
@@ -1,3 +1,5 @@
1
+ # NOTE: This file MUST be in sync with couchbase-sdk-cxx-black-duck-manifest.yaml
2
+
1
3
  include(cmake/CPM.cmake)
2
4
 
3
5
  # https://cmake.org/cmake/help/v3.28/policy/CMP0063.html
@@ -426,7 +426,7 @@ class bucket_impl
426
426
  }
427
427
  self->update_config(cfg);
428
428
  self->drain_deferred_queue();
429
- self->fetch_config({});
429
+ self->poll_config({});
430
430
  }
431
431
  asio::post(asio::bind_executor(self->ctx_, [h = std::move(h), ec, cfg = std::move(cfg)]() mutable { h(ec, cfg); }));
432
432
  });
@@ -482,15 +482,11 @@ class bucket_impl
482
482
  }
483
483
  }
484
484
 
485
- void fetch_config(std::error_code ec)
485
+ void fetch_config()
486
486
  {
487
- if (ec == asio::error::operation_aborted || closed_) {
488
- return;
489
- }
490
- if (heartbeat_timer_.expiry() > std::chrono::steady_clock::now()) {
487
+ if (closed_) {
491
488
  return;
492
489
  }
493
-
494
490
  std::optional<io::mcbp_session> session{};
495
491
  {
496
492
  std::scoped_lock lock(sessions_mutex_);
@@ -499,7 +495,7 @@ class bucket_impl
499
495
  std::size_t i = start;
500
496
  do {
501
497
  auto ptr = sessions_.find(i % sessions_.size());
502
- if (ptr != sessions_.end() && ptr->second.supports_gcccp()) {
498
+ if (ptr != sessions_.end() && ptr->second.is_bootstrapped() && ptr->second.supports_gcccp()) {
503
499
  session = ptr->second;
504
500
  }
505
501
  i = heartbeat_next_index_.fetch_add(1);
@@ -510,14 +506,27 @@ class bucket_impl
510
506
  req.opaque(session->next_opaque());
511
507
  session->write_and_flush(req.data());
512
508
  } else {
513
- CB_LOG_WARNING(R"({} unable to find session with GCCCP support, retry in {})", log_prefix_, heartbeat_interval_);
509
+ CB_LOG_WARNING(R"({} unable to find connected session with GCCCP support, retry in {})", log_prefix_, heartbeat_interval_);
514
510
  }
511
+ }
512
+
513
+ void poll_config(std::error_code ec)
514
+ {
515
+ if (ec == asio::error::operation_aborted || closed_) {
516
+ return;
517
+ }
518
+ if (heartbeat_timer_.expiry() > std::chrono::steady_clock::now()) {
519
+ return;
520
+ }
521
+
522
+ fetch_config();
523
+
515
524
  heartbeat_timer_.expires_after(heartbeat_interval_);
516
525
  return heartbeat_timer_.async_wait([self = shared_from_this()](std::error_code e) {
517
526
  if (e == asio::error::operation_aborted) {
518
527
  return;
519
528
  }
520
- self->fetch_config(e);
529
+ self->poll_config(e);
521
530
  });
522
531
  }
523
532
 
@@ -880,6 +889,12 @@ bucket::ping(std::shared_ptr<diag::ping_collector> collector, std::optional<std:
880
889
  return impl_->ping(std::move(collector), std::move(timeout));
881
890
  }
882
891
 
892
+ void
893
+ bucket::fetch_config()
894
+ {
895
+ return impl_->fetch_config();
896
+ }
897
+
883
898
  void
884
899
  bucket::update_config(topology::configuration config)
885
900
  {
@@ -177,6 +177,7 @@ class bucket
177
177
  });
178
178
  }
179
179
 
180
+ void fetch_config();
180
181
  void update_config(topology::configuration config) override;
181
182
  void bootstrap(utils::movable_function<void(std::error_code, topology::configuration)>&& handler);
182
183
  void with_configuration(utils::movable_function<void(std::error_code, topology::configuration)>&& handler);
@@ -114,6 +114,26 @@ class ping_collector_impl
114
114
  }
115
115
  };
116
116
 
117
+ template<typename Request>
118
+ constexpr bool
119
+ is_feature_supported(const Request& /* request */, const configuration_capabilities& /* capabilities */)
120
+ {
121
+ return true;
122
+ }
123
+
124
+ constexpr bool
125
+ is_feature_supported(const operations::search_request& request, const configuration_capabilities& capabilities)
126
+ {
127
+ if (request.scope_name && !capabilities.supports_scoped_search_indexes()) {
128
+ return false;
129
+ }
130
+ if (request.vector_search && !capabilities.supports_vector_search()) {
131
+ return false;
132
+ }
133
+
134
+ return true;
135
+ }
136
+
117
137
  class cluster_impl : public std::enable_shared_from_this<cluster_impl>
118
138
  {
119
139
  public:
@@ -238,10 +258,14 @@ class cluster_impl : public std::enable_shared_from_this<cluster_impl>
238
258
  auto ptr = buckets_.find(bucket_name);
239
259
  if (ptr == buckets_.end()) {
240
260
  std::vector<protocol::hello_feature> known_features;
261
+
262
+ auto origin = origin_;
241
263
  if (session_ && session_->has_config()) {
242
264
  known_features = session_->supported_features();
265
+ origin = { origin_, session_->config().value() };
243
266
  }
244
- b = std::make_shared<bucket>(id_, ctx_, tls_, tracer_, meter_, bucket_name, origin_, known_features, dns_srv_tracker_);
267
+
268
+ b = std::make_shared<bucket>(id_, ctx_, tls_, tracer_, meter_, bucket_name, origin, known_features, dns_srv_tracker_);
245
269
  buckets_.try_emplace(bucket_name, b);
246
270
  }
247
271
  }
@@ -326,6 +350,9 @@ class cluster_impl : public std::enable_shared_from_this<cluster_impl>
326
350
  if (stopped_) {
327
351
  return handler(request.make_response({ errc::network::cluster_closed }, response_type{}));
328
352
  }
353
+ if (!is_feature_supported(request, session_manager_->configuration_capabilities())) {
354
+ return handler(request.make_response({ errc::common::feature_not_available }, response_type{}));
355
+ }
329
356
  if constexpr (operations::is_compound_operation_v<Request>) {
330
357
  return request.execute(shared_from_this(), std::forward<Handler>(handler));
331
358
  } else {
@@ -355,8 +382,7 @@ class cluster_impl : public std::enable_shared_from_this<cluster_impl>
355
382
  handler(request.make_response({ ec }, {}));
356
383
  return;
357
384
  }
358
- auto bucket_caps = config.bucket_capabilities;
359
- if (bucket_caps.find(cap) == bucket_caps.end()) {
385
+ if (!config.capabilities.has_bucket_capability(cap)) {
360
386
  handler(request.make_response({ errc::common::feature_not_available }, {}));
361
387
  return;
362
388
  }
@@ -479,7 +479,7 @@ class collection_impl : public std::enable_shared_from_this<collection_impl>
479
479
  bucket_name_,
480
480
  [core = core_, r = std::move(request), h = std::move(handler)](std::error_code ec,
481
481
  const core::topology::configuration& config) mutable {
482
- if (!config.supports_subdoc_read_replica()) {
482
+ if (!config.capabilities.supports_subdoc_read_replica()) {
483
483
  ec = errc::common::feature_not_available;
484
484
  }
485
485
 
@@ -601,7 +601,7 @@ class collection_impl : public std::enable_shared_from_this<collection_impl>
601
601
  bucket_name_,
602
602
  [core = core_, r = std::move(request), h = std::move(handler)](std::error_code ec,
603
603
  const core::topology::configuration& config) mutable {
604
- if (!config.supports_subdoc_read_replica()) {
604
+ if (!config.capabilities.supports_subdoc_read_replica()) {
605
605
  ec = errc::common::feature_not_available;
606
606
  }
607
607
  if (r->specs().size() > 16) {
@@ -215,7 +215,7 @@ class query_index_manager_impl : public std::enable_shared_from_this<query_index
215
215
  const std::string& scope_name,
216
216
  const std::string& collection_name,
217
217
  std::string index_name,
218
- std::vector<std::string> fields,
218
+ std::vector<std::string> keys,
219
219
  const create_query_index_options::built& options,
220
220
  create_query_index_handler&& handler) const
221
221
  {
@@ -225,7 +225,7 @@ class query_index_manager_impl : public std::enable_shared_from_this<query_index
225
225
  scope_name,
226
226
  collection_name,
227
227
  std::move(index_name),
228
- std::move(fields),
228
+ std::move(keys),
229
229
  {},
230
230
  false /* is_primary */,
231
231
  options.ignore_if_exists,
@@ -521,22 +521,22 @@ collection_query_index_manager::get_all_indexes(const get_all_query_indexes_opti
521
521
 
522
522
  void
523
523
  collection_query_index_manager::create_index(std::string index_name,
524
- std::vector<std::string> fields,
524
+ std::vector<std::string> keys,
525
525
  const create_query_index_options& options,
526
526
  create_query_index_handler&& handler) const
527
527
  {
528
528
  return impl_->create_index(
529
- bucket_name_, scope_name_, collection_name_, std::move(index_name), std::move(fields), options.build(), std::move(handler));
529
+ bucket_name_, scope_name_, collection_name_, std::move(index_name), std::move(keys), options.build(), std::move(handler));
530
530
  }
531
531
 
532
532
  auto
533
533
  collection_query_index_manager::create_index(std::string index_name,
534
- std::vector<std::string> fields,
534
+ std::vector<std::string> keys,
535
535
  const create_query_index_options& options) const -> std::future<manager_error_context>
536
536
  {
537
537
  auto barrier = std::make_shared<std::promise<manager_error_context>>();
538
538
  auto future = barrier->get_future();
539
- create_index(std::move(index_name), std::move(fields), options, [barrier](auto ctx) { barrier->set_value(std::move(ctx)); });
539
+ create_index(std::move(index_name), std::move(keys), options, [barrier](auto ctx) { barrier->set_value(std::move(ctx)); });
540
540
  return future;
541
541
  }
542
542
 
@@ -58,6 +58,12 @@ class http_session_manager
58
58
  meter_ = std::move(meter);
59
59
  }
60
60
 
61
+ auto configuration_capabilities() const -> configuration_capabilities
62
+ {
63
+ std::scoped_lock config_lock(config_mutex_);
64
+ return config_.capabilities;
65
+ }
66
+
61
67
  void update_config(topology::configuration config) override
62
68
  {
63
69
  std::scoped_lock config_lock(config_mutex_, sessions_mutex_);
@@ -387,7 +393,7 @@ class http_session_manager
387
393
  cluster_options options_{};
388
394
 
389
395
  topology::configuration config_{};
390
- std::mutex config_mutex_{};
396
+ mutable std::mutex config_mutex_{};
391
397
  std::map<service_type, std::list<std::shared_ptr<http_session>>> busy_sessions_{};
392
398
  std::map<service_type, std::list<std::shared_ptr<http_session>>> idle_sessions_{};
393
399
  std::size_t next_index_{ 0 };
@@ -289,6 +289,16 @@ struct mcbp_command : public std::enable_shared_from_this<mcbp_command<Manager,
289
289
  if (status == key_value_status_code::unknown_collection) {
290
290
  return self->handle_unknown_collection();
291
291
  }
292
+ if (status == key_value_status_code::config_only) {
293
+ CB_LOG_DEBUG(
294
+ "{} server returned status 0x{:02x} ({}) meaning that the node does not serve data operations, requesting new "
295
+ "configuration and retrying",
296
+ self->session_->log_prefix(),
297
+ msg.header.status(),
298
+ status);
299
+ self->manager_->fetch_config();
300
+ return io::retry_orchestrator::maybe_retry(self->manager_, self, retry_reason::service_response_code_indicated, ec);
301
+ }
292
302
  if (error_code && error_code.value().has_retry_attribute()) {
293
303
  reason = retry_reason::key_value_error_map_retry_indicated;
294
304
  } else {
@@ -455,6 +455,16 @@ class mcbp_session_impl
455
455
  case protocol::client_opcode::get_cluster_config: {
456
456
  protocol::cmd_info info{ session_->connection_endpoints_.remote_address,
457
457
  session_->connection_endpoints_.remote.port() };
458
+ if (session_->origin_.options().dump_configuration) {
459
+ std::string_view config_text{ reinterpret_cast<const char*>(msg.body.data()), msg.body.size() };
460
+ CB_LOG_TRACE(
461
+ "{} configuration from get_cluster_config request (bootstrap, size={}, endpoint=\"{}:{}\"), {}",
462
+ session_->log_prefix_,
463
+ config_text.size(),
464
+ info.endpoint_address,
465
+ info.endpoint_port,
466
+ config_text);
467
+ }
458
468
  protocol::client_response<protocol::get_cluster_config_response_body> resp(std::move(msg), info);
459
469
  if (resp.status() == key_value_status_code::success) {
460
470
  session_->update_configuration(resp.body().config());
@@ -860,6 +870,8 @@ class mcbp_session_impl
860
870
  if (stopped_) {
861
871
  return;
862
872
  }
873
+ bootstrapped_ = false;
874
+ bootstrap_handler_ = nullptr;
863
875
  state_ = diag::endpoint_state::connecting;
864
876
  if (stream_->is_open()) {
865
877
  std::string old_id = stream_->id();
@@ -908,6 +920,11 @@ class mcbp_session_impl
908
920
  return stopped_;
909
921
  }
910
922
 
923
+ [[nodiscard]] bool is_bootstrapped() const
924
+ {
925
+ return bootstrapped_;
926
+ }
927
+
911
928
  void on_stop(utils::movable_function<void()> handler)
912
929
  {
913
930
  on_stop_handler_ = std::move(handler);
@@ -1139,6 +1156,11 @@ class mcbp_session_impl
1139
1156
  return supports_gcccp_;
1140
1157
  }
1141
1158
 
1159
+ std::optional<topology::configuration> config() const
1160
+ {
1161
+ return config_;
1162
+ }
1163
+
1142
1164
  [[nodiscard]] bool has_config() const
1143
1165
  {
1144
1166
  return configured_;
@@ -1539,7 +1561,7 @@ class mcbp_session_impl
1539
1561
  CB_LOG_TRACE("{} MCBP recv {}", self->log_prefix_, mcbp_header_view(msg.header_data()));
1540
1562
  if (self->bootstrapped_) {
1541
1563
  self->handler_->handle(std::move(msg));
1542
- } else {
1564
+ } else if (self->bootstrap_handler_) {
1543
1565
  self->bootstrap_handler_->handle(std::move(msg));
1544
1566
  }
1545
1567
  if (self->stopped_) {
@@ -1722,6 +1744,12 @@ mcbp_session::is_stopped() const
1722
1744
  return impl_->is_stopped();
1723
1745
  }
1724
1746
 
1747
+ bool
1748
+ mcbp_session::is_bootstrapped() const
1749
+ {
1750
+ return impl_->is_bootstrapped();
1751
+ }
1752
+
1725
1753
  std::uint32_t
1726
1754
  mcbp_session::next_opaque()
1727
1755
  {
@@ -1818,6 +1846,12 @@ mcbp_session::index() const
1818
1846
  return impl_->index();
1819
1847
  }
1820
1848
 
1849
+ std::optional<topology::configuration>
1850
+ mcbp_session::config() const
1851
+ {
1852
+ return impl_->config();
1853
+ }
1854
+
1821
1855
  bool
1822
1856
  mcbp_session::has_config() const
1823
1857
  {
@@ -97,6 +97,7 @@ class mcbp_session
97
97
  [[nodiscard]] const std::string& log_prefix() const;
98
98
  [[nodiscard]] bool cancel(std::uint32_t opaque, std::error_code ec, retry_reason reason);
99
99
  [[nodiscard]] bool is_stopped() const;
100
+ [[nodiscard]] bool is_bootstrapped() const;
100
101
  [[nodiscard]] std::uint32_t next_opaque();
101
102
  [[nodiscard]] std::optional<std::uint32_t> get_collection_uid(const std::string& collection_path);
102
103
  [[nodiscard]] mcbp_context context() const;
@@ -118,6 +119,7 @@ class mcbp_session
118
119
  void stop(retry_reason reason);
119
120
  [[nodiscard]] std::size_t index() const;
120
121
  [[nodiscard]] bool has_config() const;
122
+ [[nodiscard]] std::optional<topology::configuration> config() const;
121
123
  [[nodiscard]] diag::endpoint_diag_info diag_info() const;
122
124
  void on_configuration_update(std::shared_ptr<config_listener> handler);
123
125
  void ping(std::shared_ptr<diag::ping_reporter> handler, std::optional<std::chrono::milliseconds> = {}) const;
@@ -32,7 +32,7 @@ struct design_document {
32
32
  std::optional<std::string> reduce{};
33
33
  };
34
34
 
35
- std::string rev;
35
+ std::optional<std::string> rev;
36
36
  std::string name;
37
37
  design_document_namespace ns;
38
38
  std::map<std::string, view> views;
@@ -72,7 +72,7 @@
72
72
  */
73
73
  #define COUCHBASE_CXX_CLIENT_HAS_COLLECTION_QUERY_INDEX_MANAGEMENT 1
74
74
 
75
- #define COUCHBASE_CXX_CLIENT_TRANSACTIONS_EXT_PARALLEL_UNSTAGING
75
+ #define COUCHBASE_CXX_CLIENT_TRANSACTIONS_EXT_PARALLEL_UNSTAGING 1
76
76
 
77
77
  /**
78
78
  * core cluster implementation has been hidden and not accessible through the public API
@@ -111,3 +111,18 @@
111
111
  * Scope level search index management is supported via couchbase::scope::search_indexes()
112
112
  */
113
113
  #define COUCHBASE_CXX_CLIENT_HAS_SCOPE_SEARCH_INDEX_MANAGEMENT 1
114
+
115
+ /**
116
+ * Support for couchbase::codec::raw_json_transcoder
117
+ */
118
+ #define COUCHBASE_CXX_CLIENT_HAS_RAW_JSON_TRANSCODER 1
119
+
120
+ /**
121
+ * Support for couchbase::codec::raw_string_transcoder
122
+ */
123
+ #define COUCHBASE_CXX_CLIENT_HAS_RAW_STRING_TRANSCODER 1
124
+
125
+ /**
126
+ * Transaction's transaction_operation_failed has a public getter for its final_error
127
+ */
128
+ #define COUCHBASE_CXX_CLIENT_TRANSACTIONS_CAN_FETCH_TO_RAISE 1
@@ -69,7 +69,7 @@ struct lookup_in_all_replicas_request {
69
69
  id.bucket(),
70
70
  [core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
71
71
  std::error_code ec, const topology::configuration& config) mutable {
72
- if (!config.supports_subdoc_read_replica()) {
72
+ if (!config.capabilities.supports_subdoc_read_replica()) {
73
73
  ec = errc::common::feature_not_available;
74
74
  }
75
75
 
@@ -66,7 +66,7 @@ struct lookup_in_any_replica_request {
66
66
  id.bucket(),
67
67
  [core, id = id, timeout = timeout, specs = specs, parent_span = parent_span, h = std::forward<Handler>(handler)](
68
68
  std::error_code ec, const topology::configuration& config) mutable {
69
- if (!config.supports_subdoc_read_replica()) {
69
+ if (!config.capabilities.supports_subdoc_read_replica()) {
70
70
  ec = errc::common::feature_not_available;
71
71
  }
72
72
  if (specs.size() > 16) {
@@ -47,7 +47,7 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
47
47
  }
48
48
  } else {
49
49
  body["statement"] = "PREPARE " + statement;
50
- if (context.config.supports_enhanced_prepared_statements()) {
50
+ if (context.config.capabilities.supports_enhanced_prepared_statements()) {
51
51
  body["auto_execute"] = true;
52
52
  } else {
53
53
  extract_encoded_plan_ = true;
@@ -87,7 +87,7 @@ query_request::encode_to(query_request::encoded_request_type& encoded, http_cont
87
87
  break;
88
88
  }
89
89
  if (use_replica.has_value()) {
90
- if (context.config.supports_read_from_replica()) {
90
+ if (context.config.capabilities.supports_read_from_replica()) {
91
91
  if (use_replica.value()) {
92
92
  body["use_replica"] = "on";
93
93
  } else {
@@ -36,20 +36,20 @@ search_request::encode_to(search_request::encoded_request_type& encoded, http_co
36
36
  };
37
37
 
38
38
  if (show_request.has_value()) {
39
- body["showrequest"] = show_request.value() ? "true" : "false";
39
+ body["showrequest"] = show_request.value();
40
40
  }
41
41
 
42
42
  if (vector_search.has_value()) {
43
43
  body["knn"] = utils::json::parse(vector_search.value());
44
- }
45
- if (vector_query_combination.has_value()) {
46
- switch (*vector_query_combination) {
47
- case couchbase::core::vector_query_combination::combination_or:
48
- body["knn_operator"] = "or";
49
- break;
50
- case couchbase::core::vector_query_combination::combination_and:
51
- body["knn_operator"] = "and";
52
- break;
44
+ if (vector_query_combination.has_value()) {
45
+ switch (*vector_query_combination) {
46
+ case couchbase::core::vector_query_combination::combination_or:
47
+ body["knn_operator"] = "or";
48
+ break;
49
+ case couchbase::core::vector_query_combination::combination_and:
50
+ body["knn_operator"] = "and";
51
+ break;
52
+ }
53
53
  }
54
54
  }
55
55
 
@@ -77,6 +77,9 @@ document_view_request::encode_to(document_view_request::encoded_request_type& en
77
77
  if (group_level) {
78
78
  query_string.emplace_back(fmt::format("group_level={}", *group_level));
79
79
  }
80
+ if (full_set) {
81
+ query_string.emplace_back(fmt::format("full_set={}", full_set.value() ? "true" : "false"));
82
+ }
80
83
  if (order) {
81
84
  switch (*order) {
82
85
  case couchbase::core::view_sort_order::descending:
@@ -86,6 +86,7 @@ struct document_view_request {
86
86
  std::optional<std::uint32_t> group_level;
87
87
  bool debug{ false };
88
88
  std::map<std::string, std::string> raw{};
89
+ std::optional<bool> full_set;
89
90
 
90
91
  std::optional<couchbase::core::view_sort_order> order;
91
92
  std::optional<couchbase::core::view_on_error> on_error;
@@ -17,7 +17,6 @@
17
17
 
18
18
  #include "query_index_create.hxx"
19
19
 
20
- #include "core/utils/join_strings.hxx"
21
20
  #include "core/utils/json.hxx"
22
21
  #include "core/utils/keyspace.hxx"
23
22
  #include "error_utils.hxx"
@@ -49,19 +48,31 @@ query_index_create_request::encode_to(encoded_request_type& encoded, http_contex
49
48
  if (with) {
50
49
  with_clause = fmt::format("WITH {}", utils::json::generate(with));
51
50
  }
51
+ std::string encoded_keys{};
52
+ for (std::size_t i = 0; i < keys.size(); i++) {
53
+ if (i != 0) {
54
+ encoded_keys += ", ";
55
+ }
56
+ auto key = keys.at(i);
57
+
58
+ // Add backticks around the key unless they are already present
59
+ if (key.at(0) == '`' && key.at(key.size() - 1) == '`') {
60
+ encoded_keys += key;
61
+ } else {
62
+ encoded_keys += fmt::format("`{}`", key);
63
+ }
64
+ }
52
65
  std::string keyspace = utils::build_keyspace(*this);
53
- tao::json::value body{ { "statement",
54
- is_primary ? fmt::format(R"(CREATE PRIMARY INDEX {} ON {} USING GSI {})",
55
- index_name.empty() ? "" : fmt::format("`{}`", index_name),
56
- keyspace,
57
- with_clause)
58
- : fmt::format(R"(CREATE INDEX `{}` ON {}({}) {} USING GSI {})",
59
- index_name,
60
- keyspace,
61
- utils::join_strings(fields, ", "),
62
- where_clause,
63
- with_clause) },
64
- { "client_context_id", encoded.client_context_id } };
66
+ tao::json::value body{
67
+ { "statement",
68
+ is_primary ? fmt::format(R"(CREATE PRIMARY INDEX {} ON {} USING GSI {})",
69
+ index_name.empty() ? "" : fmt::format("`{}`", index_name),
70
+ keyspace,
71
+ with_clause)
72
+ : fmt::format(
73
+ R"(CREATE INDEX `{}` ON {}({}) {} USING GSI {})", index_name, keyspace, encoded_keys, where_clause, with_clause) },
74
+ { "client_context_id", encoded.client_context_id }
75
+ };
65
76
  if (query_ctx.has_value()) {
66
77
  body["query_context"] = query_ctx.value();
67
78
  }
@@ -49,7 +49,7 @@ struct query_index_create_request {
49
49
  std::string scope_name;
50
50
  std::string collection_name;
51
51
  std::string index_name{};
52
- std::vector<std::string> fields;
52
+ std::vector<std::string> keys;
53
53
  query_context query_ctx;
54
54
  bool is_primary{ false };
55
55
  bool ignore_if_exists{ false };
@@ -18,6 +18,7 @@
18
18
  #include "origin.hxx"
19
19
 
20
20
  #include "core/utils/connection_string.hxx"
21
+ #include "topology/configuration.hxx"
21
22
 
22
23
  #include <fmt/chrono.h>
23
24
  #include <fmt/core.h>
@@ -281,6 +282,19 @@ couchbase::core::origin::origin(const couchbase::core::origin& other)
281
282
  , next_node_(nodes_.begin())
282
283
  {
283
284
  }
285
+
286
+ couchbase::core::origin::origin(const origin& other, const topology::configuration& config)
287
+ : origin(other)
288
+ {
289
+ nodes_.clear();
290
+ for (const auto& node : config.nodes) {
291
+ if (auto port = options_.enable_tls ? node.services_tls.key_value : node.services_plain.key_value; port.has_value()) {
292
+ nodes_.emplace_back(node.hostname, std::to_string(port.value()));
293
+ }
294
+ }
295
+ next_node_ = nodes_.begin();
296
+ }
297
+
284
298
  couchbase::core::origin::origin(couchbase::core::cluster_credentials auth,
285
299
  const std::string& hostname,
286
300
  std::uint16_t port,
@@ -40,6 +40,11 @@ struct cluster_credentials {
40
40
  [[nodiscard]] bool uses_certificate() const;
41
41
  };
42
42
 
43
+ namespace topology
44
+ {
45
+ struct configuration;
46
+ }
47
+
43
48
  struct origin {
44
49
  using node_entry = std::pair<std::string, std::string>;
45
50
  using node_list = std::vector<node_entry>;
@@ -49,6 +54,7 @@ struct origin {
49
54
 
50
55
  origin(origin&& other) = default;
51
56
  origin(const origin& other);
57
+ origin(const origin& other, const topology::configuration& config);
52
58
  origin(cluster_credentials auth, const std::string& hostname, std::uint16_t port, cluster_options options);
53
59
  origin(cluster_credentials auth, const std::string& hostname, const std::string& port, cluster_options options);
54
60
  origin(cluster_credentials auth, const utils::connection_string& connstr);
@@ -202,6 +202,8 @@ map_status_code(protocol::client_opcode opcode, std::uint16_t status)
202
202
 
203
203
  case key_value_status_code::unknown:
204
204
  break;
205
+ case key_value_status_code::config_only:
206
+ break;
205
207
  }
206
208
  return errc::network::protocol_error;
207
209
  }
@@ -103,6 +103,7 @@ is_valid_status(std::uint16_t code)
103
103
  case key_value_status_code::range_scan_more:
104
104
  case key_value_status_code::range_scan_complete:
105
105
  case key_value_status_code::range_scan_vb_uuid_not_equal:
106
+ case key_value_status_code::config_only:
106
107
  return true;
107
108
  case key_value_status_code::unknown:
108
109
  return false;